Compare commits
210 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e33c727e8b | ||
|
|
f886b3fb2b | ||
|
|
b1cc15e85b | ||
|
|
3aa765e429 | ||
|
|
93d084a1d1 | ||
|
|
c7a3e09407 | ||
|
|
09525c7530 | ||
|
|
a7e15fe73c | ||
|
|
a31c27c7cf | ||
|
|
1caf7c7bd2 | ||
|
|
0eb0c9b388 | ||
|
|
7dc61cdc89 | ||
|
|
af1b2f30c9 | ||
|
|
37b4fc7e31 | ||
|
|
da85d102e3 | ||
|
|
35fe1092d3 | ||
|
|
f2d486e771 | ||
|
|
fee677786e | ||
|
|
aa83ecdb3b | ||
|
|
a153176469 | ||
|
|
1c6384b6a5 | ||
|
|
e8db526f51 | ||
|
|
fa13ed4391 | ||
|
|
23f0dca992 | ||
|
|
45ab3b51d8 | ||
|
|
49670d216b | ||
|
|
e2237d8cd2 | ||
|
|
91f078fe35 | ||
|
|
a546cb881d | ||
|
|
84d5dffd9f | ||
|
|
a8e286f7e1 | ||
|
|
9b05494ebc | ||
|
|
30ef20a208 | ||
|
|
a4002ef467 | ||
|
|
9d758a216b | ||
|
|
af13f8dd2c | ||
|
|
88423f2574 | ||
|
|
ee632a5519 | ||
|
|
dfe47bcc42 | ||
|
|
6d3dcaa59e | ||
|
|
1bc0df1569 | ||
|
|
a98ba994bd | ||
|
|
cd671221c5 | ||
|
|
bce3919748 | ||
|
|
61b66e83f1 | ||
|
|
a5db8cd14c | ||
|
|
2021c2fa3e | ||
|
|
484d3fd8c7 | ||
|
|
3bf8699f95 | ||
|
|
58c24f8007 | ||
|
|
e61bc34eb1 | ||
|
|
8b2cfd45fa | ||
|
|
ae9f56be10 | ||
|
|
9aed0e3a73 | ||
|
|
88850a6e05 | ||
|
|
9e881407bd | ||
|
|
3188db7b90 | ||
|
|
a82ca62b66 | ||
|
|
e9465717ab | ||
|
|
e89031f1af | ||
|
|
596fad182e | ||
|
|
ed69adedcd | ||
|
|
1dbf7d4a3a | ||
|
|
2a9d0fc6fb | ||
|
|
45db96679e | ||
|
|
1d15f51238 | ||
|
|
ed7c82fa5e | ||
|
|
3b273cecac | ||
|
|
d764b6cc3b | ||
|
|
08c4729eb4 | ||
|
|
5561d3e7f3 | ||
|
|
491d6ce1d5 | ||
|
|
cd55eeb77c | ||
|
|
3230952d57 | ||
|
|
df3bb8028a | ||
|
|
28b7b15da1 | ||
|
|
aa37b19698 | ||
|
|
02e889e449 | ||
|
|
486ce00b8e | ||
|
|
eb481cee8c | ||
|
|
fbc9d8009b | ||
|
|
04fd3d90f8 | ||
|
|
a489f8cb5e | ||
|
|
e2e4b7fb37 | ||
|
|
c97ad98f92 | ||
|
|
b24eb22c6b | ||
|
|
06ba4e2ce8 | ||
|
|
0eb4577a82 | ||
|
|
43498769f0 | ||
|
|
60c0bc1e6b | ||
|
|
6a5c63e1e3 | ||
|
|
d47ea77811 | ||
|
|
7840746bd9 | ||
|
|
49ea629f3f | ||
|
|
13c72a986c | ||
|
|
08af3eae44 | ||
|
|
27bdcbbd83 | ||
|
|
2c4d7d66ef | ||
|
|
d1cc5270a3 | ||
|
|
75c5b6029b | ||
|
|
fa14a9cfcd | ||
|
|
aeb9ea5ac2 | ||
|
|
798841be82 | ||
|
|
cc6eb4b15f | ||
|
|
14eee81dc6 | ||
|
|
55ebb27878 | ||
|
|
87046410ef | ||
|
|
f9b3198714 | ||
|
|
48b62393a4 | ||
|
|
a00f8dade7 | ||
|
|
9daa2fb6f5 | ||
|
|
8d81d264f4 | ||
|
|
5ef7060098 | ||
|
|
938368ba21 | ||
|
|
fe2f1965d6 | ||
|
|
30ed8f5580 | ||
|
|
dc9e7cd1fe | ||
|
|
76f40e2528 | ||
|
|
8024f7f7a8 | ||
|
|
eb7fa25270 | ||
|
|
ee7647dc67 | ||
|
|
bd2f53bc8b | ||
|
|
e8a7956b6f | ||
|
|
2b24dc25fb | ||
|
|
35cc5aa06f | ||
|
|
c1dd49e075 | ||
|
|
c76ee4b868 | ||
|
|
e23bf48052 | ||
|
|
7e0ad232b0 | ||
|
|
63adfb1590 | ||
|
|
f9806b43c3 | ||
|
|
c4c9c6d37d | ||
|
|
33f3b0c1d9 | ||
|
|
abb8ae02a5 | ||
|
|
97728c4f0b | ||
|
|
f74b7f7401 | ||
|
|
b06fd8a933 | ||
|
|
1bb0804d60 | ||
|
|
998245ffd6 | ||
|
|
7a033bb825 | ||
|
|
a441b00951 | ||
|
|
88985a46ed | ||
|
|
34ead0430b | ||
|
|
66ab2df97f | ||
|
|
b656f7c083 | ||
|
|
873db281e8 | ||
|
|
6bf1486935 | ||
|
|
ffa1943177 | ||
|
|
ac429dc8e1 | ||
|
|
3766d5c962 | ||
|
|
20f9a1d908 | ||
|
|
dcb74f558e | ||
|
|
0794aaa2c2 | ||
|
|
74801de315 | ||
|
|
f80d5b8c9e | ||
|
|
d900006973 | ||
|
|
39f849590b | ||
|
|
818738beec | ||
|
|
bc2a4a3bb8 | ||
|
|
a4a8ccea8c | ||
|
|
36dcfa3e82 | ||
|
|
94f33570e3 | ||
|
|
44d6912a55 | ||
|
|
3a4497a1c3 | ||
|
|
3ee13cae02 | ||
|
|
99cf3a38c5 | ||
|
|
3ae24329eb | ||
|
|
01b13d797c | ||
|
|
306e8e9873 | ||
|
|
9577c8c1b7 | ||
|
|
925a0ca1a0 | ||
|
|
b694bfa351 | ||
|
|
a2fc32c64b | ||
|
|
88504ab869 | ||
|
|
e38754e802 | ||
|
|
eb6f32bfc3 | ||
|
|
f110601fb4 | ||
|
|
2a508c6e5f | ||
|
|
fd6144d95b | ||
|
|
60d4e7b09f | ||
|
|
b38838c6bf | ||
|
|
708973e51d | ||
|
|
dac9e69f9e | ||
|
|
39aa33749b | ||
|
|
da68ec6e19 | ||
|
|
15a3ebd467 | ||
|
|
9110fac9a2 | ||
|
|
83f42ede36 | ||
|
|
0ce71bbec0 | ||
|
|
46d142cbf6 | ||
|
|
38c3bcf9a0 | ||
|
|
6e9afdc94f | ||
|
|
c4d28e3b2a | ||
|
|
77261e1ee0 | ||
|
|
903a5df9a5 | ||
|
|
c810ecd081 | ||
|
|
dce9dfce0e | ||
|
|
3d72663689 | ||
|
|
a2b16e89a4 | ||
|
|
b35f4c5a83 | ||
|
|
41eb4f1725 | ||
|
|
94bc221669 | ||
|
|
822d298a55 | ||
|
|
273c6020ba | ||
|
|
1b07f64057 | ||
|
|
80d9c44b22 | ||
|
|
dc0cd088cf | ||
|
|
c69c026728 | ||
|
|
b5f4e1187f | ||
|
|
827bcec186 |
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@@ -1,31 +1,48 @@
|
||||
name: CI
|
||||
on: [ push, pull_request ]
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [ master ]
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
node: [ "0.10", "0.12", 4, 6, 8, 10, latest ]
|
||||
node: [ "0.8", "0.10", "0.12", "4", "6", "8", "10", "12", latest ]
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
script: [ compress, mocha, release/benchmark, release/jetstream ]
|
||||
exclude:
|
||||
- node: "0.8"
|
||||
script: release/benchmark
|
||||
- node: "0.8"
|
||||
script: release/jetstream
|
||||
name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
NODE: ${{ matrix.node }}
|
||||
TYPE: ${{ matrix.script }}
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/cache@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: tmp
|
||||
key: tmp ${{ matrix.script }}
|
||||
- name: Perform tests
|
||||
shell: bash
|
||||
run: |
|
||||
git clone --branch v1.5.3 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add $NODE && nvs use $NODE'; do
|
||||
cd ~/.nvs
|
||||
while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done
|
||||
cd -
|
||||
done
|
||||
. ~/.nvs/nvs.sh --version
|
||||
nvs add $NODE
|
||||
nvs use $NODE
|
||||
node --version
|
||||
npm --version --no-update-notifier
|
||||
npm install --no-audit --no-optional --no-save --no-update-notifier
|
||||
npm config set audit false
|
||||
npm config set optional false
|
||||
npm config set save false
|
||||
npm config set strict-ssl false
|
||||
npm config set update-notifier false
|
||||
npm --version
|
||||
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
||||
node test/$TYPE
|
||||
|
||||
38
.github/workflows/ufuzz.yml
vendored
38
.github/workflows/ufuzz.yml
vendored
@@ -1,7 +1,12 @@
|
||||
name: Fuzzing
|
||||
on:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: "*/15 * * * *"
|
||||
- cron: "*/5 * * * *"
|
||||
env:
|
||||
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
||||
CAUSE: ${{ github.event_name }}
|
||||
TOKEN: ${{ github.token }}
|
||||
jobs:
|
||||
ufuzz:
|
||||
strategy:
|
||||
@@ -11,15 +16,32 @@ jobs:
|
||||
name: ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: Perform fuzzing
|
||||
shell: bash
|
||||
run: |
|
||||
git clone --branch v1.5.3 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add 8 && nvs use 8'; do
|
||||
cd ~/.nvs
|
||||
while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done
|
||||
cd -
|
||||
done
|
||||
. ~/.nvs/nvs.sh --version
|
||||
nvs add 10
|
||||
nvs use 10
|
||||
nvs use 8
|
||||
node --version
|
||||
npm --version --no-update-notifier
|
||||
npm install --no-audit --no-optional --no-save --no-update-notifier
|
||||
node test/ufuzz/job 3600000
|
||||
npm config set audit false
|
||||
npm config set optional false
|
||||
npm config set save false
|
||||
npm config set strict-ssl false
|
||||
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..."
|
||||
else
|
||||
node test/ufuzz/job $PERIOD
|
||||
fi
|
||||
|
||||
52
README.md
52
README.md
@@ -4,8 +4,8 @@ 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/UglifyJS2/tree/v2.x)**.
|
||||
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
||||
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage) that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/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/).
|
||||
|
||||
@@ -126,6 +126,7 @@ a double dash to prevent input files being used as option arguments:
|
||||
`includeSources` Pass this flag if you want to include
|
||||
the content of source files in the
|
||||
source map as sourcesContent property.
|
||||
`names` Include symbol names in the source map.
|
||||
`root` Path to the original source to be included in
|
||||
the source map.
|
||||
`url` If specified, path to the source map to append in
|
||||
@@ -159,6 +160,9 @@ Additional options:
|
||||
|
||||
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
|
||||
|
||||
- `--source-map "names=false"` to omit symbol names if you want to reduce size
|
||||
of the source map file.
|
||||
|
||||
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
|
||||
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
|
||||
`//# sourceMappingURL=` directive.
|
||||
@@ -208,17 +212,16 @@ Example:
|
||||
To enable the mangler you need to pass `--mangle` (`-m`). The following
|
||||
(comma-separated) options are supported:
|
||||
|
||||
- `toplevel` (default `false`) -- mangle names declared in the top level scope.
|
||||
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or
|
||||
`with` are used.
|
||||
|
||||
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or `with` are used.
|
||||
- `reserved` (default: `[]`) -- when mangling is enabled but you want to
|
||||
prevent certain names from being mangled, you can declare those names with
|
||||
`--mangle reserved` — pass a comma-separated list of names. For example:
|
||||
|
||||
When mangling is enabled but you want to prevent certain names from being
|
||||
mangled, you can declare those names with `--mangle reserved` — pass a
|
||||
comma-separated list of names. For example:
|
||||
uglifyjs ... -m reserved=['$','require','exports']
|
||||
|
||||
uglifyjs ... -m reserved=['$','require','exports']
|
||||
|
||||
to prevent the `require`, `exports` and `$` names from being changed.
|
||||
to prevent the `require`, `exports` and `$` names from being changed.
|
||||
|
||||
### CLI mangling property names (`--mangle-props`)
|
||||
|
||||
@@ -593,6 +596,9 @@ var result = UglifyJS.minify({"compiled.js": "compiled code"}, {
|
||||
|
||||
If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.url`.
|
||||
|
||||
If you wish to reduce file size of the source map, set option `sourceMap.names`
|
||||
to be `false` and all symbol names will be omitted.
|
||||
|
||||
## Parse options
|
||||
|
||||
- `bare_returns` (default `false`) -- support top level `return` statements
|
||||
@@ -650,8 +656,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
- `hoist_props` (default: `true`) -- hoist properties from constant object and
|
||||
array literals into regular variables subject to a set of constraints. For example:
|
||||
`var o={p:1, q:2}; f(o.p, o.q);` is converted to `f(1, 2);`. Note: `hoist_props`
|
||||
works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher,
|
||||
and the `compress` option `toplevel` enabled.
|
||||
works best with `toplevel` and `mangle` enabled, alongside with `compress` option
|
||||
`passes` set to `2` or higher.
|
||||
|
||||
- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
|
||||
by default because it seems to increase the size of the output in general)
|
||||
@@ -906,7 +912,7 @@ can pass additional arguments that control the code output:
|
||||
|
||||
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
|
||||
function expressions. See
|
||||
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
|
||||
[#640](https://github.com/mishoo/UglifyJS/issues/640) for more details.
|
||||
|
||||
# Miscellaneous
|
||||
|
||||
@@ -1065,8 +1071,8 @@ var result = UglifyJS.minify(ast, {
|
||||
### Working with Uglify AST
|
||||
|
||||
Transversal and transformation of the native AST can be performed through
|
||||
[`TreeWalker`](https://github.com/mishoo/UglifyJS2/blob/master/lib/ast.js) and
|
||||
[`TreeTransformer`](https://github.com/mishoo/UglifyJS2/blob/master/lib/transform.js)
|
||||
[`TreeWalker`](https://github.com/mishoo/UglifyJS/blob/master/lib/ast.js) and
|
||||
[`TreeTransformer`](https://github.com/mishoo/UglifyJS/blob/master/lib/transform.js)
|
||||
respectively.
|
||||
|
||||
### ESTree / SpiderMonkey AST
|
||||
@@ -1150,3 +1156,19 @@ 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()`).
|
||||
- When `toplevel` is enabled, UglifyJS effectively assumes input code is wrapped
|
||||
within `function(){ ... }`, thus forbids aliasing of declared global variables:
|
||||
```js
|
||||
A = "FAIL";
|
||||
var B = "FAIL";
|
||||
// can be `global`, `self`, `window` etc.
|
||||
var top = function() {
|
||||
return this;
|
||||
}();
|
||||
// "PASS"
|
||||
top.A = "PASS";
|
||||
console.log(A);
|
||||
// "FAIL" after compress and/or mangle
|
||||
top.B = "PASS";
|
||||
console.log(B);
|
||||
```
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
build: off
|
||||
matrix:
|
||||
fast_finish: true
|
||||
test_script:
|
||||
- echo No longer in use
|
||||
478
bin/uglifyjs
478
bin/uglifyjs
@@ -8,166 +8,252 @@ require("../tools/exit");
|
||||
var fs = require("fs");
|
||||
var info = require("../package.json");
|
||||
var path = require("path");
|
||||
var program = require("commander");
|
||||
var UglifyJS = require("../tools/node");
|
||||
|
||||
var skip_keys = [ "cname", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ];
|
||||
var files = {};
|
||||
var options = {
|
||||
compress: false,
|
||||
mangle: false
|
||||
var options = {};
|
||||
var short_forms = {
|
||||
b: "beautify",
|
||||
c: "compress",
|
||||
d: "define",
|
||||
e: "enclose",
|
||||
h: "help",
|
||||
m: "mangle",
|
||||
o: "output",
|
||||
O: "output-opts",
|
||||
p: "parse",
|
||||
v: "version",
|
||||
V: "version",
|
||||
};
|
||||
program.version(info.name + " " + info.version);
|
||||
program.parseArgv = program.parse;
|
||||
program.parse = undefined;
|
||||
if (process.argv.indexOf("ast") >= 0) program.helpInformation = UglifyJS.describe_ast;
|
||||
else if (process.argv.indexOf("options") >= 0) program.helpInformation = function() {
|
||||
var text = [];
|
||||
var options = UglifyJS.default_options();
|
||||
for (var option in options) {
|
||||
text.push("--" + (option == "output" ? "beautify" : option == "sourceMap" ? "source-map" : option) + " options:");
|
||||
text.push(format_object(options[option]));
|
||||
text.push("");
|
||||
var args = process.argv.slice(2);
|
||||
var paths = [];
|
||||
var output, nameCache;
|
||||
var specified = {};
|
||||
while (args.length) {
|
||||
var arg = args.shift();
|
||||
if (arg[0] != "-") {
|
||||
paths.push(arg);
|
||||
} else if (arg == "--") {
|
||||
paths = paths.concat(args);
|
||||
break;
|
||||
} else if (arg[1] == "-") {
|
||||
process_option(arg.slice(2));
|
||||
} else [].forEach.call(arg.slice(1), function(letter, index, arg) {
|
||||
if (!(letter in short_forms)) fatal("invalid option -" + letter);
|
||||
process_option(short_forms[letter], index + 1 < arg.length);
|
||||
});
|
||||
}
|
||||
|
||||
function process_option(name, no_value) {
|
||||
specified[name] = true;
|
||||
switch (name) {
|
||||
case "help":
|
||||
switch (read_value()) {
|
||||
case "ast":
|
||||
print(UglifyJS.describe_ast());
|
||||
break;
|
||||
case "options":
|
||||
var text = [];
|
||||
var toplevels = [];
|
||||
var padding = "";
|
||||
var defaults = UglifyJS.default_options();
|
||||
for (var name in defaults) {
|
||||
var option = defaults[name];
|
||||
if (option && typeof option == "object") {
|
||||
text.push("--" + ({
|
||||
output: "beautify",
|
||||
sourceMap: "source-map",
|
||||
}[name] || name) + " options:");
|
||||
text.push(format_object(option));
|
||||
text.push("");
|
||||
} else {
|
||||
if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
|
||||
toplevels.push([ {
|
||||
keep_fnames: "keep-fnames",
|
||||
nameCache: "name-cache",
|
||||
}[name] || name, option ]);
|
||||
}
|
||||
}
|
||||
toplevels.forEach(function(tokens) {
|
||||
text.push("--" + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
|
||||
});
|
||||
print(text.join("\n"));
|
||||
break;
|
||||
default:
|
||||
print([
|
||||
"Usage: uglifyjs [files...] [options]",
|
||||
"",
|
||||
"Options:",
|
||||
" -h, --help Print usage information.",
|
||||
" `--help options` for details on available options.",
|
||||
" -v, -V, --version Print version number.",
|
||||
" -p, --parse <options> Specify parser options.",
|
||||
" -c, --compress [options] Enable compressor/specify compressor options.",
|
||||
" -m, --mangle [options] Mangle names/specify mangler options.",
|
||||
" --mangle-props [options] Mangle properties/specify mangler options.",
|
||||
" -b, --beautify [options] Beautify output/specify output options.",
|
||||
" -O, --output-opts <options> Output options (beautify disabled).",
|
||||
" -o, --output <file> Output file (default STDOUT).",
|
||||
" --comments [filter] Preserve copyright comments in the output.",
|
||||
" --config-file <file> Read minify() options from JSON file.",
|
||||
" -d, --define <expr>[=value] Global definitions.",
|
||||
" -e, --enclose [arg[,...][:value[,...]]] Embed everything in a big function, with configurable argument(s) & value(s).",
|
||||
" --ie8 Support non-standard Internet Explorer 8.",
|
||||
" --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
|
||||
" --name-cache <file> File to hold mangled name mappings.",
|
||||
" --rename Force symbol expansion.",
|
||||
" --no-rename Disable symbol expansion.",
|
||||
" --self Build UglifyJS as a library (implies --wrap UglifyJS)",
|
||||
" --source-map [options] Enable source map/specify source map options.",
|
||||
" --timings Display operations run time on STDERR.",
|
||||
" --toplevel Compress and/or mangle variables in toplevel scope.",
|
||||
" --validate Perform validation during AST manipulations.",
|
||||
" --verbose Print diagnostic messages.",
|
||||
" --warn Print warning messages.",
|
||||
" --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"));
|
||||
}
|
||||
process.exit();
|
||||
case "version":
|
||||
print(info.name + " " + info.version);
|
||||
process.exit();
|
||||
case "config-file":
|
||||
var config = JSON.parse(read_file(read_value(true)));
|
||||
if (config.mangle && config.mangle.properties && config.mangle.properties.regex) {
|
||||
config.mangle.properties.regex = UglifyJS.parse(config.mangle.properties.regex, {
|
||||
expression: true,
|
||||
}).value;
|
||||
}
|
||||
for (var key in config) if (!(key in options)) options[key] = config[key];
|
||||
break;
|
||||
case "compress":
|
||||
case "mangle":
|
||||
options[name] = parse_js(read_value(), options[name]);
|
||||
break;
|
||||
case "source-map":
|
||||
options.sourceMap = parse_js(read_value(), options.sourceMap);
|
||||
break;
|
||||
case "enclose":
|
||||
options[name] = read_value();
|
||||
break;
|
||||
case "ie8":
|
||||
case "timings":
|
||||
case "toplevel":
|
||||
case "validate":
|
||||
options[name] = true;
|
||||
break;
|
||||
case "keep-fnames":
|
||||
options.keep_fnames = true;
|
||||
break;
|
||||
case "wrap":
|
||||
options[name] = read_value(true);
|
||||
break;
|
||||
case "verbose":
|
||||
options.warnings = "verbose";
|
||||
break;
|
||||
case "warn":
|
||||
if (!options.warnings) options.warnings = true;
|
||||
break;
|
||||
case "beautify":
|
||||
options.output = parse_js(read_value(), options.output);
|
||||
if (!("beautify" in options.output)) options.output.beautify = true;
|
||||
break;
|
||||
case "output-opts":
|
||||
options.output = parse_js(read_value(true), options.output);
|
||||
break;
|
||||
case "comments":
|
||||
if (typeof options.output != "object") options.output = {};
|
||||
options.output.comments = read_value();
|
||||
if (options.output.comments === true) options.output.comments = "some";
|
||||
break;
|
||||
case "define":
|
||||
if (typeof options.compress != "object") options.compress = {};
|
||||
options.compress.global_defs = parse_js(read_value(true), options.compress.global_defs, "define");
|
||||
break;
|
||||
case "mangle-props":
|
||||
if (typeof options.mangle != "object") options.mangle = {};
|
||||
options.mangle.properties = parse_js(read_value(), options.mangle.properties);
|
||||
break;
|
||||
case "name-cache":
|
||||
nameCache = read_value(true);
|
||||
options.nameCache = JSON.parse(read_file(nameCache, "{}"));
|
||||
break;
|
||||
case "output":
|
||||
output = read_value(true);
|
||||
break;
|
||||
case "parse":
|
||||
options.parse = parse_js(read_value(true), options.parse);
|
||||
break;
|
||||
case "rename":
|
||||
options.rename = true;
|
||||
break;
|
||||
case "no-rename":
|
||||
options.rename = false;
|
||||
break;
|
||||
case "reduce-test":
|
||||
case "self":
|
||||
break;
|
||||
default:
|
||||
fatal("invalid option --" + name);
|
||||
}
|
||||
return text.join("\n");
|
||||
};
|
||||
program.option("-p, --parse <options>", "Specify parser options.", parse_js());
|
||||
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js());
|
||||
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
|
||||
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
|
||||
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js());
|
||||
program.option("-O, --output-opts [options]", "Output options (beautify disabled).", parse_js());
|
||||
program.option("-o, --output <file>", "Output file (default STDOUT).");
|
||||
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
||||
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
||||
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
|
||||
program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed everything in a big function, with configurable argument(s) & value(s).");
|
||||
program.option("--ie8", "Support non-standard Internet Explorer 8.");
|
||||
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
|
||||
program.option("--name-cache <file>", "File to hold mangled name mappings.");
|
||||
program.option("--rename", "Force symbol expansion.");
|
||||
program.option("--no-rename", "Disable symbol expansion.");
|
||||
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
|
||||
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js());
|
||||
program.option("--timings", "Display operations run time on STDERR.");
|
||||
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
|
||||
program.option("--verbose", "Print diagnostic messages.");
|
||||
program.option("--warn", "Print warning messages.");
|
||||
program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally.");
|
||||
program.option("--reduce-test", "Reduce a standalone `console.log` based test case.");
|
||||
program.arguments("[files...]").parseArgv(process.argv);
|
||||
if (program.configFile) {
|
||||
options = JSON.parse(read_file(program.configFile));
|
||||
if (options.mangle && options.mangle.properties && options.mangle.properties.regex) {
|
||||
options.mangle.properties.regex = UglifyJS.parse(options.mangle.properties.regex, {
|
||||
expression: true
|
||||
}).value;
|
||||
|
||||
function read_value(required) {
|
||||
if (no_value || !args.length || args[0][0] == "-") {
|
||||
if (required) fatal("missing option argument for --" + name);
|
||||
return true;
|
||||
}
|
||||
return args.shift();
|
||||
}
|
||||
}
|
||||
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
|
||||
fatal("cannot write source map to STDOUT");
|
||||
}
|
||||
[
|
||||
"compress",
|
||||
"enclose",
|
||||
"ie8",
|
||||
"mangle",
|
||||
"sourceMap",
|
||||
"toplevel",
|
||||
"wrap"
|
||||
].forEach(function(name) {
|
||||
if (name in program) {
|
||||
options[name] = program[name];
|
||||
}
|
||||
if (!output && options.sourceMap && options.sourceMap.url != "inline") fatal("cannot write source map to STDOUT");
|
||||
if (specified["beautify"] && specified["output-opts"]) fatal("--beautify cannot be used with --output-opts");
|
||||
[ "compress", "mangle" ].forEach(function(name) {
|
||||
if (!(name in options)) options[name] = false;
|
||||
});
|
||||
if (program.verbose) {
|
||||
options.warnings = "verbose";
|
||||
} else if (program.warn) {
|
||||
options.warnings = true;
|
||||
if (options.mangle && options.mangle.properties) {
|
||||
if (options.mangle.properties.domprops) {
|
||||
delete options.mangle.properties.domprops;
|
||||
} else {
|
||||
if (typeof options.mangle.properties != "object") options.mangle.properties = {};
|
||||
if (!Array.isArray(options.mangle.properties.reserved)) options.mangle.properties.reserved = [];
|
||||
require("../tools/domprops").forEach(function(name) {
|
||||
UglifyJS.push_uniq(options.mangle.properties.reserved, name);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (output == "ast") options.output = {
|
||||
ast: true,
|
||||
code: false,
|
||||
};
|
||||
if (options.parse && (options.parse.acorn || options.parse.spidermonkey)
|
||||
&& options.sourceMap && options.sourceMap.content == "inline") {
|
||||
fatal("inline source map only works with built-in parser");
|
||||
}
|
||||
if (options.warnings) {
|
||||
UglifyJS.AST_Node.log_function(print_error, options.warnings == "verbose");
|
||||
delete options.warnings;
|
||||
}
|
||||
if (program.beautify) {
|
||||
options.output = typeof program.beautify == "object" ? program.beautify : {};
|
||||
if (!("beautify" in options.output)) {
|
||||
options.output.beautify = true;
|
||||
}
|
||||
}
|
||||
if (program.outputOpts) {
|
||||
if (program.beautify) fatal("--beautify cannot be used with --output-opts");
|
||||
options.output = typeof program.outputOpts == "object" ? program.outputOpts : {};
|
||||
}
|
||||
if (program.comments) {
|
||||
if (typeof options.output != "object") options.output = {};
|
||||
options.output.comments = typeof program.comments == "string" ? program.comments : "some";
|
||||
}
|
||||
if (program.define) {
|
||||
if (typeof options.compress != "object") options.compress = {};
|
||||
if (typeof options.compress.global_defs != "object") options.compress.global_defs = {};
|
||||
for (var expr in program.define) {
|
||||
options.compress.global_defs[expr] = program.define[expr];
|
||||
}
|
||||
}
|
||||
if (program.keepFnames) {
|
||||
options.keep_fnames = true;
|
||||
}
|
||||
if (program.mangleProps) {
|
||||
if (program.mangleProps.domprops) {
|
||||
delete program.mangleProps.domprops;
|
||||
} else {
|
||||
if (typeof program.mangleProps != "object") program.mangleProps = {};
|
||||
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
|
||||
require("../tools/domprops").forEach(function(name) {
|
||||
UglifyJS.push_uniq(program.mangleProps.reserved, name);
|
||||
});
|
||||
}
|
||||
if (typeof options.mangle != "object") options.mangle = {};
|
||||
options.mangle.properties = program.mangleProps;
|
||||
}
|
||||
if (program.nameCache) {
|
||||
options.nameCache = JSON.parse(read_file(program.nameCache, "{}"));
|
||||
}
|
||||
if (program.output == "ast") {
|
||||
options.output = {
|
||||
ast: true,
|
||||
code: false
|
||||
};
|
||||
}
|
||||
if (program.parse) {
|
||||
if (!program.parse.acorn && !program.parse.spidermonkey) {
|
||||
options.parse = program.parse;
|
||||
} else if (program.sourceMap && program.sourceMap.content == "inline") {
|
||||
fatal("inline source map only works with built-in parser");
|
||||
}
|
||||
}
|
||||
if (~program.rawArgs.indexOf("--rename")) {
|
||||
options.rename = true;
|
||||
} else if (!program.rename) {
|
||||
options.rename = false;
|
||||
}
|
||||
var convert_path = function(name) {
|
||||
return name;
|
||||
};
|
||||
if (typeof program.sourceMap == "object" && "base" in program.sourceMap) {
|
||||
if (typeof options.sourceMap == "object" && "base" in options.sourceMap) {
|
||||
convert_path = function() {
|
||||
var base = program.sourceMap.base;
|
||||
var base = options.sourceMap.base;
|
||||
delete options.sourceMap.base;
|
||||
return function(name) {
|
||||
return path.relative(base, name);
|
||||
};
|
||||
}();
|
||||
}
|
||||
if (program.self) {
|
||||
if (program.args.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
|
||||
if (specified["self"]) {
|
||||
if (paths.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
|
||||
if (!options.wrap) options.wrap = "UglifyJS";
|
||||
simple_glob(UglifyJS.FILES).forEach(function(name) {
|
||||
files[convert_path(name)] = read_file(name);
|
||||
});
|
||||
run();
|
||||
} else if (program.args.length) {
|
||||
simple_glob(program.args).forEach(function(name) {
|
||||
paths = UglifyJS.FILES;
|
||||
}
|
||||
if (paths.length) {
|
||||
simple_glob(paths).forEach(function(name) {
|
||||
files[convert_path(name)] = read_file(name);
|
||||
});
|
||||
run();
|
||||
@@ -188,15 +274,14 @@ function convert_ast(fn) {
|
||||
}
|
||||
|
||||
function run() {
|
||||
var content = program.sourceMap && program.sourceMap.content;
|
||||
var content = options.sourceMap && options.sourceMap.content;
|
||||
if (content && content != "inline") {
|
||||
UglifyJS.AST_Node.info("Using input source map: " + content);
|
||||
options.sourceMap.content = read_file(content, content);
|
||||
}
|
||||
if (program.timings) options.timings = true;
|
||||
try {
|
||||
if (program.parse) {
|
||||
if (program.parse.acorn) {
|
||||
if (options.parse) {
|
||||
if (options.parse.acorn) {
|
||||
files = convert_ast(function(toplevel, name) {
|
||||
return require("acorn").parse(files[name], {
|
||||
locations: true,
|
||||
@@ -204,7 +289,7 @@ function run() {
|
||||
sourceFile: name
|
||||
});
|
||||
});
|
||||
} else if (program.parse.spidermonkey) {
|
||||
} else if (options.parse.spidermonkey) {
|
||||
files = convert_ast(function(toplevel, name) {
|
||||
var obj = JSON.parse(files[name]);
|
||||
if (!toplevel) return obj;
|
||||
@@ -216,14 +301,17 @@ function run() {
|
||||
} catch (ex) {
|
||||
fatal(ex);
|
||||
}
|
||||
if (program.reduceTest) {
|
||||
// load on demand - assumes dev tree checked out
|
||||
var result;
|
||||
if (specified["reduce-test"]) {
|
||||
// load on demand - assumes cloned repository
|
||||
var reduce_test = require("../test/reduce");
|
||||
var testcase = files[0] || files[Object.keys(files)[0]];
|
||||
var result = reduce_test(testcase, options, {verbose: true});
|
||||
}
|
||||
else {
|
||||
var result = UglifyJS.minify(files, options);
|
||||
if (Object.keys(files).length != 1) fatal("can only test on a single file");
|
||||
result = reduce_test(files[Object.keys(files)[0]], options, {
|
||||
log: print_error,
|
||||
verbose: true,
|
||||
});
|
||||
} else {
|
||||
result = UglifyJS.minify(files, options);
|
||||
}
|
||||
if (result.error) {
|
||||
var ex = result.error;
|
||||
@@ -253,10 +341,8 @@ function run() {
|
||||
print_error(format_object(ex.defs));
|
||||
}
|
||||
fatal(ex);
|
||||
} else if (program.output == "ast") {
|
||||
if (!options.compress && !options.mangle) {
|
||||
result.ast.figure_out_scope({});
|
||||
}
|
||||
} else if (output == "ast") {
|
||||
if (!options.compress && !options.mangle) result.ast.figure_out_scope({});
|
||||
print(JSON.stringify(result.ast, function(key, value) {
|
||||
if (value) switch (key) {
|
||||
case "thedef":
|
||||
@@ -282,26 +368,22 @@ function run() {
|
||||
}
|
||||
return value;
|
||||
}, 2));
|
||||
} else if (program.output == "spidermonkey") {
|
||||
} else if (output == "spidermonkey") {
|
||||
print(JSON.stringify(UglifyJS.minify(result.code, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
output: {
|
||||
ast: true,
|
||||
code: false
|
||||
}
|
||||
},
|
||||
}).ast.to_mozilla_ast(), null, 2));
|
||||
} else if (program.output) {
|
||||
fs.writeFileSync(program.output, result.code);
|
||||
if (result.map) {
|
||||
fs.writeFileSync(program.output + ".map", result.map);
|
||||
}
|
||||
} else if (output) {
|
||||
fs.writeFileSync(output, result.code);
|
||||
if (result.map) fs.writeFileSync(output + ".map", result.map);
|
||||
} else {
|
||||
print(result.code);
|
||||
}
|
||||
if (program.nameCache) {
|
||||
fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
|
||||
}
|
||||
if (nameCache) fs.writeFileSync(nameCache, JSON.stringify(options.nameCache));
|
||||
if (result.timings) for (var phase in result.timings) {
|
||||
print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
|
||||
}
|
||||
@@ -337,7 +419,7 @@ function simple_glob(glob) {
|
||||
.replace(/\?/g, "[^/\\\\]") + "$";
|
||||
var mod = process.platform === "win32" ? "i" : "";
|
||||
var rx = new RegExp(pattern, mod);
|
||||
var results = entries.filter(function(name) {
|
||||
var results = entries.sort().filter(function(name) {
|
||||
return rx.test(name);
|
||||
}).map(function(name) {
|
||||
return path.join(dir, name);
|
||||
@@ -357,47 +439,45 @@ function read_file(path, default_value) {
|
||||
}
|
||||
}
|
||||
|
||||
function parse_js(flag) {
|
||||
return function(value, options) {
|
||||
options = options || {};
|
||||
try {
|
||||
UglifyJS.parse(value, {
|
||||
expression: true
|
||||
}).walk(new UglifyJS.TreeWalker(function(node) {
|
||||
if (node instanceof UglifyJS.AST_Assign) {
|
||||
var name = node.left.print_to_string();
|
||||
var value = node.right;
|
||||
if (flag) {
|
||||
options[name] = value;
|
||||
} else if (value instanceof UglifyJS.AST_Array) {
|
||||
options[name] = value.elements.map(to_string);
|
||||
} else {
|
||||
options[name] = to_string(value);
|
||||
}
|
||||
return true;
|
||||
function parse_js(value, options, flag) {
|
||||
if (!options || typeof options != "object") options = {};
|
||||
if (typeof value == "string") try {
|
||||
UglifyJS.parse(value, {
|
||||
expression: true
|
||||
}).walk(new UglifyJS.TreeWalker(function(node) {
|
||||
if (node instanceof UglifyJS.AST_Assign) {
|
||||
var name = node.left.print_to_string();
|
||||
var value = node.right;
|
||||
if (flag) {
|
||||
options[name] = value;
|
||||
} else if (value instanceof UglifyJS.AST_Array) {
|
||||
options[name] = value.elements.map(to_string);
|
||||
} else {
|
||||
options[name] = to_string(value);
|
||||
}
|
||||
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_PropAccess) {
|
||||
var name = node.print_to_string();
|
||||
options[name] = true;
|
||||
return true;
|
||||
}
|
||||
if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
|
||||
|
||||
function to_string(value) {
|
||||
return value instanceof UglifyJS.AST_Constant ? value.value : value.print_to_string({
|
||||
quote_keys: true
|
||||
});
|
||||
}
|
||||
}));
|
||||
} catch (ex) {
|
||||
if (flag) {
|
||||
fatal("cannot parse arguments for '" + flag + "': " + value);
|
||||
} else {
|
||||
options[value] = null;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_PropAccess) {
|
||||
var name = node.print_to_string();
|
||||
options[name] = true;
|
||||
return true;
|
||||
}
|
||||
if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
|
||||
|
||||
function to_string(value) {
|
||||
return value instanceof UglifyJS.AST_Constant ? value.value : value.print_to_string({
|
||||
quote_keys: true
|
||||
});
|
||||
}
|
||||
}));
|
||||
} catch (ex) {
|
||||
if (flag) {
|
||||
fatal("cannot parse arguments for '" + flag + "': " + value);
|
||||
} else {
|
||||
options[value] = null;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function skip_key(key) {
|
||||
|
||||
618
lib/ast.js
618
lib/ast.js
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
@@ -110,12 +110,30 @@ var AST_Node = DEFNODE("Node", "start end", {
|
||||
start: "[AST_Token] The first token of this node",
|
||||
end: "[AST_Token] The last token of this node"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this);
|
||||
},
|
||||
walk: function(visitor) {
|
||||
return this._walk(visitor); // not sure the indirection will be any help
|
||||
}
|
||||
visitor.visit(this);
|
||||
},
|
||||
_validate: noop,
|
||||
validate: function() {
|
||||
var ctor = this.CTOR;
|
||||
do {
|
||||
ctor.prototype._validate.call(this);
|
||||
} while (ctor = ctor.BASE);
|
||||
},
|
||||
validate_ast: function() {
|
||||
var marker = {};
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (node.validate_visited === marker) {
|
||||
throw new Error(string_template("cannot reuse {type} from [{file}:{line},{col}]", {
|
||||
type: "AST_" + node.TYPE,
|
||||
file: node.start.file,
|
||||
line: node.start.line,
|
||||
col: node.start.col,
|
||||
}));
|
||||
}
|
||||
node.validate_visited = marker;
|
||||
}));
|
||||
},
|
||||
}, null);
|
||||
|
||||
(AST_Node.log_function = function(fn, verbose) {
|
||||
@@ -138,6 +156,32 @@ var AST_Node = DEFNODE("Node", "start end", {
|
||||
}
|
||||
})();
|
||||
|
||||
var restore_transforms = [];
|
||||
AST_Node.enable_validation = function() {
|
||||
AST_Node.disable_validation();
|
||||
(function validate_transform(ctor) {
|
||||
var transform = ctor.prototype.transform;
|
||||
ctor.prototype.transform = function(tw, in_list) {
|
||||
var node = transform.call(this, tw, in_list);
|
||||
if (node instanceof AST_Node) {
|
||||
node.validate();
|
||||
} else if (!(node === null || in_list && List.is_op(node))) {
|
||||
throw new Error("invalid transformed value: " + node);
|
||||
}
|
||||
return node;
|
||||
};
|
||||
restore_transforms.push(function() {
|
||||
ctor.prototype.transform = transform;
|
||||
});
|
||||
ctor.SUBCLASSES.forEach(validate_transform);
|
||||
})(this);
|
||||
};
|
||||
|
||||
AST_Node.disable_validation = function() {
|
||||
var restore;
|
||||
while (restore = restore_transforms.pop()) restore();
|
||||
};
|
||||
|
||||
/* -----[ statements ]----- */
|
||||
|
||||
var AST_Statement = DEFNODE("Statement", null, {
|
||||
@@ -154,23 +198,37 @@ var AST_Directive = DEFNODE("Directive", "value quote", {
|
||||
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
||||
quote: "[string] the original quote character"
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.value != "string") throw new Error("value must be string");
|
||||
},
|
||||
}, 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)) {
|
||||
throw new Error(prop + " cannot be AST_Statement");
|
||||
}
|
||||
}
|
||||
|
||||
var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
||||
$documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
|
||||
$propdoc: {
|
||||
body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.body._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.body.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "body");
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
function walk_body(node, visitor) {
|
||||
node.body.forEach(function(node) {
|
||||
node._walk(visitor);
|
||||
node.walk(visitor);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -179,11 +237,18 @@ var AST_Block = DEFNODE("Block", "body", {
|
||||
$propdoc: {
|
||||
body: "[AST_Statement*] an array of statements"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
walk_body(this, visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
walk_body(node, visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_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");
|
||||
});
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
|
||||
@@ -198,7 +263,11 @@ var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
||||
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
|
||||
$propdoc: {
|
||||
body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
|
||||
}
|
||||
},
|
||||
_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");
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
||||
@@ -206,10 +275,11 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
||||
$propdoc: {
|
||||
label: "[AST_Label] a label definition"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.label._walk(visitor);
|
||||
this.body._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.label.walk(visitor);
|
||||
node.body.walk(visitor);
|
||||
});
|
||||
},
|
||||
clone: function(deep) {
|
||||
@@ -218,14 +288,20 @@ 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;
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (!(this.label instanceof AST_Label)) throw new Error("label must be AST_Label");
|
||||
},
|
||||
}, AST_StatementWithBody);
|
||||
|
||||
var AST_IterationStatement = DEFNODE("IterationStatement", null, {
|
||||
@@ -236,25 +312,30 @@ var AST_DWLoop = DEFNODE("DWLoop", "condition", {
|
||||
$documentation: "Base class for do/while statements",
|
||||
$propdoc: {
|
||||
condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "condition");
|
||||
},
|
||||
}, AST_IterationStatement);
|
||||
|
||||
var AST_Do = DEFNODE("Do", null, {
|
||||
$documentation: "A `do` statement",
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.body._walk(visitor);
|
||||
this.condition._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.body.walk(visitor);
|
||||
node.condition.walk(visitor);
|
||||
});
|
||||
}
|
||||
}, AST_DWLoop);
|
||||
|
||||
var AST_While = DEFNODE("While", null, {
|
||||
$documentation: "A `while` statement",
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.condition._walk(visitor);
|
||||
this.body._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.condition.walk(visitor);
|
||||
node.body.walk(visitor);
|
||||
});
|
||||
}
|
||||
}, AST_DWLoop);
|
||||
@@ -266,14 +347,26 @@ var AST_For = DEFNODE("For", "init condition step", {
|
||||
condition: "[AST_Node?] the `for` termination clause, or null if empty",
|
||||
step: "[AST_Node?] the `for` update clause, or null if empty"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
if (this.init) this.init._walk(visitor);
|
||||
if (this.condition) this.condition._walk(visitor);
|
||||
if (this.step) this.step._walk(visitor);
|
||||
this.body._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.init) node.init.walk(visitor);
|
||||
if (node.condition) node.condition.walk(visitor);
|
||||
if (node.step) node.step.walk(visitor);
|
||||
node.body.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
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)) {
|
||||
throw new Error("init cannot be AST_Statement");
|
||||
}
|
||||
}
|
||||
if (this.condition != null) must_be_expression(this, "condition");
|
||||
if (this.step != null) must_be_expression(this, "step");
|
||||
},
|
||||
}, AST_IterationStatement);
|
||||
|
||||
var AST_ForIn = DEFNODE("ForIn", "init object", {
|
||||
@@ -282,13 +375,22 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
|
||||
init: "[AST_Node] the `for/in` initialization code",
|
||||
object: "[AST_Node] the object that we're looping through"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.init._walk(visitor);
|
||||
this.object._walk(visitor);
|
||||
this.body._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.init.walk(visitor);
|
||||
node.object.walk(visitor);
|
||||
node.body.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_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");
|
||||
}
|
||||
must_be_expression(this, "object");
|
||||
},
|
||||
}, AST_IterationStatement);
|
||||
|
||||
var AST_With = DEFNODE("With", "expression", {
|
||||
@@ -296,26 +398,30 @@ var AST_With = DEFNODE("With", "expression", {
|
||||
$propdoc: {
|
||||
expression: "[AST_Node] the `with` expression"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.expression._walk(visitor);
|
||||
this.body._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
node.body.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
},
|
||||
}, AST_StatementWithBody);
|
||||
|
||||
/* -----[ scope and functions ]----- */
|
||||
|
||||
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||
var AST_Scope = DEFNODE("Scope", "cname enclosed uses_eval uses_with parent_scope functions variables make_def", {
|
||||
$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)",
|
||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
|
||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||
},
|
||||
clone: function(deep) {
|
||||
var node = this._clone(deep);
|
||||
@@ -326,7 +432,12 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
|
||||
},
|
||||
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");
|
||||
}
|
||||
},
|
||||
}, AST_Block);
|
||||
|
||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
@@ -380,27 +491,44 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
||||
argnames: "[AST_SymbolFunarg*] array of function arguments",
|
||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
if (this.name) this.name._walk(visitor);
|
||||
this.argnames.forEach(function(argname) {
|
||||
argname._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.name) node.name.walk(visitor);
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(visitor);
|
||||
});
|
||||
walk_body(this, visitor);
|
||||
walk_body(node, visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
this.argnames.forEach(function(node) {
|
||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
||||
});
|
||||
},
|
||||
}, AST_Scope);
|
||||
|
||||
var AST_Accessor = DEFNODE("Accessor", null, {
|
||||
$documentation: "A setter/getter function. The `name` property is always null."
|
||||
$documentation: "A setter/getter function. The `name` property is always null.",
|
||||
_validate: function() {
|
||||
if (this.name != null) throw new Error("name must be null");
|
||||
},
|
||||
}, AST_Lambda);
|
||||
|
||||
var AST_Function = DEFNODE("Function", "inlined", {
|
||||
$documentation: "A function expression"
|
||||
$documentation: "A 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_Defun = DEFNODE("Defun", "inlined", {
|
||||
$documentation: "A function definition"
|
||||
$documentation: "A function definition",
|
||||
_validate: function() {
|
||||
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
|
||||
},
|
||||
}, AST_Lambda);
|
||||
|
||||
/* -----[ JUMPS ]----- */
|
||||
@@ -414,19 +542,26 @@ var AST_Exit = DEFNODE("Exit", "value", {
|
||||
$propdoc: {
|
||||
value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, this.value && function() {
|
||||
this.value._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.value) node.value.walk(visitor);
|
||||
});
|
||||
}
|
||||
}, AST_Jump);
|
||||
|
||||
var AST_Return = DEFNODE("Return", null, {
|
||||
$documentation: "A `return` statement"
|
||||
$documentation: "A `return` statement",
|
||||
_validate: function() {
|
||||
if (this.value != null) must_be_expression(this, "value");
|
||||
},
|
||||
}, AST_Exit);
|
||||
|
||||
var AST_Throw = DEFNODE("Throw", null, {
|
||||
$documentation: "A `throw` statement"
|
||||
$documentation: "A `throw` statement",
|
||||
_validate: function() {
|
||||
must_be_expression(this, "value");
|
||||
},
|
||||
}, AST_Exit);
|
||||
|
||||
var AST_LoopControl = DEFNODE("LoopControl", "label", {
|
||||
@@ -434,11 +569,17 @@ var AST_LoopControl = DEFNODE("LoopControl", "label", {
|
||||
$propdoc: {
|
||||
label: "[AST_LabelRef?] the label, or null if none",
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, this.label && function() {
|
||||
this.label._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.label) node.label.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.label != null) {
|
||||
if (!(this.label instanceof AST_LabelRef)) throw new Error("label must be AST_LabelRef");
|
||||
}
|
||||
},
|
||||
}, AST_Jump);
|
||||
|
||||
var AST_Break = DEFNODE("Break", null, {
|
||||
@@ -457,13 +598,21 @@ var AST_If = DEFNODE("If", "condition alternative", {
|
||||
condition: "[AST_Node] the `if` condition",
|
||||
alternative: "[AST_Statement?] the `else` part, or null if not present"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.condition._walk(visitor);
|
||||
this.body._walk(visitor);
|
||||
if (this.alternative) this.alternative._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.condition.walk(visitor);
|
||||
node.body.walk(visitor);
|
||||
if (node.alternative) node.alternative.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
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");
|
||||
}
|
||||
},
|
||||
}, AST_StatementWithBody);
|
||||
|
||||
/* -----[ SWITCH ]----- */
|
||||
@@ -473,12 +622,16 @@ var AST_Switch = DEFNODE("Switch", "expression", {
|
||||
$propdoc: {
|
||||
expression: "[AST_Node] the `switch` “discriminant”"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.expression._walk(visitor);
|
||||
walk_body(this, visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
walk_body(node, visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
},
|
||||
}, AST_Block);
|
||||
|
||||
var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
|
||||
@@ -494,12 +647,16 @@ var AST_Case = DEFNODE("Case", "expression", {
|
||||
$propdoc: {
|
||||
expression: "[AST_Node] the `case` expression"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.expression._walk(visitor);
|
||||
walk_body(this, visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
walk_body(node, visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
},
|
||||
}, AST_SwitchBranch);
|
||||
|
||||
/* -----[ EXCEPTIONS ]----- */
|
||||
@@ -510,13 +667,22 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
||||
bcatch: "[AST_Catch?] the catch block, or null if not present",
|
||||
bfinally: "[AST_Finally?] the finally block, or null if not present"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
walk_body(this, visitor);
|
||||
if (this.bcatch) this.bcatch._walk(visitor);
|
||||
if (this.bfinally) this.bfinally._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
walk_body(node, visitor);
|
||||
if (node.bcatch) node.bcatch.walk(visitor);
|
||||
if (node.bfinally) node.bfinally.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.bcatch != null) {
|
||||
if (!(this.bcatch instanceof AST_Catch)) throw new Error("bcatch must be AST_Catch");
|
||||
}
|
||||
if (this.bfinally != null) {
|
||||
if (!(this.bfinally instanceof AST_Finally)) throw new Error("bfinally must be AST_Finally");
|
||||
}
|
||||
},
|
||||
}, AST_Block);
|
||||
|
||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||
@@ -524,12 +690,16 @@ var AST_Catch = DEFNODE("Catch", "argname", {
|
||||
$propdoc: {
|
||||
argname: "[AST_SymbolCatch] symbol for the exception"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.argname._walk(visitor);
|
||||
walk_body(this, visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.argname.walk(visitor);
|
||||
walk_body(node, visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||
},
|
||||
}, AST_Block);
|
||||
|
||||
var AST_Finally = DEFNODE("Finally", null, {
|
||||
@@ -543,17 +713,23 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
||||
$propdoc: {
|
||||
definitions: "[AST_VarDef*] array of variable definitions"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.definitions.forEach(function(defn) {
|
||||
defn._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.definitions.forEach(function(defn) {
|
||||
defn.walk(visitor);
|
||||
});
|
||||
});
|
||||
}
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_Var = DEFNODE("Var", null, {
|
||||
$documentation: "A `var` statement"
|
||||
$documentation: "A `var` statement",
|
||||
_validate: function() {
|
||||
this.definitions.forEach(function(node) {
|
||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||
});
|
||||
},
|
||||
}, AST_Definitions);
|
||||
|
||||
var AST_VarDef = DEFNODE("VarDef", "name value", {
|
||||
@@ -562,30 +738,49 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
|
||||
name: "[AST_SymbolVar] name of the variable",
|
||||
value: "[AST_Node?] initializer, or null of there's no initializer"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.name._walk(visitor);
|
||||
if (this.value) this.value._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.name.walk(visitor);
|
||||
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 ]----- */
|
||||
|
||||
var AST_Call = DEFNODE("Call", "expression args", {
|
||||
function must_be_expressions(node, prop) {
|
||||
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)) {
|
||||
throw new Error(prop + " cannot contain AST_Statement");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var AST_Call = DEFNODE("Call", "expression args pure", {
|
||||
$documentation: "A function call expression",
|
||||
$propdoc: {
|
||||
expression: "[AST_Node] expression to invoke as function",
|
||||
args: "[AST_Node*] array of arguments"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.expression._walk(visitor);
|
||||
this.args.forEach(function(node) {
|
||||
node._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
node.args.forEach(function(arg) {
|
||||
arg.walk(visitor);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
must_be_expressions(this, "args");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_New = DEFNODE("New", null, {
|
||||
@@ -597,13 +792,18 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
|
||||
$propdoc: {
|
||||
expressions: "[AST_Node*] array of expressions (at least two)"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.expressions.forEach(function(node) {
|
||||
node._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expressions.forEach(function(expr) {
|
||||
expr.walk(visitor);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.expressions.length < 2) throw new Error("expressions must contain multiple elements");
|
||||
must_be_expressions(this, "expressions");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
|
||||
@@ -623,26 +823,37 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
|
||||
return;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_Dot = DEFNODE("Dot", null, {
|
||||
$documentation: "A dotted property access expression",
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.expression._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.property != "string") throw new Error("property must be string");
|
||||
},
|
||||
}, AST_PropAccess);
|
||||
|
||||
var AST_Sub = DEFNODE("Sub", null, {
|
||||
$documentation: "Index-style property access, i.e. `a[\"foo\"]`",
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.expression._walk(visitor);
|
||||
this.property._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
node.property.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "property");
|
||||
},
|
||||
}, AST_PropAccess);
|
||||
|
||||
var AST_Unary = DEFNODE("Unary", "operator expression", {
|
||||
@@ -651,11 +862,16 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
|
||||
operator: "[string] the operator",
|
||||
expression: "[AST_Node] expression that this unary operator applies to"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.expression._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.operator != "string") throw new Error("operator must be string");
|
||||
must_be_expression(this, "expression");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
|
||||
@@ -673,12 +889,18 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
|
||||
operator: "[string] the operator",
|
||||
right: "[AST_Node] right-hand side expression"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.left._walk(visitor);
|
||||
this.right._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.left.walk(visitor);
|
||||
node.right.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "left");
|
||||
if (typeof this.operator != "string") throw new Error("operator must be string");
|
||||
must_be_expression(this, "right");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
|
||||
@@ -688,17 +910,26 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative",
|
||||
consequent: "[AST_Node]",
|
||||
alternative: "[AST_Node]"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.condition._walk(visitor);
|
||||
this.consequent._walk(visitor);
|
||||
this.alternative._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.condition.walk(visitor);
|
||||
node.consequent.walk(visitor);
|
||||
node.alternative.walk(visitor);
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "condition");
|
||||
must_be_expression(this, "consequent");
|
||||
must_be_expression(this, "alternative");
|
||||
},
|
||||
});
|
||||
|
||||
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 "="');
|
||||
},
|
||||
}, AST_Binary);
|
||||
|
||||
/* -----[ LITERALS ]----- */
|
||||
@@ -708,13 +939,17 @@ var AST_Array = DEFNODE("Array", "elements", {
|
||||
$propdoc: {
|
||||
elements: "[AST_Node*] array of elements"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.elements.forEach(function(element) {
|
||||
element._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.elements.forEach(function(element) {
|
||||
element.walk(visitor);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expressions(this, "elements");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_Object = DEFNODE("Object", "properties", {
|
||||
@@ -722,13 +957,19 @@ var AST_Object = DEFNODE("Object", "properties", {
|
||||
$propdoc: {
|
||||
properties: "[AST_ObjectProperty*] array of properties"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.properties.forEach(function(prop) {
|
||||
prop._walk(visitor);
|
||||
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)) throw new Error("properties must be AST_ObjectProperty[]");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||
@@ -737,9 +978,10 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||
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."
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function() {
|
||||
this.value._walk(visitor);
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.value.walk(visitor);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -748,15 +990,27 @@ 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");
|
||||
must_be_expression(this, "value");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
|
||||
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);
|
||||
|
||||
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", {
|
||||
@@ -766,6 +1020,9 @@ var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
||||
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, {
|
||||
@@ -817,6 +1074,9 @@ var AST_LabelRef = DEFNODE("LabelRef", null, {
|
||||
|
||||
var AST_This = DEFNODE("This", null, {
|
||||
$documentation: "The `this` symbol",
|
||||
_validate: function() {
|
||||
if (this.name !== "this") throw new Error('name must be "this"');
|
||||
},
|
||||
}, AST_Symbol);
|
||||
|
||||
var AST_Constant = DEFNODE("Constant", null, {
|
||||
@@ -828,21 +1088,30 @@ var AST_String = DEFNODE("String", "value quote", {
|
||||
$propdoc: {
|
||||
value: "[string] the contents of this string",
|
||||
quote: "[string] the original quote character"
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.value != "string") throw new Error("value must be string");
|
||||
},
|
||||
}, AST_Constant);
|
||||
|
||||
var AST_Number = DEFNODE("Number", "value", {
|
||||
$documentation: "A number literal",
|
||||
$propdoc: {
|
||||
value: "[number] the numeric value",
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.value != "number") throw new Error("value must be number");
|
||||
},
|
||||
}, AST_Constant);
|
||||
|
||||
var AST_RegExp = DEFNODE("RegExp", "value", {
|
||||
$documentation: "A regexp literal",
|
||||
$propdoc: {
|
||||
value: "[RegExp] the actual regexp"
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (!(this.value instanceof RegExp)) throw new Error("value must be RegExp");
|
||||
},
|
||||
}, AST_Constant);
|
||||
|
||||
var AST_Atom = DEFNODE("Atom", null, {
|
||||
@@ -891,21 +1160,16 @@ var AST_True = DEFNODE("True", null, {
|
||||
/* -----[ TreeWalker ]----- */
|
||||
|
||||
function TreeWalker(callback) {
|
||||
this.visit = callback;
|
||||
this.stack = [];
|
||||
this.callback = callback;
|
||||
this.directives = Object.create(null);
|
||||
this.stack = [];
|
||||
}
|
||||
TreeWalker.prototype = {
|
||||
_visit: function(node, descend) {
|
||||
visit: function(node, descend) {
|
||||
this.push(node);
|
||||
var ret = this.visit(node, descend ? function() {
|
||||
descend.call(node);
|
||||
} : noop);
|
||||
if (!ret && descend) {
|
||||
descend.call(node);
|
||||
}
|
||||
var done = this.callback(node, descend || noop);
|
||||
if (!done && descend) descend();
|
||||
this.pop();
|
||||
return ret;
|
||||
},
|
||||
parent: function(n) {
|
||||
return this.stack[this.stack.length - 2 - (n || 0)];
|
||||
|
||||
2291
lib/compress.js
2291
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -85,9 +85,11 @@ function minify(files, options) {
|
||||
sourceMap: false,
|
||||
timings: false,
|
||||
toplevel: false,
|
||||
validate: false,
|
||||
warnings: false,
|
||||
wrap: false,
|
||||
}, true);
|
||||
if (options.validate) AST_Node.enable_validation();
|
||||
var timings = options.timings && {
|
||||
start: Date.now()
|
||||
};
|
||||
@@ -129,6 +131,7 @@ function minify(files, options) {
|
||||
content: null,
|
||||
filename: null,
|
||||
includeSources: false,
|
||||
names: true,
|
||||
root: null,
|
||||
url: null,
|
||||
}, true);
|
||||
@@ -138,7 +141,7 @@ function minify(files, options) {
|
||||
warnings.push(warning);
|
||||
}, options.warnings == "verbose");
|
||||
if (timings) timings.parse = Date.now();
|
||||
var source_maps, toplevel;
|
||||
var toplevel;
|
||||
if (files instanceof AST_Toplevel) {
|
||||
toplevel = files;
|
||||
} else {
|
||||
@@ -151,19 +154,17 @@ function minify(files, options) {
|
||||
if (typeof source_map_content == "string" && source_map_content != "inline") {
|
||||
source_map_content = parse_source_map(source_map_content);
|
||||
}
|
||||
source_maps = source_map_content && Object.create(null);
|
||||
if (source_map_content) options.sourceMap.orig = Object.create(null);
|
||||
for (var name in files) if (HOP(files, name)) {
|
||||
options.parse.filename = name;
|
||||
options.parse.toplevel = toplevel = parse(files[name], options.parse);
|
||||
if (source_maps) {
|
||||
if (source_map_content == "inline") {
|
||||
var inlined_content = read_source_map(name, toplevel);
|
||||
if (inlined_content) {
|
||||
source_maps[name] = parse_source_map(inlined_content);
|
||||
}
|
||||
} else {
|
||||
source_maps[name] = source_map_content;
|
||||
if (source_map_content == "inline") {
|
||||
var inlined_content = read_source_map(name, toplevel);
|
||||
if (inlined_content) {
|
||||
options.sourceMap.orig[name] = parse_source_map(inlined_content);
|
||||
}
|
||||
} else if (source_map_content) {
|
||||
options.sourceMap.orig[name] = source_map_content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,13 +178,17 @@ function minify(files, options) {
|
||||
toplevel = toplevel[action](option);
|
||||
files[toplevel.start.file] = toplevel.print_to_string().replace(orig, "");
|
||||
});
|
||||
if (options.validate) toplevel.validate_ast();
|
||||
if (timings) timings.rename = Date.now();
|
||||
if (options.rename) {
|
||||
toplevel.figure_out_scope(options.mangle);
|
||||
toplevel.expand_names(options.mangle);
|
||||
}
|
||||
if (timings) timings.compress = Date.now();
|
||||
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
|
||||
if (options.compress) {
|
||||
toplevel = new Compressor(options.compress).compress(toplevel);
|
||||
if (options.validate) toplevel.validate_ast();
|
||||
}
|
||||
if (timings) timings.scope = Date.now();
|
||||
if (options.mangle) toplevel.figure_out_scope(options.mangle);
|
||||
if (timings) timings.mangle = Date.now();
|
||||
@@ -192,9 +197,7 @@ function minify(files, options) {
|
||||
toplevel.mangle_names(options.mangle);
|
||||
}
|
||||
if (timings) timings.properties = Date.now();
|
||||
if (options.mangle && options.mangle.properties) {
|
||||
toplevel = mangle_properties(toplevel, options.mangle.properties);
|
||||
}
|
||||
if (options.mangle && options.mangle.properties) mangle_properties(toplevel, options.mangle.properties);
|
||||
if (timings) timings.output = Date.now();
|
||||
var result = {};
|
||||
if (options.output.ast) {
|
||||
@@ -202,19 +205,13 @@ function minify(files, options) {
|
||||
}
|
||||
if (!HOP(options.output, "code") || options.output.code) {
|
||||
if (options.sourceMap) {
|
||||
options.output.source_map = SourceMap({
|
||||
file: options.sourceMap.filename,
|
||||
orig: source_maps,
|
||||
root: options.sourceMap.root
|
||||
});
|
||||
options.output.source_map = SourceMap(options.sourceMap);
|
||||
if (options.sourceMap.includeSources) {
|
||||
if (files instanceof AST_Toplevel) {
|
||||
throw new Error("original source content unavailable");
|
||||
} else for (var name in files) if (HOP(files, name)) {
|
||||
options.output.source_map.get().setSourceContent(name, files[name]);
|
||||
options.output.source_map.setSourceContent(name, files[name]);
|
||||
}
|
||||
} else {
|
||||
options.output.source_map.get()._sourcesContents = null;
|
||||
}
|
||||
}
|
||||
delete options.output.ast;
|
||||
@@ -260,5 +257,7 @@ function minify(files, options) {
|
||||
return result;
|
||||
} catch (ex) {
|
||||
return { error: ex };
|
||||
} finally {
|
||||
AST_Node.disable_validation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
var args = {
|
||||
start : my_start_token(key),
|
||||
end : my_end_token(M.value),
|
||||
key : key.type == "Identifier" ? key.name : key.value,
|
||||
key : "" + key[key.type == "Identifier" ? "name" : "value"],
|
||||
value : from_moz(M.value)
|
||||
};
|
||||
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||
@@ -212,7 +212,14 @@
|
||||
end : my_end_token(M),
|
||||
name : M.name
|
||||
});
|
||||
}
|
||||
},
|
||||
ThisExpression: function(M) {
|
||||
return new AST_This({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
name : "this",
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
MOZ_TO_ME.UpdateExpression =
|
||||
@@ -245,7 +252,6 @@
|
||||
map("VariableDeclarator", AST_VarDef, "id>name, init>value");
|
||||
map("CatchClause", AST_Catch, "param>argname, body%body");
|
||||
|
||||
map("ThisExpression", AST_This);
|
||||
map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
|
||||
map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
|
||||
map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
|
||||
@@ -407,6 +413,10 @@
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_This, function To_Moz_ThisExpression() {
|
||||
return { type: "ThisExpression" };
|
||||
});
|
||||
|
||||
def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
|
||||
var flags = M.value.toString().match(/[gimuy]*$/)[0];
|
||||
var value = "/" + M.value.raw_source + "/" + flags;
|
||||
|
||||
396
lib/output.js
396
lib/output.js
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
@@ -100,7 +100,7 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
|
||||
var indentation = 0;
|
||||
var indentation = options.indent_start;
|
||||
var current_col = 0;
|
||||
var current_line = 1;
|
||||
var current_pos = 0;
|
||||
@@ -191,10 +191,6 @@ function OutputStream(options) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function make_indent(back) {
|
||||
return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
|
||||
}
|
||||
|
||||
/* -----[ beautification/minification ]----- */
|
||||
|
||||
var has_parens = false;
|
||||
@@ -305,6 +301,7 @@ function OutputStream(options) {
|
||||
|| (ch == "/" && ch == prev)
|
||||
|| ((ch == "+" || ch == "-") && ch == last)
|
||||
|| str == "--" && last == "!"
|
||||
|| str == "in" && prev == "/"
|
||||
|| last == "--" && ch == ">") {
|
||||
OUTPUT += " ";
|
||||
current_col++;
|
||||
@@ -344,9 +341,7 @@ function OutputStream(options) {
|
||||
};
|
||||
|
||||
var indent = options.beautify ? function(half) {
|
||||
if (options.beautify) {
|
||||
print(make_indent(half ? 0.5 : 0));
|
||||
}
|
||||
print(repeat_string(" ", half ? indentation - (options.indent_level >> 1) : indentation));
|
||||
} : noop;
|
||||
|
||||
var with_indent = options.beautify ? function(col, cont) {
|
||||
@@ -574,9 +569,9 @@ function OutputStream(options) {
|
||||
get : get,
|
||||
toString : get,
|
||||
indent : indent,
|
||||
indentation : function() { return indentation },
|
||||
current_width : function() { return current_col - indentation },
|
||||
should_break : function() { return options.width && this.current_width() >= options.width },
|
||||
should_break : readonly ? noop : function() {
|
||||
return options.width && current_col - indentation >= options.width;
|
||||
},
|
||||
has_parens : function() { return has_parens },
|
||||
newline : newline,
|
||||
print : print,
|
||||
@@ -629,13 +624,7 @@ function OutputStream(options) {
|
||||
var use_asm = false;
|
||||
|
||||
AST_Node.DEFMETHOD("print", function(stream, force_parens) {
|
||||
var self = this, generator = self._codegen;
|
||||
function doit() {
|
||||
stream.prepend_comments(self);
|
||||
self.add_source_map(stream);
|
||||
generator(self, stream);
|
||||
stream.append_comments(self);
|
||||
}
|
||||
var self = this;
|
||||
stream.push_node(self);
|
||||
if (force_parens || self.needs_parens(stream)) {
|
||||
stream.with_parens(doit);
|
||||
@@ -643,9 +632,14 @@ function OutputStream(options) {
|
||||
doit();
|
||||
}
|
||||
stream.pop_node();
|
||||
});
|
||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||
|
||||
function doit() {
|
||||
stream.prepend_comments(self);
|
||||
self.add_source_map(stream);
|
||||
self._codegen(stream);
|
||||
stream.append_comments(self);
|
||||
}
|
||||
});
|
||||
AST_Node.DEFMETHOD("print_to_string", function(options) {
|
||||
var s = OutputStream(options);
|
||||
this.print(s);
|
||||
@@ -688,78 +682,66 @@ function OutputStream(options) {
|
||||
|
||||
PARENS(AST_Unary, function(output) {
|
||||
var p = output.parent();
|
||||
return p instanceof AST_PropAccess && p.expression === this
|
||||
|| p instanceof AST_Call && p.expression === this;
|
||||
return (p instanceof AST_Call || p instanceof AST_PropAccess) && p.expression === this;
|
||||
});
|
||||
|
||||
PARENS(AST_Sequence, function(output) {
|
||||
var p = output.parent();
|
||||
// (foo, bar)() or foo(1, (2, 3), 4)
|
||||
return p instanceof AST_Call
|
||||
// !(foo, bar, baz)
|
||||
|| p instanceof AST_Unary
|
||||
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||
return p instanceof AST_Array
|
||||
// 1 + (2, 3) + 4 ==> 8
|
||||
|| p instanceof AST_Binary
|
||||
// var a = (1, 2), b = a + a; ==> b == 4
|
||||
|| p instanceof AST_VarDef
|
||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
|| p instanceof AST_PropAccess && p.expression === this
|
||||
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||
|| p instanceof AST_Array
|
||||
// { foo: (1, 2) }.foo ==> 2
|
||||
|| p instanceof AST_ObjectProperty
|
||||
// new (foo, bar) or foo(1, (2, 3), 4)
|
||||
|| p instanceof AST_Call
|
||||
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||
// ==> 20 (side effect, set a := 10 and b := 20)
|
||||
|| p instanceof AST_Conditional;
|
||||
|| p instanceof AST_Conditional
|
||||
// { foo: (1, 2) }.foo ==> 2
|
||||
|| p instanceof AST_ObjectProperty
|
||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
|| p instanceof AST_PropAccess && p.expression === this
|
||||
// !(foo, bar, baz)
|
||||
|| p instanceof AST_Unary
|
||||
// var a = (1, 2), b = a + a; ==> b == 4
|
||||
|| p instanceof AST_VarDef;
|
||||
});
|
||||
|
||||
PARENS(AST_Binary, function(output) {
|
||||
var p = output.parent();
|
||||
// (foo && bar)()
|
||||
if (p instanceof AST_Call && p.expression === this)
|
||||
return true;
|
||||
// typeof (foo && bar)
|
||||
if (p instanceof AST_Unary)
|
||||
return true;
|
||||
// (foo && bar)["prop"], (foo && bar).prop
|
||||
if (p instanceof AST_PropAccess && p.expression === this)
|
||||
return true;
|
||||
// this deals with precedence: 3 * (2 + 1)
|
||||
if (p instanceof AST_Binary) {
|
||||
var po = p.operator, pp = PRECEDENCE[po];
|
||||
var so = this.operator, sp = PRECEDENCE[so];
|
||||
if (pp > sp
|
||||
|| (pp == sp
|
||||
&& this === p.right)) {
|
||||
return true;
|
||||
}
|
||||
return pp > sp || (pp == sp && this === p.right);
|
||||
}
|
||||
// (foo && bar)()
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
// (foo && bar)["prop"], (foo && bar).prop
|
||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||
// typeof (foo && bar)
|
||||
if (p instanceof AST_Unary) return true;
|
||||
});
|
||||
|
||||
PARENS(AST_PropAccess, function(output) {
|
||||
var node = this;
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_New && p.expression === this) {
|
||||
// i.e. new (foo.bar().baz)
|
||||
if (p instanceof AST_New && p.expression === node) {
|
||||
// i.e. new (foo().bar)
|
||||
//
|
||||
// if there's one call into this subtree, then we need
|
||||
// parens around it too, otherwise the call will be
|
||||
// interpreted as passing the arguments to the upper New
|
||||
// expression.
|
||||
var parens = false;
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (parens || node instanceof AST_Scope) return true;
|
||||
if (node instanceof AST_Call) {
|
||||
parens = true;
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
return parens;
|
||||
do {
|
||||
node = node.expression;
|
||||
} while (node instanceof AST_PropAccess);
|
||||
return node.TYPE == "Call";
|
||||
}
|
||||
});
|
||||
|
||||
PARENS(AST_Call, function(output) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_New && p.expression === this) return true;
|
||||
if (p instanceof AST_New) return p.expression === this;
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||
if (output.option('webkit')) {
|
||||
var g = output.parent(1);
|
||||
@@ -772,49 +754,43 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
PARENS(AST_New, function(output) {
|
||||
if (need_constructor_parens(this, output)) return false;
|
||||
var p = output.parent();
|
||||
if (!need_constructor_parens(this, output)
|
||||
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
||||
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
||||
return true;
|
||||
// (new foo)(bar)
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
// (new Date).getTime(), (new Date)["getTime"]()
|
||||
return p instanceof AST_PropAccess;
|
||||
});
|
||||
|
||||
PARENS(AST_Number, function(output) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||
var value = this.value;
|
||||
// https://github.com/mishoo/UglifyJS2/issues/115
|
||||
// https://github.com/mishoo/UglifyJS2/pull/1009
|
||||
if (value < 0 || /^0/.test(make_num(value))) {
|
||||
return true;
|
||||
}
|
||||
// https://github.com/mishoo/UglifyJS/issues/115
|
||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||
return value < 0 || /^0/.test(make_num(value));
|
||||
}
|
||||
});
|
||||
|
||||
PARENS([ AST_Assign, AST_Conditional ], function(output) {
|
||||
var p = output.parent();
|
||||
// !(a = false) → true
|
||||
if (p instanceof AST_Unary)
|
||||
return true;
|
||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||
if (p instanceof AST_Binary && !(p instanceof AST_Assign))
|
||||
return true;
|
||||
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
||||
// (a = func)() —or— new (a = Object)()
|
||||
if (p instanceof AST_Call && p.expression === this)
|
||||
return true;
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
// (a = foo) ? bar : baz
|
||||
if (p instanceof AST_Conditional && p.condition === this)
|
||||
return true;
|
||||
if (p instanceof AST_Conditional) return p.condition === this;
|
||||
// (a = foo)["prop"] —or— (a = foo).prop
|
||||
if (p instanceof AST_PropAccess && p.expression === this)
|
||||
return true;
|
||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||
// !(a = false) → true
|
||||
if (p instanceof AST_Unary) return true;
|
||||
});
|
||||
|
||||
/* -----[ PRINTERS ]----- */
|
||||
|
||||
DEFPRINT(AST_Directive, function(self, output) {
|
||||
var quote = self.quote;
|
||||
var value = self.value;
|
||||
DEFPRINT(AST_Directive, function(output) {
|
||||
var quote = this.quote;
|
||||
var value = this.value;
|
||||
switch (output.option("quote_style")) {
|
||||
case 0:
|
||||
case 2:
|
||||
@@ -827,7 +803,7 @@ function OutputStream(options) {
|
||||
output.print(quote + value + quote);
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Debugger, function(self, output) {
|
||||
DEFPRINT(AST_Debugger, function(output) {
|
||||
output.print("debugger");
|
||||
output.semicolon();
|
||||
});
|
||||
@@ -863,21 +839,21 @@ function OutputStream(options) {
|
||||
force_statement(this.body, output);
|
||||
});
|
||||
|
||||
DEFPRINT(AST_Statement, function(self, output) {
|
||||
self.body.print(output);
|
||||
DEFPRINT(AST_Statement, function(output) {
|
||||
this.body.print(output);
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Toplevel, function(self, output) {
|
||||
display_body(self.body, true, output, true);
|
||||
DEFPRINT(AST_Toplevel, function(output) {
|
||||
display_body(this.body, true, output, true);
|
||||
output.print("");
|
||||
});
|
||||
DEFPRINT(AST_LabeledStatement, function(self, output) {
|
||||
self.label.print(output);
|
||||
DEFPRINT(AST_LabeledStatement, function(output) {
|
||||
this.label.print(output);
|
||||
output.colon();
|
||||
self.body.print(output);
|
||||
this.body.print(output);
|
||||
});
|
||||
DEFPRINT(AST_SimpleStatement, function(self, output) {
|
||||
self.body.print(output);
|
||||
DEFPRINT(AST_SimpleStatement, function(output) {
|
||||
this.body.print(output);
|
||||
output.semicolon();
|
||||
});
|
||||
function print_braced_empty(self, output) {
|
||||
@@ -894,13 +870,14 @@ function OutputStream(options) {
|
||||
});
|
||||
} else print_braced_empty(self, output);
|
||||
}
|
||||
DEFPRINT(AST_BlockStatement, function(self, output) {
|
||||
print_braced(self, output);
|
||||
DEFPRINT(AST_BlockStatement, function(output) {
|
||||
print_braced(this, output);
|
||||
});
|
||||
DEFPRINT(AST_EmptyStatement, function(self, output) {
|
||||
DEFPRINT(AST_EmptyStatement, function(output) {
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Do, function(self, output) {
|
||||
DEFPRINT(AST_Do, function(output) {
|
||||
var self = this;
|
||||
output.print("do");
|
||||
output.space();
|
||||
make_block(self.body, output);
|
||||
@@ -912,7 +889,8 @@ function OutputStream(options) {
|
||||
});
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_While, function(self, output) {
|
||||
DEFPRINT(AST_While, function(output) {
|
||||
var self = this;
|
||||
output.print("while");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -921,7 +899,8 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_For, function(self, output) {
|
||||
DEFPRINT(AST_For, function(output) {
|
||||
var self = this;
|
||||
output.print("for");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -950,7 +929,8 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_ForIn, function(self, output) {
|
||||
DEFPRINT(AST_ForIn, function(output) {
|
||||
var self = this;
|
||||
output.print("for");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -963,7 +943,8 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_With, function(self, output) {
|
||||
DEFPRINT(AST_With, function(output) {
|
||||
var self = this;
|
||||
output.print("with");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -974,7 +955,7 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
/* -----[ functions ]----- */
|
||||
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
|
||||
DEFPRINT(AST_Lambda, function(output, nokeyword) {
|
||||
var self = this;
|
||||
if (!nokeyword) {
|
||||
output.print("function");
|
||||
@@ -992,32 +973,23 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
print_braced(self, output, true);
|
||||
});
|
||||
DEFPRINT(AST_Lambda, function(self, output) {
|
||||
self._do_print(output);
|
||||
});
|
||||
|
||||
/* -----[ jumps ]----- */
|
||||
function print_jump(output, kind, target) {
|
||||
output.print(kind);
|
||||
if (target) {
|
||||
output.space();
|
||||
target.print(output);
|
||||
}
|
||||
output.semicolon();
|
||||
function print_jump(kind, prop) {
|
||||
return function(output) {
|
||||
output.print(kind);
|
||||
var target = this[prop];
|
||||
if (target) {
|
||||
output.space();
|
||||
target.print(output);
|
||||
}
|
||||
output.semicolon();
|
||||
};
|
||||
}
|
||||
|
||||
DEFPRINT(AST_Return, function(self, output) {
|
||||
print_jump(output, "return", self.value);
|
||||
});
|
||||
DEFPRINT(AST_Throw, function(self, output) {
|
||||
print_jump(output, "throw", self.value);
|
||||
});
|
||||
DEFPRINT(AST_Break, function(self, output) {
|
||||
print_jump(output, "break", self.label);
|
||||
});
|
||||
DEFPRINT(AST_Continue, function(self, output) {
|
||||
print_jump(output, "continue", self.label);
|
||||
});
|
||||
DEFPRINT(AST_Return, print_jump("return", "value"));
|
||||
DEFPRINT(AST_Throw, print_jump("throw", "value"));
|
||||
DEFPRINT(AST_Break, print_jump("break", "label"));
|
||||
DEFPRINT(AST_Continue, print_jump("continue", "label"));
|
||||
|
||||
/* -----[ if ]----- */
|
||||
function make_then(self, output) {
|
||||
@@ -1046,7 +1018,8 @@ function OutputStream(options) {
|
||||
}
|
||||
force_statement(self.body, output);
|
||||
}
|
||||
DEFPRINT(AST_If, function(self, output) {
|
||||
DEFPRINT(AST_If, function(output) {
|
||||
var self = this;
|
||||
output.print("if");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -1068,7 +1041,8 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
/* -----[ switch ]----- */
|
||||
DEFPRINT(AST_Switch, function(self, output) {
|
||||
DEFPRINT(AST_Switch, function(output) {
|
||||
var self = this;
|
||||
output.print("switch");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -1086,28 +1060,30 @@ function OutputStream(options) {
|
||||
});
|
||||
});
|
||||
});
|
||||
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
|
||||
function print_branch_body(self, output) {
|
||||
output.newline();
|
||||
this.body.forEach(function(stmt) {
|
||||
self.body.forEach(function(stmt) {
|
||||
output.indent();
|
||||
stmt.print(output);
|
||||
output.newline();
|
||||
});
|
||||
});
|
||||
DEFPRINT(AST_Default, function(self, output) {
|
||||
}
|
||||
DEFPRINT(AST_Default, function(output) {
|
||||
output.print("default:");
|
||||
self._do_print_body(output);
|
||||
print_branch_body(this, output);
|
||||
});
|
||||
DEFPRINT(AST_Case, function(self, output) {
|
||||
DEFPRINT(AST_Case, function(output) {
|
||||
var self = this;
|
||||
output.print("case");
|
||||
output.space();
|
||||
self.expression.print(output);
|
||||
output.print(":");
|
||||
self._do_print_body(output);
|
||||
print_branch_body(self, output);
|
||||
});
|
||||
|
||||
/* -----[ exceptions ]----- */
|
||||
DEFPRINT(AST_Try, function(self, output) {
|
||||
DEFPRINT(AST_Try, function(output) {
|
||||
var self = this;
|
||||
output.print("try");
|
||||
output.space();
|
||||
print_braced(self, output);
|
||||
@@ -1120,7 +1096,8 @@ function OutputStream(options) {
|
||||
self.bfinally.print(output);
|
||||
}
|
||||
});
|
||||
DEFPRINT(AST_Catch, function(self, output) {
|
||||
DEFPRINT(AST_Catch, function(output) {
|
||||
var self = this;
|
||||
output.print("catch");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
@@ -1129,13 +1106,14 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
print_braced(self, output);
|
||||
});
|
||||
DEFPRINT(AST_Finally, function(self, output) {
|
||||
DEFPRINT(AST_Finally, function(output) {
|
||||
output.print("finally");
|
||||
output.space();
|
||||
print_braced(self, output);
|
||||
print_braced(this, output);
|
||||
});
|
||||
|
||||
DEFPRINT(AST_Var, function(self, output) {
|
||||
DEFPRINT(AST_Var, function(output) {
|
||||
var self = this;
|
||||
output.print("var");
|
||||
output.space();
|
||||
self.definitions.forEach(function(def, i) {
|
||||
@@ -1149,7 +1127,7 @@ function OutputStream(options) {
|
||||
function parenthesize_for_noin(node, output, noin) {
|
||||
var parens = false;
|
||||
// need to take some precautions here:
|
||||
// https://github.com/mishoo/UglifyJS2/issues/60
|
||||
// https://github.com/mishoo/UglifyJS/issues/60
|
||||
if (noin) node.walk(new TreeWalker(function(node) {
|
||||
if (parens || node instanceof AST_Scope) return true;
|
||||
if (node instanceof AST_Binary && node.operator == "in") {
|
||||
@@ -1160,7 +1138,8 @@ function OutputStream(options) {
|
||||
node.print(output, parens);
|
||||
}
|
||||
|
||||
DEFPRINT(AST_VarDef, function(self, output) {
|
||||
DEFPRINT(AST_VarDef, function(output) {
|
||||
var self = this;
|
||||
self.name.print(output);
|
||||
if (self.value) {
|
||||
output.space();
|
||||
@@ -1173,10 +1152,7 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
/* -----[ other expressions ]----- */
|
||||
DEFPRINT(AST_Call, function(self, output) {
|
||||
self.expression.print(output);
|
||||
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
||||
return;
|
||||
function print_call_args(self, output) {
|
||||
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
||||
output.add_mapping(self.start);
|
||||
}
|
||||
@@ -1186,14 +1162,20 @@ function OutputStream(options) {
|
||||
expr.print(output);
|
||||
});
|
||||
});
|
||||
}
|
||||
DEFPRINT(AST_Call, function(output) {
|
||||
this.expression.print(output);
|
||||
print_call_args(this, output);
|
||||
});
|
||||
DEFPRINT(AST_New, function(self, output) {
|
||||
DEFPRINT(AST_New, function(output) {
|
||||
var self = this;
|
||||
output.print("new");
|
||||
output.space();
|
||||
AST_Call.prototype._codegen(self, output);
|
||||
self.expression.print(output);
|
||||
if (need_constructor_parens(self, output)) print_call_args(self, output);
|
||||
});
|
||||
DEFPRINT(AST_Sequence, function(self, output) {
|
||||
self.expressions.forEach(function(node, index) {
|
||||
DEFPRINT(AST_Sequence, function(output) {
|
||||
this.expressions.forEach(function(node, index) {
|
||||
if (index > 0) {
|
||||
output.comma();
|
||||
if (output.should_break()) {
|
||||
@@ -1204,7 +1186,8 @@ function OutputStream(options) {
|
||||
node.print(output);
|
||||
});
|
||||
});
|
||||
DEFPRINT(AST_Dot, function(self, output) {
|
||||
DEFPRINT(AST_Dot, function(output) {
|
||||
var self = this;
|
||||
var expr = self.expression;
|
||||
expr.print(output);
|
||||
var prop = self.property;
|
||||
@@ -1225,35 +1208,38 @@ function OutputStream(options) {
|
||||
output.print_name(prop);
|
||||
}
|
||||
});
|
||||
DEFPRINT(AST_Sub, function(self, output) {
|
||||
self.expression.print(output);
|
||||
DEFPRINT(AST_Sub, function(output) {
|
||||
this.expression.print(output);
|
||||
output.print("[");
|
||||
self.property.print(output);
|
||||
this.property.print(output);
|
||||
output.print("]");
|
||||
});
|
||||
DEFPRINT(AST_UnaryPrefix, function(self, output) {
|
||||
var op = self.operator;
|
||||
DEFPRINT(AST_UnaryPrefix, function(output) {
|
||||
var op = this.operator;
|
||||
var exp = this.expression;
|
||||
output.print(op);
|
||||
if (/^[a-z]/i.test(op)
|
||||
|| (/[+-]$/.test(op)
|
||||
&& self.expression instanceof AST_UnaryPrefix
|
||||
&& /^[+-]/.test(self.expression.operator))) {
|
||||
&& exp instanceof AST_UnaryPrefix
|
||||
&& /^[+-]/.test(exp.operator))) {
|
||||
output.space();
|
||||
}
|
||||
self.expression.print(output);
|
||||
exp.print(output);
|
||||
});
|
||||
DEFPRINT(AST_UnaryPostfix, function(self, output) {
|
||||
self.expression.print(output);
|
||||
output.print(self.operator);
|
||||
DEFPRINT(AST_UnaryPostfix, function(output) {
|
||||
this.expression.print(output);
|
||||
output.print(this.operator);
|
||||
});
|
||||
DEFPRINT(AST_Binary, function(self, output) {
|
||||
DEFPRINT(AST_Binary, function(output) {
|
||||
var self = this;
|
||||
self.left.print(output);
|
||||
output.space();
|
||||
output.print(self.operator);
|
||||
output.space();
|
||||
self.right.print(output);
|
||||
});
|
||||
DEFPRINT(AST_Conditional, function(self, output) {
|
||||
DEFPRINT(AST_Conditional, function(output) {
|
||||
var self = this;
|
||||
self.condition.print(output);
|
||||
output.space();
|
||||
output.print("?");
|
||||
@@ -1265,10 +1251,10 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
/* -----[ literals ]----- */
|
||||
DEFPRINT(AST_Array, function(self, output) {
|
||||
output.with_square(function() {
|
||||
var a = self.elements, len = a.length;
|
||||
if (len > 0) output.space();
|
||||
DEFPRINT(AST_Array, function(output) {
|
||||
var a = this.elements, len = a.length;
|
||||
output.with_square(len > 0 ? function() {
|
||||
output.space();
|
||||
a.forEach(function(exp, i) {
|
||||
if (i) output.comma();
|
||||
exp.print(output);
|
||||
@@ -1278,12 +1264,13 @@ function OutputStream(options) {
|
||||
if (i === len - 1 && exp instanceof AST_Hole)
|
||||
output.comma();
|
||||
});
|
||||
if (len > 0) output.space();
|
||||
});
|
||||
output.space();
|
||||
} : noop);
|
||||
});
|
||||
DEFPRINT(AST_Object, function(self, output) {
|
||||
if (self.properties.length > 0) output.with_block(function() {
|
||||
self.properties.forEach(function(prop, i) {
|
||||
DEFPRINT(AST_Object, function(output) {
|
||||
var props = this.properties;
|
||||
if (props.length > 0) output.with_block(function() {
|
||||
props.forEach(function(prop, i) {
|
||||
if (i) {
|
||||
output.print(",");
|
||||
output.newline();
|
||||
@@ -1293,7 +1280,7 @@ function OutputStream(options) {
|
||||
});
|
||||
output.newline();
|
||||
});
|
||||
else print_braced_empty(self, output);
|
||||
else print_braced_empty(this, output);
|
||||
});
|
||||
|
||||
function print_property_name(key, quote, output) {
|
||||
@@ -1312,47 +1299,48 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
|
||||
DEFPRINT(AST_ObjectKeyVal, function(self, output) {
|
||||
DEFPRINT(AST_ObjectKeyVal, function(output) {
|
||||
var self = this;
|
||||
print_property_name(self.key, self.quote, output);
|
||||
output.colon();
|
||||
self.value.print(output);
|
||||
});
|
||||
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, output) {
|
||||
output.print(type);
|
||||
output.space();
|
||||
print_property_name(this.key.name, this.quote, output);
|
||||
this.value._do_print(output, true);
|
||||
});
|
||||
DEFPRINT(AST_ObjectSetter, function(self, output) {
|
||||
self._print_getter_setter("set", output);
|
||||
});
|
||||
DEFPRINT(AST_ObjectGetter, function(self, output) {
|
||||
self._print_getter_setter("get", output);
|
||||
});
|
||||
DEFPRINT(AST_Symbol, function(self, output) {
|
||||
var def = self.definition();
|
||||
output.print_name(def && def.mangled_name || self.name);
|
||||
function print_accessor(type) {
|
||||
return function(output) {
|
||||
var self = this;
|
||||
output.print(type);
|
||||
output.space();
|
||||
print_property_name(self.key.name, self.quote, output);
|
||||
self.value._codegen(output, true);
|
||||
};
|
||||
}
|
||||
DEFPRINT(AST_ObjectGetter, print_accessor("get"));
|
||||
DEFPRINT(AST_ObjectSetter, print_accessor("set"));
|
||||
DEFPRINT(AST_Symbol, function(output) {
|
||||
var def = this.definition();
|
||||
output.print_name(def && def.mangled_name || this.name);
|
||||
});
|
||||
DEFPRINT(AST_Hole, noop);
|
||||
DEFPRINT(AST_This, function(self, output) {
|
||||
DEFPRINT(AST_This, function(output) {
|
||||
output.print("this");
|
||||
});
|
||||
DEFPRINT(AST_Constant, function(self, output) {
|
||||
output.print(self.value);
|
||||
DEFPRINT(AST_Constant, function(output) {
|
||||
output.print(this.value);
|
||||
});
|
||||
DEFPRINT(AST_String, function(self, output) {
|
||||
output.print_string(self.value, self.quote);
|
||||
DEFPRINT(AST_String, function(output) {
|
||||
output.print_string(this.value, this.quote);
|
||||
});
|
||||
DEFPRINT(AST_Number, function(self, output) {
|
||||
if (use_asm && self.start && self.start.raw != null) {
|
||||
output.print(self.start.raw);
|
||||
DEFPRINT(AST_Number, function(output) {
|
||||
var start = this.start;
|
||||
if (use_asm && start && start.raw != null) {
|
||||
output.print(start.raw);
|
||||
} else {
|
||||
output.print(make_num(self.value));
|
||||
output.print(make_num(this.value));
|
||||
}
|
||||
});
|
||||
|
||||
DEFPRINT(AST_RegExp, function(self, output) {
|
||||
var regexp = self.value;
|
||||
DEFPRINT(AST_RegExp, function(output) {
|
||||
var regexp = this.value;
|
||||
var str = regexp.toString();
|
||||
var end = str.lastIndexOf("/");
|
||||
if (regexp.raw_source) {
|
||||
@@ -1386,7 +1374,7 @@ function OutputStream(options) {
|
||||
}
|
||||
}));
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === this)
|
||||
output.print(" ");
|
||||
});
|
||||
|
||||
@@ -1470,7 +1458,6 @@ function OutputStream(options) {
|
||||
AST_Node,
|
||||
// since the label symbol will mark it
|
||||
AST_LabeledStatement,
|
||||
AST_Toplevel,
|
||||
], noop);
|
||||
|
||||
// XXX: I'm not exactly sure if we need it for all of these nodes,
|
||||
@@ -1482,7 +1469,6 @@ function OutputStream(options) {
|
||||
AST_Constant,
|
||||
AST_Debugger,
|
||||
AST_Definitions,
|
||||
AST_Directive,
|
||||
AST_Finally,
|
||||
AST_Jump,
|
||||
AST_Lambda,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
@@ -948,7 +948,7 @@ function parse($TEXT, options) {
|
||||
if (!(stat instanceof AST_IterationStatement)) {
|
||||
// check for `continue` that refers to this label.
|
||||
// those should be reported as syntax errors.
|
||||
// https://github.com/mishoo/UglifyJS2/issues/287
|
||||
// https://github.com/mishoo/UglifyJS/issues/287
|
||||
label.references.forEach(function(ref) {
|
||||
if (ref instanceof AST_Continue) {
|
||||
ref = ref.label.start;
|
||||
@@ -1092,7 +1092,7 @@ function parse($TEXT, options) {
|
||||
|
||||
function switch_body_() {
|
||||
expect("{");
|
||||
var a = [], cur = null, branch = null, tmp;
|
||||
var a = [], branch, cur, default_branch, tmp;
|
||||
while (!is("punc", "}")) {
|
||||
if (is("eof")) expect_token("punc", "}");
|
||||
if (is("keyword", "case")) {
|
||||
@@ -1107,12 +1107,14 @@ function parse($TEXT, options) {
|
||||
expect(":");
|
||||
} else if (is("keyword", "default")) {
|
||||
if (branch) branch.end = prev();
|
||||
if (default_branch) croak("More than one default clause in switch statement");
|
||||
cur = [];
|
||||
branch = new AST_Default({
|
||||
start : (tmp = S.token, next(), expect(":"), tmp),
|
||||
body : cur
|
||||
});
|
||||
a.push(branch);
|
||||
default_branch = branch;
|
||||
} else {
|
||||
if (!cur) unexpected();
|
||||
cur.push(statement());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
function find_builtins(reserved) {
|
||||
var builtins = function() {
|
||||
var names = [];
|
||||
// NaN will be included due to Number.NaN
|
||||
[
|
||||
"null",
|
||||
@@ -67,19 +68,21 @@ function find_builtins(reserved) {
|
||||
].forEach(function(ctor) {
|
||||
Object.getOwnPropertyNames(ctor).map(add);
|
||||
if (ctor.prototype) {
|
||||
Object.getOwnPropertyNames(new ctor()).map(add);
|
||||
Object.getOwnPropertyNames(ctor.prototype).map(add);
|
||||
}
|
||||
});
|
||||
return makePredicate(names);
|
||||
|
||||
function add(name) {
|
||||
push_uniq(reserved, name);
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
function reserve_quoted_keys(ast, reserved) {
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal && node.quote) {
|
||||
add(node.key);
|
||||
if (node instanceof AST_ObjectKeyVal) {
|
||||
if (node.quote) add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
@@ -91,17 +94,14 @@ function reserve_quoted_keys(ast, reserved) {
|
||||
}
|
||||
|
||||
function addStrings(node, add) {
|
||||
node.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Sequence) {
|
||||
addStrings(node.tail_node(), add);
|
||||
} else if (node instanceof AST_String) {
|
||||
add(node.value);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
addStrings(node.consequent, add);
|
||||
addStrings(node.alternative, add);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
if (node instanceof AST_Conditional) {
|
||||
addStrings(node.consequent, add);
|
||||
addStrings(node.alternative, add);
|
||||
} else if (node instanceof AST_Sequence) {
|
||||
addStrings(node.tail_node(), add);
|
||||
} else if (node instanceof AST_String) {
|
||||
add(node.value);
|
||||
}
|
||||
}
|
||||
|
||||
function mangle_properties(ast, options) {
|
||||
@@ -110,21 +110,21 @@ function mangle_properties(ast, options) {
|
||||
cache: null,
|
||||
debug: false,
|
||||
keep_quoted: false,
|
||||
only_cache: false,
|
||||
regex: null,
|
||||
reserved: null,
|
||||
}, true);
|
||||
|
||||
var reserved = options.reserved;
|
||||
if (!Array.isArray(reserved)) reserved = [];
|
||||
if (!options.builtins) find_builtins(reserved);
|
||||
var reserved = Object.create(options.builtins ? null : builtins);
|
||||
if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) {
|
||||
reserved[name] = true;
|
||||
});
|
||||
|
||||
var cname = -1;
|
||||
var cache;
|
||||
if (options.cache) {
|
||||
cache = options.cache.props;
|
||||
cache.each(function(mangled_name) {
|
||||
push_uniq(reserved, mangled_name);
|
||||
cache.each(function(name) {
|
||||
reserved[name] = true;
|
||||
});
|
||||
} else {
|
||||
cache = new Dictionary();
|
||||
@@ -139,62 +139,92 @@ function mangle_properties(ast, options) {
|
||||
var debug_suffix;
|
||||
if (debug) debug_suffix = options.debug === true ? "" : options.debug;
|
||||
|
||||
var names_to_mangle = [];
|
||||
var unmangleable = [];
|
||||
var names_to_mangle = Object.create(null);
|
||||
var unmangleable = Object.create(reserved);
|
||||
|
||||
// step 1: find candidates to mangle
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal) {
|
||||
if (node instanceof AST_Binary) {
|
||||
if (node.operator == "in") addStrings(node.left, add);
|
||||
} else if (node.TYPE == "Call") {
|
||||
var exp = node.expression;
|
||||
if (exp instanceof AST_Dot) switch (exp.property) {
|
||||
case "defineProperty":
|
||||
case "getOwnPropertyDescriptor":
|
||||
if (node.args.length < 2) break;
|
||||
exp = exp.expression;
|
||||
if (!(exp instanceof AST_SymbolRef)) break;
|
||||
if (exp.name != "Object") break;
|
||||
if (!exp.definition().undeclared) break;
|
||||
addStrings(node.args[1], add);
|
||||
break;
|
||||
case "hasOwnProperty":
|
||||
if (node.args.length < 1) break;
|
||||
addStrings(node.args[0], add);
|
||||
break;
|
||||
}
|
||||
} 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);
|
||||
} else if (node instanceof AST_Dot) {
|
||||
add(node.property);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
} else if (node instanceof AST_Call
|
||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||
addStrings(node.args[1], add);
|
||||
}
|
||||
}));
|
||||
|
||||
// step 2: transform the tree, renaming properties
|
||||
return ast.transform(new TreeTransformer(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal) {
|
||||
// step 2: renaming properties
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Binary) {
|
||||
if (node.operator == "in") mangleStrings(node.left);
|
||||
} else if (node.TYPE == "Call") {
|
||||
var exp = node.expression;
|
||||
if (exp instanceof AST_Dot) switch (exp.property) {
|
||||
case "defineProperty":
|
||||
case "getOwnPropertyDescriptor":
|
||||
if (node.args.length < 2) break;
|
||||
exp = exp.expression;
|
||||
if (!(exp instanceof AST_SymbolRef)) break;
|
||||
if (exp.name != "Object") break;
|
||||
if (!exp.definition().undeclared) break;
|
||||
mangleStrings(node.args[1]);
|
||||
break;
|
||||
case "hasOwnProperty":
|
||||
if (node.args.length < 1) break;
|
||||
mangleStrings(node.args[0]);
|
||||
break;
|
||||
}
|
||||
} 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);
|
||||
} else if (node instanceof AST_Dot) {
|
||||
node.property = mangle(node.property);
|
||||
} else if (!options.keep_quoted && node instanceof AST_Sub) {
|
||||
node.property = mangleStrings(node.property);
|
||||
} else if (node instanceof AST_Call
|
||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||
node.args[1] = mangleStrings(node.args[1]);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
if (!options.keep_quoted) mangleStrings(node.property);
|
||||
}
|
||||
}));
|
||||
|
||||
// only function declarations after this line
|
||||
|
||||
function can_mangle(name) {
|
||||
if (unmangleable.indexOf(name) >= 0) return false;
|
||||
if (reserved.indexOf(name) >= 0) return false;
|
||||
if (options.only_cache) return cache.has(name);
|
||||
if (unmangleable[name]) return false;
|
||||
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function should_mangle(name) {
|
||||
if (reserved[name]) return false;
|
||||
if (regex && !regex.test(name)) return false;
|
||||
if (reserved.indexOf(name) >= 0) return false;
|
||||
return cache.has(name) || names_to_mangle.indexOf(name) >= 0;
|
||||
return cache.has(name) || names_to_mangle[name];
|
||||
}
|
||||
|
||||
function add(name) {
|
||||
if (can_mangle(name)) push_uniq(names_to_mangle, name);
|
||||
if (!should_mangle(name)) push_uniq(unmangleable, name);
|
||||
if (can_mangle(name)) names_to_mangle[name] = true;
|
||||
if (!should_mangle(name)) unmangleable[name] = true;
|
||||
}
|
||||
|
||||
function mangle(name) {
|
||||
@@ -218,17 +248,13 @@ function mangle_properties(ast, options) {
|
||||
}
|
||||
|
||||
function mangleStrings(node) {
|
||||
return node.transform(new TreeTransformer(function(node) {
|
||||
if (node instanceof AST_Sequence) {
|
||||
var last = node.expressions.length - 1;
|
||||
node.expressions[last] = mangleStrings(node.expressions[last]);
|
||||
} else if (node instanceof AST_String) {
|
||||
node.value = mangle(node.value);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
node.consequent = mangleStrings(node.consequent);
|
||||
node.alternative = mangleStrings(node.alternative);
|
||||
}
|
||||
return node;
|
||||
}));
|
||||
if (node instanceof AST_Sequence) {
|
||||
mangleStrings(node.expressions.tail_node());
|
||||
} else if (node instanceof AST_String) {
|
||||
node.value = mangle(node.value);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
mangleStrings(node.consequent);
|
||||
mangleStrings(node.alternative);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
112
lib/scope.js
112
lib/scope.js
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
@@ -43,23 +43,21 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
function SymbolDef(scope, orig, init) {
|
||||
function SymbolDef(id, scope, orig, init) {
|
||||
this.eliminated = 0;
|
||||
this.global = false;
|
||||
this.id = id;
|
||||
this.init = init;
|
||||
this.lambda = orig instanceof AST_SymbolLambda;
|
||||
this.mangled_name = null;
|
||||
this.name = orig.name;
|
||||
this.orig = [ orig ];
|
||||
this.init = init;
|
||||
this.eliminated = 0;
|
||||
this.scope = scope;
|
||||
this.references = [];
|
||||
this.replaced = 0;
|
||||
this.global = false;
|
||||
this.mangled_name = null;
|
||||
this.scope = scope;
|
||||
this.undeclared = false;
|
||||
this.id = SymbolDef.next_id++;
|
||||
this.lambda = orig instanceof AST_SymbolLambda;
|
||||
}
|
||||
|
||||
SymbolDef.next_id = 1;
|
||||
|
||||
SymbolDef.prototype = {
|
||||
unmangleable: function(options) {
|
||||
return this.global && !options.toplevel
|
||||
@@ -98,8 +96,9 @@ 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;
|
||||
@@ -151,6 +150,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
scope.def_variable(node).defun = defun;
|
||||
}
|
||||
});
|
||||
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
|
||||
@@ -162,17 +164,22 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var name = node.name;
|
||||
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
||||
s.uses_eval = true;
|
||||
}
|
||||
}
|
||||
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;
|
||||
@@ -226,6 +233,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
} else {
|
||||
new_def = scope.def_variable(node);
|
||||
}
|
||||
old_def.defun = new_def.scope;
|
||||
old_def.orig.concat(old_def.references).forEach(function(node) {
|
||||
node.thedef = new_def;
|
||||
node.reference(options);
|
||||
@@ -240,7 +248,7 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
if (globals.has(name)) {
|
||||
return globals.get(name);
|
||||
} else {
|
||||
var g = new SymbolDef(this, node);
|
||||
var g = this.make_def(node);
|
||||
g.undeclared = true;
|
||||
g.global = true;
|
||||
globals.set(name, g);
|
||||
@@ -248,23 +256,28 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
}
|
||||
});
|
||||
|
||||
function init_scope_vars(scope, parent) {
|
||||
scope.cname = -1; // the current index for mangling functions/variables
|
||||
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||
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
|
||||
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_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
|
||||
init_scope_vars(this, parent_scope);
|
||||
});
|
||||
|
||||
AST_Lambda.DEFMETHOD("init_scope_vars", function() {
|
||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||
AST_Lambda.DEFMETHOD("init_scope_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,
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -305,7 +318,7 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
||||
def.orig.push(symbol);
|
||||
if (def.init instanceof AST_Function) def.init = init;
|
||||
} else {
|
||||
def = new SymbolDef(this, symbol, init);
|
||||
def = this.make_def(symbol, init);
|
||||
this.variables.set(symbol.name, def);
|
||||
def.global = !this.parent_scope;
|
||||
}
|
||||
@@ -376,18 +389,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,
|
||||
@@ -533,11 +538,8 @@ 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.forEach(function(sym) {
|
||||
sym.name = name;
|
||||
});
|
||||
def.references.forEach(function(sym) {
|
||||
sym.name = name;
|
||||
def.orig.concat(def.references).forEach(function(sym) {
|
||||
if (sym.definition() === def) sym.name = name;
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -550,22 +552,24 @@ 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 {
|
||||
AST_Node.prototype.print = function(stream, force_parens) {
|
||||
this._print(stream, force_parens);
|
||||
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
||||
base54.consider(this.name, -1);
|
||||
} else if (options.properties) {
|
||||
if (this instanceof AST_Dot) {
|
||||
base54.consider(this.property, -1);
|
||||
} else if (this instanceof AST_Sub) {
|
||||
skip_string(this.property);
|
||||
}
|
||||
}
|
||||
AST_Symbol.prototype.add_source_map = function() {
|
||||
if (!this.unmangleable(options)) base54.consider(this.name, -1);
|
||||
};
|
||||
if (options.properties) {
|
||||
AST_Dot.prototype.add_source_map = function() {
|
||||
base54.consider(this.property, -1);
|
||||
};
|
||||
AST_Sub.prototype.add_source_map = function() {
|
||||
skip_string(this.property);
|
||||
};
|
||||
}
|
||||
base54.consider(this.print_to_string(), 1);
|
||||
} finally {
|
||||
AST_Node.prototype.print = AST_Node.prototype._print;
|
||||
AST_Symbol.prototype.add_source_map = fn;
|
||||
delete AST_Dot.prototype.add_source_map;
|
||||
delete AST_Sub.prototype.add_source_map;
|
||||
}
|
||||
base54.sort();
|
||||
|
||||
|
||||
191
lib/sourcemap.js
191
lib/sourcemap.js
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
@@ -43,62 +43,149 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// a small wrapper around fitzgen's source-map library
|
||||
function SourceMap(options) {
|
||||
options = defaults(options, {
|
||||
file: null,
|
||||
root: null,
|
||||
orig: null,
|
||||
orig_line_diff: 0,
|
||||
dest_line_diff: 0,
|
||||
}, true);
|
||||
var generator = new MOZ_SourceMap.SourceMapGenerator({
|
||||
file: options.file,
|
||||
sourceRoot: options.root
|
||||
});
|
||||
var maps = options.orig && Object.create(null);
|
||||
if (maps) for (var source in options.orig) {
|
||||
var map = new MOZ_SourceMap.SourceMapConsumer(options.orig[source]);
|
||||
if (Array.isArray(options.orig[source].sources)) {
|
||||
map._sources.toArray().forEach(function(source) {
|
||||
var sourceContent = map.sourceContentFor(source, true);
|
||||
if (sourceContent) generator.setSourceContent(source, sourceContent);
|
||||
});
|
||||
var vlq_char = characters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
|
||||
var vlq_bits = vlq_char.reduce(function(map, ch, bits) {
|
||||
map[ch] = bits;
|
||||
return map;
|
||||
}, Object.create(null));
|
||||
|
||||
function vlq_decode(indices, str) {
|
||||
var value = 0;
|
||||
var shift = 0;
|
||||
for (var i = 0, j = 0; i < str.length; i++) {
|
||||
var bits = vlq_bits[str[i]];
|
||||
value += (bits & 31) << shift;
|
||||
if (bits & 32) {
|
||||
shift += 5;
|
||||
} else {
|
||||
indices[j++] += value & 1 ? 0x80000000 | -(value >> 1) : value >> 1;
|
||||
value = shift = 0;
|
||||
}
|
||||
maps[source] = map;
|
||||
}
|
||||
return {
|
||||
add: function(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||
var map = maps && maps[source];
|
||||
if (map) {
|
||||
var info = map.originalPositionFor({
|
||||
line: orig_line,
|
||||
column: orig_col
|
||||
return j;
|
||||
}
|
||||
|
||||
function vlq_encode(num) {
|
||||
var result = "";
|
||||
num = Math.abs(num) << 1 | num >>> 31;
|
||||
do {
|
||||
var bits = num & 31;
|
||||
if (num >>>= 5) bits |= 32;
|
||||
result += vlq_char[bits];
|
||||
} while (num);
|
||||
return result;
|
||||
}
|
||||
|
||||
function create_array_map() {
|
||||
var map = Object.create(null);
|
||||
var array = [];
|
||||
array.index = function(name) {
|
||||
if (!HOP(map, name)) {
|
||||
map[name] = array.length;
|
||||
array.push(name);
|
||||
}
|
||||
return map[name];
|
||||
};
|
||||
return array;
|
||||
}
|
||||
|
||||
function SourceMap(options) {
|
||||
var sources = create_array_map();
|
||||
var sources_content = options.includeSources && Object.create(null);
|
||||
var names = create_array_map();
|
||||
var mappings = "";
|
||||
if (options.orig) Object.keys(options.orig).forEach(function(name) {
|
||||
var map = options.orig[name];
|
||||
var indices = [ 0, 0, 1, 0, 0 ];
|
||||
options.orig[name] = {
|
||||
names: map.names,
|
||||
mappings: map.mappings.split(/;/).map(function(line) {
|
||||
indices[0] = 0;
|
||||
return line.split(/,/).map(function(segment) {
|
||||
return indices.slice(0, vlq_decode(indices, segment));
|
||||
});
|
||||
if (info.source === null) return;
|
||||
source = info.source;
|
||||
orig_line = info.line;
|
||||
orig_col = info.column;
|
||||
name = info.name || name;
|
||||
}
|
||||
generator.addMapping({
|
||||
name: name,
|
||||
source: source,
|
||||
generated: {
|
||||
line: gen_line + options.dest_line_diff,
|
||||
column: gen_col
|
||||
},
|
||||
original: {
|
||||
line: orig_line + options.orig_line_diff,
|
||||
column: orig_col
|
||||
}),
|
||||
sources: map.sources,
|
||||
};
|
||||
if (!sources_content || !map.sourcesContent) return;
|
||||
for (var i = 0; i < map.sources.length; i++) {
|
||||
var content = map.sourcesContent[i];
|
||||
if (content) sources_content[map.sources[i]] = content;
|
||||
}
|
||||
});
|
||||
var prev_source;
|
||||
var generated_line = 1;
|
||||
var generated_column = 0;
|
||||
var source_index = 0;
|
||||
var original_line = 1;
|
||||
var original_column = 0;
|
||||
var name_index = 0;
|
||||
return {
|
||||
add: options.orig ? function(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||
var map = options.orig[source];
|
||||
if (map) {
|
||||
var segments = map.mappings[orig_line - 1];
|
||||
if (!segments) return;
|
||||
var indices;
|
||||
for (var i = 0; i < segments.length; i++) {
|
||||
var col = segments[i][0];
|
||||
if (orig_col >= col) indices = segments[i];
|
||||
if (orig_col <= col) break;
|
||||
}
|
||||
});
|
||||
},
|
||||
get: function() {
|
||||
return generator;
|
||||
},
|
||||
if (!indices || indices.length < 4) {
|
||||
source = null;
|
||||
} else {
|
||||
source = map.sources[indices[1]];
|
||||
orig_line = indices[2];
|
||||
orig_col = indices[3];
|
||||
if (indices.length > 4) name = map.names[indices[4]];
|
||||
}
|
||||
}
|
||||
add(source, gen_line, gen_col, orig_line, orig_col, name);
|
||||
} : add,
|
||||
setSourceContent: sources_content ? function(source, content) {
|
||||
sources_content[source] = content;
|
||||
} : noop,
|
||||
toString: function() {
|
||||
return JSON.stringify(generator.toJSON());
|
||||
return JSON.stringify({
|
||||
version: 3,
|
||||
file: options.filename || undefined,
|
||||
sourceRoot: options.root || undefined,
|
||||
sources: sources,
|
||||
sourcesContent: sources_content ? sources.map(function(source) {
|
||||
return sources_content[source] || null;
|
||||
}) : undefined,
|
||||
names: names,
|
||||
mappings: mappings,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||
if (prev_source == null && source == null) return;
|
||||
prev_source = source;
|
||||
if (generated_line < gen_line) {
|
||||
generated_column = 0;
|
||||
do {
|
||||
mappings += ";";
|
||||
} while (++generated_line < gen_line);
|
||||
} else if (mappings) {
|
||||
mappings += ",";
|
||||
}
|
||||
mappings += vlq_encode(gen_col - generated_column);
|
||||
generated_column = gen_col;
|
||||
if (source == null) return;
|
||||
var src_idx = sources.index(source);
|
||||
mappings += vlq_encode(src_idx - source_index);
|
||||
source_index = src_idx;
|
||||
mappings += vlq_encode(orig_line - original_line);
|
||||
original_line = orig_line;
|
||||
mappings += vlq_encode(orig_col - original_column);
|
||||
original_column = orig_col;
|
||||
if (options.names && name != null) {
|
||||
var name_idx = names.index(name);
|
||||
mappings += vlq_encode(name_idx - name_index);
|
||||
name_index = name_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
|
||||
73
lib/utils.js
73
lib/utils.js
@@ -1,7 +1,7 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
https://github.com/mishoo/UglifyJS
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
@@ -87,15 +87,13 @@ DefaultsError.prototype.name = "DefaultsError";
|
||||
configure_error_stack(DefaultsError);
|
||||
|
||||
function defaults(args, defs, croak) {
|
||||
if (args === true) args = {};
|
||||
var ret = args || {};
|
||||
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
|
||||
throw new DefaultsError("`" + i + "` is not a supported option", defs);
|
||||
if (croak) for (var i in args) {
|
||||
if (HOP(args, i) && !HOP(defs, i)) throw new DefaultsError("`" + i + "` is not a supported option", defs);
|
||||
}
|
||||
for (var i in defs) if (HOP(defs, i)) {
|
||||
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
|
||||
for (var i in args) {
|
||||
if (HOP(args, i)) defs[i] = args[i];
|
||||
}
|
||||
return ret;
|
||||
return defs;
|
||||
}
|
||||
|
||||
function merge(obj, ext) {
|
||||
@@ -114,48 +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.at_top = function(val) { return new AtTop(val); };
|
||||
List.splice = function(val) { return new Splice(val); };
|
||||
List.last = function(val) { return new Last(val); };
|
||||
List.is_op = function(val) {
|
||||
return val === skip || val instanceof Splice;
|
||||
};
|
||||
List.splice = function(val) {
|
||||
return new Splice(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;
|
||||
})();
|
||||
|
||||
@@ -217,6 +196,12 @@ Dictionary.prototype = {
|
||||
return this;
|
||||
},
|
||||
has: function(key) { return ("$" + key) in this._values },
|
||||
all: function(predicate) {
|
||||
for (var i in this._values)
|
||||
if (!predicate(this._values[i], i.substr(1)))
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
each: function(f) {
|
||||
for (var i in this._values)
|
||||
f(this._values[i], i.substr(1));
|
||||
|
||||
@@ -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.8.1",
|
||||
"version": "3.10.3",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -11,7 +11,7 @@
|
||||
"Alex Lam <alexlamsl@gmail.com>",
|
||||
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
|
||||
],
|
||||
"repository": "mishoo/UglifyJS2",
|
||||
"repository": "mishoo/UglifyJS",
|
||||
"main": "tools/node.js",
|
||||
"bin": {
|
||||
"uglifyjs": "bin/uglifyjs"
|
||||
@@ -22,10 +22,6 @@
|
||||
"tools",
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "~2.20.3",
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "~7.1.0",
|
||||
"semver": "~6.3.0"
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
|
||||
var createHash = require("crypto").createHash;
|
||||
var fetch = require("./fetch");
|
||||
var fork = require("child_process").fork;
|
||||
var spawn = require("child_process").spawn;
|
||||
var zlib = require("zlib");
|
||||
var args = process.argv.slice(2);
|
||||
if (!args.length) {
|
||||
args.push("-mc");
|
||||
}
|
||||
if (!args.length) args.push("-mc");
|
||||
args.unshift("bin/uglifyjs");
|
||||
args.push("--timings");
|
||||
var urls = [
|
||||
"https://code.jquery.com/jquery-3.4.1.js",
|
||||
@@ -70,18 +69,20 @@ urls.forEach(function(url) {
|
||||
};
|
||||
fetch(url, function(err, res) {
|
||||
if (err) throw err;
|
||||
var uglifyjs = fork("bin/uglifyjs", args, { silent: true });
|
||||
var uglifyjs = spawn(process.argv[0], args, { silent: true });
|
||||
res.on("data", function(data) {
|
||||
results[url].input += data.length;
|
||||
}).pipe(uglifyjs.stdin);
|
||||
var sha1 = createHash("sha1");
|
||||
uglifyjs.stdout.on("data", function(data) {
|
||||
results[url].output += data.length;
|
||||
}).pipe(zlib.createGzip({
|
||||
level: zlib.Z_BEST_COMPRESSION
|
||||
})).on("data", function(data) {
|
||||
results[url].gzip += data.length;
|
||||
}).pipe(createHash("sha1")).on("data", function(data) {
|
||||
results[url].sha1 = data.toString("hex");
|
||||
sha1.update(data);
|
||||
}).on("end", function() {
|
||||
results[url].sha1 = sha1.digest("hex");
|
||||
done();
|
||||
});
|
||||
uglifyjs.stderr.setEncoding("utf8");
|
||||
|
||||
@@ -63,7 +63,7 @@ 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/UglifyJS2/issues/348
|
||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS/issues/348
|
||||
try {
|
||||
var ast = U.parse(script, {
|
||||
filename: file
|
||||
@@ -188,6 +188,7 @@ function reminify(orig_options, input_code, input_formatted, stdout) {
|
||||
}
|
||||
});
|
||||
var options_formatted = JSON.stringify(options, null, 4);
|
||||
options.validate = true;
|
||||
var result = U.minify(input_code, options);
|
||||
if (result.error) {
|
||||
log([
|
||||
@@ -251,6 +252,7 @@ function run_code(code, toplevel) {
|
||||
|
||||
function test_case(test) {
|
||||
log(" Running test [{name}]", { name: test.name });
|
||||
U.AST_Node.enable_validation();
|
||||
var output_options = test.beautify || {};
|
||||
var expect;
|
||||
if (test.expect) {
|
||||
@@ -267,6 +269,7 @@ function test_case(test) {
|
||||
quote_style: 3,
|
||||
});
|
||||
try {
|
||||
input.validate_ast();
|
||||
U.parse(input_code);
|
||||
} catch (ex) {
|
||||
log([
|
||||
@@ -309,12 +312,10 @@ function test_case(test) {
|
||||
if (test.mangle) {
|
||||
output.compute_char_frequency(test.mangle);
|
||||
output.mangle_names(test.mangle);
|
||||
if (test.mangle.properties) {
|
||||
output = U.mangle_properties(output, test.mangle.properties);
|
||||
}
|
||||
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
||||
}
|
||||
output = make_code(output, output_options);
|
||||
if (expect != output) {
|
||||
var output_code = make_code(output, output_options);
|
||||
if (expect != output_code) {
|
||||
log([
|
||||
"!!! failed",
|
||||
"---INPUT---",
|
||||
@@ -327,14 +328,15 @@ function test_case(test) {
|
||||
"",
|
||||
].join("\n"), {
|
||||
input: input_formatted,
|
||||
output: output,
|
||||
output: output_code,
|
||||
expected: expect
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// expect == output
|
||||
try {
|
||||
U.parse(output);
|
||||
output.validate_ast();
|
||||
U.parse(output_code);
|
||||
} catch (ex) {
|
||||
log([
|
||||
"!!! Test matched expected result but cannot parse output",
|
||||
@@ -348,7 +350,7 @@ function test_case(test) {
|
||||
"",
|
||||
].join("\n"), {
|
||||
input: input_formatted,
|
||||
output: output,
|
||||
output: output_code,
|
||||
error: ex,
|
||||
});
|
||||
return false;
|
||||
@@ -407,7 +409,7 @@ function test_case(test) {
|
||||
});
|
||||
return false;
|
||||
}
|
||||
actual = run_code(output, toplevel);
|
||||
actual = run_code(output_code, toplevel);
|
||||
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
||||
log([
|
||||
"!!! failed",
|
||||
|
||||
@@ -243,20 +243,18 @@ issue_3273: {
|
||||
arguments: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
console.log(a, a);
|
||||
a++;
|
||||
console.log(a, a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
@@ -264,26 +262,43 @@ issue_3273: {
|
||||
]
|
||||
}
|
||||
|
||||
issue_3273_no_call_arg: {
|
||||
options = {
|
||||
arguments: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
arguments[0] = "FAIL";
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
arguments[0] = "FAIL";
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_3273_reduce_vars: {
|
||||
options = {
|
||||
arguments: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
console.log(a, a);
|
||||
a++;
|
||||
console.log(a, a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
@@ -296,22 +311,20 @@ issue_3273_local_strict: {
|
||||
arguments: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
"use strict";
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
"use strict";
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
@@ -325,22 +338,20 @@ issue_3273_local_strict_reduce_vars: {
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
"use strict";
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
"use strict";
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
@@ -354,21 +365,19 @@ issue_3273_global_strict: {
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
@@ -383,21 +392,19 @@ issue_3273_global_strict_reduce_vars: {
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
(function(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
})(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
|
||||
@@ -91,8 +91,7 @@ asm_mixed: {
|
||||
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
||||
function logSum(start, end) {
|
||||
start |= 0, end |= 0;
|
||||
var sum = 0, p = 0, q = 0;
|
||||
for (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) {
|
||||
|
||||
@@ -407,3 +407,57 @@ issue_3429_2: {
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_3949_1: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 42;
|
||||
function f() {
|
||||
var b = a;
|
||||
b = b >> 2;
|
||||
return 100 + b;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
var a = 42;
|
||||
function f() {
|
||||
var b = a;
|
||||
b >>= 2;
|
||||
return 100 + b;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "110"
|
||||
}
|
||||
|
||||
issue_3949_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 42;
|
||||
function f() {
|
||||
var b = a;
|
||||
b = 5 & b;
|
||||
return 100 + b;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
var a = 42;
|
||||
function f() {
|
||||
var b = a;
|
||||
b &= 5;
|
||||
return 100 + b;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "100"
|
||||
}
|
||||
@@ -62,7 +62,7 @@ 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(i++), 7);
|
||||
console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(4), 7);
|
||||
}
|
||||
function f2() {
|
||||
var s = "abcdef", i = 2;
|
||||
@@ -74,13 +74,14 @@ collapse_vars_side_effects_1: {
|
||||
log = console.log.bind(console),
|
||||
x = s.charAt(i++),
|
||||
y = s.charAt(i++);
|
||||
log(x, s.charAt(i++), y, 7);
|
||||
log(x, s.charAt(4), y, 7);
|
||||
}
|
||||
function f4() {
|
||||
var i = 10,
|
||||
x = i += 2,
|
||||
y = i += 3;
|
||||
console.log.bind(console)(x, i += 4, y, 19);
|
||||
var i = 10;
|
||||
i += 2,
|
||||
i += 3,
|
||||
i += 4;
|
||||
console.log.bind(console)(12, 19, 15, 19);
|
||||
}
|
||||
f1(), f2(), f3(), f4();
|
||||
}
|
||||
@@ -803,8 +804,7 @@ collapse_vars_assignment: {
|
||||
expect: {
|
||||
function log(x) { return console.log(x), x; }
|
||||
function f0(c) {
|
||||
var a = 3 / c;
|
||||
return a = a;
|
||||
return 3 / c;
|
||||
}
|
||||
function f1(c) {
|
||||
return 1 - 3 / c;
|
||||
@@ -917,7 +917,7 @@ collapse_vars_lvalues_drop_assign: {
|
||||
}
|
||||
}
|
||||
|
||||
collapse_vars_misc1: {
|
||||
collapse_vars_misc: {
|
||||
options = {
|
||||
booleans: true,
|
||||
collapse_vars: true,
|
||||
@@ -971,8 +971,8 @@ collapse_vars_misc1: {
|
||||
function f7() { var b = window.a * window.z; return b + b }
|
||||
function f8() { var b = window.a * window.z; return b + (5 + b) }
|
||||
function f9() { var b = window.a * window.z; return bar() || b }
|
||||
function f10(x) { var a = 5; return a += 3; }
|
||||
function f11(x) { var a = 5; return a += 2; }
|
||||
function f10(x) { return 8; }
|
||||
function f11(x) { return 7; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1599,7 +1599,7 @@ collapse_vars_constants: {
|
||||
}
|
||||
}
|
||||
|
||||
collapse_vars_arguments: {
|
||||
collapse_vars_arguments_1: {
|
||||
options = {
|
||||
booleans: true,
|
||||
collapse_vars: true,
|
||||
@@ -1636,6 +1636,78 @@ collapse_vars_arguments: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_arguments_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function log(a, b) {
|
||||
console.log(b);
|
||||
}
|
||||
function f(c) {
|
||||
var d = arguments[0];
|
||||
c = "FAIL";
|
||||
log(c, d);
|
||||
}
|
||||
f();
|
||||
f("PASS");
|
||||
}
|
||||
expect: {
|
||||
function log(a, b) {
|
||||
console.log(b);
|
||||
}
|
||||
function f(c) {
|
||||
var d = arguments[0];
|
||||
log(c = "FAIL", d);
|
||||
}
|
||||
f();
|
||||
f("PASS");
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
collapse_vars_arguments_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function log(a, b) {
|
||||
console.log(b);
|
||||
}
|
||||
function f(c) {
|
||||
var args = arguments;
|
||||
console.log(c);
|
||||
var d = args[0];
|
||||
c = "FAIL";
|
||||
log(c, d);
|
||||
}
|
||||
f();
|
||||
f("PASS");
|
||||
}
|
||||
expect: {
|
||||
function log(a, b) {
|
||||
console.log(b);
|
||||
}
|
||||
function f(c) {
|
||||
var args = arguments;
|
||||
console.log(c);
|
||||
var d = args[0];
|
||||
log(c = "FAIL", d);
|
||||
}
|
||||
f();
|
||||
f("PASS");
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
"undefined",
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
collapse_vars_short_circuit: {
|
||||
options = {
|
||||
booleans: true,
|
||||
@@ -2012,6 +2084,7 @@ issue_1631_3: {
|
||||
join_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function g() {
|
||||
@@ -2031,8 +2104,8 @@ issue_1631_3: {
|
||||
function f() {
|
||||
return a = 2, 4;
|
||||
}
|
||||
var a = 0, b = 1, t = f();
|
||||
return b = a + t;
|
||||
var a = 0, t = f();
|
||||
return a + t;
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
@@ -2204,8 +2277,8 @@ var_defs: {
|
||||
}
|
||||
expect: {
|
||||
var f1 = function(x, y) {
|
||||
var r = x + y, a = r * r - r, b = 7;
|
||||
console.log(a + b);
|
||||
var r = x + y, z = r * r - r, b = 7;
|
||||
console.log(z + b);
|
||||
};
|
||||
f1("1", 0);
|
||||
}
|
||||
@@ -2569,8 +2642,7 @@ chained_3: {
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
var c = 1;
|
||||
c = b;
|
||||
var c = 1, c = b;
|
||||
b++;
|
||||
return c;
|
||||
}(0, 2));
|
||||
@@ -2665,8 +2737,8 @@ double_def_1: {
|
||||
a();
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
(a = (a = x) && y)();
|
||||
var a = x;
|
||||
(a = a && y)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2699,8 +2771,8 @@ toplevel_single_reference: {
|
||||
}
|
||||
expect: {
|
||||
for (var b in x) {
|
||||
var a;
|
||||
b(a = b);
|
||||
var a = b;
|
||||
b(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3001,8 +3073,7 @@ issue_2298: {
|
||||
expect: {
|
||||
!function() {
|
||||
(function() {
|
||||
var a = undefined;
|
||||
var undefined = a++;
|
||||
0;
|
||||
try {
|
||||
!function(b) {
|
||||
(void 0)[1] = "foo";
|
||||
@@ -3836,20 +3907,19 @@ issue_2436_3: {
|
||||
}(o));
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
console.log(function(c) {
|
||||
o = {
|
||||
({
|
||||
a: 3,
|
||||
b: 4,
|
||||
};
|
||||
});
|
||||
return {
|
||||
x: c.a,
|
||||
y: c.b,
|
||||
};
|
||||
}(o));
|
||||
}({
|
||||
a: 1,
|
||||
b: 2,
|
||||
}));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -4071,16 +4141,15 @@ issue_2436_10: {
|
||||
}(o).join(" "));
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
};
|
||||
function f(n) {
|
||||
o = { b: 3 };
|
||||
({ b: 3 });
|
||||
return n;
|
||||
}
|
||||
console.log([
|
||||
(c = o).a,
|
||||
(c = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
}).a,
|
||||
f(c.b),
|
||||
c.b,
|
||||
].join(" "));
|
||||
@@ -4243,8 +4312,7 @@ issue_2497: {
|
||||
if (true)
|
||||
for (var i = 0; i < 1; ++i)
|
||||
for (var k = 0; k < 1; ++k) {
|
||||
value = 1;
|
||||
value = value ? value + 1 : 0;
|
||||
value = (value = 1) ? value + 1 : 0;
|
||||
}
|
||||
else
|
||||
for (i = 0; i < 1; ++i)
|
||||
@@ -6892,6 +6960,30 @@ sequence_in_iife_2: {
|
||||
}
|
||||
expect: {
|
||||
var a = "foo", b = 42;
|
||||
b = a;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "foo foo"
|
||||
}
|
||||
|
||||
sequence_in_iife_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "foo", b = 42;
|
||||
(function() {
|
||||
var c = (b = a, b);
|
||||
})();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = "foo";
|
||||
console.log(a, a);
|
||||
}
|
||||
expect_stdout: "foo foo"
|
||||
@@ -7806,3 +7898,665 @@ issue_3744: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
assign_value_def: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
while (1) {
|
||||
var b = a[0], c = a[1];
|
||||
d = b;
|
||||
e = c;
|
||||
if (c[0] - e[0] > c[1] - d[1]) break;
|
||||
return "PASS";
|
||||
}
|
||||
var d, e;
|
||||
return "FAIL";
|
||||
}
|
||||
console.log(f([
|
||||
[ 1, 2 ],
|
||||
[ 3, 4 ],
|
||||
]));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
while (1) {
|
||||
var b = a[0], c = a[1];
|
||||
if (c[0] - c[0] > c[1] - b[1]) break;
|
||||
return "PASS";
|
||||
}
|
||||
return "FAIL";
|
||||
}
|
||||
console.log(f([
|
||||
[ 1, 2 ],
|
||||
[ 3, 4 ],
|
||||
]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
join_vars_value_def: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
join_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
while (1) {
|
||||
var b = a[0], c = a[1];
|
||||
d = b;
|
||||
e = c;
|
||||
if (c[0] - e[0] > c[1] - d[1]) break;
|
||||
return "PASS";
|
||||
}
|
||||
var d, e;
|
||||
return "FAIL";
|
||||
}
|
||||
console.log(f([
|
||||
[ 1, 2 ],
|
||||
[ 3, 4 ],
|
||||
]));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
while (1) {
|
||||
var b = a[0], c = a[1];
|
||||
if (c[0] - c[0] > c[1] - b[1]) break;
|
||||
return "PASS";
|
||||
}
|
||||
return "FAIL";
|
||||
}
|
||||
console.log(f([
|
||||
[ 1, 2 ],
|
||||
[ 3, 4 ],
|
||||
]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
var_value_def: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
while (1) {
|
||||
var b = a[0], c = a[1], d = b, e = c;
|
||||
if (c[0] - e[0] > c[1] - d[1]) break;
|
||||
return "PASS";
|
||||
}
|
||||
var d, e;
|
||||
return "FAIL";
|
||||
}
|
||||
console.log(f([
|
||||
[ 1, 2 ],
|
||||
[ 3, 4 ],
|
||||
]));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
while (1) {
|
||||
var b = a[0], c = a[1];
|
||||
if (c[0] - c[0] > c[1] - b[1]) break;
|
||||
return "PASS";
|
||||
}
|
||||
return "FAIL";
|
||||
}
|
||||
console.log(f([
|
||||
[ 1, 2 ],
|
||||
[ 3, 4 ],
|
||||
]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangleable_var: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
var b = a(), c = a(), d = b;
|
||||
return c.p(c, d);
|
||||
}
|
||||
console.log(f(function() {
|
||||
return {
|
||||
p: function() {
|
||||
return "PASS"
|
||||
},
|
||||
};
|
||||
}));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
var b = a(), c = a();
|
||||
return c.p(c, b);
|
||||
}
|
||||
console.log(f(function() {
|
||||
return {
|
||||
p: function() {
|
||||
return "PASS";
|
||||
}
|
||||
};
|
||||
}));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3884_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 1;
|
||||
{
|
||||
a++ + a || a;
|
||||
b <<= a;
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 1;
|
||||
b <<= ++a;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "101 32"
|
||||
}
|
||||
|
||||
issue_3884_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 1;
|
||||
{
|
||||
a++ + a || a;
|
||||
b <<= a;
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
console.log(101, 32);
|
||||
}
|
||||
expect_stdout: "101 32"
|
||||
}
|
||||
|
||||
issue_3891: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function log(a) {
|
||||
console.log(typeof a);
|
||||
}
|
||||
log(function f() {
|
||||
try {
|
||||
do {
|
||||
var b = function() {}();
|
||||
} while (f = 0, b.p);
|
||||
} catch (e) {
|
||||
var f;
|
||||
b;
|
||||
}
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
function log(a) {
|
||||
console.log(typeof a);
|
||||
}
|
||||
log(function() {
|
||||
try {
|
||||
do {} while ((void 0).p);
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_3894: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function log(msg) {
|
||||
console.log(msg ? "FAIL" : "PASS");
|
||||
}
|
||||
var a, c;
|
||||
(function(b) {
|
||||
a = c = 0,
|
||||
log(b);
|
||||
})(-0);
|
||||
log(a);
|
||||
log(c);
|
||||
}
|
||||
expect: {
|
||||
function log(msg) {
|
||||
console.log(msg ? "FAIL" : "PASS");
|
||||
}
|
||||
var a, c;
|
||||
void log(-(a = c = 0));
|
||||
log(a);
|
||||
log(c);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3897: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
(function() {
|
||||
function f(b) {
|
||||
b = a = 1 + a;
|
||||
a = 1 + a;
|
||||
console.log(b);
|
||||
}
|
||||
f();
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
(function() {
|
||||
function f(b) {
|
||||
b = a = 1 + a;
|
||||
a = 1 + a;
|
||||
console.log(b);
|
||||
}
|
||||
f();
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"2",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3908: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
if (console) {
|
||||
var o = {
|
||||
p: !1
|
||||
}, a = o;
|
||||
}
|
||||
console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
console && 0;
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3927: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
console.log(function(b) {
|
||||
try {
|
||||
try {
|
||||
if (a + (b = "PASS", true)) return;
|
||||
b.p;
|
||||
} finally {
|
||||
return b;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
console.log(function(b) {
|
||||
try {
|
||||
try {
|
||||
if (a + (b = "PASS", true)) return;
|
||||
b.p;
|
||||
} finally {
|
||||
return b;
|
||||
}
|
||||
} catch (e) {}
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
operator_in: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function log(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
var a = "FAIL";
|
||||
try {
|
||||
a = "PASS";
|
||||
0 in null;
|
||||
log("FAIL", a);
|
||||
} catch (e) {}
|
||||
log(a);
|
||||
}
|
||||
expect: {
|
||||
function log(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
var a = "FAIL";
|
||||
try {
|
||||
a = "PASS";
|
||||
0 in null;
|
||||
log("FAIL", a);
|
||||
} catch (e) {}
|
||||
log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3971: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0 == typeof f, b = 0;
|
||||
{
|
||||
var a = void (a++ + (b |= a));
|
||||
}
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var a = 0 == typeof f, b = 0;
|
||||
var a = void (b |= ++a);
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3976: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
console.log("FAIL");
|
||||
}
|
||||
(function(a) {
|
||||
function g() {
|
||||
if ((a = 0) || f(0)) {
|
||||
f();
|
||||
} else {
|
||||
f();
|
||||
}
|
||||
if (h(a = 0));
|
||||
}
|
||||
function h() {
|
||||
g();
|
||||
}
|
||||
})();
|
||||
console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
console.log("FAIL");
|
||||
}
|
||||
void 0;
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4012: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
try {
|
||||
throw 2;
|
||||
} catch (b) {
|
||||
a = "PASS";
|
||||
if (--b)
|
||||
return;
|
||||
if (3);
|
||||
} finally {
|
||||
console.log(a);
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
try {
|
||||
throw 2;
|
||||
} catch (b) {
|
||||
a = "PASS";
|
||||
if (--b)
|
||||
return;
|
||||
if (3);
|
||||
} finally {
|
||||
console.log(a);
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
global_assign: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
this.A = "FAIL";
|
||||
A = "PASS";
|
||||
B = "FAIL";
|
||||
console.log(A);
|
||||
}
|
||||
expect: {
|
||||
this.A = "FAIL";
|
||||
A = "PASS";
|
||||
B = "FAIL";
|
||||
console.log(A);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
global_read: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
a = this.A;
|
||||
A = 1;
|
||||
a ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
a = this.A;
|
||||
A = 1;
|
||||
a ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4038: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
a = this;
|
||||
a = a.A;
|
||||
A = 1;
|
||||
a ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
a = (a = this).A;
|
||||
A = 1;
|
||||
a ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4040: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = console.log("PASS") && a.p;
|
||||
delete NaN;
|
||||
}
|
||||
expect: {
|
||||
var a = console.log("PASS") && a.p;
|
||||
delete NaN;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4047_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
console.log(+function(a) {
|
||||
b = a;
|
||||
(a >>= 0) && console.log("PASS");
|
||||
}(--b + (0 !== typeof A)));
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
var a;
|
||||
console.log((a = --b + ((a = 0) !== typeof A), +void ((a >>= 0) && console.log("PASS"))));
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"NaN",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4047_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
console.log(+function(a) {
|
||||
b = a;
|
||||
(a >>= 0) && console.log("PASS");
|
||||
}(--b + (0 !== typeof A)));
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
console.log((a = +(0 !== typeof A), +void ((a >>= 0) && console.log("PASS"))));
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"NaN",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4051: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
var a = (b = b.p, "FAIL"), b = b;
|
||||
} catch (e) {}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
var a = (b = b.p, "FAIL"), b = b;
|
||||
} catch (e) {}
|
||||
console.log(a);
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -93,6 +93,59 @@ self_comparison_2: {
|
||||
expect_stdout: "false true"
|
||||
}
|
||||
|
||||
self_comparison_3: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
function f() {
|
||||
var b = a;
|
||||
a = null;
|
||||
return b;
|
||||
}
|
||||
for (var i = 0; i < 2; i++)
|
||||
console.log(f() === f());
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
function f() {
|
||||
var b = a;
|
||||
a = null;
|
||||
return b;
|
||||
}
|
||||
for (var i = 0; i < 2; i++)
|
||||
console.log(f() === f());
|
||||
}
|
||||
expect_stdout: [
|
||||
"false",
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
self_comparison_4: {
|
||||
options = {
|
||||
booleans: true,
|
||||
comparisons: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
console.log(o == o, o != o);
|
||||
console.log(o === o, o !== o);
|
||||
}
|
||||
expect: {
|
||||
console.log(!0, !1);
|
||||
console.log(!0, !1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"true false",
|
||||
"true false",
|
||||
]
|
||||
}
|
||||
|
||||
issue_2857_1: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
|
||||
@@ -1384,7 +1384,7 @@ hoist_decl: {
|
||||
}
|
||||
expect: {
|
||||
var a, b;
|
||||
x() ? y() : z();
|
||||
(x() ? y : z)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1666,3 +1666,130 @@ issue_3668: {
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
conditional_assignments_1: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b, c, d) {
|
||||
a = b;
|
||||
if (c) a = d;
|
||||
return a;
|
||||
}
|
||||
function g(a, b, c, d) {
|
||||
a = b;
|
||||
if (c); else a = d;
|
||||
return a;
|
||||
}
|
||||
console.log(f(0, "FAIL", 1, "PASS"), g(0, "PASS", 1, "FAIL"));
|
||||
}
|
||||
expect: {
|
||||
function f(a, b, c, d) {
|
||||
return a = c ? d : b, a;
|
||||
}
|
||||
function g(a, b, c, d) {
|
||||
return a = c ? b : d, a;
|
||||
}
|
||||
console.log(f(0, "FAIL", 1, "PASS"), g(0, "PASS", 1, "FAIL"));
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
conditional_assignments_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f1(b, c, d) {
|
||||
a = b;
|
||||
if (c) a = d;
|
||||
return a;
|
||||
}
|
||||
function f2(a, c, d) {
|
||||
a = b;
|
||||
if (c) a = d;
|
||||
return a;
|
||||
}
|
||||
function f3(a, b, d) {
|
||||
a = b;
|
||||
if (c) a = d;
|
||||
return a;
|
||||
}
|
||||
function f4(a, b, c) {
|
||||
a = b;
|
||||
if (c) a = d;
|
||||
return a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f1(b, c, d) {
|
||||
return a = c ? d : b, a;
|
||||
}
|
||||
function f2(a, c, d) {
|
||||
return a = b, c && (a = d), a;
|
||||
}
|
||||
function f3(a, b, d) {
|
||||
return a = b, c && (a = d), a;
|
||||
}
|
||||
function f4(a, b, c) {
|
||||
return a = b, c && (a = d), a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conditional_assignments_3: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, b) {
|
||||
a = "PASS";
|
||||
if (b) a = a;
|
||||
return a;
|
||||
}(0, 1));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
return a = "PASS", b && (a = a), a;
|
||||
}(0, 1));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3808_1: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
a = "PASS", [] + "" && (a = "FAIL");
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
a = [] + "" ? "FAIL" : "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3808_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
console.log((a = "PASS", [] + "" && (a = "FAIL")), a);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
console.log((a = "PASS", [] + "" && (a = "FAIL")), a);
|
||||
}
|
||||
expect_stdout: " PASS"
|
||||
}
|
||||
|
||||
@@ -97,6 +97,66 @@ dead_code_constant_boolean_should_warn_more: {
|
||||
node_version: "<=4"
|
||||
}
|
||||
|
||||
trim_try: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
var a;
|
||||
} catch (e) {
|
||||
console.log("FAIL");
|
||||
} finally {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
trim_finally_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
console.log("PASS");
|
||||
} finally {
|
||||
var a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
var a;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
trim_finally_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
} finally {
|
||||
var a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
console.log("PASS");
|
||||
var a;
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
try_catch_finally: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
@@ -130,10 +190,7 @@ try_catch_finally: {
|
||||
a = 3;
|
||||
console.log("PASS");
|
||||
}();
|
||||
try {
|
||||
console.log(a);
|
||||
} finally {
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
@@ -179,7 +236,7 @@ collapse_vars_lvalues_drop_assign: {
|
||||
}
|
||||
}
|
||||
|
||||
collapse_vars_misc1: {
|
||||
collapse_vars_misc: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
dead_code: true,
|
||||
@@ -892,3 +949,416 @@ issue_3578: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3830_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
set p(v) {
|
||||
o = o.p = o = v;
|
||||
}
|
||||
};
|
||||
o.p = "PASS";
|
||||
console.log(o);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
set p(v) {
|
||||
o = o.p = o = v;
|
||||
}
|
||||
};
|
||||
o.p = "PASS";
|
||||
console.log(o);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3830_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
a = o[a] = a = v;
|
||||
}
|
||||
};
|
||||
o[a] = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
a = o[a] = a = v;
|
||||
}
|
||||
};
|
||||
o[a] = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3830_3: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
a = o[f()] = a = v;
|
||||
}
|
||||
};
|
||||
o[f()] = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
a = o[f()] = a = v;
|
||||
}
|
||||
};
|
||||
o[f()] = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3830_4: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return o;
|
||||
}
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
a = f()[a] = a = v;
|
||||
}
|
||||
};
|
||||
f()[a] = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return o;
|
||||
}
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
a = f()[a] = a = v;
|
||||
}
|
||||
};
|
||||
f()[a] = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3830_5: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return o;
|
||||
}
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
a = f()[g()] = a = v;
|
||||
}
|
||||
};
|
||||
f()[g()] = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return o;
|
||||
}
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
a = f()[g()] = a = v;
|
||||
}
|
||||
};
|
||||
f()[g()] = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3830_6: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return o;
|
||||
}
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
function h(v) {
|
||||
a = f()[g()] = a = v;
|
||||
}
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
h(v);
|
||||
}
|
||||
};
|
||||
o.FAIL = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return o;
|
||||
}
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
function h(v) {
|
||||
a = f()[g()] = a = v;
|
||||
}
|
||||
var a = "FAIL";
|
||||
var o = {
|
||||
set FAIL(v) {
|
||||
h(v);
|
||||
}
|
||||
};
|
||||
o.FAIL = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
redundant_assignments: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
var a = a = "PASS", b = "FAIL";
|
||||
b = b = "PASS";
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS", b = "FAIL";
|
||||
b = "PASS";
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
self_assignments_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
a = a;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
a;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
self_assignments_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "q", o = {
|
||||
p: "PASS",
|
||||
};
|
||||
o.p = o.p;
|
||||
o[a] = o[a];
|
||||
console.log(o.p, o[a]);
|
||||
}
|
||||
expect: {
|
||||
var a = "q", o = {
|
||||
p: "PASS",
|
||||
};
|
||||
console.log(o.p, o[a]);
|
||||
}
|
||||
expect_stdout: "PASS undefined"
|
||||
}
|
||||
|
||||
self_assignments_3: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "q", o = {
|
||||
p: "FAIL",
|
||||
get q() {
|
||||
return "PASS";
|
||||
},
|
||||
set q(v) {
|
||||
this.p = v;
|
||||
},
|
||||
};
|
||||
o.p = o.p;
|
||||
o[a] = o[a];
|
||||
console.log(o.p, o[a]);
|
||||
}
|
||||
expect: {
|
||||
var a = "q", o = {
|
||||
p: "FAIL",
|
||||
get q() {
|
||||
return "PASS";
|
||||
},
|
||||
set q(v) {
|
||||
this.p = v;
|
||||
},
|
||||
};
|
||||
o.p = o.p;
|
||||
o[a] = o[a];
|
||||
console.log(o.p, o[a]);
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
self_assignments_4: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var i = 0, l = [ "PASS" ];
|
||||
l[0] = l[0];
|
||||
l[i] = l[i];
|
||||
console.log(l[0], i);
|
||||
}
|
||||
expect: {
|
||||
var i = 0, l = [ "PASS" ];
|
||||
console.log(l[0], i);
|
||||
}
|
||||
expect_stdout: "PASS 0"
|
||||
}
|
||||
|
||||
self_assignments_5: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
passes: 3,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var i = 0, l = [ "FAIL", "PASS" ];
|
||||
l[0] = l[0];
|
||||
l[i] = l[i];
|
||||
l[i++] = l[i++];
|
||||
console.log(l[0], i);
|
||||
}
|
||||
expect: {
|
||||
var i = 0, l = [ "FAIL", "PASS" ];
|
||||
l[0];
|
||||
l[0];
|
||||
l[0] = l[1];
|
||||
console.log(l[0], 2);
|
||||
}
|
||||
expect_stdout: "PASS 2"
|
||||
}
|
||||
|
||||
self_assignments_6: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
p: "PASS",
|
||||
};
|
||||
console.log(o.p = o.p);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
p: "PASS",
|
||||
};
|
||||
console.log(o.p);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3967: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
a = 0 in (a = "PASS");
|
||||
} catch (e) {}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
a = 0 in (a = "PASS");
|
||||
} catch (e) {}
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4051: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
delete (A = A);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
delete (A = A);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ simple_statement_is_not_a_directive: {
|
||||
drop_lone_use_strict: {
|
||||
options = {
|
||||
directives: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f1() {
|
||||
@@ -66,10 +66,8 @@ drop_lone_use_strict: {
|
||||
function f1() {
|
||||
}
|
||||
function f2() {
|
||||
"use strict";
|
||||
function f3() {
|
||||
}
|
||||
}
|
||||
(function() {})();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2285,7 +2285,7 @@ issue_3598: {
|
||||
try {
|
||||
(function() {
|
||||
a = "PASS";
|
||||
var c = (void (c.p = 0))[!1];
|
||||
(void ((void 0).p = 0))[!1];
|
||||
})();
|
||||
} catch (e) {}
|
||||
console.log(a);
|
||||
@@ -2366,7 +2366,7 @@ function_parameter_ie8: {
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function f() {
|
||||
(function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
})();
|
||||
@@ -2444,3 +2444,407 @@ issue_3746: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
drop_duplicated_side_effects: {
|
||||
options = {
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
for (var i = 1; i--;)
|
||||
var a = 0, b = ++a;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
for (var i = 1; i--;)
|
||||
a = 0, ++a;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
drop_duplicated_var_catch: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
try {
|
||||
x();
|
||||
} catch (a) {
|
||||
var a, a;
|
||||
}
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
try {
|
||||
x();
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_3802_1: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
a += 0;
|
||||
var a = function() {};
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
a += 0;
|
||||
a = function() {};
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_3802_2: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
a += 0;
|
||||
var a = function() {};
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
0;
|
||||
var a = function() {};
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_3899: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
functions: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
a = a + 1;
|
||||
var a = function f(b) {
|
||||
return function() {
|
||||
return b;
|
||||
};
|
||||
}(2);
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
function a() {
|
||||
return 2;
|
||||
}
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
cross_scope_assign_chain: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a, b = 0;
|
||||
(function() {
|
||||
a = b;
|
||||
a++;
|
||||
while (b++);
|
||||
})();
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
expect: {
|
||||
var a, b = 0;
|
||||
(function() {
|
||||
a = b;
|
||||
a++;
|
||||
while (b++);
|
||||
})();
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
assign_if_assign_read: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
var b;
|
||||
do {
|
||||
b = "FAIL";
|
||||
if (Array.isArray(a)) {
|
||||
b = a[0];
|
||||
console.log(b);
|
||||
}
|
||||
} while (!console);
|
||||
})([ "PASS" ]);
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
var b;
|
||||
do {
|
||||
"FAIL";
|
||||
if (Array.isArray(a)) {
|
||||
b = a[0];
|
||||
console.log(b);
|
||||
}
|
||||
} while (!console);
|
||||
})([ "PASS" ]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3951: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = console.log("PASS");
|
||||
console.log(a);
|
||||
a = "0";
|
||||
console.log(a.p = 0);
|
||||
a && a;
|
||||
}
|
||||
expect: {
|
||||
var a = console.log("PASS");
|
||||
console.log(a);
|
||||
a = "0";
|
||||
console.log(a.p = 0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"undefined",
|
||||
"0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3956: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
function f(b) {
|
||||
console.log(b);
|
||||
a = 1;
|
||||
}
|
||||
var c = f(c += 0);
|
||||
(function(d) {
|
||||
console.log(d);
|
||||
})(console.log(a) ^ 1, c);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
var c, d;
|
||||
c += 0,
|
||||
console.log(NaN),
|
||||
d = 1 ^ console.log(1),
|
||||
console.log(d);
|
||||
}
|
||||
expect_stdout: [
|
||||
"NaN",
|
||||
"1",
|
||||
"1",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3962_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
function f(b, c) {
|
||||
do {
|
||||
var d = console + e, e = 0..toString() === b;
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}
|
||||
var a = f(a--, 1);
|
||||
a;
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
a = (function(c) {
|
||||
do {
|
||||
console;
|
||||
0..toString();
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}((a--, 1)), 0);
|
||||
void 0;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3962_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
function f(b, c) {
|
||||
do {
|
||||
var d = console + e, e = 0..toString() === b;
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}
|
||||
var a = f(a--, 1);
|
||||
a;
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
a = (function(c) {
|
||||
do {
|
||||
console;
|
||||
0..toString();
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}((a--, 1)), 0);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3986: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 0;
|
||||
(function() {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (e) {
|
||||
a++;
|
||||
}
|
||||
b = b && 0;
|
||||
})(b *= a);
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b = 0;
|
||||
(function() {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (e) {
|
||||
a++;
|
||||
}
|
||||
b = b && 0;
|
||||
})(b *= a);
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4017: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
console.log(function f() {
|
||||
var b = c &= 0;
|
||||
var c = a++ + (A = a);
|
||||
var d = c && c[f];
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
console.log(function() {
|
||||
c &= 0;
|
||||
var c = (a++, A = a, 0);
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4025: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 0, c = 0, d = a++;
|
||||
try {
|
||||
var e = console.log(c), f = b;
|
||||
} finally {
|
||||
var d = b = 1, d = c + 1;
|
||||
c = 0;
|
||||
}
|
||||
console.log(a, b, d);
|
||||
}
|
||||
expect: {
|
||||
var d, c = 0;
|
||||
try {
|
||||
console.log(c);
|
||||
} finally {
|
||||
d = c + 1;
|
||||
c = 0;
|
||||
}
|
||||
console.log(1, 1, d);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"1 1 1",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -558,34 +558,51 @@ unsafe_array: {
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
[1, , 3][1],
|
||||
[1, 2, 3, a] + 1,
|
||||
[1, 2, 3, 4] + 1,
|
||||
[1, 2, 3, a][0] + 1,
|
||||
[1, 2, 3, 4][0] + 1,
|
||||
[1, 2, 3, 4][6 - 5] + 1,
|
||||
[1, , 3, 4][6 - 5] + 1,
|
||||
[[1, 2], [3, 4]][0] + 1,
|
||||
[[1, 2], [3, 4]][6 - 5][1] + 1,
|
||||
[[1, 2], , [3, 4]][6 - 5][1] + 1
|
||||
);
|
||||
var a = "PASS";
|
||||
Array.prototype[1] = a;
|
||||
console.log([, ].length);
|
||||
console.log("" + [, , ]);
|
||||
console.log([1, , 3][1]);
|
||||
console.log([1, 2, 3, a] + 1);
|
||||
console.log([1, 2, 3, 4] + 1);
|
||||
console.log([1, 2, 3, a][0] + 1);
|
||||
console.log([1, 2, 3, 4][0] + 1);
|
||||
console.log([1, 2, 3, 4][6 - 5] + 1);
|
||||
console.log([1, , 3, 4][6 - 5] + 1);
|
||||
console.log([[1, 2], [3, 4]][0] + 1);
|
||||
console.log([[1, 2], [3, 4]][6 - 5][1] + 1);
|
||||
console.log([[1, 2], , [3, 4]][6 - 5][1] + 1);
|
||||
}
|
||||
expect: {
|
||||
console.log(
|
||||
void 0,
|
||||
[1, 2, 3, a] + 1,
|
||||
"1,2,3,41",
|
||||
[1, 2, 3, a][0] + 1,
|
||||
2,
|
||||
3,
|
||||
NaN,
|
||||
"1,21",
|
||||
5,
|
||||
(void 0)[1] + 1
|
||||
);
|
||||
var a = "PASS";
|
||||
Array.prototype[1] = a;
|
||||
console.log([, ].length);
|
||||
console.log("" + [, , ]);
|
||||
console.log([1, , 3][1]);
|
||||
console.log([1, 2, 3, a] + 1);
|
||||
console.log("1,2,3,41");
|
||||
console.log([1, 2, 3, a][0] + 1);
|
||||
console.log(2);
|
||||
console.log(3);
|
||||
console.log([1, , 3, 4][1] + 1);
|
||||
console.log("1,21");
|
||||
console.log(5);
|
||||
console.log([[1, 2], , [3, 4]][1][1] + 1);
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_stdout: [
|
||||
"1",
|
||||
",PASS",
|
||||
"PASS",
|
||||
"1,2,3,PASS1",
|
||||
"1,2,3,41",
|
||||
"2",
|
||||
"2",
|
||||
"3",
|
||||
"PASS1",
|
||||
"1,21",
|
||||
"5",
|
||||
"A1",
|
||||
]
|
||||
}
|
||||
|
||||
unsafe_string: {
|
||||
@@ -1579,9 +1596,9 @@ issue_2968_1: {
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function() {
|
||||
b = -(a = 42),
|
||||
void ((a <<= 0) && (a[(c = "PASS", 0 >>> (b += 1))] = 0));
|
||||
var a, b;
|
||||
a = 42,
|
||||
void ((a <<= 0) && (a[(c = "PASS", 0)] = 0));
|
||||
var a;
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
@@ -2174,3 +2191,720 @@ issue_3738: {
|
||||
}
|
||||
expect_stdout: "Infinity"
|
||||
}
|
||||
|
||||
issue_3755: {
|
||||
options = {
|
||||
booleans: true,
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
console.log((/4/.exec(1 + (!0 - 5 / "23")) || 0).p);
|
||||
}
|
||||
expect: {
|
||||
console.log((/4/.exec(!0 - 5 / "23" + 1), 0).p);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
void_side_effects: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = void console.log("PASS");
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
console.log(void 0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"undefined",
|
||||
]
|
||||
}
|
||||
|
||||
no_returns: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function() {
|
||||
console.log("PASS");
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
console.log(void 0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"undefined",
|
||||
]
|
||||
}
|
||||
|
||||
void_returns: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function f() {
|
||||
function g(b) {
|
||||
if (b) console.log("FAIL");
|
||||
}
|
||||
while (1) {
|
||||
console.log("PASS");
|
||||
try {
|
||||
if (console) return;
|
||||
} catch (e) {
|
||||
return g(e);
|
||||
}
|
||||
}
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
function g(b) {
|
||||
if (b) console.log("FAIL");
|
||||
}
|
||||
while (1) {
|
||||
console.log("PASS");
|
||||
try {
|
||||
if (console) return;
|
||||
} catch (e) {
|
||||
return g(e);
|
||||
}
|
||||
}
|
||||
})();
|
||||
console.log(void 0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"undefined",
|
||||
]
|
||||
}
|
||||
|
||||
void_returns_recursive: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function f() {
|
||||
function g(b) {
|
||||
return f();
|
||||
}
|
||||
while (1) {
|
||||
console.log("PASS");
|
||||
try {
|
||||
if (console) return;
|
||||
} catch (e) {
|
||||
return g(e);
|
||||
}
|
||||
}
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = function f() {
|
||||
function g(b) {
|
||||
return f();
|
||||
}
|
||||
while (1) {
|
||||
console.log("PASS");
|
||||
try {
|
||||
if (console) return;
|
||||
} catch (e) {
|
||||
return g();
|
||||
}
|
||||
}
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"undefined",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3878_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b = function(a) {
|
||||
return (a = 0) == (a && this > (a += 0));
|
||||
}();
|
||||
console.log(b ? "PASS" : "FAIL");
|
||||
}
|
||||
expect: {
|
||||
console.log(true ? "PASS" : "FAIL");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3878_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "foo";
|
||||
a++ + a;
|
||||
a && a;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "foo";
|
||||
a++ + a;
|
||||
a;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_3882: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
return console.log(a++), a && this;
|
||||
}
|
||||
var b = f();
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = function(a) {
|
||||
return console.log(a++), a && this;
|
||||
}();
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: [
|
||||
"NaN",
|
||||
"NaN",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3887: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(b) {
|
||||
try {
|
||||
b-- && console.log("PASS");
|
||||
} catch (a_2) {}
|
||||
})(1);
|
||||
}
|
||||
expect: {
|
||||
(function(b) {
|
||||
try {
|
||||
1, console.log("PASS");
|
||||
} catch (a_2) {}
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3903: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
function f(b, c) {
|
||||
return console, c;
|
||||
}
|
||||
var d = f(f(), a = a);
|
||||
console.log(d);
|
||||
}
|
||||
expect: {
|
||||
function f(b, c) {
|
||||
return console, c;
|
||||
}
|
||||
f(f(), "PASS");
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3905: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
passes: 2,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a, a) {
|
||||
return console.log(a = 0), a && console.log("FAIL");
|
||||
})("foo", 42);
|
||||
}
|
||||
expect: {
|
||||
(function(a, a) {
|
||||
return console.log(a = 0), a && console.log("FAIL");
|
||||
})("foo", 42);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_3920: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function(b) {
|
||||
return (b[b = 0] = 0) >= (b ? 0 : 1);
|
||||
}("foo");
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
(function(b) {
|
||||
"foo"[0] = 0;
|
||||
})();
|
||||
console.log(false);
|
||||
}
|
||||
expect_stdout: "false"
|
||||
}
|
||||
|
||||
inlined_increment_prefix: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
(function() {
|
||||
++a;
|
||||
})();
|
||||
console.log(a += 0);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
void ++a;
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
inlined_increment_postfix: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
(function() {
|
||||
a++;
|
||||
})();
|
||||
console.log(a += 0);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
void a++;
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
compound_assignment_to_property: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
1 + (0..p >>= 0) && console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
1 + (0..p >>= 0),
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2208_assign: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
a = 42;
|
||||
console.log({
|
||||
p: function() {
|
||||
return function() {
|
||||
return this.a;
|
||||
}();
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect: {
|
||||
a = 42;
|
||||
console.log({
|
||||
p: function() {
|
||||
return function() {
|
||||
return this.a;
|
||||
}();
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_2208_postfix: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
a = 41;
|
||||
a++;
|
||||
console.log({
|
||||
p: function() {
|
||||
return function() {
|
||||
return this.a;
|
||||
}();
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect: {
|
||||
a = 41;
|
||||
a++;
|
||||
console.log({
|
||||
p: function() {
|
||||
return function() {
|
||||
return this.a;
|
||||
}();
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_2208_prefix: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
a = 43;
|
||||
--a;
|
||||
console.log({
|
||||
p: function() {
|
||||
return function() {
|
||||
return this.a;
|
||||
}();
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect: {
|
||||
a = 43;
|
||||
--a;
|
||||
console.log({
|
||||
p: function() {
|
||||
return function() {
|
||||
return this.a;
|
||||
}();
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_3933: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a, b) {
|
||||
a && (b ^= 1) && console.log("PASS");
|
||||
})(1);
|
||||
}
|
||||
expect: {
|
||||
(function(a, b) {
|
||||
1, 1, console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3935: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f(a) {
|
||||
return a++;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(NaN);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_3937: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var a = 123;
|
||||
(a++ + (b = a))[b] ? 0 ? a : b : 0 ? a : b;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 123;
|
||||
(a++ + (b = a))[b], 0, b;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "124 124"
|
||||
}
|
||||
|
||||
issue_3944: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
function f() {
|
||||
while (function() {
|
||||
var a = 0 == (b && b.p), b = console.log(a);
|
||||
}());
|
||||
f;
|
||||
}
|
||||
f();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
void function f() {
|
||||
while (a = 0 == (a = void 0), console.log(a), void 0);
|
||||
var a;
|
||||
f;
|
||||
}();
|
||||
}
|
||||
expect_stdout: "false"
|
||||
}
|
||||
|
||||
issue_3953: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
(a += 0 * (a = 0)) && console.log("PASS");
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
(a += 0 * (a = 0)) && console.log("PASS");
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3988: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(b) {
|
||||
return ("" + (b &= 0))[b && this];
|
||||
}
|
||||
var a = f();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = function(b) {
|
||||
return ("" + (b &= 0))[b && this];
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
operator_in: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
Object.prototype.PASS = 0;
|
||||
console.log(0 in [ 1 ]);
|
||||
console.log(0 in [ , ]);
|
||||
console.log(0 / 0 in { NaN: 2 });
|
||||
console.log("PASS" in { });
|
||||
console.log("FAIL" in { });
|
||||
console.log("toString" in { });
|
||||
console.log("toString" in { toString: 3 });
|
||||
}
|
||||
expect: {
|
||||
Object.prototype.PASS = 0;
|
||||
console.log(true);
|
||||
console.log(0 in [ , ]);
|
||||
console.log(true);
|
||||
console.log("PASS" in { });
|
||||
console.log("FAIL" in { });
|
||||
console.log("toString" in { });
|
||||
console.log(true);
|
||||
}
|
||||
expect_stdout: [
|
||||
"true",
|
||||
"false",
|
||||
"true",
|
||||
"true",
|
||||
"false",
|
||||
"true",
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3997: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = function f(b) {
|
||||
return b[b += this] = b;
|
||||
}(0);
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
var a = function f(b) {
|
||||
return b[b += this] = b;
|
||||
}(0);
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "string"
|
||||
}
|
||||
|
||||
issue_4035: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
(function() {
|
||||
var b = --a;
|
||||
console.log(delete (0 + b));
|
||||
console.log(delete (1 * b));
|
||||
console.log(delete (b + 0));
|
||||
console.log(delete (b - 0));
|
||||
console.log(delete (b / 1));
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
(function() {
|
||||
var b = --a;
|
||||
console.log((0 + b, true));
|
||||
console.log((1 * b, true));
|
||||
console.log((0 + b, true));
|
||||
console.log((b - 0, true));
|
||||
console.log((b / 1, true));
|
||||
})();
|
||||
}
|
||||
expect_stdout: [
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"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"
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,20 @@ must_replace: {
|
||||
}
|
||||
}
|
||||
|
||||
repeated_nodes: {
|
||||
options = {
|
||||
global_defs: {
|
||||
"@N": "rand()",
|
||||
},
|
||||
}
|
||||
input: {
|
||||
console.log(N, N);
|
||||
}
|
||||
expect: {
|
||||
console.log(rand(), rand());
|
||||
}
|
||||
}
|
||||
|
||||
keyword: {
|
||||
options = {
|
||||
global_defs: {
|
||||
|
||||
@@ -767,18 +767,17 @@ issue_3071_1: {
|
||||
var obj = {};
|
||||
obj.one = 1;
|
||||
obj.two = 2;
|
||||
console.log(obj.one);
|
||||
console.log(obj.one, obj.two);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log(1);
|
||||
console.log(1, 2);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
expect_stdout: "1 2"
|
||||
}
|
||||
|
||||
issue_3071_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
hoist_props: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
@@ -793,19 +792,18 @@ issue_3071_2: {
|
||||
obj = {};
|
||||
obj.one = 1;
|
||||
obj.two = 2;
|
||||
console.log(obj.one);
|
||||
console.log(obj.one, obj.two);
|
||||
var obj;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log(1);
|
||||
console.log(1, 2);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
expect_stdout: "1 2"
|
||||
}
|
||||
|
||||
issue_3071_2_toplevel: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
hoist_props: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
@@ -821,14 +819,14 @@ issue_3071_2_toplevel: {
|
||||
obj = {};
|
||||
obj.one = 1;
|
||||
obj.two = 2;
|
||||
console.log(obj.one);
|
||||
console.log(obj.one, obj.two);
|
||||
var obj;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log(1);
|
||||
console.log(1, 2);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
expect_stdout: "1 2"
|
||||
}
|
||||
|
||||
issue_3071_3: {
|
||||
@@ -914,3 +912,132 @@ issue_3440: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3868: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(function(t) {
|
||||
t = {};
|
||||
({
|
||||
get p() {},
|
||||
q: (console.log("PASS"), +t),
|
||||
}).r;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function(t) {
|
||||
t = {};
|
||||
({
|
||||
get p() {},
|
||||
q: (console.log("PASS"), +t),
|
||||
}).r;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3871: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
do {
|
||||
var b = {
|
||||
get null() {
|
||||
c;
|
||||
}
|
||||
};
|
||||
} while (!b);
|
||||
return "PASS";
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
do {
|
||||
var b = {
|
||||
get null() {
|
||||
c;
|
||||
}
|
||||
};
|
||||
} while (!b);
|
||||
return "PASS";
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3945_1: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
o.p;
|
||||
var o = {
|
||||
q: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
o.p;
|
||||
var o = {
|
||||
q: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_3945_2: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof o);
|
||||
var o = {
|
||||
p: 0,
|
||||
};
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof o);
|
||||
var o = {
|
||||
p: 0,
|
||||
};
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4023: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
hoist_props: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
typeofs: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var a = function() {
|
||||
return { p: 0 };
|
||||
}();
|
||||
return console.log("undefined" != typeof a);
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
console.log(void 0 !== {});
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
@@ -2223,13 +2223,13 @@ issue_3523_rename_ie8: {
|
||||
expect: {
|
||||
var a = 0, b, c = "FAIL";
|
||||
(function() {
|
||||
var c, n, t, o, a, r, f, i, u, e, h, l, v, y;
|
||||
var c, n, t, o, a, r, e, f, i, u, h, l, v, y;
|
||||
})();
|
||||
try {
|
||||
throw 0;
|
||||
} catch (e) {
|
||||
(function() {
|
||||
(function n() {
|
||||
(function e() {
|
||||
c = "PASS";
|
||||
})();
|
||||
})();
|
||||
@@ -2389,7 +2389,7 @@ issue_3703: {
|
||||
var a = "PASS";
|
||||
(function() {
|
||||
var b;
|
||||
var c = function g() {
|
||||
var c = function() {
|
||||
a = "FAIL";
|
||||
};
|
||||
a ? b |= c : b.p;
|
||||
@@ -2420,3 +2420,297 @@ issue_3750: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3823: {
|
||||
options = {
|
||||
ie8: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
for (var i = 0; i < 1; i++) {
|
||||
var a = a ? function f() {
|
||||
f;
|
||||
} : 0;
|
||||
console.log("PASS", typeof f);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (var i = 0; i < 1; i++) {
|
||||
(function f() {
|
||||
f;
|
||||
});
|
||||
console.log("PASS", typeof f);
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS undefined"
|
||||
}
|
||||
|
||||
issue_3825: {
|
||||
options = {
|
||||
ie8: true,
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({}[void (0..length ? 1 : 2)]);
|
||||
}
|
||||
expect: {
|
||||
console.log({}[void 0]);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_3889: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
a = 0;
|
||||
(function a() {
|
||||
var a;
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
a = 0;
|
||||
(function a() {
|
||||
var a;
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_3918: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
if (console.log("PASS")) {
|
||||
var a = function f() {
|
||||
f.p;
|
||||
try {
|
||||
console.log("FAIL");
|
||||
} catch (e) {}
|
||||
}, b = a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
console.log("PASS") && (a = function f() {
|
||||
f.p;
|
||||
try {
|
||||
console.log("FAIL");
|
||||
} catch (o) {}
|
||||
}, a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3999: {
|
||||
rename = true
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
(function f() {
|
||||
for (var i = 0; i < 2; i++)
|
||||
try {
|
||||
f[0];
|
||||
} catch (f) {
|
||||
var f = 0;
|
||||
console.log(i);
|
||||
}
|
||||
})();
|
||||
})(typeof f);
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function f() {
|
||||
for (var o = 0; o < 2; o++)
|
||||
try {
|
||||
f[0];
|
||||
} catch (f) {
|
||||
var f = 0;
|
||||
console.log(o);
|
||||
}
|
||||
})();
|
||||
})(typeof f);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"1",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4001: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
ie8: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
function f() {
|
||||
return a;
|
||||
var b;
|
||||
}
|
||||
var c = f();
|
||||
(function g() {
|
||||
c[42];
|
||||
f;
|
||||
})();
|
||||
(function a() {});
|
||||
}(42));
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
var a;
|
||||
console.log((a = 42, void f()[42], void function a() {}));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4015: {
|
||||
rename = true
|
||||
mangle = {
|
||||
ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var n, a = 0, b;
|
||||
function f() {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (b) {
|
||||
(function g() {
|
||||
(function b() {
|
||||
a++;
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var n, o = 0, c;
|
||||
function t() {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (c) {
|
||||
(function n() {
|
||||
(function c() {
|
||||
o++;
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
t();
|
||||
console.log(o);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_4019: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {
|
||||
ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = function() {
|
||||
try {
|
||||
console.log("FAIL");
|
||||
} catch (b) {}
|
||||
}, a = (console.log(a.length), ++a);
|
||||
}
|
||||
expect: {
|
||||
var o = function() {
|
||||
try {
|
||||
console.log("FAIL");
|
||||
} catch (o) {}
|
||||
}, o = (console.log(o.length), ++o);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4028: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
function a() {
|
||||
try {
|
||||
A;
|
||||
} catch (e) {}
|
||||
}
|
||||
var b = a += a;
|
||||
console.log(typeof b);
|
||||
}
|
||||
expect: {
|
||||
function a() {
|
||||
try {
|
||||
A;
|
||||
} catch (a) {}
|
||||
}
|
||||
var b = a += a;
|
||||
console.log(typeof b);
|
||||
}
|
||||
expect_stdout: "string"
|
||||
}
|
||||
|
||||
issue_2737: {
|
||||
options = {
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
a();
|
||||
})(function f() {
|
||||
console.log(typeof f);
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
a();
|
||||
})(function f() {
|
||||
console.log(typeof f);
|
||||
});
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
@@ -573,3 +573,24 @@ issue_3600: {
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
iife_if_return_simple: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
inline: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
if (console)
|
||||
return console.log("PASS");
|
||||
console.log("FAIL");
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console ? console.log("PASS") : console.log("FAIL");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -90,13 +90,13 @@ non_hoisted_function_after_return_2a: {
|
||||
"WARN: Declarations 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: 37",
|
||||
"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]",
|
||||
"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: 37, count: 18",
|
||||
"INFO: pass 1: last_count: 36, count: 18",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -248,13 +248,13 @@ non_hoisted_function_after_return_2a_strict: {
|
||||
"WARN: Declarations 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: 48",
|
||||
"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]",
|
||||
"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: 48, count: 29",
|
||||
"INFO: pass 1: last_count: 47, count: 29",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,9 @@ issue_1639_1: {
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
for (var a = 100, b = 10, L1 = 5; --L1 > 0;)
|
||||
if (--b, 0) var ignore = 0;
|
||||
for (var a = 100, b = 10, L1 = 5, ignore; --L1 > 0;) {
|
||||
--b;
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "100 6"
|
||||
|
||||
@@ -35,11 +35,7 @@ f7: {
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_exact: [
|
||||
"var b = 10;",
|
||||
"",
|
||||
"!function() {",
|
||||
" b = 100;",
|
||||
"}(), console.log(100, b);",
|
||||
"console.log(100, 100);",
|
||||
]
|
||||
expect_stdout: true
|
||||
expect_stdout: "100 100"
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ warn: {
|
||||
}().length);
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]",
|
||||
"WARN: Function.prototype.arguments not supported [test/compress/issue-2719.js:5,19]",
|
||||
"WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]",
|
||||
]
|
||||
}
|
||||
|
||||
128
test/compress/issue-3768.js
Normal file
128
test/compress/issue-3768.js
Normal file
@@ -0,0 +1,128 @@
|
||||
mangle: {
|
||||
mangle = {
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var e = eval, x = 42;
|
||||
(function() {
|
||||
console.log(e("typeof x"));
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
var e = eval, x = 42;
|
||||
(function() {
|
||||
console.log(e("typeof x"));
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
compress: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var a = 42;
|
||||
return eval("typeof a");
|
||||
}(), function(e) {
|
||||
var a = null;
|
||||
return e("typeof a");
|
||||
}(eval), function(eval) {
|
||||
var a = false;
|
||||
return eval("typeof a");
|
||||
}(eval), function(f) {
|
||||
var a = "STRING";
|
||||
var eval = f;
|
||||
return eval("typeof a");
|
||||
}(eval), function(g) {
|
||||
var a = eval;
|
||||
function eval() {
|
||||
return g;
|
||||
}
|
||||
return eval()("typeof a");
|
||||
}(eval));
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var a = 42;
|
||||
return eval("typeof a");
|
||||
}(), (0, eval)("typeof a"), function(eval) {
|
||||
var a = false;
|
||||
return eval("typeof a");
|
||||
}(eval), function(f) {
|
||||
var a = "STRING";
|
||||
var eval = f;
|
||||
return eval("typeof a");
|
||||
}(eval), function(g) {
|
||||
var a = eval;
|
||||
function eval() {
|
||||
return g;
|
||||
}
|
||||
return eval()("typeof a");
|
||||
}(eval));
|
||||
}
|
||||
expect_stdout: "number undefined boolean string undefined"
|
||||
}
|
||||
|
||||
call_arg_1: {
|
||||
mangle = {
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var z = "foo";
|
||||
(function() {
|
||||
var z = false;
|
||||
(function(e) {
|
||||
var z = 42;
|
||||
e("console.log(typeof z)");
|
||||
})(eval);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
var z = "foo";
|
||||
(function() {
|
||||
var o = false;
|
||||
(function(o) {
|
||||
var a = 42;
|
||||
o("console.log(typeof z)");
|
||||
})(eval);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
call_arg_2: {
|
||||
mangle = {
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
function eval() {
|
||||
console.log("PASS");
|
||||
}
|
||||
var z = "foo";
|
||||
(function() {
|
||||
var z = false;
|
||||
(function(e) {
|
||||
var z = 42;
|
||||
e("console.log(typeof z)");
|
||||
})(eval);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
function n() {
|
||||
console.log("PASS");
|
||||
}
|
||||
var o = "foo";
|
||||
(function() {
|
||||
var o = false;
|
||||
(function(o) {
|
||||
var n = 42;
|
||||
o("console.log(typeof z)");
|
||||
})(n);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
@@ -8,7 +8,7 @@ remove_sequence: {
|
||||
(0, 1, _decorators.logThis)();
|
||||
}
|
||||
expect: {
|
||||
eval();
|
||||
(0, eval)();
|
||||
logThis();
|
||||
(0, _decorators.logThis)();
|
||||
}
|
||||
|
||||
@@ -53,20 +53,23 @@ this_binding_conditionals: {
|
||||
this_binding_collapse_vars: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var c = a; c();
|
||||
var d = a.b; d();
|
||||
var e = eval; e();
|
||||
function f() {
|
||||
"use strict";
|
||||
var c = a; c();
|
||||
var d = a.b; d();
|
||||
var e = eval; e();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
a();
|
||||
(0, a.b)();
|
||||
(0, eval)();
|
||||
function f() {
|
||||
"use strict";
|
||||
a();
|
||||
(0, a.b)();
|
||||
(0, eval)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +100,7 @@ this_binding_side_effects: {
|
||||
(function(foo) {
|
||||
foo();
|
||||
(0, foo.bar)();
|
||||
eval("console.log(foo);");
|
||||
(0, eval)("console.log(foo);");
|
||||
}());
|
||||
(function(foo) {
|
||||
"use strict";
|
||||
@@ -144,7 +147,7 @@ this_binding_sequences: {
|
||||
return eval("this");
|
||||
}()),
|
||||
console.log(typeof function() {
|
||||
return eval("this");
|
||||
return (0, eval)("this");
|
||||
}()),
|
||||
console.log(typeof function() {
|
||||
"use strict";
|
||||
|
||||
1057
test/compress/join_vars.js
Normal file
1057
test/compress/join_vars.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -306,8 +306,7 @@ issue_2298: {
|
||||
expect: {
|
||||
!function() {
|
||||
(function() {
|
||||
var a = undefined;
|
||||
var undefined = a++;
|
||||
0;
|
||||
try {
|
||||
!function() {
|
||||
(void 0)[1] = "foo";
|
||||
@@ -1226,8 +1225,7 @@ chained_3: {
|
||||
}
|
||||
expect: {
|
||||
console.log(function(b) {
|
||||
var c = 1;
|
||||
c = b;
|
||||
var c = 1, c = b;
|
||||
b++;
|
||||
return c;
|
||||
}(2));
|
||||
|
||||
@@ -3,6 +3,7 @@ labels_1: {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
if_return: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
out: {
|
||||
@@ -21,6 +22,7 @@ labels_2: {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
if_return: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
out: {
|
||||
@@ -61,6 +63,7 @@ labels_4: {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
if_return: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
out: for (var i = 0; i < 5; ++i) {
|
||||
@@ -105,6 +108,9 @@ labels_5: {
|
||||
}
|
||||
|
||||
labels_6: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
out: break out;
|
||||
};
|
||||
@@ -159,6 +165,7 @@ labels_9: {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
if_return: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
out: while (foo) {
|
||||
|
||||
@@ -549,6 +549,7 @@ issue_2740_2: {
|
||||
dead_code: true,
|
||||
loops: true,
|
||||
passes: 2,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
L1: while (x()) {
|
||||
@@ -564,6 +565,7 @@ issue_2740_3: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
L1: for (var x = 0; x < 3; x++) {
|
||||
@@ -589,6 +591,7 @@ issue_2740_4: {
|
||||
dead_code: true,
|
||||
loops: true,
|
||||
passes: 2,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
L1: for (var x = 0; x < 3; x++) {
|
||||
@@ -613,6 +616,7 @@ issue_2740_5: {
|
||||
dead_code: true,
|
||||
loops: true,
|
||||
passes: 2,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
L1: for (var x = 0; x < 3; x++) {
|
||||
@@ -752,7 +756,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]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -763,6 +797,7 @@ issue_3631_1: {
|
||||
loops: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
@@ -789,6 +824,7 @@ issue_3631_2: {
|
||||
loops: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
L: for (var a = 1; a--; console.log(b)) {
|
||||
@@ -927,3 +963,49 @@ 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"
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ evaluate_string_length: {
|
||||
}
|
||||
}
|
||||
|
||||
mangle_properties: {
|
||||
mangle_properties_1: {
|
||||
mangle = {
|
||||
properties: {
|
||||
keep_quoted: false,
|
||||
@@ -152,6 +152,53 @@ mangle_properties: {
|
||||
}
|
||||
}
|
||||
|
||||
mangle_properties_2: {
|
||||
mangle = {
|
||||
properties: {
|
||||
reserved: [
|
||||
"value",
|
||||
]
|
||||
},
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
prop1: 1,
|
||||
};
|
||||
Object.defineProperty(o, "prop2", {
|
||||
value: 2,
|
||||
});
|
||||
Object.defineProperties(o, {
|
||||
prop3: {
|
||||
value: 3,
|
||||
},
|
||||
});
|
||||
console.log("prop1", o.prop1, "prop1" in o);
|
||||
console.log("prop2", o.prop2, o.hasOwnProperty("prop2"));
|
||||
console.log("prop3", o.prop3, Object.getOwnPropertyDescriptor(o, "prop3").value);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
o: 1,
|
||||
};
|
||||
Object.defineProperty(o, "p", {
|
||||
value: 2,
|
||||
});
|
||||
Object.defineProperties(o, {
|
||||
r: {
|
||||
value: 3,
|
||||
},
|
||||
});
|
||||
console.log("prop1", o.o, "o" in o);
|
||||
console.log("prop2", o.p, o.hasOwnProperty("p"));
|
||||
console.log("prop3", o.r, Object.getOwnPropertyDescriptor(o, "r").value);
|
||||
}
|
||||
expect_stdout: [
|
||||
"prop1 1 true",
|
||||
"prop2 2 true",
|
||||
"prop3 3 3",
|
||||
]
|
||||
}
|
||||
|
||||
mangle_unquoted_properties: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
@@ -1046,16 +1093,22 @@ array_hole: {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
[ 1, 2, , 3][1],
|
||||
[ 1, 2, , 3][2],
|
||||
[ 1, 2, , 3][3]
|
||||
);
|
||||
Array.prototype[2] = "PASS";
|
||||
console.log([ 1, 2, , 3 ][1]);
|
||||
console.log([ 1, 2, , 3 ][2]);
|
||||
console.log([ 1, 2, , 3 ][3]);
|
||||
}
|
||||
expect: {
|
||||
console.log(2, void 0, 3);
|
||||
Array.prototype[2] = "PASS";
|
||||
console.log(2);
|
||||
console.log([ , , , ][2]);
|
||||
console.log(3);
|
||||
}
|
||||
expect_stdout: "2 undefined 3"
|
||||
expect_stdout: [
|
||||
"2",
|
||||
"PASS",
|
||||
"3",
|
||||
]
|
||||
}
|
||||
|
||||
new_this: {
|
||||
@@ -1143,558 +1196,6 @@ const_prop_assign_pure: {
|
||||
}
|
||||
}
|
||||
|
||||
join_object_assignments_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var x = {
|
||||
a: 1,
|
||||
c: (console.log("c"), "C"),
|
||||
};
|
||||
x.b = 2;
|
||||
x[3] = function() {
|
||||
console.log(x);
|
||||
},
|
||||
x["a"] = /foo/,
|
||||
x.bar = x;
|
||||
return x;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var x = {
|
||||
a: 1,
|
||||
c: (console.log("c"), "C"),
|
||||
b: 2,
|
||||
3: function() {
|
||||
console.log(x);
|
||||
},
|
||||
a: /foo/,
|
||||
};
|
||||
x.bar = x;
|
||||
return x;
|
||||
}());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
join_object_assignments_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
hoist_props: true,
|
||||
join_vars: true,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
foo: 1,
|
||||
};
|
||||
o.bar = 2;
|
||||
o.baz = 3;
|
||||
console.log(o.foo, o.bar + o.bar, o.foo * o.bar * o.baz);
|
||||
}
|
||||
expect: {
|
||||
console.log(1, 4, 6);
|
||||
}
|
||||
expect_stdout: "1 4 6"
|
||||
}
|
||||
|
||||
join_object_assignments_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
a: "PASS",
|
||||
}, a = o.a;
|
||||
o.a = "FAIL";
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
a: "PASS",
|
||||
}, a = o.a;
|
||||
o.a = "FAIL";
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
join_object_assignments_4: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var o;
|
||||
console.log(o);
|
||||
o = {};
|
||||
o.a = "foo";
|
||||
console.log(o.b);
|
||||
o.b = "bar";
|
||||
console.log(o.a);
|
||||
}
|
||||
expect: {
|
||||
var o;
|
||||
console.log(o),
|
||||
o = {
|
||||
a: "foo",
|
||||
},
|
||||
console.log(o.b),
|
||||
o.b = "bar",
|
||||
console.log(o.a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
"undefined",
|
||||
"foo",
|
||||
]
|
||||
}
|
||||
|
||||
join_object_assignments_return_1: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
p: 3
|
||||
};
|
||||
return o.q = "foo";
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
p: 3,
|
||||
q: "foo"
|
||||
};
|
||||
return o.q;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "foo"
|
||||
}
|
||||
|
||||
join_object_assignments_return_2: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
p: 3
|
||||
};
|
||||
return o.q = /foo/,
|
||||
o.r = "bar";
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
p: 3,
|
||||
q: /foo/,
|
||||
r: "bar"
|
||||
};
|
||||
return o.r;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "bar"
|
||||
}
|
||||
|
||||
join_object_assignments_return_3: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
p: 3
|
||||
};
|
||||
return o.q = "foo",
|
||||
o.p += "",
|
||||
console.log(o.q),
|
||||
o.p;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
p: 3,
|
||||
q: "foo"
|
||||
};
|
||||
return o.p += "",
|
||||
console.log(o.q),
|
||||
o.p;
|
||||
}());
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"3",
|
||||
]
|
||||
}
|
||||
|
||||
join_object_assignments_for: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
p: 3
|
||||
};
|
||||
for (o.q = "foo"; console.log(o.q););
|
||||
return o.p;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
for (var o = {
|
||||
p: 3,
|
||||
q: "foo"
|
||||
}; console.log(o.q););
|
||||
return o.p;
|
||||
}());
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"3",
|
||||
]
|
||||
}
|
||||
|
||||
join_object_assignments_if: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var o = {};
|
||||
if (o.a = "PASS") return o.a;
|
||||
}())
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o = { a: "PASS" };
|
||||
if (o.a) return o.a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
join_object_assignments_forin: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var o = {};
|
||||
for (var a in o.a = "PASS", o)
|
||||
return o[a];
|
||||
}())
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o = { a: "PASS" };
|
||||
for (var a in o)
|
||||
return o[a];
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
join_object_assignments_negative: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[0] = 0;
|
||||
o[-0] = 1;
|
||||
o[-1] = 2;
|
||||
console.log(o[0], o[-0], o[-1]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
0: 0,
|
||||
0: 1,
|
||||
"-1": 2
|
||||
};
|
||||
console.log(o[0], o[-0], o[-1]);
|
||||
}
|
||||
expect_stdout: "1 1 2"
|
||||
}
|
||||
|
||||
join_object_assignments_NaN_1: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[NaN] = 1;
|
||||
o[0/0] = 2;
|
||||
console.log(o[NaN], o[NaN]);
|
||||
}
|
||||
expect: {
|
||||
var o = {};
|
||||
o[NaN] = 1;
|
||||
o[0/0] = 2;
|
||||
console.log(o[NaN], o[NaN]);
|
||||
}
|
||||
expect_stdout: "2 2"
|
||||
}
|
||||
|
||||
join_object_assignments_NaN_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[NaN] = 1;
|
||||
o[0/0] = 2;
|
||||
console.log(o[NaN], o[NaN]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
NaN: 1,
|
||||
NaN: 2
|
||||
};
|
||||
console.log(o.NaN, o.NaN);
|
||||
}
|
||||
expect_stdout: "2 2"
|
||||
}
|
||||
|
||||
join_object_assignments_null_0: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[null] = 1;
|
||||
console.log(o[null]);
|
||||
}
|
||||
expect: {
|
||||
var o = {};
|
||||
o[null] = 1;
|
||||
console.log(o[null]);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
join_object_assignments_null_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[null] = 1;
|
||||
console.log(o[null]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
null: 1
|
||||
};
|
||||
console.log(o.null);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
join_object_assignments_void_0: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[void 0] = 1;
|
||||
console.log(o[void 0]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
undefined: 1
|
||||
};
|
||||
console.log(o[void 0]);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
join_object_assignments_undefined_1: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[undefined] = 1;
|
||||
console.log(o[undefined]);
|
||||
}
|
||||
expect: {
|
||||
var o = {};
|
||||
o[void 0] = 1;
|
||||
console.log(o[void 0]);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
join_object_assignments_undefined_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[undefined] = 1;
|
||||
console.log(o[undefined]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
undefined : 1
|
||||
};
|
||||
console.log(o[void 0]);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
join_object_assignments_Infinity: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[Infinity] = 1;
|
||||
o[1/0] = 2;
|
||||
o[-Infinity] = 3;
|
||||
o[-1/0] = 4;
|
||||
console.log(o[Infinity], o[1/0], o[-Infinity], o[-1/0]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
Infinity: 1,
|
||||
Infinity: 2,
|
||||
"-Infinity": 3,
|
||||
"-Infinity": 4
|
||||
};
|
||||
console.log(o[1/0], o[1/0], o[-1/0], o[-1/0]);
|
||||
}
|
||||
expect_stdout: "2 2 4 4"
|
||||
}
|
||||
|
||||
join_object_assignments_regex: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
o[/rx/] = 1;
|
||||
console.log(o[/rx/]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
"/rx/": 1
|
||||
};
|
||||
console.log(o[/rx/]);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2816: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var o = {
|
||||
a: 1
|
||||
};
|
||||
o.b = 2;
|
||||
o.a = 3;
|
||||
o.c = 4;
|
||||
console.log(o.a, o.b, o.c);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2
|
||||
};
|
||||
o.a = 3;
|
||||
o.c = 4;
|
||||
console.log(o.a, o.b, o.c);
|
||||
}
|
||||
expect_stdout: "3 2 4"
|
||||
}
|
||||
|
||||
issue_2893_1: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
get a() {
|
||||
return "PASS";
|
||||
},
|
||||
};
|
||||
o.a = "FAIL";
|
||||
console.log(o.a);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
get a() {
|
||||
return "PASS";
|
||||
},
|
||||
};
|
||||
o.a = "FAIL";
|
||||
console.log(o.a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2893_2: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
set a(v) {
|
||||
this.b = v;
|
||||
},
|
||||
b: "FAIL",
|
||||
};
|
||||
o.a = "PASS";
|
||||
console.log(o.b);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
set a(v) {
|
||||
this.b = v;
|
||||
},
|
||||
b: "FAIL",
|
||||
};
|
||||
o.a = "PASS";
|
||||
console.log(o.b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_869_1: {
|
||||
mangle = {
|
||||
properties: {
|
||||
@@ -1856,36 +1357,6 @@ issue_3188_3: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
join_expr: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
(function() {
|
||||
var a = 0;
|
||||
switch ((a = {}) && (a.b = 0)) {
|
||||
case 0:
|
||||
c = "PASS";
|
||||
}
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function() {
|
||||
var a = 0;
|
||||
switch (a = { b: 0 }, a.b) {
|
||||
case 0:
|
||||
c = "PASS";
|
||||
}
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3389: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
|
||||
@@ -136,7 +136,7 @@ relational: {
|
||||
side_effects :true,
|
||||
}
|
||||
input: {
|
||||
foo() in foo();
|
||||
foo() in new foo();
|
||||
foo() instanceof bar();
|
||||
foo() < "bar";
|
||||
bar() > foo();
|
||||
@@ -680,3 +680,130 @@ issue_3325_2: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3858: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var f = function(a) {
|
||||
return /*@__PURE__*/ function(b) {
|
||||
console.log(b);
|
||||
}(a);
|
||||
};
|
||||
f("PASS");
|
||||
}
|
||||
expect: {
|
||||
var f = function(a) {
|
||||
return function() {
|
||||
console.log(a);
|
||||
}();
|
||||
};
|
||||
f("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
inline_pure_call_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var f = function(a) {
|
||||
return /*@__PURE__*/ function(b) {
|
||||
console.log(b);
|
||||
}(a);
|
||||
};
|
||||
f("PASS");
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
inline_pure_call_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var f = function(a) {
|
||||
return /*@__PURE__*/ function(b) {
|
||||
console.log(b);
|
||||
}(a);
|
||||
};
|
||||
var a = f("PASS");
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
inline_pure_call_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var f = function(a) {
|
||||
return /*@__PURE__*/ function(b) {
|
||||
console.log(b);
|
||||
}(a);
|
||||
};
|
||||
var a = f("PASS");
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = function() {
|
||||
console.log("PASS");
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"undefined",
|
||||
]
|
||||
}
|
||||
|
||||
inline_pure_call_4: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = /*@__PURE__*/ function() {
|
||||
return console.log("PASS"), 42;
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = function() {
|
||||
return console.log("PASS"), 42;
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"42",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -223,6 +223,25 @@ unsafe_evaluate: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_evaluate_defun: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
function f() {}
|
||||
return ++f;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(NaN);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
unsafe_evaluate_side_effect_free_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
@@ -886,7 +905,7 @@ use_before_var: {
|
||||
}
|
||||
expect: {
|
||||
function f(){
|
||||
console.log(t);
|
||||
console.log(void 0);
|
||||
var t = 1;
|
||||
}
|
||||
}
|
||||
@@ -962,12 +981,12 @@ inner_var_for_1: {
|
||||
expect: {
|
||||
function f() {
|
||||
var a = 1;
|
||||
x(1, b, d);
|
||||
for (var b = 2, c = 3; x(1, b, 3, d); x(1, b, 3, d)) {
|
||||
x(1, void 0, d);
|
||||
for (var b = 2, c = 3; x(1, 2, 3, d); x(1, 2, 3, d)) {
|
||||
var d = 4, e = 5;
|
||||
x(1, b, 3, d, e);
|
||||
x(1, 2, 3, d, e);
|
||||
}
|
||||
x(1, b, 3, d, e);
|
||||
x(1, 2, 3, d, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1178,11 +1197,10 @@ toplevel_on_loops_1: {
|
||||
while (x);
|
||||
}
|
||||
expect: {
|
||||
function bar() {
|
||||
console.log("bar:", --x);
|
||||
}
|
||||
var x = 3;
|
||||
for (;bar(), x;);
|
||||
for (;function() {
|
||||
console.log("bar:", --x);
|
||||
}(), x;);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -1235,10 +1253,9 @@ toplevel_on_loops_2: {
|
||||
while (x);
|
||||
}
|
||||
expect: {
|
||||
function bar() {
|
||||
for (;;) (function() {
|
||||
console.log("bar:");
|
||||
}
|
||||
for (;;) bar();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1503,10 +1520,7 @@ func_inline: {
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
console.log(1 + h());
|
||||
var h = function() {
|
||||
return 2;
|
||||
};
|
||||
console.log(1 + (void 0)());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2017,6 +2031,7 @@ issue_1670_4: {
|
||||
|
||||
issue_1670_5: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
@@ -2048,6 +2063,7 @@ issue_1670_5: {
|
||||
|
||||
issue_1670_6: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
@@ -2289,11 +2305,10 @@ redefine_farg_2: {
|
||||
console.log(f([]), g([]), h([]));
|
||||
}
|
||||
expect: {
|
||||
console.log((a = [], typeof a), "number",function(a, b) {
|
||||
console.log(typeof [], "number",function(a, b) {
|
||||
a = b;
|
||||
return typeof a;
|
||||
}([]));
|
||||
var a;
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
@@ -2356,8 +2371,7 @@ delay_def: {
|
||||
return;
|
||||
}
|
||||
function g() {
|
||||
return a;
|
||||
var a = 1;
|
||||
return;
|
||||
}
|
||||
console.log(f(), g());
|
||||
}
|
||||
@@ -2379,7 +2393,7 @@ delay_def_lhs: {
|
||||
expect: {
|
||||
console.log(function() {
|
||||
long_name++;
|
||||
return long_name;
|
||||
return NaN;
|
||||
var long_name;
|
||||
}());
|
||||
}
|
||||
@@ -2635,11 +2649,9 @@ var_assign_5: {
|
||||
}
|
||||
expect: {
|
||||
!function() {
|
||||
var a;
|
||||
!function(b) {
|
||||
a = 2,
|
||||
console.log(a, b);
|
||||
}(a);
|
||||
console.log(2, void 0);
|
||||
}();
|
||||
}();
|
||||
}
|
||||
expect_stdout: "2 undefined"
|
||||
@@ -2660,8 +2672,8 @@ var_assign_6: {
|
||||
}
|
||||
expect: {
|
||||
!function() {
|
||||
var a = function(){}(a = 1);
|
||||
console.log(a);
|
||||
(function(){}());
|
||||
console.log(void 0);
|
||||
}();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
@@ -2708,8 +2720,8 @@ issue_1814_1: {
|
||||
expect: {
|
||||
!function() {
|
||||
!function(a) {
|
||||
console.log(a++, 42);
|
||||
}(0);
|
||||
console.log(0, 42);
|
||||
}();
|
||||
}();
|
||||
}
|
||||
expect_stdout: "0 42"
|
||||
@@ -2735,8 +2747,8 @@ issue_1814_2: {
|
||||
expect: {
|
||||
!function() {
|
||||
!function(a) {
|
||||
console.log("321", a++);
|
||||
}(0);
|
||||
console.log("321", 0);
|
||||
}();
|
||||
}();
|
||||
}
|
||||
expect_stdout: "321 0"
|
||||
@@ -4213,13 +4225,12 @@ issue_2450_4: {
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
function f(b) {
|
||||
console.log(a === b);
|
||||
a = b;
|
||||
}
|
||||
function g() {}
|
||||
for (var i = 3; --i >= 0;)
|
||||
f(g);
|
||||
(function(b) {
|
||||
console.log(a === b);
|
||||
a = b;
|
||||
})(g);
|
||||
}
|
||||
expect_stdout: [
|
||||
"false",
|
||||
@@ -4320,14 +4331,13 @@ perf_1: {
|
||||
console.log(sum);
|
||||
}
|
||||
expect: {
|
||||
function indirect_foo(x, y, z) {
|
||||
return function(x, y, z) {
|
||||
return x < y ? x * y + z : x * z - y;
|
||||
}(x, y, z);
|
||||
}
|
||||
var sum = 0;
|
||||
for (var i = 0; i < 100; ++i)
|
||||
sum += indirect_foo(i, i + 1, 3 * i);
|
||||
sum += function(x, y, z) {
|
||||
return function(x, y, z) {
|
||||
return x < y ? x * y + z : x * z - y;
|
||||
}(x, y, z);
|
||||
}(i, i + 1, 3 * i);
|
||||
console.log(sum);
|
||||
}
|
||||
expect_stdout: "348150"
|
||||
@@ -4388,14 +4398,13 @@ perf_3: {
|
||||
console.log(sum);
|
||||
}
|
||||
expect: {
|
||||
var indirect_foo = function(x, y, z) {
|
||||
return function(x, y, z) {
|
||||
return x < y ? x * y + z : x * z - y;
|
||||
}(x, y, z);
|
||||
}
|
||||
var sum = 0;
|
||||
for (var i = 0; i < 100; ++i)
|
||||
sum += indirect_foo(i, i + 1, 3 * i);
|
||||
sum += function(x, y, z) {
|
||||
return function(x, y, z) {
|
||||
return x < y ? x * y + z : x * z - y;
|
||||
}(x, y, z);
|
||||
}(i, i + 1, 3 * i);
|
||||
console.log(sum);
|
||||
}
|
||||
expect_stdout: "348150"
|
||||
@@ -4457,14 +4466,13 @@ perf_5: {
|
||||
console.log(sum);
|
||||
}
|
||||
expect: {
|
||||
function indirect_foo(x, y, z) {
|
||||
return function(x, y, z) {
|
||||
return x < y ? x * y + z : x * z - y;
|
||||
}(x, y, z);
|
||||
}
|
||||
var sum = 0;
|
||||
for (var i = 0; i < 100; ++i)
|
||||
sum += indirect_foo(i, i + 1, 3 * i);
|
||||
sum += function(x, y, z) {
|
||||
return function(x, y, z) {
|
||||
return x < y ? x * y + z : x * z - y;
|
||||
}(x, y, z);
|
||||
}(i, i + 1, 3 * i);
|
||||
console.log(sum);
|
||||
}
|
||||
expect_stdout: "348150"
|
||||
@@ -4525,14 +4533,13 @@ perf_7: {
|
||||
console.log(sum);
|
||||
}
|
||||
expect: {
|
||||
var indirect_foo = function(x, y, z) {
|
||||
return function(x, y, z) {
|
||||
return x < y ? x * y + z : x * z - y;
|
||||
}(x, y, z);
|
||||
}
|
||||
var sum = 0;
|
||||
for (var i = 0; i < 100; ++i)
|
||||
sum += indirect_foo(i, i + 1, 3 * i);
|
||||
sum += function(x, y, z) {
|
||||
return function(x, y, z) {
|
||||
return x < y ? x * y + z : x * z - y;
|
||||
}(x, y, z);
|
||||
}(i, i + 1, 3 * i);
|
||||
console.log(sum);
|
||||
}
|
||||
expect_stdout: "348150"
|
||||
@@ -4571,7 +4578,7 @@ perf_8: {
|
||||
expect_stdout: "348150"
|
||||
}
|
||||
|
||||
issue_2485: {
|
||||
issue_2485_1: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
@@ -4619,6 +4626,53 @@ issue_2485: {
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
issue_2485_2: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var foo = function(bar) {
|
||||
var n = function(a, b) {
|
||||
return a + b;
|
||||
};
|
||||
var sumAll = function(arg) {
|
||||
return arg.reduce(n, 0);
|
||||
};
|
||||
var runSumAll = function(arg) {
|
||||
return sumAll(arg);
|
||||
};
|
||||
bar.baz = function(arg) {
|
||||
var n = runSumAll(arg);
|
||||
return (n.get = 1), n;
|
||||
};
|
||||
return bar;
|
||||
};
|
||||
var bar = foo({});
|
||||
console.log(bar.baz([1, 2, 3]));
|
||||
}
|
||||
expect: {
|
||||
var foo = function(bar) {
|
||||
var n = function(a, b) {
|
||||
return a + b;
|
||||
};
|
||||
var runSumAll = function(arg) {
|
||||
return arg.reduce(n, 0);
|
||||
};
|
||||
bar.baz = function(arg) {
|
||||
var n = runSumAll(arg);
|
||||
return (n.get = 1), n;
|
||||
};
|
||||
return bar;
|
||||
};
|
||||
var bar = foo({});
|
||||
console.log(bar.baz([1, 2, 3]));
|
||||
}
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
issue_2455: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
@@ -4667,7 +4721,7 @@ escape_conditional: {
|
||||
function bar() {}
|
||||
(function() {
|
||||
var thing = baz();
|
||||
if (thing !== (thing = baz()))
|
||||
if (thing !== baz())
|
||||
console.log("FAIL");
|
||||
else
|
||||
console.log("PASS");
|
||||
@@ -4705,7 +4759,7 @@ escape_sequence: {
|
||||
function bar() {}
|
||||
(function() {
|
||||
var thing = baz();
|
||||
if (thing !== (thing = baz()))
|
||||
if (thing !== baz())
|
||||
console.log("FAIL");
|
||||
else
|
||||
console.log("PASS");
|
||||
@@ -4750,7 +4804,7 @@ escape_throw: {
|
||||
function foo() {}
|
||||
(function() {
|
||||
var thing = baz();
|
||||
if (thing !== (thing = baz()))
|
||||
if (thing !== baz())
|
||||
console.log("FAIL");
|
||||
else
|
||||
console.log("PASS");
|
||||
@@ -4787,7 +4841,7 @@ escape_local_conditional: {
|
||||
}
|
||||
(function() {
|
||||
var thing = baz();
|
||||
if (thing !== (thing = baz()))
|
||||
if (thing !== baz())
|
||||
console.log("PASS");
|
||||
else
|
||||
console.log("FAIL");
|
||||
@@ -4824,7 +4878,7 @@ escape_local_sequence: {
|
||||
}
|
||||
(function() {
|
||||
var thing = baz();
|
||||
if (thing !== (thing = baz()))
|
||||
if (thing !== baz())
|
||||
console.log("PASS");
|
||||
else
|
||||
console.log("FAIL");
|
||||
@@ -4868,7 +4922,7 @@ escape_local_throw: {
|
||||
}
|
||||
(function() {
|
||||
var thing = baz();
|
||||
if (thing !== (thing = baz()))
|
||||
if (thing !== baz())
|
||||
console.log("PASS");
|
||||
else
|
||||
console.log("FAIL");
|
||||
@@ -4922,11 +4976,7 @@ inverted_var: {
|
||||
console.log(1, 2, 3, 4, 5, function c() {
|
||||
c = 6;
|
||||
return c;
|
||||
}(), 7, function() {
|
||||
c = 8;
|
||||
return c;
|
||||
var c = "foo";
|
||||
}());
|
||||
}(), 7, 8);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -5122,9 +5172,7 @@ defun_var_3: {
|
||||
var a = 42, b;
|
||||
}
|
||||
expect: {
|
||||
function a() {}
|
||||
console.log(typeof a, "function");
|
||||
var a = 42;
|
||||
console.log("function", "function");
|
||||
}
|
||||
expect_stdout: "function function"
|
||||
}
|
||||
@@ -5435,8 +5483,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"
|
||||
@@ -5455,8 +5502,7 @@ lvalues_def_2: {
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
var a = b += 1;
|
||||
b = NaN;
|
||||
var a = b += 1, b = NaN;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "2 NaN"
|
||||
@@ -6511,17 +6557,17 @@ issue_3240_3: {
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function f(b) {
|
||||
f();
|
||||
function f(b) {
|
||||
if (!f.a) f.a = 0;
|
||||
console.log(f.a.toString());
|
||||
var g = function() {
|
||||
(function() {
|
||||
(b ? function() {} : function() {
|
||||
f.a++;
|
||||
f(1);
|
||||
})();
|
||||
};
|
||||
g();
|
||||
})();
|
||||
})();
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -6555,7 +6601,8 @@ issue_3240_4: {
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function f(b) {
|
||||
f();
|
||||
function f(b) {
|
||||
if (!f.a) f.a = 0;
|
||||
console.log(f.a.toString());
|
||||
(function() {
|
||||
@@ -6564,7 +6611,7 @@ issue_3240_4: {
|
||||
f(1);
|
||||
})();
|
||||
})();
|
||||
})();
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -6867,9 +6914,517 @@ issue_3666: {
|
||||
} finally {
|
||||
for (;!a;)
|
||||
a++;
|
||||
var b = a = "PASS";
|
||||
a = "PASS";
|
||||
}
|
||||
console.log(a, b);
|
||||
console.log(a, "PASS");
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
issue_3774: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var f = function() {
|
||||
function g() {
|
||||
if (!g.p) {
|
||||
g.p = 1;
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
return function() {
|
||||
g();
|
||||
};
|
||||
}();
|
||||
f();
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
var f = function() {
|
||||
function g() {
|
||||
if (!g.p) {
|
||||
g.p = 1;
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
return function() {
|
||||
g();
|
||||
};
|
||||
}();
|
||||
f();
|
||||
f();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
flatten_iife: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
while (!console);
|
||||
a++;
|
||||
(function() {
|
||||
while (!console);
|
||||
a = "PASS";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
while (!console);
|
||||
0;
|
||||
(function() {
|
||||
while (!console);
|
||||
a = "PASS";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3844: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
if (!console) switch (A = 0) {
|
||||
case console.log("FAIL"):
|
||||
return;
|
||||
}
|
||||
return typeof A;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
if (!console) switch (A = 0) {
|
||||
case console.log("FAIL"):
|
||||
return;
|
||||
}
|
||||
return typeof A;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_3866: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
{
|
||||
return "PASS";
|
||||
var a = 0;
|
||||
}
|
||||
return --a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3880: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
while (a.var ^= 1);
|
||||
console.log("PASS");
|
||||
})(function() {});
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
while (a.var ^= 1);
|
||||
console.log("PASS");
|
||||
})(function() {});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3894: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function log(msg) {
|
||||
console.log(msg ? "FAIL" : "PASS");
|
||||
}
|
||||
var a;
|
||||
(function(b) {
|
||||
a = 0,
|
||||
log(b);
|
||||
})(-0);
|
||||
}
|
||||
expect: {
|
||||
function log(msg) {
|
||||
console.log(msg ? "FAIL" : "PASS");
|
||||
}
|
||||
var a;
|
||||
void log(-(a = 0));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3922: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
var b;
|
||||
b && b[c];
|
||||
a |= this;
|
||||
console.log("PASS");
|
||||
var c = a.undefined;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
0;
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3949_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
(function f(a) {
|
||||
var a = void (a = 0, g);
|
||||
function g() {
|
||||
console.log(typeof a);
|
||||
}
|
||||
g();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function f(a) {
|
||||
var a = void (a = 0, g);
|
||||
function g() {
|
||||
console.log(typeof a);
|
||||
}
|
||||
g();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_3949_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f(a) {
|
||||
var a = void (a = 0, g);
|
||||
function g() {
|
||||
console.log(typeof a);
|
||||
}
|
||||
g();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
a = void (a = 0, g);
|
||||
function g() {
|
||||
console.log(typeof a);
|
||||
}
|
||||
g();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_3949_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
function f() {}
|
||||
for (var a, i = 3; 0 <= --i; ) {
|
||||
a = f;
|
||||
console.log(a === b);
|
||||
var b = a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {}
|
||||
for (var a, i = 3; 0 <= --i; ) {
|
||||
a = f;
|
||||
console.log(a === b);
|
||||
var b = a;
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"false",
|
||||
"true",
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3949_4: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
function f() {}
|
||||
for (var a, i = 3; 0 <= --i; ) {
|
||||
a = f;
|
||||
console.log(a === b);
|
||||
var b = a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {}
|
||||
for (var a, i = 3; 0 <= --i; ) {
|
||||
a = f;
|
||||
console.log(a === b);
|
||||
var b = a;
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"false",
|
||||
"true",
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
local_assignment_lambda: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
function f() {
|
||||
a = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
f();
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
console.log("PASS");
|
||||
}
|
||||
f(),
|
||||
f();
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
local_assignment_loop: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
do {
|
||||
a = "PASS";
|
||||
console.log(a);
|
||||
} while (!console);
|
||||
}
|
||||
expect: {
|
||||
do {
|
||||
console.log("PASS");
|
||||
} while (!console);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3957_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
while (a += console.log(a = 0))
|
||||
a = 0;
|
||||
}
|
||||
f("FAIL");
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
while (a += console.log(a = 0))
|
||||
a = 0;
|
||||
}
|
||||
f("FAIL");
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3957_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
while (a += console.log(a = 0))
|
||||
a = 0;
|
||||
}
|
||||
f("FAIL");
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
while (a += console.log(a = 0))
|
||||
a = 0;
|
||||
}
|
||||
f("FAIL");
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3958: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
(function(b) {
|
||||
(function(c) {
|
||||
console.log(c[0] = 1);
|
||||
})(a = b);
|
||||
--a;
|
||||
})([]);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
(function(b) {
|
||||
(function(c) {
|
||||
console.log(c[0] = 1);
|
||||
})(a = []);
|
||||
--a;
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3974: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
var a = 0 in 0;
|
||||
0 && a;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
var a = 0 in 0;
|
||||
0 && a;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4030: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
{
|
||||
delete (a = "PASS");
|
||||
A = "PASS";
|
||||
}
|
||||
console.log(A);
|
||||
}
|
||||
expect: {
|
||||
A = "PASS";
|
||||
console.log(A);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
global_assign: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
A = "FAIL";
|
||||
this.A = "PASS";
|
||||
console.log(A);
|
||||
}
|
||||
expect: {
|
||||
A = "FAIL";
|
||||
this.A = "PASS";
|
||||
console.log(A);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -80,3 +80,21 @@ log_global: {
|
||||
}
|
||||
expect_stdout: "[object global]"
|
||||
}
|
||||
|
||||
issue_4054: {
|
||||
input: {
|
||||
console.log({
|
||||
set p(v) {
|
||||
throw "FAIL";
|
||||
},
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
set p(v) {
|
||||
throw "FAIL";
|
||||
},
|
||||
});
|
||||
}
|
||||
expect_stdout: "{ p: [Setter] }"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -97,9 +97,8 @@ issue_2233_2: {
|
||||
var RegExp;
|
||||
UndeclaredGlobal;
|
||||
function foo() {
|
||||
var Number;
|
||||
AnotherUndeclaredGlobal;
|
||||
Number.isNaN;
|
||||
(void 0).isNaN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,3 +274,120 @@ drop_value: {
|
||||
foo(), bar();
|
||||
}
|
||||
}
|
||||
|
||||
operator_in: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
"foo" in true;
|
||||
console.log("FAIL");
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
0 in true;
|
||||
console.log("FAIL");
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3983_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
function f() {
|
||||
g && g();
|
||||
}
|
||||
f();
|
||||
function g() {
|
||||
0 ? a : 0;
|
||||
}
|
||||
var b = a;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
g();
|
||||
function g() {}
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3983_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
function f() {
|
||||
g && g();
|
||||
}
|
||||
f();
|
||||
function g() {
|
||||
0 ? a : 0;
|
||||
}
|
||||
var b = a;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4008: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
function f(b, b) {
|
||||
console.log(b);
|
||||
}
|
||||
f && f(a && a[a]);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
function f(b, b) {
|
||||
console.log(b);
|
||||
}
|
||||
f(a[a]);
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
constant_switch_1: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -19,6 +20,7 @@ constant_switch_1: {
|
||||
|
||||
constant_switch_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -39,6 +41,7 @@ constant_switch_2: {
|
||||
|
||||
constant_switch_3: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -60,6 +63,7 @@ constant_switch_3: {
|
||||
|
||||
constant_switch_4: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -86,6 +90,7 @@ constant_switch_4: {
|
||||
|
||||
constant_switch_5: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -120,6 +125,7 @@ constant_switch_5: {
|
||||
|
||||
constant_switch_6: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -154,6 +160,7 @@ constant_switch_6: {
|
||||
|
||||
constant_switch_7: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -197,6 +204,7 @@ constant_switch_7: {
|
||||
|
||||
constant_switch_8: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -226,6 +234,7 @@ constant_switch_8: {
|
||||
|
||||
constant_switch_9: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -315,6 +324,7 @@ keep_default: {
|
||||
|
||||
issue_1663: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -551,6 +561,7 @@ issue_441_2: {
|
||||
|
||||
issue_1674: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
@@ -876,6 +887,7 @@ beautify: {
|
||||
|
||||
issue_1758: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
@@ -898,15 +910,16 @@ issue_1758: {
|
||||
|
||||
issue_2535: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch(w(), 42) {
|
||||
case 13: x();
|
||||
case 42: y();
|
||||
default: z();
|
||||
case 13: x();
|
||||
case 42: y();
|
||||
default: z();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
@@ -919,6 +932,7 @@ issue_2535: {
|
||||
|
||||
issue_1750: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
switches: true,
|
||||
@@ -963,6 +977,7 @@ drop_switch_1: {
|
||||
|
||||
drop_switch_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
@@ -1007,6 +1022,7 @@ drop_switch_3: {
|
||||
|
||||
drop_switch_4: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
@@ -1028,3 +1044,140 @@ drop_switch_4: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
drop_switch_5: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (A) {
|
||||
case B:
|
||||
x();
|
||||
default:
|
||||
}
|
||||
switch (C) {
|
||||
default:
|
||||
y();
|
||||
case D:
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
A === B && x();
|
||||
C !== D && y();
|
||||
}
|
||||
}
|
||||
|
||||
drop_switch_6: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (A) {
|
||||
case B:
|
||||
default:
|
||||
x();
|
||||
}
|
||||
switch (C) {
|
||||
default:
|
||||
case D:
|
||||
y();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
A === B;
|
||||
x();
|
||||
C !== D;
|
||||
y();
|
||||
}
|
||||
}
|
||||
|
||||
drop_switch_7: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (A) {
|
||||
case B:
|
||||
w();
|
||||
default:
|
||||
x();
|
||||
}
|
||||
switch (C) {
|
||||
default:
|
||||
y();
|
||||
case D:
|
||||
z();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
A === B && w();
|
||||
x();
|
||||
C !== D && y();
|
||||
z();
|
||||
}
|
||||
}
|
||||
|
||||
drop_switch_8: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (A) {
|
||||
case B:
|
||||
w();
|
||||
break;
|
||||
default:
|
||||
x();
|
||||
}
|
||||
switch (C) {
|
||||
default:
|
||||
y();
|
||||
break;
|
||||
case D:
|
||||
z();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
(A === B ? w : x)();
|
||||
(C !== D ? y : z)();
|
||||
}
|
||||
}
|
||||
|
||||
issue_4059: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (0) {
|
||||
default:
|
||||
case 1:
|
||||
break;
|
||||
case a:
|
||||
break;
|
||||
var a;
|
||||
}
|
||||
console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
switch (0) {
|
||||
default:
|
||||
break;
|
||||
case a:
|
||||
break;
|
||||
var a;
|
||||
}
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ label_if_break: {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
L: if (true) {
|
||||
|
||||
@@ -435,3 +435,25 @@ emberjs_global: {
|
||||
}
|
||||
expect_stdout: Error("PASS")
|
||||
}
|
||||
|
||||
issue_3817: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
conditionals: true,
|
||||
passes: 2,
|
||||
typeofs: true,
|
||||
}
|
||||
input: {
|
||||
if ("A" == typeof A || !console.log("PASS")) switch (false) {
|
||||
case "undefined" == typeof A:
|
||||
console.log("FAIL");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
if ("A" == typeof A || !console.log("PASS")) switch (false) {
|
||||
case "undefined" == typeof A:
|
||||
console.log("FAIL");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -13,3 +13,4 @@ exports["to_ascii"] = to_ascii;
|
||||
exports["tokenizer"] = tokenizer;
|
||||
exports["TreeTransformer"] = TreeTransformer;
|
||||
exports["TreeWalker"] = TreeWalker;
|
||||
exports["vlq_decode"] = vlq_decode;
|
||||
|
||||
4
test/input/invalid/switch.js
Normal file
4
test/input/invalid/switch.js
Normal file
@@ -0,0 +1,4 @@
|
||||
switch (0) {
|
||||
default:
|
||||
default:
|
||||
}
|
||||
@@ -1,2 +1,41 @@
|
||||
function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i]}return arr2}else{return Array.from(arr)}}var _require=require("bar"),foo=_require.foo;var _require2=require("world"),hello=_require2.hello;foo.x.apply(foo,_toConsumableArray(foo.y(hello.z)));
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiYXJyIl0sIm1hcHBpbmdzIjoiMEpBQWNBLEtBQVFDIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3Qge2Zvb30gPSByZXF1aXJlKFwiYmFyXCIpO1xuY29uc3Qge2hlbGxvfSA9IHJlcXVpcmUoXCJ3b3JsZFwiKTtcblxuZm9vLngoLi4uZm9vLnkoaGVsbG8ueikpO1xuIl19
|
||||
"use strict";
|
||||
|
||||
function _toConsumableArray(arr) {
|
||||
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
|
||||
}
|
||||
|
||||
function _nonIterableSpread() {
|
||||
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
||||
}
|
||||
|
||||
function _unsupportedIterableToArray(o, minLen) {
|
||||
if (!o) return;
|
||||
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
||||
var n = Object.prototype.toString.call(o).slice(8, -1);
|
||||
if (n === "Object" && o.constructor) n = o.constructor.name;
|
||||
if (n === "Map" || n === "Set") return Array.from(n);
|
||||
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
||||
}
|
||||
|
||||
function _iterableToArray(iter) {
|
||||
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
|
||||
}
|
||||
|
||||
function _arrayWithoutHoles(arr) {
|
||||
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
|
||||
}
|
||||
|
||||
function _arrayLikeToArray(arr, len) {
|
||||
if (len == null || len > arr.length) len = arr.length;
|
||||
for (var i = 0, arr2 = new Array(len); i < len; i++) {
|
||||
arr2[i] = arr[i];
|
||||
}
|
||||
return arr2;
|
||||
}
|
||||
|
||||
var _require = require("bar"), foo = _require.foo;
|
||||
|
||||
var _require2 = require("world"), hello = _require2.hello;
|
||||
|
||||
foo.x.apply(foo, _toConsumableArray(foo.y(hello.z)));
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHtmb299ID0gcmVxdWlyZShcImJhclwiKTtcbmNvbnN0IHtoZWxsb30gPSByZXF1aXJlKFwid29ybGRcIik7XG5cbmZvby54KC4uLmZvby55KGhlbGxvLnopKTtcbiJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiZm9vIiwiaGVsbG8iLCJ4IiwiYXBwbHkiLCJfdG9Db25zdW1hYmxlQXJyYXkiLCJ5IiwieiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7ZUFBY0EsUUFBUSxRQUFmQyxNLFNBQUFBOztBLGdCQUNTRCxRQUFRLFVBQWpCRSxRLFVBQUFBOztBQUVQRCxJQUFJRSxFQUFKQyxNQUFBSCxLQUFHSSxtQkFBTUosSUFBSUssRUFBRUosTUFBTUsifQ==
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
||||
"use strict";
|
||||
|
||||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
||||
|
||||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
||||
|
||||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
||||
|
||||
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
|
||||
|
||||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
||||
|
||||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
||||
|
||||
var _require = require("bar"),
|
||||
foo = _require.foo;
|
||||
|
||||
@@ -1 +1,11 @@
|
||||
{"version":3,"sources":["input2.js"],"names":["require","foo","hello","x","apply","_toConsumableArray","y","z"],"mappings":"kLAAcA,QAAQ,OAAfC,aAAAA,kBACSD,QAAQ,SAAjBE,gBAAAA,MAEPD,IAAIE,EAAJC,MAAAH,IAAAI,mBAASJ,IAAIK,EAAEJ,MAAMK","sourcesContent":["const {foo} = require(\"bar\");\nconst {hello} = require(\"world\");\n\nfoo.x(...foo.y(hello.z));\n"]}
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [
|
||||
"input.js"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";;;;;;;;;;;;;;eAAc,OAAO,CAAC,KAAD,C;IAAd,G,YAAA,G;;gBACS,OAAO,CAAC,OAAD,C;IAAhB,K,aAAA,K;;AAEP,GAAG,CAAC,CAAJ,OAAA,GAAG,qBAAM,GAAG,CAAC,CAAJ,CAAM,KAAK,CAAC,CAAZ,CAAN,EAAH",
|
||||
"sourcesContent": [
|
||||
"const {foo} = require(\"bar\");\nconst {hello} = require(\"world\");\n\nfoo.x(...foo.y(hello.z));\n"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
new function(){console.log(3)};
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9
|
||||
|
||||
@@ -2,4 +2,4 @@ function test(a){
|
||||
"aaaaaaaaaaaaaaaa"
|
||||
;a(err,data),a(err,
|
||||
data)}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7QUFDVjtDQUNBQSxFQUFTQyxJQUFLQyxNQUNkRixFQUFTQztBQUFLQyJ9
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7O0NBRVZBLEVBQVNDLElBQUtDLE1BQ2RGLEVBQVNDO0FBQUtDIn0=
|
||||
@@ -1,2 +1,2 @@
|
||||
new function(){console.log(3)};
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9
|
||||
|
||||
5
test/input/reduce/diff_error.js
Normal file
5
test/input/reduce/diff_error.js
Normal file
@@ -0,0 +1,5 @@
|
||||
(function f(a) {
|
||||
do {
|
||||
console.log(f.length);
|
||||
} while (console.log(f += 0));
|
||||
})();
|
||||
19
test/input/reduce/diff_error.reduced.js
Normal file
19
test/input/reduce/diff_error.reduced.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// (beautified)
|
||||
(function f(a) {
|
||||
do {
|
||||
console.log(f.length);
|
||||
} while (console.log(f += 0));
|
||||
})();
|
||||
// output: 1
|
||||
// function(){}0
|
||||
//
|
||||
// minify: 0
|
||||
// function(){}0
|
||||
//
|
||||
// options: {
|
||||
// "compress": {
|
||||
// "keep_fargs": false,
|
||||
// "unsafe": true
|
||||
// },
|
||||
// "mangle": false
|
||||
// }
|
||||
@@ -1,6 +1,6 @@
|
||||
function f(x) {
|
||||
return g(x);
|
||||
function g(x) {
|
||||
return x;
|
||||
return x + x;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,15 @@ if (typeof phantom == "undefined") {
|
||||
require("../tools/exit");
|
||||
var args = process.argv.slice(2);
|
||||
var debug = args.indexOf("--debug");
|
||||
if (debug >= 0) {
|
||||
if (debug < 0) {
|
||||
debug = false;
|
||||
} else {
|
||||
args.splice(debug, 1);
|
||||
debug = true;
|
||||
} else {
|
||||
debug = false;
|
||||
}
|
||||
if (!args.length) {
|
||||
args.push("-mcb", "beautify=false,webkit");
|
||||
}
|
||||
args.push("--timings");
|
||||
if (!args.length) args.push("-mcb", "beautify=false,webkit");
|
||||
args.unshift("bin/uglifyjs");
|
||||
args.push("--validate", "--timings");
|
||||
var child_process = require("child_process");
|
||||
var fetch = require("./fetch");
|
||||
var http = require("http");
|
||||
@@ -39,10 +38,10 @@ if (typeof phantom == "undefined") {
|
||||
});
|
||||
if (/\.js$/.test(url)) {
|
||||
var stderr = "";
|
||||
var uglifyjs = child_process.fork("bin/uglifyjs", args, {
|
||||
var uglifyjs = child_process.spawn(process.argv[0], args, {
|
||||
silent: true
|
||||
}).on("exit", function(code) {
|
||||
console.log("uglifyjs", url.slice(site.length + 1), args.join(" "));
|
||||
console.log("uglifyjs", url.slice(site.length + 1), args.slice(1).join(" "));
|
||||
console.log(stderr);
|
||||
if (code) throw new Error("uglifyjs failed with code " + code);
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ var assert = require("assert");
|
||||
var exec = require("child_process").exec;
|
||||
var fs = require("fs");
|
||||
var run_code = require("../sandbox").run_code;
|
||||
var to_ascii = require("../node").to_ascii;
|
||||
|
||||
function read(path) {
|
||||
return fs.readFileSync(path, "utf8");
|
||||
@@ -48,6 +49,62 @@ describe("bin/uglifyjs", function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with --source-map names=true", function(done) {
|
||||
exec([
|
||||
uglifyjscmd,
|
||||
"--beautify",
|
||||
"--source-map", [
|
||||
"names=true",
|
||||
"url=inline",
|
||||
].join(","),
|
||||
].join(" "), function(err, stdout) {
|
||||
if (err) throw err;
|
||||
var expected = [
|
||||
"var obj = {",
|
||||
" p: a,",
|
||||
" q: b",
|
||||
"};",
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,",
|
||||
].join("\n")
|
||||
assert.strictEqual(stdout.slice(0, expected.length), expected);
|
||||
var map = JSON.parse(to_ascii(stdout.slice(expected.length).trim()));
|
||||
assert.deepEqual(map.names, [ "obj", "p", "a", "q", "b" ]);
|
||||
done();
|
||||
}).stdin.end([
|
||||
"var obj = {",
|
||||
" p: a,",
|
||||
" q: b",
|
||||
"};",
|
||||
].join("\n"));
|
||||
});
|
||||
it("Should work with --source-map names=false", function(done) {
|
||||
exec([
|
||||
uglifyjscmd,
|
||||
"--beautify",
|
||||
"--source-map", [
|
||||
"names=false",
|
||||
"url=inline",
|
||||
].join(","),
|
||||
].join(" "), function(err, stdout) {
|
||||
if (err) throw err;
|
||||
var expected = [
|
||||
"var obj = {",
|
||||
" p: a,",
|
||||
" q: b",
|
||||
"};",
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,",
|
||||
].join("\n")
|
||||
assert.strictEqual(stdout.slice(0, expected.length), expected);
|
||||
var map = JSON.parse(to_ascii(stdout.slice(expected.length).trim()));
|
||||
assert.deepEqual(map.names, []);
|
||||
done();
|
||||
}).stdin.end([
|
||||
"var obj = {",
|
||||
" p: a,",
|
||||
" q: b",
|
||||
"};",
|
||||
].join("\n"));
|
||||
});
|
||||
it("Should give sensible error against invalid input source map", function(done) {
|
||||
var command = uglifyjscmd + " test/mocha.js --source-map content=blah,url=inline --verbose";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
@@ -109,9 +166,12 @@ describe("bin/uglifyjs", function() {
|
||||
}
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
"--source-map", "content=" + mapFile,
|
||||
"--source-map", "includeSources=true",
|
||||
"--source-map", "url=inline",
|
||||
"--beautify",
|
||||
"--source-map", [
|
||||
"content=" + mapFile,
|
||||
"includeSources",
|
||||
"url=inline",
|
||||
].join(","),
|
||||
].join(" ");
|
||||
|
||||
var child = exec(command, function(err, stdout) {
|
||||
@@ -189,7 +249,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should work with `--output-opts`", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/issue-1482/input.js -O';
|
||||
var command = uglifyjscmd + ' test/input/issue-1482/input.js -O ascii_only';
|
||||
exec(command, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
|
||||
@@ -197,7 +257,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should fail when both --beautify & --output-opts are specified", function(done) {
|
||||
var command = uglifyjscmd + " test/input/issue-520/input.js -bO";
|
||||
var command = uglifyjscmd + " test/input/issue-520/input.js -bO ascii_only";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stderr, "ERROR: --beautify cannot be used with --output-opts\n");
|
||||
@@ -245,7 +305,7 @@ describe("bin/uglifyjs", function() {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, [
|
||||
"var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();",
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUFBLE1BQWdCQyxRQUFRQyxJQUFJLEVBQUUsSUFBTyxJQUFJRixJQ0FuRCxJQUFJRyxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUVBLE1BQWNDLFFBQVFDLElBQUksRUFBRSxJQUFPLElBQUlGLElDQW5ELElBQUlHLElBQU0sV0FDTixTQUFTQyxJQUFLRCxLQUNWLE9BQU9BLElBR1gsT0FBT0MsSUFMRCJ9",
|
||||
"",
|
||||
].join("\n"));
|
||||
var stderrLines = stderr.split("\n");
|
||||
@@ -270,7 +330,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should fail with invalid syntax", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/simple.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/simple.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
var lines = stderr.split(/\n/);
|
||||
@@ -282,7 +342,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should fail with correct marking of tabs", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/tab.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/tab.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
var lines = stderr.split(/\n/);
|
||||
@@ -294,7 +354,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should fail with correct marking at start of line", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/eof.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/eof.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
var lines = stderr.split(/\n/);
|
||||
@@ -306,7 +366,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should fail with a missing loop body", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/loop-no-body.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/loop-no-body.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
var lines = stderr.split(/\n/);
|
||||
@@ -318,7 +378,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (5--)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/assign_1.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -332,7 +392,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (Math.random() /= 2)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/assign_2.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -346,7 +406,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (++this)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/assign_3.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -360,7 +420,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (++null)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/assign_4.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -374,7 +434,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (a.=)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/dot_1.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -388,7 +448,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (%.a)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/dot_2.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -402,7 +462,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (a./();)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/dot_3.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -416,7 +476,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error ({%: 1})", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/object.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/object.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -430,7 +490,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (delete x)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/delete.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/delete.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -444,7 +504,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (function g(arguments))", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/function_1.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/function_1.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -458,7 +518,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (function eval())", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/function_2.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/function_2.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -472,7 +532,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (iife arguments())", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/function_3.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/function_3.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -486,7 +546,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (catch (eval))", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/try.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/try.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -500,7 +560,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (var eval)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/var.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/var.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -514,7 +574,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (else)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/else.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/else.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -528,7 +588,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (return)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/return.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/return.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -542,7 +602,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (for-in init)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/for-in_1.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/for-in_1.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -556,7 +616,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (for-in var)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/for-in_2.js';
|
||||
var command = uglifyjscmd + " test/input/invalid/for-in_2.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
@@ -569,6 +629,18 @@ describe("bin/uglifyjs", function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (switch defaults)", function(done) {
|
||||
var command = uglifyjscmd + " test/input/invalid/switch.js";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
var lines = stderr.split(/\n/);
|
||||
assert.strictEqual(lines[0], "Parse error at test/input/invalid/switch.js:3,2");
|
||||
assert.strictEqual(lines[1], " default:");
|
||||
assert.strictEqual(lines[2], " ^");
|
||||
assert.strictEqual(lines[3], "ERROR: More than one default clause in switch statement");
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should handle literal string as source map input", function(done) {
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
@@ -587,7 +659,7 @@ describe("bin/uglifyjs", function() {
|
||||
});
|
||||
|
||||
function read_map() {
|
||||
var map = JSON.parse(read("./test/input/issue-1236/simple.js.map"));
|
||||
var map = JSON.parse(read("test/input/issue-1236/simple.js.map"));
|
||||
delete map.sourcesContent;
|
||||
return JSON.stringify(map).replace(/"/g, '\\"');
|
||||
}
|
||||
@@ -657,7 +729,7 @@ describe("bin/uglifyjs", function() {
|
||||
var command = uglifyjscmd + " test/input/issue-3315/input.js --config-file test/input/issue-3315/config.json";
|
||||
exec(command, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, 'function f(){"aaaaaaaaaa";var a={prop:1,a:2};return a.prop+a.a}\n');
|
||||
assert.strictEqual(stdout, 'function f(){"aaaaaaaaaa";var a={prop:1,t:2};return a.prop+a.t}\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -674,7 +746,7 @@ describe("bin/uglifyjs", function() {
|
||||
var command = uglifyjscmd + " test/input/rename/input.js --rename";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c}}\n");
|
||||
assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c+c}}\n");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -682,7 +754,7 @@ describe("bin/uglifyjs", function() {
|
||||
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2 --no-rename";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, "function f(n){return function(n){return n}(n)}\n");
|
||||
assert.strictEqual(stdout, "function f(n){return function(n){return n+n}(n)}\n");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -690,7 +762,7 @@ describe("bin/uglifyjs", function() {
|
||||
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, "function f(n){return n}\n");
|
||||
assert.strictEqual(stdout, "function f(n){return n+n}\n");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -698,7 +770,7 @@ describe("bin/uglifyjs", function() {
|
||||
var command = uglifyjscmd + " test/input/rename/input.js -c passes=2";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, "function f(x){return function(x){return x}(x)}\n");
|
||||
assert.strictEqual(stdout, "function f(x){return function(x){return x+x}(x)}\n");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var assert = require("assert");
|
||||
var readFileSync = require("fs").readFileSync;
|
||||
var run_code = require("../sandbox").run_code;
|
||||
var UglifyJS = require("../../");
|
||||
var UglifyJS = require("../..");
|
||||
|
||||
function read(path) {
|
||||
return readFileSync(path, "utf8");
|
||||
@@ -9,18 +9,30 @@ function read(path) {
|
||||
|
||||
describe("minify", function() {
|
||||
it("Should test basic sanity of minify with default options", function() {
|
||||
var js = 'function foo(bar) { if (bar) return 3; else return 7; var u = not_called(); }';
|
||||
var js = "function foo(bar) { if (bar) return 3; else return 7; var u = not_called(); }";
|
||||
var result = UglifyJS.minify(js);
|
||||
assert.strictEqual(result.code, 'function foo(n){return n?3:7}');
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, "function foo(n){return n?3:7}");
|
||||
});
|
||||
|
||||
it("Should not mutate minify `options`", function() {
|
||||
var options = {
|
||||
compress: true,
|
||||
mangle: false,
|
||||
output: {},
|
||||
};
|
||||
var value = JSON.stringify(options);
|
||||
var result = UglifyJS.minify("print(6 * 7);", options);
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, "print(42);");
|
||||
assert.strictEqual(JSON.stringify(options), value);
|
||||
})
|
||||
it("Should skip inherited keys from `files`", function() {
|
||||
var files = Object.create({ skip: this });
|
||||
files[0] = "alert(1 + 1)";
|
||||
var result = UglifyJS.minify(files);
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, "alert(2);");
|
||||
});
|
||||
|
||||
it("Should work with mangle.cache", function() {
|
||||
var cache = {};
|
||||
var original = "";
|
||||
@@ -53,7 +65,6 @@ describe("minify", function() {
|
||||
].join(""));
|
||||
assert.strictEqual(run_code(compressed, true), run_code(original, true));
|
||||
});
|
||||
|
||||
it("Should work with nameCache", function() {
|
||||
var cache = {};
|
||||
var original = "";
|
||||
@@ -86,7 +97,6 @@ describe("minify", function() {
|
||||
].join(""));
|
||||
assert.strictEqual(run_code(compressed, true), run_code(original, true));
|
||||
});
|
||||
|
||||
it("Should avoid cached names when mangling top-level variables", function() {
|
||||
var cache = {};
|
||||
var original = "";
|
||||
@@ -115,7 +125,6 @@ describe("minify", function() {
|
||||
].join(""));
|
||||
assert.strictEqual(run_code(compressed, true), run_code(original, true));
|
||||
});
|
||||
|
||||
it("Should avoid cached names when mangling inner-scoped variables", function() {
|
||||
var cache = {};
|
||||
var original = "";
|
||||
@@ -139,7 +148,6 @@ describe("minify", function() {
|
||||
].join(""));
|
||||
assert.strictEqual(run_code(compressed, true), run_code(original, true));
|
||||
});
|
||||
|
||||
it("Should not parse invalid use of reserved words", function() {
|
||||
assert.strictEqual(UglifyJS.minify("function enum(){}").error, undefined);
|
||||
assert.strictEqual(UglifyJS.minify("function static(){}").error, undefined);
|
||||
@@ -155,7 +163,6 @@ describe("minify", function() {
|
||||
}});
|
||||
assert.strictEqual(result.code, 'var foo={"x":1,y:2,"z":3};');
|
||||
});
|
||||
|
||||
it("Should preserve quote styles when quote_style is 3", function() {
|
||||
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||
var result = UglifyJS.minify(js, {
|
||||
@@ -165,7 +172,6 @@ describe("minify", function() {
|
||||
}});
|
||||
assert.strictEqual(result.code, 'var foo={"x":1,y:2,\'z\':3};');
|
||||
});
|
||||
|
||||
it("Should not preserve quotes in object literals when disabled", function() {
|
||||
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||
var result = UglifyJS.minify(js, {
|
||||
|
||||
@@ -486,4 +486,19 @@ describe("operator", function() {
|
||||
assert.strictEqual(UglifyJS.parse(exp[0]).print_to_string(), exp[1] + ";");
|
||||
});
|
||||
});
|
||||
it("Should preserve space between /regex/ and `in`", function() {
|
||||
[
|
||||
"/regex/ in {}",
|
||||
"/regex/g in {}",
|
||||
"0 + /regex/ in {}",
|
||||
"0 + /regex/g in {}",
|
||||
].forEach(function(exp) {
|
||||
var code = UglifyJS.parse(exp).print_to_string();
|
||||
try {
|
||||
assert.strictEqual(UglifyJS.parse(code).print_to_string(), code);
|
||||
} catch (ex) {
|
||||
assert.fail("Failed to reparse: " + exp + "\n" + ex);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -186,7 +186,7 @@ describe("test/reduce.js", function() {
|
||||
].join("\n"));
|
||||
});
|
||||
it("Should reduce infinite loops with reasonable performance", function() {
|
||||
if (semver.satisfies(process.version, "0.10")) return;
|
||||
if (semver.satisfies(process.version, "<=0.10")) return;
|
||||
this.timeout(120000);
|
||||
var result = reduce_test("while (/9/.test(1 - .8));", {
|
||||
compress: {
|
||||
@@ -211,7 +211,7 @@ describe("test/reduce.js", function() {
|
||||
it("Should ignore difference in Error.message", function() {
|
||||
var result = reduce_test("null[function() {\n}];");
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, (semver.satisfies(process.version, "0.10") ? [
|
||||
assert.strictEqual(result.code, (semver.satisfies(process.version, "<=0.10") ? [
|
||||
"// Can't reproduce test failure",
|
||||
"// minify options: {}",
|
||||
] : [
|
||||
@@ -246,4 +246,68 @@ describe("test/reduce.js", function() {
|
||||
"// }",
|
||||
].join("\n"));
|
||||
});
|
||||
it("Should reduce test case which differs only in Error.message", function() {
|
||||
var code = [
|
||||
"var a=0;",
|
||||
"try{",
|
||||
"null[function(){}]",
|
||||
"}catch(e){",
|
||||
"for(var i in e.toString())",
|
||||
"a++,console.log()",
|
||||
"}",
|
||||
"console.log(a);",
|
||||
].join("");
|
||||
var result = reduce_test(code, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
output: {
|
||||
beautify: true,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.deepEqual(result.warnings, []);
|
||||
assert.strictEqual(result.code.replace(/function \(/g, "function("), (semver.satisfies(process.version, "<=0.10") ? [
|
||||
"// Can't reproduce test failure",
|
||||
"// minify options: {",
|
||||
'// "compress": false,',
|
||||
'// "mangle": false,',
|
||||
'// "output": {',
|
||||
'// "beautify": true',
|
||||
"// }",
|
||||
"// }",
|
||||
] : [
|
||||
[
|
||||
"try{",
|
||||
"null[function(){}]",
|
||||
"}catch(e){",
|
||||
"console.log(e)",
|
||||
"}",
|
||||
].join(""),
|
||||
"// output: TypeError: Cannot read property 'function(){}' of null",
|
||||
"// ",
|
||||
"// minify: TypeError: Cannot read property 'function() {}' of null",
|
||||
"// ",
|
||||
"// options: {",
|
||||
'// "compress": false,',
|
||||
'// "mangle": false,',
|
||||
'// "output": {',
|
||||
'// "beautify": true',
|
||||
"// }",
|
||||
"// }",
|
||||
]).join("\n"));
|
||||
});
|
||||
it("Should handle corner cases when intermediate case differs only in Error.message", function() {
|
||||
if (semver.satisfies(process.version, "<=0.10")) return;
|
||||
var result = reduce_test(read("test/input/reduce/diff_error.js"), {
|
||||
compress: {
|
||||
keep_fargs: false,
|
||||
unsafe: true,
|
||||
},
|
||||
mangle: false,
|
||||
}, {
|
||||
verbose: false,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, read("test/input/reduce/diff_error.reduced.js"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
var assert = require("assert");
|
||||
var readFileSync = require("fs").readFileSync;
|
||||
var SourceMapConsumer = require("source-map").SourceMapConsumer;
|
||||
var fs = require("fs");
|
||||
var UglifyJS = require("../node");
|
||||
|
||||
function read(path) {
|
||||
return readFileSync(path, "utf8");
|
||||
return fs.readFileSync(path, "utf8");
|
||||
}
|
||||
|
||||
function source_map(code) {
|
||||
return JSON.parse(UglifyJS.minify(code, {
|
||||
var result = UglifyJS.minify(code, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: true,
|
||||
}).map);
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
return JSON.parse(result.map);
|
||||
}
|
||||
|
||||
function get_map() {
|
||||
@@ -44,7 +45,7 @@ function prepare_map(sourceMap) {
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
return new SourceMapConsumer(result.map);
|
||||
return JSON.parse(result.map);
|
||||
}
|
||||
|
||||
describe("sourcemaps", function() {
|
||||
@@ -66,6 +67,40 @@ describe("sourcemaps", function() {
|
||||
].join("\n"));
|
||||
assert.deepEqual(map.names, [ "enabled", "x" ]);
|
||||
});
|
||||
it("Should work with sourceMap.names=true", function() {
|
||||
var result = UglifyJS.minify([
|
||||
"var obj = {",
|
||||
" p: a,",
|
||||
" q: b",
|
||||
"};",
|
||||
].join("\n"), {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
names: true,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
var map = JSON.parse(result.map);
|
||||
assert.deepEqual(map.names, [ "obj", "p", "a", "q", "b" ]);
|
||||
});
|
||||
it("Should work with sourceMap.names=false", function() {
|
||||
var result = UglifyJS.minify([
|
||||
"var obj = {",
|
||||
" p: a,",
|
||||
" q: b",
|
||||
"};",
|
||||
].join("\n"), {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
names: false,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
var map = JSON.parse(result.map);
|
||||
assert.deepEqual(map.names, []);
|
||||
});
|
||||
it("Should mark array/object literals", function() {
|
||||
var result = UglifyJS.minify([
|
||||
"var obj = {};",
|
||||
@@ -87,7 +122,7 @@ describe("sourcemaps", function() {
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, code);
|
||||
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI","sourceRoot":"//foo.bar/"}');
|
||||
assert.strictEqual(result.map, '{"version":3,"sourceRoot":"//foo.bar/","sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI"}');
|
||||
});
|
||||
it("Should produce same source map with DOS or UNIX line endings", function() {
|
||||
var code = [
|
||||
@@ -108,9 +143,9 @@ describe("sourcemaps", function() {
|
||||
|
||||
describe("inSourceMap", function() {
|
||||
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled", function() {
|
||||
var result = UglifyJS.minify(read("./test/input/issue-1236/simple.js"), {
|
||||
var result = UglifyJS.minify(read("test/input/issue-1236/simple.js"), {
|
||||
sourceMap: {
|
||||
content: read("./test/input/issue-1236/simple.js.map"),
|
||||
content: read("test/input/issue-1236/simple.js.map"),
|
||||
filename: "simple.min.js",
|
||||
includeSources: true
|
||||
}
|
||||
@@ -122,7 +157,7 @@ describe("sourcemaps", function() {
|
||||
assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
||||
});
|
||||
it("Should process inline source map", function() {
|
||||
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), {
|
||||
var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
|
||||
compress: { toplevel: true },
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
@@ -131,10 +166,10 @@ describe("sourcemaps", function() {
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-520/output.js", "utf8"));
|
||||
assert.strictEqual(result.code + "\n", read("test/input/issue-520/output.js"));
|
||||
});
|
||||
it("Should warn for missing inline source map", function() {
|
||||
var result = UglifyJS.minify(read("./test/input/issue-1323/sample.js"), {
|
||||
var result = UglifyJS.minify(read("test/input/issue-1323/sample.js"), {
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
content: "inline"
|
||||
@@ -146,8 +181,8 @@ describe("sourcemaps", function() {
|
||||
});
|
||||
it("Should handle multiple input and inline source map", function() {
|
||||
var result = UglifyJS.minify([
|
||||
read("./test/input/issue-520/input.js"),
|
||||
read("./test/input/issue-1323/sample.js"),
|
||||
read("test/input/issue-520/input.js"),
|
||||
read("test/input/issue-1323/sample.js"),
|
||||
], {
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
@@ -163,7 +198,7 @@ describe("sourcemaps", function() {
|
||||
assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]);
|
||||
});
|
||||
it("Should drop source contents for includeSources=false", function() {
|
||||
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), {
|
||||
var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
@@ -186,7 +221,7 @@ describe("sourcemaps", function() {
|
||||
assert.ok(!("sourcesContent" in map));
|
||||
});
|
||||
it("Should parse the correct sourceMappingURL", function() {
|
||||
var result = UglifyJS.minify(read("./test/input/issue-3294/input.js"), {
|
||||
var result = UglifyJS.minify(read("test/input/issue-3294/input.js"), {
|
||||
compress: { toplevel: true },
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
@@ -195,10 +230,10 @@ describe("sourcemaps", function() {
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-3294/output.js", "utf8"));
|
||||
assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js"));
|
||||
});
|
||||
it("Should work in presence of unrecognised annotations", function() {
|
||||
var result = UglifyJS.minify(read("./test/input/issue-3441/input.js"), {
|
||||
var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
@@ -230,7 +265,7 @@ describe("sourcemaps", function() {
|
||||
assert.strictEqual(code, "var a=function(n){return n};");
|
||||
});
|
||||
it("Should work with max_line_len", function() {
|
||||
var result = UglifyJS.minify(read("./test/input/issue-505/input.js"), {
|
||||
var result = UglifyJS.minify(read("test/input/issue-505/input.js"), {
|
||||
compress: {
|
||||
directives: false,
|
||||
},
|
||||
@@ -242,7 +277,7 @@ describe("sourcemaps", function() {
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
|
||||
assert.strictEqual(result.code, read("test/input/issue-505/output.js"));
|
||||
});
|
||||
it("Should work with unicode characters", function() {
|
||||
var code = [
|
||||
@@ -278,32 +313,42 @@ describe("sourcemaps", function() {
|
||||
});
|
||||
|
||||
describe("input sourcemaps", function() {
|
||||
it("Should not modify input source map", function() {
|
||||
var orig = get_map();
|
||||
var original = JSON.stringify(orig);
|
||||
var map = prepare_map(orig);
|
||||
assert.strictEqual(JSON.stringify(orig), original);
|
||||
});
|
||||
it("Should copy over original sourcesContent", function() {
|
||||
var orig = get_map();
|
||||
var map = prepare_map(orig);
|
||||
assert.equal(map.sourceContentFor("index.js"), orig.sourcesContent[0]);
|
||||
assert.strictEqual(map.sources.length, 1);
|
||||
assert.strictEqual(map.sources[0], "index.js");
|
||||
assert.strictEqual(map.sourcesContent.length, 1);
|
||||
assert.equal(map.sourcesContent[0], orig.sourcesContent[0]);
|
||||
});
|
||||
it("Should copy sourcesContent if sources are relative", function() {
|
||||
var relativeMap = get_map();
|
||||
relativeMap.sources = ['./index.js'];
|
||||
var map = prepare_map(relativeMap);
|
||||
assert.notEqual(map.sourcesContent, null);
|
||||
assert.equal(map.sourcesContent.length, 1);
|
||||
assert.equal(map.sourceContentFor("index.js"), relativeMap.sourcesContent[0]);
|
||||
assert.strictEqual(map.sources.length, 1);
|
||||
assert.strictEqual(map.sources[0], "./index.js");
|
||||
assert.strictEqual(map.sourcesContent.length, 1);
|
||||
assert.equal(map.sourcesContent[0], relativeMap.sourcesContent[0]);
|
||||
});
|
||||
it("Should not have invalid mappings from inputSourceMap", function() {
|
||||
var map = prepare_map(get_map());
|
||||
// The original source has only 2 lines, check that mappings don't have more lines
|
||||
var msg = "Mapping should not have higher line number than the original file had";
|
||||
map.eachMapping(function(mapping) {
|
||||
assert.ok(mapping.originalLine <= 2, msg);
|
||||
});
|
||||
map.allGeneratedPositionsFor({
|
||||
source: "index.js",
|
||||
line: 1,
|
||||
column: 1
|
||||
}).forEach(function(pos) {
|
||||
assert.ok(pos.line <= 2, msg);
|
||||
var lines = map.mappings.split(/;/);
|
||||
assert.ok(lines.length <= 2, msg);
|
||||
var indices = [ 0, 0, 1, 0, 0];
|
||||
lines.forEach(function(segments) {
|
||||
indices[0] = 0;
|
||||
segments.split(/,/).forEach(function(segment) {
|
||||
UglifyJS.vlq_decode(indices, segment);
|
||||
assert.ok(indices[2] <= 2, msg);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,11 +24,22 @@ function try_beautify(code) {
|
||||
}
|
||||
}
|
||||
|
||||
function test(original, estree, description) {
|
||||
var transformed = UglifyJS.minify(UglifyJS.AST_Node.from_mozilla_ast(estree), {
|
||||
function validate(ast) {
|
||||
try {
|
||||
ast.walk(new UglifyJS.TreeWalker(function(node) {
|
||||
node.validate();
|
||||
}));
|
||||
} catch (e) {
|
||||
return { error: e };
|
||||
}
|
||||
return UglifyJS.minify(ast, {
|
||||
compress: false,
|
||||
mangle: false
|
||||
mangle: false,
|
||||
});
|
||||
}
|
||||
|
||||
function test(original, estree, description) {
|
||||
var transformed = validate(UglifyJS.AST_Node.from_mozilla_ast(estree));
|
||||
if (transformed.error || original !== transformed.code) {
|
||||
console.log("//=============================================================");
|
||||
console.log("// !!!!!! Failed... round", round);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var fs = require("fs");
|
||||
|
||||
new Function("MOZ_SourceMap", "exports", require("../tools/node").FILES.map(function(file) {
|
||||
new Function("exports", require("../tools/node").FILES.map(function(file) {
|
||||
if (/exports\.js$/.test(file)) file = require.resolve("./exports");
|
||||
return fs.readFileSync(file, "utf8");
|
||||
}).join("\n\n"))(require("source-map"), exports);
|
||||
}).join("\n\n"))(exports);
|
||||
|
||||
250
test/reduce.js
250
test/reduce.js
@@ -1,37 +1,45 @@
|
||||
var crypto = require("crypto");
|
||||
var U = require("./node");
|
||||
var U = require("..");
|
||||
var List = U.List;
|
||||
var os = require("os");
|
||||
var sandbox = require("./sandbox");
|
||||
|
||||
// Reduce a ufuzz-style `console.log` based test case by iteratively replacing
|
||||
// AST nodes with various permutations. Each AST_Statement in the tree is also
|
||||
// speculatively dropped to determine whether it is needed. If the altered
|
||||
// tree and the last known good tree produce the same non-nil error-free output
|
||||
// after being run, then the permutation survives to the next generation and
|
||||
// is the basis for subsequent iterations. The test case is reduced as a
|
||||
// consequence of complex expressions being replaced with simpler ones.
|
||||
// This function assumes that the testcase will not result in a parse or
|
||||
// runtime Error. Note that a reduced test case will have different runtime
|
||||
// output - it is not functionally equivalent to the original. The only criteria
|
||||
// is that once the generated reduced test case is run without minification, it
|
||||
// will produce different output from the code minified with `minify_options`.
|
||||
// Returns a `minify` result object with an additonal boolean property `reduced`.
|
||||
// Reduce a test case by iteratively replacing AST nodes with various
|
||||
// permutations. Each AST_Statement in the tree is also speculatively dropped
|
||||
// to determine whether it is needed. If the altered tree and the last known
|
||||
// good tree produce the same output after being run, then the permutation
|
||||
// survives to the next generation and is the basis for subsequent iterations.
|
||||
// The test case is reduced as a consequence of complex expressions being
|
||||
// replaced with simpler ones. Note that a reduced test case will have
|
||||
// different runtime output - it is not functionally equivalent to the
|
||||
// original. The only criteria is that once the generated reduced test case is
|
||||
// run without minification, it will produce different output from the code
|
||||
// minified with `minify_options`. Returns a `minify` result object.
|
||||
|
||||
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 max_iterations = reduce_options.max_iterations || 1000;
|
||||
var max_timeout = reduce_options.max_timeout || 10000;
|
||||
var warnings = [];
|
||||
var log = reduce_options.log || function(msg) {
|
||||
warnings.push(msg);
|
||||
};
|
||||
var verbose = reduce_options.verbose;
|
||||
var minify_options_json = JSON.stringify(minify_options, null, 2);
|
||||
var result_cache = Object.create(null);
|
||||
var test_for_diff = compare_run_code;
|
||||
// the initial timeout to assess the viability of the test case must be large
|
||||
var differs = producesDifferentResultWhenMinified(result_cache, testcase, minify_options, max_timeout);
|
||||
var differs = test_for_diff(testcase, minify_options, result_cache, max_timeout);
|
||||
|
||||
if (verbose) {
|
||||
console.error("// Node.js " + process.version + " on " + os.platform() + " " + os.arch());
|
||||
log("// Node.js " + process.version + " on " + os.platform() + " " + os.arch());
|
||||
}
|
||||
if (differs.error && [ "DefaultsError", "SyntaxError" ].indexOf(differs.error.name) < 0) {
|
||||
test_for_diff = test_minify;
|
||||
differs = test_for_diff(testcase, minify_options, result_cache, max_timeout);
|
||||
}
|
||||
if (!differs) {
|
||||
// same stdout result produced when minified
|
||||
@@ -39,16 +47,19 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
code: [
|
||||
"// Can't reproduce test failure",
|
||||
"// minify options: " + to_comment(minify_options_json)
|
||||
].join("\n")
|
||||
].join("\n"),
|
||||
warnings: warnings,
|
||||
};
|
||||
} else if (differs.timed_out) {
|
||||
return {
|
||||
code: [
|
||||
"// Can't reproduce test failure within " + max_timeout + "ms",
|
||||
"// minify options: " + to_comment(minify_options_json)
|
||||
].join("\n")
|
||||
].join("\n"),
|
||||
warnings: warnings,
|
||||
};
|
||||
} else if (differs.error) {
|
||||
differs.warnings = warnings;
|
||||
return differs;
|
||||
} else if (is_error(differs.unminified_result)
|
||||
&& is_error(differs.minified_result)
|
||||
@@ -57,7 +68,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
code: [
|
||||
"// No differences except in error message",
|
||||
"// minify options: " + to_comment(minify_options_json)
|
||||
].join("\n")
|
||||
].join("\n"),
|
||||
warnings: warnings,
|
||||
};
|
||||
} else {
|
||||
max_timeout = Math.min(100 * differs.elapsed, max_timeout);
|
||||
@@ -125,40 +137,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_Binary) {
|
||||
CHANGED = true;
|
||||
var permute = ((node.start._permute += step) * steps | 0) % 4;
|
||||
var expr = [
|
||||
node.left,
|
||||
node.right,
|
||||
][ permute & 1 ];
|
||||
if (permute < 2) return expr;
|
||||
// wrap with console.log()
|
||||
return new U.AST_Call({
|
||||
expression: new U.AST_Dot({
|
||||
expression: new U.AST_SymbolRef({
|
||||
name: "console",
|
||||
start: {},
|
||||
}),
|
||||
property: "log",
|
||||
start: {},
|
||||
}),
|
||||
args: [ expr ],
|
||||
start: {},
|
||||
});
|
||||
}
|
||||
else if (node instanceof U.AST_Catch || node instanceof U.AST_Finally) {
|
||||
// drop catch or finally block
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return null;
|
||||
}
|
||||
else if (node instanceof U.AST_Conditional) {
|
||||
CHANGED = true;
|
||||
return [
|
||||
node.condition,
|
||||
node.consequent,
|
||||
node.alternative,
|
||||
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||
return permute < 2 ? expr : wrap_with_console_log(expr);
|
||||
}
|
||||
else if (node instanceof U.AST_BlockStatement) {
|
||||
if (in_list) {
|
||||
@@ -193,12 +178,26 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
return to_sequence(seq);
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_Catch) {
|
||||
// drop catch block
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return null;
|
||||
}
|
||||
else if (node instanceof U.AST_Conditional) {
|
||||
CHANGED = true;
|
||||
return [
|
||||
node.condition,
|
||||
node.consequent,
|
||||
node.alternative,
|
||||
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||
}
|
||||
else if (node instanceof U.AST_Defun) {
|
||||
switch (((node.start._permute += step) * steps | 0) % 2) {
|
||||
case 0:
|
||||
CHANGED = true;
|
||||
return List.skip;
|
||||
case 1:
|
||||
default:
|
||||
if (!has_exit(node)) {
|
||||
// hoist function declaration body
|
||||
var body = node.body;
|
||||
@@ -230,15 +229,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
return to_statement(expr);
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_PropAccess) {
|
||||
var expr = [
|
||||
node.expression,
|
||||
node.property instanceof U.AST_Node && node.property,
|
||||
][ node.start._permute++ % 2 ];
|
||||
if (expr) {
|
||||
CHANGED = true;
|
||||
return expr;
|
||||
}
|
||||
else if (node instanceof U.AST_Finally) {
|
||||
// drop finally block
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return null;
|
||||
}
|
||||
else if (node instanceof U.AST_For) {
|
||||
var expr = [
|
||||
@@ -287,6 +282,16 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_PropAccess) {
|
||||
var expr = [
|
||||
node.expression,
|
||||
node.property instanceof U.AST_Node && node.property,
|
||||
][ node.start._permute++ % 2 ];
|
||||
if (expr) {
|
||||
CHANGED = true;
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_SimpleStatement) {
|
||||
if (node.body instanceof U.AST_Call && node.body.expression instanceof U.AST_Function) {
|
||||
// hoist simple statement IIFE function expression body
|
||||
@@ -414,19 +419,42 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
});
|
||||
|
||||
var diff_error_message;
|
||||
for (var pass = 1; pass <= 3; ++pass) {
|
||||
var testcase_ast = U.parse(testcase);
|
||||
if (diff_error_message === testcase) {
|
||||
// only difference detected is in error message, so expose that and try again
|
||||
testcase_ast.transform(new U.TreeTransformer(function(node, descend) {
|
||||
if (node.TYPE == "Call" && node.expression.print_to_string() == "console.log") {
|
||||
return to_sequence(node.args);
|
||||
}
|
||||
if (node instanceof U.AST_Catch) {
|
||||
descend(node, this);
|
||||
node.body.unshift(new U.AST_SimpleStatement({
|
||||
body: wrap_with_console_log(new U.AST_SymbolRef(node.argname)),
|
||||
start: {},
|
||||
}));
|
||||
return node;
|
||||
}
|
||||
}));
|
||||
var code = testcase_ast.print_to_string();
|
||||
var diff = test_for_diff(code, minify_options, result_cache, max_timeout);
|
||||
if (diff && !diff.timed_out && !diff.error) {
|
||||
testcase = code;
|
||||
differs = diff;
|
||||
} else {
|
||||
testcase_ast = U.parse(testcase);
|
||||
}
|
||||
}
|
||||
diff_error_message = null;
|
||||
testcase_ast.walk(new U.TreeWalker(function(node) {
|
||||
// unshare start props to retain visit data between iterations
|
||||
node.start = JSON.parse(JSON.stringify(node.start));
|
||||
node.start._permute = 0;
|
||||
}));
|
||||
for (var c = 0; c < max_iterations; ++c) {
|
||||
if (verbose) {
|
||||
if (pass == 1 && c % 25 == 0) {
|
||||
console.error("// reduce test pass "
|
||||
+ pass + ", iteration " + c + ": " + testcase.length + " bytes");
|
||||
}
|
||||
if (verbose && pass == 1 && c % 25 == 0) {
|
||||
log("// reduce test pass " + pass + ", iteration " + c + ": " + testcase.length + " bytes");
|
||||
}
|
||||
var CHANGED = false;
|
||||
var code_ast = testcase_ast.clone(true).transform(tt);
|
||||
@@ -436,12 +464,12 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
} catch (ex) {
|
||||
// AST is not well formed.
|
||||
// no harm done - just log the error, ignore latest change and continue iterating.
|
||||
console.error("*** Error generating code from AST.");
|
||||
console.error(ex);
|
||||
console.error("*** Discarding permutation and continuing.");
|
||||
log("*** Error generating code from AST.");
|
||||
log(ex.stack);
|
||||
log("*** Discarding permutation and continuing.");
|
||||
continue;
|
||||
}
|
||||
var diff = producesDifferentResultWhenMinified(result_cache, code, minify_options, max_timeout);
|
||||
var diff = test_for_diff(code, minify_options, result_cache, max_timeout);
|
||||
if (diff) {
|
||||
if (diff.timed_out) {
|
||||
// can't trust the validity of `code_ast` and `code` when timed out.
|
||||
@@ -449,14 +477,15 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
} else if (diff.error) {
|
||||
// something went wrong during minify() - could be malformed AST or genuine bug.
|
||||
// no harm done - just log code & error, ignore latest change and continue iterating.
|
||||
console.error("*** Error during minification.");
|
||||
console.error(code);
|
||||
console.error(diff.error);
|
||||
console.error("*** Discarding permutation and continuing.");
|
||||
log("*** Error during minification.");
|
||||
log(code);
|
||||
log(diff.error.stack);
|
||||
log("*** Discarding permutation and continuing.");
|
||||
} else if (is_error(diff.unminified_result)
|
||||
&& is_error(diff.minified_result)
|
||||
&& diff.unminified_result.name == diff.minified_result.name) {
|
||||
// ignore difference in error messages caused by minification
|
||||
diff_error_message = testcase;
|
||||
} else {
|
||||
// latest permutation is valid, so use it as the basis of new changes
|
||||
testcase_ast = code_ast;
|
||||
@@ -467,27 +496,32 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
if (c == 0) break;
|
||||
if (verbose) {
|
||||
console.error("// reduce test pass " + pass + ": " + testcase.length + " bytes");
|
||||
log("// reduce test pass " + pass + ": " + testcase.length + " bytes");
|
||||
}
|
||||
}
|
||||
testcase = try_beautify(result_cache, testcase, minify_options, differs.unminified_result, max_timeout);
|
||||
testcase = try_beautify(testcase, minify_options, differs.unminified_result, result_cache, max_timeout);
|
||||
var lines = [ "" ];
|
||||
var unminified_result = strip_color_codes(differs.unminified_result);
|
||||
var minified_result = strip_color_codes(differs.minified_result);
|
||||
if (trim_trailing_whitespace(unminified_result) == trim_trailing_whitespace(minified_result)) {
|
||||
lines.push(
|
||||
"// (stringified)",
|
||||
"// output: " + JSON.stringify(unminified_result),
|
||||
"// minify: " + JSON.stringify(minified_result)
|
||||
);
|
||||
if (isNaN(max_timeout)) {
|
||||
lines.push("// minify error: " + to_comment(strip_color_codes(differs.minified_result.stack)));
|
||||
} else {
|
||||
lines.push(
|
||||
"// output: " + to_comment(unminified_result),
|
||||
"// minify: " + to_comment(minified_result)
|
||||
);
|
||||
var unminified_result = strip_color_codes(differs.unminified_result);
|
||||
var minified_result = strip_color_codes(differs.minified_result);
|
||||
if (trim_trailing_whitespace(unminified_result) == trim_trailing_whitespace(minified_result)) {
|
||||
lines.push(
|
||||
"// (stringified)",
|
||||
"// output: " + JSON.stringify(unminified_result),
|
||||
"// minify: " + JSON.stringify(minified_result)
|
||||
);
|
||||
} else {
|
||||
lines.push(
|
||||
"// output: " + to_comment(unminified_result),
|
||||
"// minify: " + to_comment(minified_result)
|
||||
);
|
||||
}
|
||||
}
|
||||
lines.push("// options: " + to_comment(minify_options_json));
|
||||
testcase.code += lines.join("\n");
|
||||
testcase.warnings = warnings;
|
||||
return testcase;
|
||||
}
|
||||
};
|
||||
@@ -504,7 +538,7 @@ function trim_trailing_whitespace(value) {
|
||||
return ("" + value).replace(/\s+$/, "");
|
||||
}
|
||||
|
||||
function try_beautify(result_cache, testcase, minify_options, expected, timeout) {
|
||||
function try_beautify(testcase, minify_options, expected, result_cache, timeout) {
|
||||
var result = U.minify(testcase, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
@@ -518,10 +552,16 @@ function try_beautify(result_cache, testcase, minify_options, expected, timeout)
|
||||
code: testcase,
|
||||
};
|
||||
var toplevel = sandbox.has_toplevel(minify_options);
|
||||
var actual = run_code(result_cache, result.code, toplevel, timeout);
|
||||
if (!sandbox.same_stdout(expected, actual)) return {
|
||||
code: testcase,
|
||||
};
|
||||
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;
|
||||
}
|
||||
@@ -592,21 +632,37 @@ function to_statement(node) {
|
||||
});
|
||||
}
|
||||
|
||||
function run_code(result_cache, code, toplevel, timeout) {
|
||||
function wrap_with_console_log(node) {
|
||||
// wrap with console.log()
|
||||
return new U.AST_Call({
|
||||
expression: new U.AST_Dot({
|
||||
expression: new U.AST_SymbolRef({
|
||||
name: "console",
|
||||
start: {},
|
||||
}),
|
||||
property: "log",
|
||||
start: {},
|
||||
}),
|
||||
args: [ node ],
|
||||
start: {},
|
||||
});
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
function producesDifferentResultWhenMinified(result_cache, code, minify_options, max_timeout) {
|
||||
function compare_run_code(code, minify_options, result_cache, max_timeout) {
|
||||
var minified = U.minify(code, minify_options);
|
||||
if (minified.error) return minified;
|
||||
|
||||
var toplevel = sandbox.has_toplevel(minify_options);
|
||||
var elapsed = Date.now();
|
||||
var unminified_result = run_code(result_cache, code, toplevel, max_timeout);
|
||||
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(result_cache, minified.code, toplevel, timeout);
|
||||
var minified_result = run_code(minified.code, toplevel, result_cache, timeout);
|
||||
|
||||
if (sandbox.same_stdout(unminified_result, minified_result)) {
|
||||
return is_timed_out(unminified_result) && is_timed_out(minified_result) && {
|
||||
@@ -619,4 +675,10 @@ function producesDifferentResultWhenMinified(result_cache, code, minify_options,
|
||||
elapsed: elapsed,
|
||||
};
|
||||
}
|
||||
Error.stackTraceLimit = Infinity;
|
||||
|
||||
function test_minify(code, minify_options) {
|
||||
var minified = U.minify(code, minify_options);
|
||||
return minified.error && {
|
||||
minified_result: minified.error,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
setInterval(function() {
|
||||
process.stderr.write("\0");
|
||||
}, 8 * 60 * 1000).unref();
|
||||
require("./run")([
|
||||
"-b",
|
||||
"-b braces",
|
||||
@@ -12,6 +9,6 @@ require("./run")([
|
||||
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto",
|
||||
].map(function(options) {
|
||||
var args = options.split(/ /);
|
||||
args.unshift("test/benchmark.js");
|
||||
args.unshift("test/benchmark.js", "--validate");
|
||||
return args;
|
||||
}));
|
||||
|
||||
@@ -40,7 +40,7 @@ function createContext() {
|
||||
arg.constructor.toString();
|
||||
if (level--) for (var key in arg) {
|
||||
var desc = Object.getOwnPropertyDescriptor(arg, key);
|
||||
if (!desc || !desc.get) arg[key] = safe_log(arg[key], level);
|
||||
if (!desc || !desc.get && !desc.set) arg[key] = safe_log(arg[key], level);
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
|
||||
49
test/ufuzz/actions.js
Normal file
49
test/ufuzz/actions.js
Normal file
@@ -0,0 +1,49 @@
|
||||
require("../../tools/exit");
|
||||
|
||||
var get = require("https").get;
|
||||
var parse = require("url").parse;
|
||||
var base = process.argv[2];
|
||||
var token = process.argv[3];
|
||||
|
||||
function read(url, callback) {
|
||||
var options = parse(url);
|
||||
options.headers = {
|
||||
"Authorization": "Token " + token,
|
||||
"User-Agent": "UglifyJS",
|
||||
};
|
||||
get(options, function(response) {
|
||||
var chunks = [];
|
||||
response.setEncoding("utf8");
|
||||
response.on("data", function(chunk) {
|
||||
chunks.push(chunk);
|
||||
}).on("end", function() {
|
||||
callback(JSON.parse(chunks.join("")));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -168,7 +168,7 @@ var VALUES = [
|
||||
"this",
|
||||
];
|
||||
|
||||
var BINARY_OPS_NO_COMMA = [
|
||||
var BINARY_OPS = [
|
||||
" + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
|
||||
" - ",
|
||||
"/",
|
||||
@@ -190,9 +190,15 @@ var BINARY_OPS_NO_COMMA = [
|
||||
"%",
|
||||
"&&",
|
||||
"||",
|
||||
"^" ];
|
||||
|
||||
var BINARY_OPS = [","].concat(BINARY_OPS_NO_COMMA);
|
||||
"^",
|
||||
",",
|
||||
];
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS.push(" in ");
|
||||
|
||||
var ASSIGNMENTS = [
|
||||
"=",
|
||||
@@ -490,11 +496,16 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
||||
var label = createLabel(canBreak, canContinue);
|
||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||
var optElementVar = "";
|
||||
if (rng(5) > 1) {
|
||||
optElementVar = "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[key" + loop + "]; ";
|
||||
}
|
||||
return "{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; " + label.target + " for (var key" + loop + " in expr" + loop + ") {" + optElementVar + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}}";
|
||||
var key = rng(10) ? "key" + loop : getVarName();
|
||||
return [
|
||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||
label.target + " for (",
|
||||
/^key/.test(key) ? "var " : "",
|
||||
key + " in expr" + loop + ") {",
|
||||
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||
"}}",
|
||||
].join("");
|
||||
case STMT_SEMI:
|
||||
return use_strict && rng(20) === 0 ? '"use strict";' : ";";
|
||||
case STMT_EXPR:
|
||||
@@ -763,11 +774,23 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
case p++:
|
||||
return createObjectLiteral(recurmax, stmtDepth, canThrow) + "." + getDotKey();
|
||||
case p++:
|
||||
var name = getVarName();
|
||||
return name + " && " + name + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]";
|
||||
return createValue() + " in " + createArrayLiteral(recurmax, stmtDepth, canThrow);
|
||||
case p++:
|
||||
return createValue() + " in " + createObjectLiteral(recurmax, stmtDepth, canThrow);
|
||||
case p++:
|
||||
var name = getVarName();
|
||||
return name + " && " + name + "." + getDotKey();
|
||||
var s = name + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]";
|
||||
return canThrow && rng(8) == 0 ? s : name + " && " + s;
|
||||
case p++:
|
||||
var name = getVarName();
|
||||
var s = name + "." + getDotKey();
|
||||
return canThrow && rng(8) == 0 ? s : name + " && " + s;
|
||||
case p++:
|
||||
case p++:
|
||||
var name = getVarName();
|
||||
var s = name + "." + getDotKey();
|
||||
s = "typeof " + s + ' == "function" && --_calls_ >= 0 && ' + s + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
return canThrow && rng(8) == 0 ? s : name + " && " + s;
|
||||
case p++:
|
||||
case p++:
|
||||
case p++:
|
||||
@@ -871,7 +894,7 @@ function createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||
}
|
||||
function _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||
return "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow)
|
||||
+ createBinaryOp(noComma) + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||
+ createBinaryOp(noComma, canThrow) + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||
}
|
||||
function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||
// intentionally generate more hardcore ops
|
||||
@@ -921,9 +944,12 @@ function createValue() {
|
||||
return VALUES[rng(VALUES.length)];
|
||||
}
|
||||
|
||||
function createBinaryOp(noComma) {
|
||||
if (noComma) return BINARY_OPS_NO_COMMA[rng(BINARY_OPS_NO_COMMA.length)];
|
||||
return BINARY_OPS[rng(BINARY_OPS.length)];
|
||||
function createBinaryOp(noComma, canThrow) {
|
||||
var op;
|
||||
do {
|
||||
op = BINARY_OPS[rng(BINARY_OPS.length)];
|
||||
} while (noComma && op == "," || !canThrow && op == " in ");
|
||||
return op;
|
||||
}
|
||||
|
||||
function createAssignment() {
|
||||
@@ -1010,20 +1036,24 @@ function log_suspects(minify_options, component) {
|
||||
if (!options) return;
|
||||
if (typeof options != "object") options = {};
|
||||
var defs = default_options[component];
|
||||
var toplevel = sandbox.has_toplevel(minify_options);
|
||||
var suspects = Object.keys(defs).filter(function(name) {
|
||||
var flip = name == "keep_fargs";
|
||||
if (flip === !(name in options ? options : defs)[name]) {
|
||||
if (flip !== (name in options ? options : defs)[name]) {
|
||||
var m = JSON.parse(JSON.stringify(minify_options));
|
||||
var o = JSON.parse(JSON.stringify(options));
|
||||
o[name] = flip;
|
||||
m[component] = o;
|
||||
m.validate = true;
|
||||
var result = UglifyJS.minify(original_code, m);
|
||||
if (result.error) {
|
||||
if (typeof uglify_code != "string") {
|
||||
return !sandbox.same_stdout(uglify_code, result.error);
|
||||
} else if (result.error) {
|
||||
errorln("Error testing options." + component + "." + name);
|
||||
errorln(result.error);
|
||||
} else {
|
||||
var r = sandbox.run_code(result.code, sandbox.has_toplevel(m));
|
||||
return sandbox.same_stdout(original_result, r);
|
||||
var r = sandbox.run_code(result.code, toplevel);
|
||||
return !sandbox.same_stdout(uglify_result, r);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1036,21 +1066,22 @@ function log_suspects(minify_options, component) {
|
||||
}
|
||||
}
|
||||
|
||||
function log_suspects_global(options) {
|
||||
var o = {};
|
||||
UglifyJS.minify("", o);
|
||||
var suspects = Object.keys(o).filter(function(component) {
|
||||
return typeof o[component] != "object";
|
||||
function log_suspects_global(options, toplevel) {
|
||||
var suspects = Object.keys(default_options).filter(function(component) {
|
||||
return typeof default_options[component] != "object";
|
||||
}).filter(function(component) {
|
||||
var m = JSON.parse(options);
|
||||
m[component] = false;
|
||||
m.validate = true;
|
||||
var result = UglifyJS.minify(original_code, m);
|
||||
if (result.error) {
|
||||
if (typeof uglify_code != "string") {
|
||||
return !sandbox.same_stdout(uglify_code, result.error);
|
||||
} else if (result.error) {
|
||||
errorln("Error testing options." + component);
|
||||
errorln(result.error);
|
||||
} else {
|
||||
var r = sandbox.run_code(result.code, sandbox.has_toplevel(m));
|
||||
return sandbox.same_stdout(original_result, r);
|
||||
var r = sandbox.run_code(result.code, toplevel);
|
||||
return !sandbox.same_stdout(uglify_result, r);
|
||||
}
|
||||
});
|
||||
if (suspects.length > 0) {
|
||||
@@ -1068,7 +1099,37 @@ function log(options) {
|
||||
errorln("//=============================================================");
|
||||
if (!ok) errorln("// !!!!!! Failed... round " + round);
|
||||
errorln("// original code");
|
||||
try_beautify(original_code, toplevel, original_result, errorln);
|
||||
var beautified = UglifyJS.minify(original_code, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
output: {
|
||||
beautify: true,
|
||||
braces: true,
|
||||
},
|
||||
});
|
||||
if (beautified.error) {
|
||||
errorln("// !!! beautify failed !!!");
|
||||
errorln(beautified.error);
|
||||
errorln("//");
|
||||
errorln(original_code);
|
||||
} else {
|
||||
var uglified = UglifyJS.minify(beautified.code, JSON.parse(options));
|
||||
var expected, actual;
|
||||
if (typeof uglify_code != "string" || uglified.error) {
|
||||
expected = uglify_code;
|
||||
actual = uglified.error;
|
||||
} else {
|
||||
expected = uglify_result;
|
||||
actual = sandbox.run_code(uglified.code, toplevel);
|
||||
}
|
||||
if (sandbox.same_stdout(expected, actual)) {
|
||||
errorln("// (beautified)");
|
||||
errorln(beautified.code);
|
||||
} else {
|
||||
errorln("//");
|
||||
errorln(original_code);
|
||||
}
|
||||
}
|
||||
errorln();
|
||||
errorln();
|
||||
errorln("//-------------------------------------------------------------");
|
||||
@@ -1081,18 +1142,6 @@ function log(options) {
|
||||
errorln(original_result);
|
||||
errorln("uglified result:");
|
||||
errorln(uglify_result);
|
||||
errorln("//-------------------------------------------------------------");
|
||||
var reduced = reduce_test(original_code, JSON.parse(options), {
|
||||
verbose: false,
|
||||
}).code;
|
||||
if (reduced) {
|
||||
errorln();
|
||||
errorln("// reduced test case (output will differ)");
|
||||
errorln();
|
||||
errorln(reduced);
|
||||
errorln();
|
||||
errorln("//-------------------------------------------------------------");
|
||||
}
|
||||
} else {
|
||||
errorln("// !!! uglify failed !!!");
|
||||
errorln(uglify_code);
|
||||
@@ -1103,16 +1152,38 @@ function log(options) {
|
||||
errorln(original_result);
|
||||
}
|
||||
}
|
||||
errorln("//-------------------------------------------------------------");
|
||||
var reduce_options = JSON.parse(options);
|
||||
reduce_options.validate = true;
|
||||
var reduced = reduce_test(original_code, reduce_options, {
|
||||
verbose: false,
|
||||
}).code;
|
||||
if (reduced) {
|
||||
errorln();
|
||||
errorln("// reduced test case (output will differ)");
|
||||
errorln();
|
||||
errorln(reduced);
|
||||
errorln();
|
||||
errorln("//-------------------------------------------------------------");
|
||||
}
|
||||
errorln("minify(options):");
|
||||
errorln(JSON.stringify(JSON.parse(options), null, 2));
|
||||
errorln();
|
||||
if (!ok && typeof uglify_code == "string") {
|
||||
Object.keys(default_options).forEach(log_suspects.bind(null, JSON.parse(options)));
|
||||
log_suspects_global(options);
|
||||
if (!ok) {
|
||||
Object.keys(default_options).filter(function(component) {
|
||||
var defs = default_options[component];
|
||||
return defs && typeof defs == "object";
|
||||
}).forEach(log_suspects.bind(null, JSON.parse(options)));
|
||||
log_suspects_global(options, toplevel);
|
||||
errorln("!!!!!! Failed... round " + round);
|
||||
}
|
||||
}
|
||||
|
||||
function sort_globals(code) {
|
||||
var globals = sandbox.run_code("throw Object.keys(this).sort();" + code);
|
||||
return globals.length ? "var " + globals.join(",") + ";" + code : code;
|
||||
}
|
||||
|
||||
function fuzzy_match(original, uglified) {
|
||||
uglified = uglified.split(" ");
|
||||
var i = uglified.length;
|
||||
@@ -1127,6 +1198,66 @@ function fuzzy_match(original, uglified) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function patch_try_catch(orig, toplevel) {
|
||||
var stack = [ {
|
||||
code: orig,
|
||||
index: 0,
|
||||
offset: 0,
|
||||
tries: [],
|
||||
} ];
|
||||
var re = /(?:(?:^|[\s{}):;])try|}\s*catch\s*\(([^)]+)\)|}\s*finally)\s*(?={)/g;
|
||||
while (stack.length) {
|
||||
var code = stack[0].code;
|
||||
var offset = stack[0].offset;
|
||||
var tries = stack[0].tries;
|
||||
var match;
|
||||
re.lastIndex = stack.shift().index;
|
||||
while (match = re.exec(code)) {
|
||||
var index = match.index + match[0].length + 1;
|
||||
if (/(?:^|[\s{}):;])try\s*$/.test(match[0])) {
|
||||
tries.unshift({ try: index - offset });
|
||||
continue;
|
||||
}
|
||||
var insert;
|
||||
if (/}\s*finally\s*$/.test(match[0])) {
|
||||
tries.shift();
|
||||
insert = 'if (typeof UFUZZ_ERROR == "object") throw UFUZZ_ERROR;';
|
||||
} else {
|
||||
while (tries.length && tries[0].catch) tries.shift();
|
||||
tries[0].catch = index - offset;
|
||||
insert = [
|
||||
"if (!" + match[1] + ".ufuzz_var) {",
|
||||
match[1] + '.ufuzz_var = "' + match[1] + '";',
|
||||
match[1] + ".ufuzz_try = " + tries[0].try + ";",
|
||||
match[1] + ".ufuzz_catch = " + tries[0].catch + ";",
|
||||
"UFUZZ_ERROR = " + match[1] + ";",
|
||||
"}",
|
||||
"throw " + match[1] + ";",
|
||||
].join("\n");
|
||||
}
|
||||
var new_code = code.slice(0, index) + insert + code.slice(index);
|
||||
var result = sandbox.run_code(new_code, toplevel);
|
||||
if (typeof result != "object" || typeof result.name != "string" || typeof result.message != "string") {
|
||||
if (!stack.filled && match[1]) stack.push({
|
||||
code: code,
|
||||
index: index && index - 1,
|
||||
offset: offset,
|
||||
tries: JSON.parse(JSON.stringify(tries)),
|
||||
});
|
||||
offset += insert.length;
|
||||
code = new_code;
|
||||
} else if (result.name == "TypeError" && /'in'/.test(result.message)) {
|
||||
index = result.ufuzz_catch;
|
||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("invalid `in`");' + orig.slice(index);
|
||||
} else if (result.name == "RangeError" && result.message == "Maximum call stack size exceeded") {
|
||||
index = result.ufuzz_try;
|
||||
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
|
||||
}
|
||||
}
|
||||
stack.filled = true;
|
||||
}
|
||||
}
|
||||
|
||||
var fallback_options = [ JSON.stringify({
|
||||
compress: false,
|
||||
mangle: false
|
||||
@@ -1144,24 +1275,37 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
(errored ? fallback_options : minify_options).forEach(function(options) {
|
||||
var o = JSON.parse(options);
|
||||
var toplevel = sandbox.has_toplevel(o);
|
||||
o.validate = true;
|
||||
uglify_code = UglifyJS.minify(original_code, o);
|
||||
original_result = orig_result[toplevel ? 1 : 0];
|
||||
if (!uglify_code.error) {
|
||||
uglify_code = uglify_code.code;
|
||||
uglify_result = sandbox.run_code(uglify_code, toplevel);
|
||||
ok = sandbox.same_stdout(original_result, uglify_result);
|
||||
if (!ok && typeof uglify_result == "string" && o.compress.unsafe_math) {
|
||||
// ignore declaration order of global variables
|
||||
if (!ok && !toplevel) {
|
||||
ok = sandbox.same_stdout(sandbox.run_code(sort_globals(original_code)), sandbox.run_code(sort_globals(uglify_code)));
|
||||
}
|
||||
// ignore numerical imprecision caused by `unsafe_math`
|
||||
if (!ok && typeof uglify_result == "string" && o.compress && o.compress.unsafe_math) {
|
||||
ok = fuzzy_match(original_result, uglify_result);
|
||||
if (!ok) {
|
||||
var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"), toplevel);
|
||||
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
||||
}
|
||||
}
|
||||
// ignore difference in error message caused by `in`
|
||||
// ignore difference in depth of termination caused by infinite recursion
|
||||
if (!ok) {
|
||||
var orig_skipped = patch_try_catch(original_code, toplevel);
|
||||
var uglify_skipped = patch_try_catch(uglify_code, toplevel);
|
||||
if (orig_skipped && uglify_skipped) {
|
||||
ok = sandbox.same_stdout(sandbox.run_code(orig_skipped, toplevel), sandbox.run_code(uglify_skipped, toplevel));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uglify_code = uglify_code.error;
|
||||
if (errored) {
|
||||
ok = uglify_code.name == original_result.name;
|
||||
}
|
||||
ok = errored && uglify_code.name == original_result.name;
|
||||
}
|
||||
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
||||
else if (errored) {
|
||||
|
||||
456
tools/domprops.html
Normal file
456
tools/domprops.html
Normal file
@@ -0,0 +1,456 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
!function(G) {
|
||||
var domprops = [];
|
||||
var objs = [ G ];
|
||||
var tagNames = [
|
||||
"a",
|
||||
"abbr",
|
||||
"acronym",
|
||||
"address",
|
||||
"applet",
|
||||
"area",
|
||||
"article",
|
||||
"aside",
|
||||
"audio",
|
||||
"b",
|
||||
"base",
|
||||
"basefont",
|
||||
"bdi",
|
||||
"bdo",
|
||||
"bgsound",
|
||||
"big",
|
||||
"blink",
|
||||
"blockquote",
|
||||
"body",
|
||||
"br",
|
||||
"button",
|
||||
"canvas",
|
||||
"caption",
|
||||
"center",
|
||||
"checked",
|
||||
"cite",
|
||||
"code",
|
||||
"col",
|
||||
"colgroup",
|
||||
"command",
|
||||
"comment",
|
||||
"compact",
|
||||
"content",
|
||||
"data",
|
||||
"datalist",
|
||||
"dd",
|
||||
"declare",
|
||||
"defer",
|
||||
"del",
|
||||
"details",
|
||||
"dfn",
|
||||
"dialog",
|
||||
"dir",
|
||||
"disabled",
|
||||
"div",
|
||||
"dl",
|
||||
"dt",
|
||||
"element",
|
||||
"em",
|
||||
"embed",
|
||||
"fieldset",
|
||||
"figcaption",
|
||||
"figure",
|
||||
"font",
|
||||
"footer",
|
||||
"form",
|
||||
"frame",
|
||||
"frameset",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"head",
|
||||
"header",
|
||||
"hgroup",
|
||||
"hr",
|
||||
"html",
|
||||
"i",
|
||||
"iframe",
|
||||
"image",
|
||||
"img",
|
||||
"input",
|
||||
"ins",
|
||||
"isindex",
|
||||
"ismap",
|
||||
"kbd",
|
||||
"keygen",
|
||||
"label",
|
||||
"legend",
|
||||
"li",
|
||||
"link",
|
||||
"listing",
|
||||
"main",
|
||||
"map",
|
||||
"mark",
|
||||
"marquee",
|
||||
"math",
|
||||
"menu",
|
||||
"menuitem",
|
||||
"meta",
|
||||
"meter",
|
||||
"multicol",
|
||||
"multiple",
|
||||
"nav",
|
||||
"nextid",
|
||||
"nobr",
|
||||
"noembed",
|
||||
"noframes",
|
||||
"nohref",
|
||||
"noresize",
|
||||
"noscript",
|
||||
"noshade",
|
||||
"nowrap",
|
||||
"object",
|
||||
"ol",
|
||||
"optgroup",
|
||||
"option",
|
||||
"output",
|
||||
"p",
|
||||
"param",
|
||||
"picture",
|
||||
"plaintext",
|
||||
"pre",
|
||||
"progress",
|
||||
"q",
|
||||
"rb",
|
||||
"readonly",
|
||||
"rp",
|
||||
"rt",
|
||||
"rtc",
|
||||
"ruby",
|
||||
"s",
|
||||
"samp",
|
||||
"script",
|
||||
"section",
|
||||
"select",
|
||||
"selected",
|
||||
"shadow",
|
||||
"slot",
|
||||
"small",
|
||||
"source",
|
||||
"spacer",
|
||||
"span",
|
||||
"strike",
|
||||
"strong",
|
||||
"style",
|
||||
"sub",
|
||||
"summary",
|
||||
"sup",
|
||||
"svg",
|
||||
"table",
|
||||
"tbody",
|
||||
"td",
|
||||
"template",
|
||||
"textarea",
|
||||
"tfoot",
|
||||
"th",
|
||||
"thead",
|
||||
"time",
|
||||
"title",
|
||||
"tr",
|
||||
"track",
|
||||
"tt",
|
||||
"u",
|
||||
"ul",
|
||||
"var",
|
||||
"video",
|
||||
"wbr",
|
||||
"xmp",
|
||||
"XXX",
|
||||
];
|
||||
for (var n = 0; n < tagNames.length; n++) {
|
||||
add(document.createElement(tagNames[n]));
|
||||
}
|
||||
var nsNames = {
|
||||
"http://www.w3.org/1998/Math/MathML": [
|
||||
"annotation",
|
||||
"annotation-xml",
|
||||
"maction",
|
||||
"maligngroup",
|
||||
"malignmark",
|
||||
"math",
|
||||
"menclose",
|
||||
"merror",
|
||||
"mfenced",
|
||||
"mfrac",
|
||||
"mglyph",
|
||||
"mi",
|
||||
"mlabeledtr",
|
||||
"mlongdiv",
|
||||
"mmultiscripts",
|
||||
"mn",
|
||||
"mo",
|
||||
"mover",
|
||||
"mpadded",
|
||||
"mphantom",
|
||||
"mprescripts",
|
||||
"mroot",
|
||||
"mrow",
|
||||
"ms",
|
||||
"mscarries",
|
||||
"mscarry",
|
||||
"msgroup",
|
||||
"msline",
|
||||
"mspace",
|
||||
"msqrt",
|
||||
"msrow",
|
||||
"mstack",
|
||||
"mstyle",
|
||||
"msub",
|
||||
"msubsup",
|
||||
"msup",
|
||||
"mtable",
|
||||
"mtd",
|
||||
"mtext",
|
||||
"mtr",
|
||||
"munder",
|
||||
"munderover",
|
||||
"none",
|
||||
"semantics",
|
||||
],
|
||||
"http://www.w3.org/2000/svg": [
|
||||
"a",
|
||||
"altGlyph",
|
||||
"altGlyphDef",
|
||||
"altGlyphItem",
|
||||
"animate",
|
||||
"animateColor",
|
||||
"animateMotion",
|
||||
"animateTransform",
|
||||
"circle",
|
||||
"clipPath",
|
||||
"color-profile",
|
||||
"cursor",
|
||||
"defs",
|
||||
"desc",
|
||||
"discard",
|
||||
"ellipse",
|
||||
"feBlend",
|
||||
"feColorMatrix",
|
||||
"feComponentTransfer",
|
||||
"feComposite",
|
||||
"feConvolveMatrix",
|
||||
"feDiffuseLighting",
|
||||
"feDisplacementMap",
|
||||
"feDistantLight",
|
||||
"feDropShadow",
|
||||
"feFlood",
|
||||
"feFuncA",
|
||||
"feFuncB",
|
||||
"feFuncG",
|
||||
"feFuncR",
|
||||
"feGaussianBlur",
|
||||
"feImage",
|
||||
"feMerge",
|
||||
"feMergeNode",
|
||||
"feMorphology",
|
||||
"feOffset",
|
||||
"fePointLight",
|
||||
"feSpecularLighting",
|
||||
"feSpotLight",
|
||||
"feTile",
|
||||
"feTurbulence",
|
||||
"filter",
|
||||
"font",
|
||||
"font-face",
|
||||
"font-face-format",
|
||||
"font-face-name",
|
||||
"font-face-src",
|
||||
"font-face-uri",
|
||||
"foreignObject",
|
||||
"g",
|
||||
"glyph",
|
||||
"glyphRef",
|
||||
"hatch",
|
||||
"hatchpath",
|
||||
"hkern",
|
||||
"image",
|
||||
"line",
|
||||
"linearGradient",
|
||||
"marker",
|
||||
"mask",
|
||||
"mesh",
|
||||
"meshgradient",
|
||||
"meshpatch",
|
||||
"meshrow",
|
||||
"metadata",
|
||||
"missing-glyph",
|
||||
"mpath",
|
||||
"path",
|
||||
"pattern",
|
||||
"polygon",
|
||||
"polyline",
|
||||
"radialGradient",
|
||||
"rect",
|
||||
"script",
|
||||
"set",
|
||||
"solidcolor",
|
||||
"stop",
|
||||
"style",
|
||||
"svg",
|
||||
"switch",
|
||||
"symbol",
|
||||
"text",
|
||||
"textPath",
|
||||
"title",
|
||||
"tref",
|
||||
"tspan",
|
||||
"unknown",
|
||||
"use",
|
||||
"view",
|
||||
"vkern",
|
||||
],
|
||||
};
|
||||
if (document.createElementNS) for (var ns in nsNames) {
|
||||
for (var n = 0; n < nsNames[ns].length; n++) {
|
||||
add(document.createElementNS(ns, nsNames[ns][n]));
|
||||
}
|
||||
}
|
||||
var skips = [
|
||||
G.alert,
|
||||
G.back,
|
||||
G.blur,
|
||||
G.captureEvents,
|
||||
G.clearImmediate,
|
||||
G.clearInterval,
|
||||
G.clearTimeout,
|
||||
G.close,
|
||||
G.confirm,
|
||||
G.console,
|
||||
G.dump,
|
||||
G.fetch,
|
||||
G.find,
|
||||
G.focus,
|
||||
G.forward,
|
||||
G.getAttention,
|
||||
G.history,
|
||||
G.home,
|
||||
G.location,
|
||||
G.moveBy,
|
||||
G.moveTo,
|
||||
G.navigator,
|
||||
G.open,
|
||||
G.openDialog,
|
||||
G.print,
|
||||
G.process,
|
||||
G.prompt,
|
||||
G.resizeBy,
|
||||
G.resizeTo,
|
||||
G.setImmediate,
|
||||
G.setInterval,
|
||||
G.setTimeout,
|
||||
G.showModalDialog,
|
||||
G.sizeToContent,
|
||||
G.stop,
|
||||
];
|
||||
var types = [];
|
||||
var interfaces = [
|
||||
"beforeunloadevent",
|
||||
"compositionevent",
|
||||
"customevent",
|
||||
"devicemotionevent",
|
||||
"deviceorientationevent",
|
||||
"dragevent",
|
||||
"event",
|
||||
"events",
|
||||
"focusevent",
|
||||
"hashchangeevent",
|
||||
"htmlevents",
|
||||
"keyboardevent",
|
||||
"messageevent",
|
||||
"mouseevent",
|
||||
"mouseevents",
|
||||
"storageevent",
|
||||
"svgevents",
|
||||
"textevent",
|
||||
"touchevent",
|
||||
"uievent",
|
||||
"uievents",
|
||||
];
|
||||
var i = 0, full = false;
|
||||
var addEvent = document.createEvent ? function(type) {
|
||||
if (~indexOf(types, type)) return;
|
||||
types.push(type);
|
||||
for (var j = 0; j < interfaces.length; j++) try {
|
||||
var event = document.createEvent(interfaces[j]);
|
||||
event.initEvent(type, true, true);
|
||||
add(event);
|
||||
} catch (e) {}
|
||||
} : function() {};
|
||||
var scanProperties = Object.getOwnPropertyNames ? function(o, fn) {
|
||||
var names = Object.getOwnPropertyNames(o);
|
||||
names.forEach(fn);
|
||||
for (var k in o) if (!~indexOf(names, k)) fn(k);
|
||||
} : function(o, fn) {
|
||||
for (var k in o) fn(k);
|
||||
};
|
||||
setTimeout(function next() {
|
||||
for (var j = 10; --j >= 0 && i < objs.length; i++) {
|
||||
var o = objs[i];
|
||||
var skip = ~indexOf(skips, o);
|
||||
try {
|
||||
scanProperties(o, function(k) {
|
||||
if (!~indexOf(domprops, k)) domprops.push(k);
|
||||
if (/^on/.test(k)) addEvent(k.slice(2));
|
||||
if (!full) try {
|
||||
add(o[k]);
|
||||
} catch (e) {}
|
||||
});
|
||||
} catch (e) {}
|
||||
if (skip || full) continue;
|
||||
try {
|
||||
add(o.__proto__);
|
||||
} catch (e) {}
|
||||
try {
|
||||
add(o.prototype);
|
||||
} catch (e) {}
|
||||
try {
|
||||
add(new o());
|
||||
} catch (e) {}
|
||||
try {
|
||||
add(o());
|
||||
} catch (e) {}
|
||||
}
|
||||
if (!full && objs.length > 20000) {
|
||||
alert(objs.length);
|
||||
full = true;
|
||||
}
|
||||
if (i < objs.length) {
|
||||
setTimeout(next, 0);
|
||||
} else {
|
||||
document.write('<pre>[\n "' + domprops.sort().join('",\n "').replace(/&/g, "&").replace(/</g, "<") + '"\n]</pre>');
|
||||
}
|
||||
}, 0);
|
||||
|
||||
function add(o) {
|
||||
if (o) switch (typeof o) {
|
||||
case "function":
|
||||
case "object":
|
||||
if (!~indexOf(objs, o)) objs.push(o);
|
||||
}
|
||||
}
|
||||
|
||||
function indexOf(list, value) {
|
||||
var j = list.length;
|
||||
while (--j >= 0) {
|
||||
if (list[j] === value) break;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
}(function() {
|
||||
return this;
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1475
tools/domprops.json
1475
tools/domprops.json
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ process.exit = function() {
|
||||
process.once("uncaughtException", function() {
|
||||
(function callback() {
|
||||
if (process.stdout.bufferSize || process.stderr.bufferSize) {
|
||||
setImmediate(callback);
|
||||
setTimeout(callback, 1);
|
||||
} else {
|
||||
exit.apply(process, args);
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@ exports.FILES = [
|
||||
require.resolve("./exports.js"),
|
||||
];
|
||||
|
||||
new Function("MOZ_SourceMap", "exports", function() {
|
||||
new Function("exports", function() {
|
||||
var code = exports.FILES.map(function(file) {
|
||||
return fs.readFileSync(file, "utf8");
|
||||
});
|
||||
code.push("exports.describe_ast = " + describe_ast.toString());
|
||||
return code.join("\n\n");
|
||||
}())(require("source-map"), exports);
|
||||
}())(exports);
|
||||
|
||||
function describe_ast() {
|
||||
var out = OutputStream({ beautify: true });
|
||||
@@ -66,8 +66,8 @@ function infer_options(options) {
|
||||
}
|
||||
|
||||
exports.default_options = function() {
|
||||
var defs = {};
|
||||
Object.keys(infer_options({ 0: 0 })).forEach(function(component) {
|
||||
var defs = infer_options({ 0: 0 });
|
||||
Object.keys(defs).forEach(function(component) {
|
||||
var options = {};
|
||||
options[component] = { 0: 0 };
|
||||
if (options = infer_options(options)) {
|
||||
|
||||
540
tools/props.html
540
tools/props.html
@@ -1,540 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
!function() {
|
||||
var names = [];
|
||||
var scanned = [];
|
||||
var to_scan = [];
|
||||
|
||||
function scan(obj) {
|
||||
if (obj && typeof obj == "object" && !~scanned.indexOf(obj)) {
|
||||
scanned.push(obj);
|
||||
to_scan.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
scan(self);
|
||||
[
|
||||
"a",
|
||||
"abbr",
|
||||
"acronym",
|
||||
"address",
|
||||
"applet",
|
||||
"area",
|
||||
"article",
|
||||
"aside",
|
||||
"audio",
|
||||
"b",
|
||||
"base",
|
||||
"basefont",
|
||||
"bdi",
|
||||
"bdo",
|
||||
"bgsound",
|
||||
"big",
|
||||
"blink",
|
||||
"blockquote",
|
||||
"body",
|
||||
"br",
|
||||
"button",
|
||||
"canvas",
|
||||
"caption",
|
||||
"center",
|
||||
"checked",
|
||||
"cite",
|
||||
"code",
|
||||
"col",
|
||||
"colgroup",
|
||||
"command",
|
||||
"comment",
|
||||
"compact",
|
||||
"content",
|
||||
"data",
|
||||
"datalist",
|
||||
"dd",
|
||||
"declare",
|
||||
"defer",
|
||||
"del",
|
||||
"details",
|
||||
"dfn",
|
||||
"dialog",
|
||||
"dir",
|
||||
"disabled",
|
||||
"div",
|
||||
"dl",
|
||||
"dt",
|
||||
"element",
|
||||
"em",
|
||||
"embed",
|
||||
"fieldset",
|
||||
"figcaption",
|
||||
"figure",
|
||||
"font",
|
||||
"footer",
|
||||
"form",
|
||||
"frame",
|
||||
"frameset",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"head",
|
||||
"header",
|
||||
"hgroup",
|
||||
"hr",
|
||||
"html",
|
||||
"i",
|
||||
"iframe",
|
||||
"image",
|
||||
"img",
|
||||
"input",
|
||||
"ins",
|
||||
"isindex",
|
||||
"ismap",
|
||||
"kbd",
|
||||
"keygen",
|
||||
"label",
|
||||
"legend",
|
||||
"li",
|
||||
"link",
|
||||
"listing",
|
||||
"main",
|
||||
"map",
|
||||
"mark",
|
||||
"marquee",
|
||||
"math",
|
||||
"menu",
|
||||
"menuitem",
|
||||
"meta",
|
||||
"meter",
|
||||
"multicol",
|
||||
"multiple",
|
||||
"nav",
|
||||
"nobr",
|
||||
"noembed",
|
||||
"noframes",
|
||||
"nohref",
|
||||
"noresize",
|
||||
"noscript",
|
||||
"noshade",
|
||||
"nowrap",
|
||||
"object",
|
||||
"ol",
|
||||
"optgroup",
|
||||
"option",
|
||||
"output",
|
||||
"p",
|
||||
"param",
|
||||
"picture",
|
||||
"plaintext",
|
||||
"pre",
|
||||
"progress",
|
||||
"q",
|
||||
"rb",
|
||||
"readonly",
|
||||
"rp",
|
||||
"rt",
|
||||
"rtc",
|
||||
"ruby",
|
||||
"s",
|
||||
"samp",
|
||||
"script",
|
||||
"section",
|
||||
"select",
|
||||
"selected",
|
||||
"shadow",
|
||||
"small",
|
||||
"source",
|
||||
"spacer",
|
||||
"span",
|
||||
"strike",
|
||||
"strong",
|
||||
"style",
|
||||
"sub",
|
||||
"summary",
|
||||
"sup",
|
||||
"svg",
|
||||
"table",
|
||||
"tbody",
|
||||
"td",
|
||||
"template",
|
||||
"textarea",
|
||||
"tfoot",
|
||||
"th",
|
||||
"thead",
|
||||
"time",
|
||||
"title",
|
||||
"tr",
|
||||
"track",
|
||||
"tt",
|
||||
"u",
|
||||
"ul",
|
||||
"var",
|
||||
"video",
|
||||
"wbr",
|
||||
"xmp",
|
||||
"XXX",
|
||||
].forEach(function(tag) {
|
||||
scan(document.createElement(tag));
|
||||
});
|
||||
[
|
||||
"abort",
|
||||
"absolutedeviceorientation",
|
||||
"activate",
|
||||
"active",
|
||||
"addsourcebuffer",
|
||||
"addstream",
|
||||
"addtrack",
|
||||
"afterprint",
|
||||
"afterscriptexecute",
|
||||
"afterupdate",
|
||||
"animationcancel",
|
||||
"animationend",
|
||||
"animationiteration",
|
||||
"animationstart",
|
||||
"appinstalled",
|
||||
"audioend",
|
||||
"audioprocess",
|
||||
"audiostart",
|
||||
"autocomplete",
|
||||
"autocompleteerror",
|
||||
"auxclick",
|
||||
"beforeactivate",
|
||||
"beforecopy",
|
||||
"beforecut",
|
||||
"beforedeactivate",
|
||||
"beforeeditfocus",
|
||||
"beforeinstallprompt",
|
||||
"beforepaste",
|
||||
"beforeprint",
|
||||
"beforescriptexecute",
|
||||
"beforeunload",
|
||||
"beforeupdate",
|
||||
"blocked",
|
||||
"blur",
|
||||
"bounce",
|
||||
"boundary",
|
||||
"cached",
|
||||
"cancel",
|
||||
"candidatewindowhide",
|
||||
"candidatewindowshow",
|
||||
"candidatewindowupdate",
|
||||
"canplay",
|
||||
"canplaythrough",
|
||||
"cellchange",
|
||||
"change",
|
||||
"chargingchange",
|
||||
"chargingtimechange",
|
||||
"checking",
|
||||
"click",
|
||||
"close",
|
||||
"compassneedscalibration",
|
||||
"complete",
|
||||
"connect",
|
||||
"connecting",
|
||||
"connectionstatechange",
|
||||
"contextmenu",
|
||||
"controllerchange",
|
||||
"controlselect",
|
||||
"copy",
|
||||
"cuechange",
|
||||
"cut",
|
||||
"dataavailable",
|
||||
"datachannel",
|
||||
"datasetchanged",
|
||||
"datasetcomplete",
|
||||
"dblclick",
|
||||
"deactivate",
|
||||
"devicechange",
|
||||
"devicelight",
|
||||
"devicemotion",
|
||||
"deviceorientation",
|
||||
"deviceorientationabsolute",
|
||||
"deviceproximity",
|
||||
"dischargingtimechange",
|
||||
"disconnect",
|
||||
"display",
|
||||
"downloading",
|
||||
"drag",
|
||||
"dragend",
|
||||
"dragenter",
|
||||
"dragexit",
|
||||
"dragleave",
|
||||
"dragover",
|
||||
"dragstart",
|
||||
"drop",
|
||||
"durationchange",
|
||||
"emptied",
|
||||
"encrypted",
|
||||
"end",
|
||||
"ended",
|
||||
"enter",
|
||||
"enterpictureinpicture",
|
||||
"error",
|
||||
"errorupdate",
|
||||
"exit",
|
||||
"filterchange",
|
||||
"finish",
|
||||
"focus",
|
||||
"focusin",
|
||||
"focusout",
|
||||
"freeze",
|
||||
"fullscreenchange",
|
||||
"fullscreenerror",
|
||||
"gesturechange",
|
||||
"gestureend",
|
||||
"gesturestart",
|
||||
"gotpointercapture",
|
||||
"hashchange",
|
||||
"help",
|
||||
"icecandidate",
|
||||
"iceconnectionstatechange",
|
||||
"icegatheringstatechange",
|
||||
"inactive",
|
||||
"input",
|
||||
"invalid",
|
||||
"keydown",
|
||||
"keypress",
|
||||
"keyup",
|
||||
"languagechange",
|
||||
"layoutcomplete",
|
||||
"leavepictureinpicture",
|
||||
"levelchange",
|
||||
"load",
|
||||
"loadeddata",
|
||||
"loadedmetadata",
|
||||
"loadend",
|
||||
"loading",
|
||||
"loadingdone",
|
||||
"loadingerror",
|
||||
"loadstart",
|
||||
"losecapture",
|
||||
"lostpointercapture",
|
||||
"mark",
|
||||
"message",
|
||||
"messageerror",
|
||||
"mousedown",
|
||||
"mouseenter",
|
||||
"mouseleave",
|
||||
"mousemove",
|
||||
"mouseout",
|
||||
"mouseover",
|
||||
"mouseup",
|
||||
"mousewheel",
|
||||
"move",
|
||||
"moveend",
|
||||
"movestart",
|
||||
"mozfullscreenchange",
|
||||
"mozfullscreenerror",
|
||||
"mozorientationchange",
|
||||
"mozpointerlockchange",
|
||||
"mozpointerlockerror",
|
||||
"mscontentzoom",
|
||||
"msfullscreenchange",
|
||||
"msfullscreenerror",
|
||||
"msgesturechange",
|
||||
"msgesturedoubletap",
|
||||
"msgestureend",
|
||||
"msgesturehold",
|
||||
"msgesturestart",
|
||||
"msgesturetap",
|
||||
"msgotpointercapture",
|
||||
"msinertiastart",
|
||||
"mslostpointercapture",
|
||||
"msmanipulationstatechanged",
|
||||
"msneedkey",
|
||||
"msorientationchange",
|
||||
"mspointercancel",
|
||||
"mspointerdown",
|
||||
"mspointerenter",
|
||||
"mspointerhover",
|
||||
"mspointerleave",
|
||||
"mspointermove",
|
||||
"mspointerout",
|
||||
"mspointerover",
|
||||
"mspointerup",
|
||||
"mssitemodejumplistitemremoved",
|
||||
"msthumbnailclick",
|
||||
"negotiationneeded",
|
||||
"nomatch",
|
||||
"noupdate",
|
||||
"obsolete",
|
||||
"offline",
|
||||
"online",
|
||||
"open",
|
||||
"orientationchange",
|
||||
"pagechange",
|
||||
"pagehide",
|
||||
"pageshow",
|
||||
"paste",
|
||||
"pause",
|
||||
"play",
|
||||
"playing",
|
||||
"pluginstreamstart",
|
||||
"pointercancel",
|
||||
"pointerdown",
|
||||
"pointerenter",
|
||||
"pointerleave",
|
||||
"pointerlockchange",
|
||||
"pointerlockerror",
|
||||
"pointermove",
|
||||
"pointerout",
|
||||
"pointerover",
|
||||
"pointerup",
|
||||
"popstate",
|
||||
"progress",
|
||||
"propertychange",
|
||||
"ratechange",
|
||||
"reading",
|
||||
"readystatechange",
|
||||
"rejectionhandled",
|
||||
"removesourcebuffer",
|
||||
"removestream",
|
||||
"removetrack",
|
||||
"reset",
|
||||
"resize",
|
||||
"resizeend",
|
||||
"resizestart",
|
||||
"resourcetimingbufferfull",
|
||||
"result",
|
||||
"resume",
|
||||
"rowenter",
|
||||
"rowexit",
|
||||
"rowsdelete",
|
||||
"rowsinserted",
|
||||
"scroll",
|
||||
"search",
|
||||
"seeked",
|
||||
"seeking",
|
||||
"select",
|
||||
"selectionchange",
|
||||
"selectstart",
|
||||
"show",
|
||||
"signalingstatechange",
|
||||
"soundend",
|
||||
"soundstart",
|
||||
"sourceclose",
|
||||
"sourceclosed",
|
||||
"sourceended",
|
||||
"sourceopen",
|
||||
"speechend",
|
||||
"speechstart",
|
||||
"stalled",
|
||||
"start",
|
||||
"statechange",
|
||||
"stop",
|
||||
"storage",
|
||||
"storagecommit",
|
||||
"submit",
|
||||
"success",
|
||||
"suspend",
|
||||
"textinput",
|
||||
"timeout",
|
||||
"timeupdate",
|
||||
"toggle",
|
||||
"touchcancel",
|
||||
"touchend",
|
||||
"touchmove",
|
||||
"touchstart",
|
||||
"track",
|
||||
"transitioncancel",
|
||||
"transitionend",
|
||||
"transitionrun",
|
||||
"transitionstart",
|
||||
"unhandledrejection",
|
||||
"unload",
|
||||
"updateready",
|
||||
"upgradeneeded",
|
||||
"userproximity",
|
||||
"versionchange",
|
||||
"visibilitychange",
|
||||
"voiceschanged",
|
||||
"volumechange",
|
||||
"vrdisplayactivate",
|
||||
"vrdisplayconnect",
|
||||
"vrdisplaydeactivate",
|
||||
"vrdisplaydisconnect",
|
||||
"vrdisplaypresentchange",
|
||||
"waiting",
|
||||
"waitingforkey",
|
||||
"warning",
|
||||
"webkitanimationend",
|
||||
"webkitanimationiteration",
|
||||
"webkitanimationstart",
|
||||
"webkitcurrentplaybacktargetiswirelesschanged",
|
||||
"webkitfullscreenchange",
|
||||
"webkitfullscreenerror",
|
||||
"webkitkeyadded",
|
||||
"webkitkeyerror",
|
||||
"webkitkeymessage",
|
||||
"webkitneedkey",
|
||||
"webkitorientationchange",
|
||||
"webkitplaybacktargetavailabilitychanged",
|
||||
"webkitpointerlockchange",
|
||||
"webkitpointerlockerror",
|
||||
"webkitresourcetimingbufferfull",
|
||||
"webkittransitionend",
|
||||
"wheel",
|
||||
"zoom",
|
||||
].forEach(function(type) {
|
||||
[
|
||||
"beforeunloadevent",
|
||||
"compositionevent",
|
||||
"customevent",
|
||||
"devicemotionevent",
|
||||
"deviceorientationevent",
|
||||
"dragevent",
|
||||
"event",
|
||||
"events",
|
||||
"focusevent",
|
||||
"hashchangeevent",
|
||||
"htmlevents",
|
||||
"keyboardevent",
|
||||
"messageevent",
|
||||
"mouseevent",
|
||||
"mouseevents",
|
||||
"storageevent",
|
||||
"svgevents",
|
||||
"textevent",
|
||||
"touchevent",
|
||||
"uievent",
|
||||
"uievents",
|
||||
].forEach(function(interface) {
|
||||
try {
|
||||
var event = document.createEvent(interface);
|
||||
event.initEvent(type, true, true);
|
||||
scan(event);
|
||||
} catch (e) {}
|
||||
});
|
||||
});
|
||||
|
||||
var obj;
|
||||
while (obj = to_scan.shift()) {
|
||||
var proto = obj;
|
||||
do {
|
||||
Object.getOwnPropertyNames(proto).forEach(function(name) {
|
||||
var visited = ~names.indexOf(name);
|
||||
if (!visited) names.push(name);
|
||||
try {
|
||||
scan(obj[name]);
|
||||
if (visited) return;
|
||||
if (/^create/.test(name)) {
|
||||
scan(obj[name]());
|
||||
}
|
||||
if (/^[A-Z]/.test(name)) {
|
||||
scan(new obj[name]());
|
||||
}
|
||||
} catch (e) {}
|
||||
});
|
||||
} while (proto = Object.getPrototypeOf(proto));
|
||||
}
|
||||
names.sort();
|
||||
document.write('<pre>[\n "');
|
||||
document.write(names.join('",\n "'));
|
||||
document.write('"\n]</pre>');
|
||||
}();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user