Compare commits
49 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 |
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -1,5 +1,8 @@
|
|||||||
name: CI
|
name: CI
|
||||||
on: [ push, pull_request ]
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
@@ -19,7 +22,7 @@ jobs:
|
|||||||
TYPE: ${{ matrix.script }}
|
TYPE: ${{ matrix.script }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/cache@v1
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: tmp
|
path: tmp
|
||||||
key: tmp ${{ matrix.script }}
|
key: tmp ${{ matrix.script }}
|
||||||
|
|||||||
16
.github/workflows/ufuzz.yml
vendored
16
.github/workflows/ufuzz.yml
vendored
@@ -2,7 +2,11 @@ name: Fuzzing
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "*/8 * * * *"
|
- cron: "*/5 * * * *"
|
||||||
|
env:
|
||||||
|
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
||||||
|
CAUSE: ${{ github.event_name }}
|
||||||
|
TOKEN: ${{ github.token }}
|
||||||
jobs:
|
jobs:
|
||||||
ufuzz:
|
ufuzz:
|
||||||
strategy:
|
strategy:
|
||||||
@@ -32,4 +36,12 @@ jobs:
|
|||||||
npm config set update-notifier false
|
npm config set update-notifier false
|
||||||
npm --version
|
npm --version
|
||||||
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
||||||
node test/ufuzz/job 3600000
|
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
|
||||||
|
|||||||
35
README.md
35
README.md
@@ -212,17 +212,16 @@ Example:
|
|||||||
To enable the mangler you need to pass `--mangle` (`-m`). The following
|
To enable the mangler you need to pass `--mangle` (`-m`). The following
|
||||||
(comma-separated) options are supported:
|
(comma-separated) options are supported:
|
||||||
|
|
||||||
- `toplevel` (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
|
uglifyjs ... -m reserved=['$','require','exports']
|
||||||
mangled, you can declare those names with `--mangle reserved` — pass a
|
|
||||||
comma-separated list of names. For example:
|
|
||||||
|
|
||||||
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`)
|
### CLI mangling property names (`--mangle-props`)
|
||||||
|
|
||||||
@@ -657,8 +656,8 @@ to be `false` and all symbol names will be omitted.
|
|||||||
- `hoist_props` (default: `true`) -- hoist properties from constant object and
|
- `hoist_props` (default: `true`) -- hoist properties from constant object and
|
||||||
array literals into regular variables subject to a set of constraints. For example:
|
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`
|
`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,
|
works best with `toplevel` and `mangle` enabled, alongside with `compress` option
|
||||||
and the `compress` option `toplevel` enabled.
|
`passes` set to `2` or higher.
|
||||||
|
|
||||||
- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
|
- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
|
||||||
by default because it seems to increase the size of the output in general)
|
by default because it seems to increase the size of the output in general)
|
||||||
@@ -1157,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 properties can be added, removed and modified (not prevented with
|
||||||
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
|
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
|
||||||
`Object.preventExtensions()` or `Object.seal()`).
|
`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);
|
||||||
|
```
|
||||||
|
|||||||
33
lib/ast.js
33
lib/ast.js
@@ -120,6 +120,20 @@ var AST_Node = DEFNODE("Node", "start end", {
|
|||||||
ctor.prototype._validate.call(this);
|
ctor.prototype._validate.call(this);
|
||||||
} while (ctor = ctor.BASE);
|
} 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);
|
}, null);
|
||||||
|
|
||||||
(AST_Node.log_function = function(fn, verbose) {
|
(AST_Node.log_function = function(fn, verbose) {
|
||||||
@@ -274,10 +288,13 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
|||||||
var label = node.label;
|
var label = node.label;
|
||||||
var def = this.label;
|
var def = this.label;
|
||||||
node.walk(new TreeWalker(function(node) {
|
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;
|
node.label.thedef = label;
|
||||||
label.references.push(node);
|
label.references.push(node);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Scope) return true;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
@@ -395,16 +412,16 @@ var AST_With = DEFNODE("With", "expression", {
|
|||||||
|
|
||||||
/* -----[ scope and functions ]----- */
|
/* -----[ 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",
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
$propdoc: {
|
$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)",
|
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) {
|
clone: function(deep) {
|
||||||
var node = this._clone(deep);
|
var node = this._clone(deep);
|
||||||
|
|||||||
503
lib/compress.js
503
lib/compress.js
@@ -167,7 +167,7 @@ merge(Compressor.prototype, {
|
|||||||
if (def.global) for (var i = 0; i < def.orig.length; i++)
|
if (def.global) for (var i = 0; i < def.orig.length; i++)
|
||||||
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return def.undeclared;
|
||||||
},
|
},
|
||||||
compress: function(node) {
|
compress: function(node) {
|
||||||
node = node.resolve_defines(this);
|
node = node.resolve_defines(this);
|
||||||
@@ -554,13 +554,6 @@ merge(Compressor.prototype, {
|
|||||||
if (is_arguments(def) && node.property instanceof AST_Number) def.reassigned = true;
|
if (is_arguments(def) && node.property instanceof AST_Number) def.reassigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var suppressor = new TreeWalker(function(node) {
|
|
||||||
if (!(node instanceof AST_Symbol)) return;
|
|
||||||
var d = node.definition();
|
|
||||||
if (!d) return;
|
|
||||||
if (node instanceof AST_SymbolRef) push_ref(d, node);
|
|
||||||
d.fixed = false;
|
|
||||||
});
|
|
||||||
def(AST_Accessor, function(tw, descend, compressor) {
|
def(AST_Accessor, function(tw, descend, compressor) {
|
||||||
push(tw);
|
push(tw);
|
||||||
reset_variables(tw, compressor, this);
|
reset_variables(tw, compressor, this);
|
||||||
@@ -587,7 +580,10 @@ merge(Compressor.prototype, {
|
|||||||
d.assignments++;
|
d.assignments++;
|
||||||
var fixed = d.fixed;
|
var fixed = d.fixed;
|
||||||
var value = eq ? node.right : node;
|
var value = eq ? node.right : node;
|
||||||
if (is_modified(compressor, tw, node, value, 0)) return;
|
if (is_modified(compressor, tw, node, value, 0)) {
|
||||||
|
d.fixed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
var safe = eq || safe_to_read(tw, d);
|
var safe = eq || safe_to_read(tw, d);
|
||||||
node.right.walk(tw);
|
node.right.walk(tw);
|
||||||
if (safe && safe_to_assign(tw, d)) {
|
if (safe && safe_to_assign(tw, d)) {
|
||||||
@@ -600,6 +596,7 @@ merge(Compressor.prototype, {
|
|||||||
return node.right;
|
return node.right;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
if (d.single_use) d.single_use = false;
|
||||||
sym.fixed = d.fixed = function() {
|
sym.fixed = d.fixed = function() {
|
||||||
return make_node(AST_Binary, node, {
|
return make_node(AST_Binary, node, {
|
||||||
operator: node.operator.slice(0, -1),
|
operator: node.operator.slice(0, -1),
|
||||||
@@ -736,11 +733,19 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_ForIn, function(tw) {
|
def(AST_ForIn, function(tw) {
|
||||||
this.init.walk(suppressor);
|
|
||||||
this.object.walk(tw);
|
this.object.walk(tw);
|
||||||
var saved_loop = tw.in_loop;
|
var saved_loop = tw.in_loop;
|
||||||
tw.in_loop = this;
|
tw.in_loop = this;
|
||||||
push(tw);
|
push(tw);
|
||||||
|
var init = this.init;
|
||||||
|
init.walk(tw);
|
||||||
|
if (init instanceof AST_Var) {
|
||||||
|
init = init.definitions[0].name;
|
||||||
|
} else while (init instanceof AST_PropAccess) {
|
||||||
|
init = init.expression.tail_node();
|
||||||
|
}
|
||||||
|
var def = init.definition();
|
||||||
|
if (def) def.fixed = false;
|
||||||
this.body.walk(tw);
|
this.body.walk(tw);
|
||||||
pop(tw);
|
pop(tw);
|
||||||
tw.in_loop = saved_loop;
|
tw.in_loop = saved_loop;
|
||||||
@@ -896,6 +901,7 @@ merge(Compressor.prototype, {
|
|||||||
if (safe_to_read(tw, d) && safe_to_assign(tw, d)) {
|
if (safe_to_read(tw, d) && safe_to_assign(tw, d)) {
|
||||||
push_ref(d, exp);
|
push_ref(d, exp);
|
||||||
mark(tw, d);
|
mark(tw, d);
|
||||||
|
if (d.single_use) d.single_use = false;
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return make_node(AST_Binary, node, {
|
return make_node(AST_Binary, node, {
|
||||||
operator: node.operator.slice(0, -1),
|
operator: node.operator.slice(0, -1),
|
||||||
@@ -1088,11 +1094,14 @@ merge(Compressor.prototype, {
|
|||||||
// func(something) because that changes the meaning of
|
// func(something) because that changes the meaning of
|
||||||
// the func (becomes lexical instead of global).
|
// the func (becomes lexical instead of global).
|
||||||
function maintain_this_binding(compressor, parent, orig, val) {
|
function maintain_this_binding(compressor, parent, orig, val) {
|
||||||
if (parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|
var wrap = false;
|
||||||
|| parent.TYPE == "Call" && parent.expression === orig && needs_unbinding(compressor, val)) {
|
if (parent.TYPE == "Call") {
|
||||||
return make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]);
|
wrap = parent.expression === orig && needs_unbinding(compressor, val);
|
||||||
|
} else if (parent instanceof AST_UnaryPrefix) {
|
||||||
|
wrap = parent.operator == "delete"
|
||||||
|
|| parent.operator == "typeof" && is_undeclared_ref(val);
|
||||||
}
|
}
|
||||||
return val;
|
return wrap ? make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]) : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
function merge_sequence(array, node) {
|
function merge_sequence(array, node) {
|
||||||
@@ -1197,7 +1206,9 @@ merge(Compressor.prototype, {
|
|||||||
function find_loop_scope_try() {
|
function find_loop_scope_try() {
|
||||||
var node = compressor.self(), level = 0;
|
var node = compressor.self(), level = 0;
|
||||||
do {
|
do {
|
||||||
if (node instanceof AST_Catch || node instanceof AST_Finally) {
|
if (node instanceof AST_Catch) {
|
||||||
|
if (!compressor.parent(level).bfinally) level++;
|
||||||
|
} else if (node instanceof AST_Finally) {
|
||||||
level++;
|
level++;
|
||||||
} else if (node instanceof AST_IterationStatement) {
|
} else if (node instanceof AST_IterationStatement) {
|
||||||
in_loop = true;
|
in_loop = true;
|
||||||
@@ -1279,7 +1290,7 @@ merge(Compressor.prototype, {
|
|||||||
col: node.start.col
|
col: node.start.col
|
||||||
});
|
});
|
||||||
if (candidate instanceof AST_UnaryPostfix) {
|
if (candidate instanceof AST_UnaryPostfix) {
|
||||||
lhs.definition().fixed = false;
|
if (lhs instanceof AST_SymbolRef) lhs.definition().fixed = false;
|
||||||
return make_node(AST_UnaryPrefix, candidate, candidate);
|
return make_node(AST_UnaryPrefix, candidate, candidate);
|
||||||
}
|
}
|
||||||
if (candidate instanceof AST_VarDef) {
|
if (candidate instanceof AST_VarDef) {
|
||||||
@@ -1379,6 +1390,7 @@ merge(Compressor.prototype, {
|
|||||||
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
|
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
|
||||||
var scan_rhs = foldable(candidate);
|
var scan_rhs = foldable(candidate);
|
||||||
if (!scan_lhs && !scan_rhs) continue;
|
if (!scan_lhs && !scan_rhs) continue;
|
||||||
|
var read_toplevel = false;
|
||||||
var modify_toplevel = false;
|
var modify_toplevel = false;
|
||||||
// Locate symbols which may execute code outside of scanning range
|
// Locate symbols which may execute code outside of scanning range
|
||||||
var lvalues = get_lvalues(candidate);
|
var lvalues = get_lvalues(candidate);
|
||||||
@@ -1541,8 +1553,9 @@ merge(Compressor.prototype, {
|
|||||||
return lvalues.has(node.name.name) || side_effects && may_modify(node.name);
|
return lvalues.has(node.name.name) || side_effects && may_modify(node.name);
|
||||||
}
|
}
|
||||||
var sym = is_lhs(node.left, node);
|
var sym = is_lhs(node.left, node);
|
||||||
if (sym && lvalues.has(sym.name)) return true;
|
|
||||||
if (sym instanceof AST_PropAccess) return true;
|
if (sym instanceof AST_PropAccess) return true;
|
||||||
|
if (!(sym instanceof AST_SymbolRef)) return false;
|
||||||
|
return lvalues.has(sym.name) || read_toplevel && compressor.exposed(sym.definition());
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_args() {
|
function extract_args() {
|
||||||
@@ -1825,7 +1838,9 @@ merge(Compressor.prototype, {
|
|||||||
if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1);
|
if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1);
|
||||||
if (parent instanceof AST_Switch) return find_stop_unused(parent, level + 1);
|
if (parent instanceof AST_Switch) return find_stop_unused(parent, level + 1);
|
||||||
if (parent instanceof AST_Unary) return find_stop_unused(parent, level + 1);
|
if (parent instanceof AST_Unary) return find_stop_unused(parent, level + 1);
|
||||||
if (parent instanceof AST_VarDef) return find_stop_unused(parent, level + 1);
|
if (parent instanceof AST_VarDef) {
|
||||||
|
return may_throw(parent) ? node : find_stop_unused(parent, level + 1);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1929,19 +1944,21 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function may_be_global(node) {
|
||||||
|
if (node instanceof AST_SymbolRef) {
|
||||||
|
node = node.fixed_value();
|
||||||
|
if (!node) return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Assign) return node.operator == "=" && may_be_global(node.right);
|
||||||
|
return node instanceof AST_PropAccess || node instanceof AST_This;
|
||||||
|
}
|
||||||
|
|
||||||
function get_lvalues(expr) {
|
function get_lvalues(expr) {
|
||||||
var lvalues = new Dictionary();
|
var lvalues = new Dictionary();
|
||||||
if (candidate instanceof AST_VarDef) lvalues.add(candidate.name.name, lhs);
|
if (expr instanceof AST_VarDef) lvalues.add(expr.name.name, lhs);
|
||||||
var scan_iife = scope instanceof AST_Toplevel;
|
var find_arguments = scope.uses_arguments && !compressor.has_directive("use strict");
|
||||||
|
var scan_toplevel = scope instanceof AST_Toplevel;
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
if (scan_iife && node.TYPE == "Call") {
|
|
||||||
var exp = node.expression;
|
|
||||||
if (exp instanceof AST_PropAccess) return;
|
|
||||||
if (exp instanceof AST_Function && !exp.contains_this()) return;
|
|
||||||
modify_toplevel = true;
|
|
||||||
scan_iife = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var value;
|
var value;
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
value = node.fixed_value() || node;
|
value = node.fixed_value() || node;
|
||||||
@@ -1949,6 +1966,28 @@ merge(Compressor.prototype, {
|
|||||||
value = node;
|
value = node;
|
||||||
}
|
}
|
||||||
if (value) lvalues.add(node.name, is_modified(compressor, tw, node, value, 0));
|
if (value) lvalues.add(node.name, is_modified(compressor, tw, node, value, 0));
|
||||||
|
if (find_arguments && node instanceof AST_Sub) {
|
||||||
|
scope.argnames.forEach(function(argname) {
|
||||||
|
if (!compressor.option("reduce_vars") || argname.definition().assignments) {
|
||||||
|
lvalues.add(argname.name, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
find_arguments = false;
|
||||||
|
}
|
||||||
|
if (!scan_toplevel) return;
|
||||||
|
if (node.TYPE == "Call") {
|
||||||
|
if (modify_toplevel) return;
|
||||||
|
var exp = node.expression;
|
||||||
|
if (exp instanceof AST_PropAccess) return;
|
||||||
|
if (exp instanceof AST_Function && !exp.contains_this()) return;
|
||||||
|
modify_toplevel = true;
|
||||||
|
} else if (node instanceof AST_PropAccess && may_be_global(node.expression)) {
|
||||||
|
if (node === lhs && !(expr instanceof AST_Unary)) {
|
||||||
|
modify_toplevel = true;
|
||||||
|
} else {
|
||||||
|
read_toplevel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
expr.walk(tw);
|
expr.walk(tw);
|
||||||
return lvalues;
|
return lvalues;
|
||||||
@@ -1958,9 +1997,12 @@ merge(Compressor.prototype, {
|
|||||||
if (expr.name instanceof AST_SymbolFunarg) {
|
if (expr.name instanceof AST_SymbolFunarg) {
|
||||||
var index = compressor.self().argnames.indexOf(expr.name);
|
var index = compressor.self().argnames.indexOf(expr.name);
|
||||||
var args = compressor.parent().args;
|
var args = compressor.parent().args;
|
||||||
if (args[index]) args[index] = make_node(AST_Number, args[index], {
|
if (args[index]) {
|
||||||
value: 0
|
args[index] = make_node(AST_Number, args[index], {
|
||||||
});
|
value: 0
|
||||||
|
});
|
||||||
|
expr.name.definition().fixed = false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var end = hit_stack.length - 1;
|
var end = hit_stack.length - 1;
|
||||||
@@ -3065,7 +3107,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
(function(def) {
|
(function(def) {
|
||||||
function to_node(value, orig) {
|
function to_node(value, orig) {
|
||||||
if (value instanceof AST_Node) return make_node(value.CTOR, orig, value);
|
if (value instanceof AST_Node) return value.clone(true);
|
||||||
if (Array.isArray(value)) return make_node(AST_Array, orig, {
|
if (Array.isArray(value)) return make_node(AST_Array, orig, {
|
||||||
elements: value.map(function(value) {
|
elements: value.map(function(value) {
|
||||||
return to_node(value, orig);
|
return to_node(value, orig);
|
||||||
@@ -3114,11 +3156,11 @@ merge(Compressor.prototype, {
|
|||||||
return this.expression._find_defs(compressor, "." + this.property + suffix);
|
return this.expression._find_defs(compressor, "." + this.property + suffix);
|
||||||
});
|
});
|
||||||
def(AST_SymbolDeclaration, function(compressor) {
|
def(AST_SymbolDeclaration, function(compressor) {
|
||||||
if (!this.global()) return;
|
if (!this.definition().global) return;
|
||||||
if (HOP(compressor.option("global_defs"), this.name)) warn(this);
|
if (HOP(compressor.option("global_defs"), this.name)) warn(this);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor, suffix) {
|
def(AST_SymbolRef, function(compressor, suffix) {
|
||||||
if (!this.global()) return;
|
if (!this.definition().global) return;
|
||||||
var defines = compressor.option("global_defs");
|
var defines = compressor.option("global_defs");
|
||||||
var name = this.name + suffix;
|
var name = this.name + suffix;
|
||||||
if (HOP(defines, name)) return to_node(defines[name], this);
|
if (HOP(defines, name)) return to_node(defines[name], this);
|
||||||
@@ -3463,7 +3505,8 @@ merge(Compressor.prototype, {
|
|||||||
var left = this.left._eval(compressor, ignore_side_effects, cached, depth);
|
var left = this.left._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (left === this.left) return this;
|
if (left === this.left) return this;
|
||||||
if (this.operator == (left ? "||" : "&&")) return left;
|
if (this.operator == (left ? "||" : "&&")) return left;
|
||||||
var right = this.right._eval(compressor, ignore_side_effects, cached, depth);
|
var rhs_ignore_side_effects = ignore_side_effects && !(left && typeof left == "object");
|
||||||
|
var right = this.right._eval(compressor, rhs_ignore_side_effects, cached, depth);
|
||||||
if (right === this.right) return this;
|
if (right === this.right) return this;
|
||||||
var result;
|
var result;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
@@ -3530,6 +3573,7 @@ merge(Compressor.prototype, {
|
|||||||
escaped[0].walk(new TreeWalker(function(node) {
|
escaped[0].walk(new TreeWalker(function(node) {
|
||||||
if (found) return true;
|
if (found) return true;
|
||||||
if (node === ref) return found = true;
|
if (node === ref) return found = true;
|
||||||
|
if (node instanceof AST_Scope) return true;
|
||||||
}));
|
}));
|
||||||
return found;
|
return found;
|
||||||
default:
|
default:
|
||||||
@@ -4416,7 +4460,7 @@ merge(Compressor.prototype, {
|
|||||||
if (drop_funcs && node !== self && node instanceof AST_Defun) {
|
if (drop_funcs && node !== self && node instanceof AST_Defun) {
|
||||||
var def = node.name.definition();
|
var def = node.name.definition();
|
||||||
if (!(def.id in in_use_ids)) {
|
if (!(def.id in in_use_ids)) {
|
||||||
log(node.name, "Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
log(node.name, "Dropping unused function {name}");
|
||||||
def.eliminated++;
|
def.eliminated++;
|
||||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
@@ -4431,7 +4475,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!(sym.definition().id in in_use_ids)) {
|
if (!(sym.definition().id in in_use_ids)) {
|
||||||
sym.__unused = true;
|
sym.__unused = true;
|
||||||
if (trim) {
|
if (trim) {
|
||||||
log(sym, "Dropping unused function argument {name} [{file}:{line},{col}]", template(sym));
|
log(sym, "Dropping unused function argument {name}");
|
||||||
a.pop();
|
a.pop();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -4454,8 +4498,18 @@ merge(Compressor.prototype, {
|
|||||||
var sym = def.name.definition();
|
var sym = def.name.definition();
|
||||||
if (!drop_vars || sym.id in in_use_ids) {
|
if (!drop_vars || sym.id in in_use_ids) {
|
||||||
if (def.value && indexOf_assign(sym, def) < 0) {
|
if (def.value && indexOf_assign(sym, def) < 0) {
|
||||||
def.value = def.value.drop_side_effect_free(compressor);
|
var write_only = def.value.write_only;
|
||||||
if (def.value) def.value.tail_node().write_only = false;
|
var value = def.value.drop_side_effect_free(compressor);
|
||||||
|
if (def.value !== value) {
|
||||||
|
def.value = value && make_sequence(def.value, [
|
||||||
|
value,
|
||||||
|
make_node(AST_Number, def.value, {
|
||||||
|
value: 0
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
} else if (def.value.write_only !== write_only) {
|
||||||
|
def.value.write_only = write_only;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var old_def, var_defs = var_defs_by_id.get(sym.id);
|
var old_def, var_defs = var_defs_by_id.get(sym.id);
|
||||||
if (!def.value) {
|
if (!def.value) {
|
||||||
@@ -4524,7 +4578,7 @@ merge(Compressor.prototype, {
|
|||||||
AST_Node.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name));
|
AST_Node.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
side_effects.push(value);
|
side_effects.push(value);
|
||||||
} else {
|
} else {
|
||||||
log(def.name, "Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
|
log(def.name, "Dropping unused variable {name}");
|
||||||
}
|
}
|
||||||
sym.eliminated++;
|
sym.eliminated++;
|
||||||
}
|
}
|
||||||
@@ -4619,19 +4673,24 @@ merge(Compressor.prototype, {
|
|||||||
return !block ? node : in_list ? List.splice(block.body) : block;
|
return !block ? node : in_list ? List.splice(block.body) : block;
|
||||||
} else if (node instanceof AST_ForIn) {
|
} else if (node instanceof AST_ForIn) {
|
||||||
if (!drop_vars || !compressor.option("loops")) return;
|
if (!drop_vars || !compressor.option("loops")) return;
|
||||||
if (!(node.init instanceof AST_Definitions)) return;
|
|
||||||
var sym = node.init.definitions[0].name;
|
|
||||||
if (sym.definition().id in in_use_ids) return;
|
|
||||||
if (!is_empty(node.body)) return;
|
if (!is_empty(node.body)) return;
|
||||||
log(sym, "Dropping unused loop variable {name} [{file}:{line},{col}]", template(sym));
|
var sym = node.init;
|
||||||
var value = node.object.drop_side_effect_free(compressor);
|
if (sym instanceof AST_Definitions) {
|
||||||
if (value) {
|
sym = sym.definitions[0].name;
|
||||||
AST_Node.warn("Side effects in object of for-in loop [{file}:{line},{col}]", template(sym));
|
} else while (sym instanceof AST_PropAccess) {
|
||||||
return make_node(AST_SimpleStatement, node, {
|
sym = sym.expression.tail_node();
|
||||||
body: value
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
var def = sym.definition();
|
||||||
|
if (!def) return;
|
||||||
|
if (def.scope !== self) return;
|
||||||
|
if (def.id in in_use_ids) return;
|
||||||
|
log(sym, "Dropping unused loop variable {name}");
|
||||||
|
var value = node.object.drop_side_effect_free(compressor);
|
||||||
|
if (!value) return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
|
AST_Node.warn("Side effects in object of for-in loop [{file}:{line},{col}]", value.start);
|
||||||
|
return make_node(AST_SimpleStatement, node, {
|
||||||
|
body: value
|
||||||
|
});
|
||||||
} else if (node instanceof AST_Sequence) {
|
} else if (node instanceof AST_Sequence) {
|
||||||
if (node.expressions.length == 1) return node.expressions[0];
|
if (node.expressions.length == 1) return node.expressions[0];
|
||||||
}
|
}
|
||||||
@@ -4651,8 +4710,8 @@ merge(Compressor.prototype, {
|
|||||||
drop_unused_call_args(call, compressor, fns_with_marked_args);
|
drop_unused_call_args(call, compressor, fns_with_marked_args);
|
||||||
});
|
});
|
||||||
|
|
||||||
function log(sym, text, props) {
|
function log(sym, text) {
|
||||||
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
|
AST_Node[sym.definition().references.length > 0 ? "info" : "warn"](text + " [{file}:{line},{col}]", template(sym));
|
||||||
}
|
}
|
||||||
|
|
||||||
function template(sym) {
|
function template(sym) {
|
||||||
@@ -4740,6 +4799,13 @@ merge(Compressor.prototype, {
|
|||||||
if (track_assigns(node_def, sym) && is_lhs(sym, node) !== sym) add_assigns(node_def, sym);
|
if (track_assigns(node_def, sym) && is_lhs(sym, node) !== sym) add_assigns(node_def, sym);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_ForIn) {
|
||||||
|
if (!drop_vars || !compressor.option("loops")) return;
|
||||||
|
if (!is_empty(node.body)) return;
|
||||||
|
if (node.init.has_side_effects(compressor)) return;
|
||||||
|
node.object.walk(tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
node_def = node.definition();
|
node_def = node.definition();
|
||||||
if (!(node_def.id in in_use_ids)) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
@@ -5063,6 +5129,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
self.transform(new TreeTransformer(function(node, descend) {
|
self.transform(new TreeTransformer(function(node, descend) {
|
||||||
|
if (node instanceof AST_Binary) return replace("right");
|
||||||
if (node instanceof AST_PropAccess) {
|
if (node instanceof AST_PropAccess) {
|
||||||
if (!(node.expression instanceof AST_SymbolRef)) return;
|
if (!(node.expression instanceof AST_SymbolRef)) return;
|
||||||
var defs = defs_by_id[node.expression.definition().id];
|
var defs = defs_by_id[node.expression.definition().id];
|
||||||
@@ -5078,10 +5145,15 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Unary) {
|
if (node instanceof AST_Unary) {
|
||||||
if (unary_side_effects[node.operator]) return;
|
if (unary_side_effects[node.operator]) return;
|
||||||
if (!(node.expression instanceof AST_SymbolRef)) return;
|
return replace("expression");
|
||||||
if (!(node.expression.definition().id in defs_by_id)) return;
|
}
|
||||||
|
|
||||||
|
function replace(prop) {
|
||||||
|
var sym = node[prop];
|
||||||
|
if (!(sym instanceof AST_SymbolRef)) return;
|
||||||
|
if (!(sym.definition().id in defs_by_id)) return;
|
||||||
var opt = node.clone();
|
var opt = node.clone();
|
||||||
opt.expression = make_node(AST_Object, node, {
|
opt[prop] = make_node(AST_Object, sym, {
|
||||||
properties: []
|
properties: []
|
||||||
});
|
});
|
||||||
return opt;
|
return opt;
|
||||||
@@ -5303,10 +5375,7 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(this, [ expression, property ]);
|
return make_sequence(this, [ expression, property ]);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor) {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
if (!this.is_declared(compressor)) return this;
|
return this.is_declared(compressor) ? null : this;
|
||||||
var def = this.definition();
|
|
||||||
if (member(this, def.references)) def.replaced++;
|
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
def(AST_This, return_null);
|
def(AST_This, return_null);
|
||||||
def(AST_Unary, function(compressor, first_in_statement) {
|
def(AST_Unary, function(compressor, first_in_statement) {
|
||||||
@@ -5314,10 +5383,7 @@ merge(Compressor.prototype, {
|
|||||||
this.write_only = !this.expression.has_side_effects(compressor);
|
this.write_only = !this.expression.has_side_effects(compressor);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) {
|
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null;
|
||||||
this.expression.definition().replaced++;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (first_in_statement && expression && is_iife_call(expression)) {
|
if (first_in_statement && expression && is_iife_call(expression)) {
|
||||||
if (expression === this.expression && this.operator == "!") return this;
|
if (expression === this.expression && this.operator == "!") return this;
|
||||||
@@ -5875,28 +5941,57 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
body[0].body = decl.concat(body[0].body);
|
body[0].body = decl.concat(body[0].body);
|
||||||
self.body = body;
|
self.body = body;
|
||||||
if (body.length == 1 && (body[0] === exact_match || body[0] === default_branch)) {
|
if (compressor.option("conditionals")) switch (body.length) {
|
||||||
var has_break = false;
|
case 1:
|
||||||
var tw = new TreeWalker(function(node) {
|
if (!no_break(body[0])) break;
|
||||||
if (has_break
|
var exp = body[0].expression;
|
||||||
|| node instanceof AST_Lambda
|
var statements = body[0].body.slice();
|
||||||
|| node instanceof AST_SimpleStatement) return true;
|
if (body[0] !== default_branch && body[0] !== exact_match) return make_node(AST_If, self, {
|
||||||
if (is_break(node, tw)) has_break = true;
|
condition: make_node(AST_Binary, self, {
|
||||||
|
operator: "===",
|
||||||
|
left: self.expression,
|
||||||
|
right: exp,
|
||||||
|
}),
|
||||||
|
body: make_node(AST_BlockStatement, self, {
|
||||||
|
body: statements,
|
||||||
|
}),
|
||||||
|
alternative: null,
|
||||||
|
}).optimize(compressor);
|
||||||
|
if (exp) statements.unshift(make_node(AST_SimpleStatement, exp, {
|
||||||
|
body: exp,
|
||||||
|
}));
|
||||||
|
statements.unshift(make_node(AST_SimpleStatement, self.expression, {
|
||||||
|
body:self.expression,
|
||||||
|
}));
|
||||||
|
return make_node(AST_BlockStatement, self, {
|
||||||
|
body: statements,
|
||||||
|
}).optimize(compressor);
|
||||||
|
case 2:
|
||||||
|
if (!member(default_branch, body) || !no_break(body[1])) break;
|
||||||
|
var statements = body[0].body.slice();
|
||||||
|
var exclusive = statements.length && is_break(statements[statements.length - 1], compressor);
|
||||||
|
if (exclusive) statements.pop();
|
||||||
|
if (!all(statements, no_break)) break;
|
||||||
|
var alternative = body[1].body.length && make_node(AST_BlockStatement, body[1], body[1]);
|
||||||
|
var node = make_node(AST_If, self, {
|
||||||
|
condition: make_node(AST_Binary, self, body[0] === default_branch ? {
|
||||||
|
operator: "!==",
|
||||||
|
left: self.expression,
|
||||||
|
right: body[1].expression,
|
||||||
|
} : {
|
||||||
|
operator: "===",
|
||||||
|
left: self.expression,
|
||||||
|
right: body[0].expression,
|
||||||
|
}),
|
||||||
|
body: make_node(AST_BlockStatement, body[0], {
|
||||||
|
body: statements,
|
||||||
|
}),
|
||||||
|
alternative: exclusive && alternative || null,
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
if (!exclusive && alternative) node = make_node(AST_BlockStatement, self, {
|
||||||
if (!has_break) {
|
body: [ node, alternative ],
|
||||||
var statements = body[0].body.slice();
|
});
|
||||||
var exp = body[0].expression;
|
return node.optimize(compressor);
|
||||||
if (exp) statements.unshift(make_node(AST_SimpleStatement, exp, {
|
|
||||||
body: exp
|
|
||||||
}));
|
|
||||||
statements.unshift(make_node(AST_SimpleStatement, self.expression, {
|
|
||||||
body:self.expression
|
|
||||||
}));
|
|
||||||
return make_node(AST_BlockStatement, self, {
|
|
||||||
body: statements
|
|
||||||
}).optimize(compressor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
@@ -5904,6 +5999,19 @@ merge(Compressor.prototype, {
|
|||||||
return node instanceof AST_Break && tw.loopcontrol_target(node) === self;
|
return node instanceof AST_Break && tw.loopcontrol_target(node) === self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function no_break(node) {
|
||||||
|
var found = false;
|
||||||
|
var tw = new TreeWalker(function(node) {
|
||||||
|
if (found
|
||||||
|
|| node instanceof AST_Lambda
|
||||||
|
|| node instanceof AST_SimpleStatement) return true;
|
||||||
|
if (is_break(node, tw)) found = true;
|
||||||
|
});
|
||||||
|
tw.push(self);
|
||||||
|
node.walk(tw);
|
||||||
|
return !found;
|
||||||
|
}
|
||||||
|
|
||||||
function eliminate_branch(branch, prev) {
|
function eliminate_branch(branch, prev) {
|
||||||
if (prev && !aborts(prev)) {
|
if (prev && !aborts(prev)) {
|
||||||
prev.body = prev.body.concat(branch.body);
|
prev.body = prev.body.concat(branch.body);
|
||||||
@@ -6305,7 +6413,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
var code = OutputStream();
|
var code = OutputStream();
|
||||||
AST_BlockStatement.prototype._codegen.call(fun, fun, code);
|
AST_BlockStatement.prototype._codegen.call(fun, code);
|
||||||
self.args = [
|
self.args = [
|
||||||
make_node(AST_String, self, {
|
make_node(AST_String, self, {
|
||||||
value: fun.argnames.map(function(arg) {
|
value: fun.argnames.map(function(arg) {
|
||||||
@@ -6415,16 +6523,11 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function return_value(stat) {
|
function return_value(stat) {
|
||||||
if (!stat) return make_node(AST_Undefined, self);
|
if (!stat) return make_node(AST_Undefined, self);
|
||||||
if (stat instanceof AST_Return) {
|
if (stat instanceof AST_Return) return stat.value || make_node(AST_Undefined, self);
|
||||||
if (!stat.value) return make_node(AST_Undefined, self);
|
if (stat instanceof AST_SimpleStatement) return make_node(AST_UnaryPrefix, stat, {
|
||||||
return stat.value.clone(true);
|
operator: "void",
|
||||||
}
|
expression: stat.body
|
||||||
if (stat instanceof AST_SimpleStatement) {
|
});
|
||||||
return make_node(AST_UnaryPrefix, stat, {
|
|
||||||
operator: "void",
|
|
||||||
expression: stat.body
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function can_flatten_body(stat) {
|
function can_flatten_body(stat) {
|
||||||
@@ -6805,72 +6908,70 @@ merge(Compressor.prototype, {
|
|||||||
var SIGN_OPS = makePredicate("+ -");
|
var SIGN_OPS = makePredicate("+ -");
|
||||||
var MULTIPLICATIVE_OPS = makePredicate("* / %");
|
var MULTIPLICATIVE_OPS = makePredicate("* / %");
|
||||||
OPT(AST_UnaryPrefix, function(self, compressor) {
|
OPT(AST_UnaryPrefix, function(self, compressor) {
|
||||||
var e = self.expression;
|
var op = self.operator;
|
||||||
|
var exp = self.expression;
|
||||||
if (compressor.option("evaluate")
|
if (compressor.option("evaluate")
|
||||||
&& self.operator == "delete"
|
&& op == "delete"
|
||||||
&& !(e instanceof AST_SymbolRef
|
&& !(exp instanceof AST_SymbolRef
|
||||||
|| e instanceof AST_PropAccess
|
|| exp instanceof AST_PropAccess
|
||||||
|| is_identifier_atom(e))) {
|
|| is_identifier_atom(exp))) {
|
||||||
if (e instanceof AST_Sequence) {
|
if (exp instanceof AST_Sequence) {
|
||||||
e = e.expressions.slice();
|
exp = exp.expressions.slice();
|
||||||
e.push(make_node(AST_True, self));
|
exp.push(make_node(AST_True, self));
|
||||||
return make_sequence(self, e).optimize(compressor);
|
return make_sequence(self, exp).optimize(compressor);
|
||||||
}
|
}
|
||||||
return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor);
|
return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("sequences")) {
|
if (compressor.option("sequences") && !(op == "typeof" && is_undeclared_ref(exp.tail_node()))) {
|
||||||
var seq = lift_sequence_in_expression(self, compressor);
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects") && self.operator == "void") {
|
if (compressor.option("side_effects") && op == "void") {
|
||||||
e = e.drop_side_effect_free(compressor);
|
exp = exp.drop_side_effect_free(compressor);
|
||||||
if (e) {
|
if (!exp) return make_node(AST_Undefined, self).optimize(compressor);
|
||||||
self.expression = e;
|
self.expression = exp;
|
||||||
return self;
|
return self;
|
||||||
} else {
|
|
||||||
return make_node(AST_Undefined, self).optimize(compressor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (compressor.option("booleans")) {
|
if (compressor.option("booleans")) {
|
||||||
if (self.operator == "!" && e.is_truthy()) {
|
if (op == "!" && exp.is_truthy()) {
|
||||||
return make_sequence(self, [ e, make_node(AST_False, self) ]).optimize(compressor);
|
return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor);
|
||||||
} else if (compressor.in_boolean_context()) switch (self.operator) {
|
} else if (compressor.in_boolean_context()) switch (op) {
|
||||||
case "!":
|
case "!":
|
||||||
if (e instanceof AST_UnaryPrefix && e.operator == "!") {
|
if (exp instanceof AST_UnaryPrefix && exp.operator == "!") {
|
||||||
// !!foo => foo, if we're in boolean context
|
// !!foo => foo, if we're in boolean context
|
||||||
return e.expression;
|
return exp.expression;
|
||||||
}
|
}
|
||||||
if (e instanceof AST_Binary) {
|
if (exp instanceof AST_Binary) {
|
||||||
self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor)));
|
self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "typeof":
|
case "typeof":
|
||||||
// typeof always returns a non-empty string, thus it's
|
// typeof always returns a non-empty string, thus it's
|
||||||
// always true in booleans
|
// always true in booleans
|
||||||
AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
||||||
return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [
|
return (exp instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [
|
||||||
e,
|
exp,
|
||||||
make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
])).optimize(compressor);
|
])).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.operator == "-" && e instanceof AST_Infinity) e = e.transform(compressor);
|
if (op == "-" && exp instanceof AST_Infinity) exp = exp.transform(compressor);
|
||||||
if (compressor.option("evaluate")
|
if (compressor.option("evaluate")
|
||||||
&& e instanceof AST_Binary
|
&& exp instanceof AST_Binary
|
||||||
&& SIGN_OPS[self.operator]
|
&& SIGN_OPS[op]
|
||||||
&& MULTIPLICATIVE_OPS[e.operator]
|
&& MULTIPLICATIVE_OPS[exp.operator]
|
||||||
&& (e.left.is_constant() || !e.right.has_side_effects(compressor))) {
|
&& (exp.left.is_constant() || !exp.right.has_side_effects(compressor))) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: e.operator,
|
operator: exp.operator,
|
||||||
left: make_node(AST_UnaryPrefix, e.left, {
|
left: make_node(AST_UnaryPrefix, exp.left, {
|
||||||
operator: self.operator,
|
operator: op,
|
||||||
expression: e.left
|
expression: exp.left
|
||||||
}),
|
}),
|
||||||
right: e.right
|
right: exp.right
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// avoids infinite recursion of numerals
|
// avoids infinite recursion of numerals
|
||||||
return self.operator == "-" && (e instanceof AST_Number || e instanceof AST_Infinity)
|
return op == "-" && (exp instanceof AST_Number || exp instanceof AST_Infinity)
|
||||||
? self : try_evaluate(compressor, self);
|
? self : try_evaluate(compressor, self);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -7027,7 +7128,7 @@ merge(Compressor.prototype, {
|
|||||||
&& self.right instanceof AST_SymbolRef
|
&& self.right instanceof AST_SymbolRef
|
||||||
&& self.left.definition() === self.right.definition()
|
&& self.left.definition() === self.right.definition()
|
||||||
&& is_object(self.left)) {
|
&& is_object(self.left)) {
|
||||||
return make_node(self.operator[0] == "=" ? AST_True : AST_False, self);
|
return make_node(self.operator[0] == "=" ? AST_True : AST_False, self).optimize(compressor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "&&":
|
case "&&":
|
||||||
@@ -7099,11 +7200,11 @@ merge(Compressor.prototype, {
|
|||||||
var parent = compressor.parent();
|
var parent = compressor.parent();
|
||||||
if (compressor.option("comparisons") && self.is_boolean(compressor)) {
|
if (compressor.option("comparisons") && self.is_boolean(compressor)) {
|
||||||
if (!(parent instanceof AST_Binary) || parent instanceof AST_Assign) {
|
if (!(parent instanceof AST_Binary) || parent instanceof AST_Assign) {
|
||||||
var negated = make_node(AST_UnaryPrefix, self, {
|
var negated = best_of(compressor, self, make_node(AST_UnaryPrefix, self, {
|
||||||
operator: "!",
|
operator: "!",
|
||||||
expression: self.negate(compressor, first_in_statement(compressor))
|
expression: self.negate(compressor, first_in_statement(compressor))
|
||||||
});
|
}));
|
||||||
self = best_of(compressor, self, negated);
|
if (negated !== self) return negated;
|
||||||
}
|
}
|
||||||
switch (self.operator) {
|
switch (self.operator) {
|
||||||
case ">": reverse("<"); break;
|
case ">": reverse("<"); break;
|
||||||
@@ -7424,56 +7525,58 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (self.left instanceof AST_Number && !self.right.is_constant()) switch (self.operator) {
|
if (!(parent instanceof AST_UnaryPrefix && parent.operator == "delete")) {
|
||||||
// 0 + n => n
|
if (self.left instanceof AST_Number && !self.right.is_constant()) switch (self.operator) {
|
||||||
case "+":
|
// 0 + n => n
|
||||||
if (self.left.value == 0) {
|
case "+":
|
||||||
if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
|
if (self.left.value == 0) {
|
||||||
operator: "+",
|
if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
|
||||||
expression: self.right
|
operator: "+",
|
||||||
}).optimize(compressor);
|
expression: self.right
|
||||||
if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right;
|
}).optimize(compressor);
|
||||||
|
if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// 1 * n => n
|
||||||
|
case "*":
|
||||||
|
if (self.left.value == 1) {
|
||||||
|
return self.right.is_number(compressor) ? self.right : make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "+",
|
||||||
|
expression: self.right
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) {
|
||||||
// 1 * n => n
|
// n + 0 => n
|
||||||
case "*":
|
case "+":
|
||||||
if (self.left.value == 1) {
|
if (self.right.value == 0) {
|
||||||
return self.right.is_number(compressor) ? self.right : make_node(AST_UnaryPrefix, self, {
|
if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
|
||||||
operator: "+",
|
operator: "+",
|
||||||
expression: self.right
|
expression: self.left
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
|
if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// n - 0 => n
|
||||||
|
case "-":
|
||||||
|
if (self.right.value == 0) {
|
||||||
|
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "+",
|
||||||
|
expression: self.left
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// n / 1 => n
|
||||||
|
case "/":
|
||||||
|
if (self.right.value == 1) {
|
||||||
|
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "+",
|
||||||
|
expression: self.left
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) {
|
|
||||||
// n + 0 => n
|
|
||||||
case "+":
|
|
||||||
if (self.right.value == 0) {
|
|
||||||
if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
|
|
||||||
operator: "+",
|
|
||||||
expression: self.left
|
|
||||||
}).optimize(compressor);
|
|
||||||
if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// n - 0 => n
|
|
||||||
case "-":
|
|
||||||
if (self.right.value == 0) {
|
|
||||||
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
|
|
||||||
operator: "+",
|
|
||||||
expression: self.left
|
|
||||||
}).optimize(compressor);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// n / 1 => n
|
|
||||||
case "/":
|
|
||||||
if (self.right.value == 1) {
|
|
||||||
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
|
|
||||||
operator: "+",
|
|
||||||
expression: self.left
|
|
||||||
}).optimize(compressor);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("typeofs")) switch (self.operator) {
|
if (compressor.option("typeofs")) switch (self.operator) {
|
||||||
@@ -7571,7 +7674,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_indexFn(node) {
|
function is_indexFn(node) {
|
||||||
return node instanceof AST_Call
|
return node.TYPE == "Call"
|
||||||
&& node.expression instanceof AST_Dot
|
&& node.expression instanceof AST_Dot
|
||||||
&& indexFns[node.expression.property];
|
&& indexFns[node.expression.property];
|
||||||
}
|
}
|
||||||
@@ -7630,6 +7733,8 @@ merge(Compressor.prototype, {
|
|||||||
single_use = false;
|
single_use = false;
|
||||||
} else if (recursive_ref(compressor, def)) {
|
} else if (recursive_ref(compressor, def)) {
|
||||||
single_use = false;
|
single_use = false;
|
||||||
|
} else if (compressor.option("ie8") && fixed.name && def !== fixed.name.definition()) {
|
||||||
|
single_use = false;
|
||||||
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
|
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
|
||||||
single_use = fixed.is_constant_expression(self.scope);
|
single_use = fixed.is_constant_expression(self.scope);
|
||||||
if (single_use == "f") {
|
if (single_use == "f") {
|
||||||
@@ -7638,8 +7743,6 @@ merge(Compressor.prototype, {
|
|||||||
scope.inlined = true;
|
scope.inlined = true;
|
||||||
} while (scope = scope.parent_scope);
|
} while (scope = scope.parent_scope);
|
||||||
}
|
}
|
||||||
} else if (compressor.option("ie8") && fixed.name && def !== fixed.name.definition()) {
|
|
||||||
single_use = false;
|
|
||||||
}
|
}
|
||||||
if (single_use) fixed.parent_scope = self.scope;
|
if (single_use) fixed.parent_scope = self.scope;
|
||||||
} else if (!fixed || !fixed.is_constant_expression()) {
|
} else if (!fixed || !fixed.is_constant_expression()) {
|
||||||
@@ -7884,12 +7987,17 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (self.left instanceof AST_SymbolRef) {
|
} else if (self.left instanceof AST_SymbolRef) {
|
||||||
if (self.operator == "=" && self.left.equivalent_to(self.right)) return self.right;
|
var parent;
|
||||||
|
if (self.operator == "=" && self.left.equivalent_to(self.right)
|
||||||
|
&& !((parent = compressor.parent()) instanceof AST_UnaryPrefix && parent.operator == "delete")) {
|
||||||
|
return self.right;
|
||||||
|
}
|
||||||
if (self.left.is_immutable()) return strip_assignment();
|
if (self.left.is_immutable()) return strip_assignment();
|
||||||
var def = self.left.definition();
|
var def = self.left.definition();
|
||||||
var scope = def.scope.resolve();
|
var scope = def.scope.resolve();
|
||||||
var local = scope === compressor.find_parent(AST_Lambda);
|
var local = scope === compressor.find_parent(AST_Lambda);
|
||||||
var level = 0, node, parent = self;
|
var level = 0, node;
|
||||||
|
parent = self;
|
||||||
do {
|
do {
|
||||||
node = parent;
|
node = parent;
|
||||||
parent = compressor.parent(level++);
|
parent = compressor.parent(level++);
|
||||||
@@ -8428,7 +8536,9 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_lhs(compressor.self(), parent)) return self;
|
if (is_lhs(compressor.self(), parent)) return self;
|
||||||
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
|
if (compressor.option("sequences")
|
||||||
|
&& parent.TYPE != "Call"
|
||||||
|
&& !(parent instanceof AST_ForIn && parent.init === self)) {
|
||||||
var seq = lift_sequence_in_expression(self, compressor);
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
@@ -8539,8 +8649,11 @@ merge(Compressor.prototype, {
|
|||||||
col: self.start.col
|
col: self.start.col
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (is_lhs(compressor.self(), compressor.parent())) return self;
|
var parent = compressor.parent();
|
||||||
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
|
if (is_lhs(compressor.self(), parent)) return self;
|
||||||
|
if (compressor.option("sequences")
|
||||||
|
&& parent.TYPE != "Call"
|
||||||
|
&& !(parent instanceof AST_ForIn && parent.init === self)) {
|
||||||
var seq = lift_sequence_in_expression(self, compressor);
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,13 +178,17 @@ function minify(files, options) {
|
|||||||
toplevel = toplevel[action](option);
|
toplevel = toplevel[action](option);
|
||||||
files[toplevel.start.file] = toplevel.print_to_string().replace(orig, "");
|
files[toplevel.start.file] = toplevel.print_to_string().replace(orig, "");
|
||||||
});
|
});
|
||||||
|
if (options.validate) toplevel.validate_ast();
|
||||||
if (timings) timings.rename = Date.now();
|
if (timings) timings.rename = Date.now();
|
||||||
if (options.rename) {
|
if (options.rename) {
|
||||||
toplevel.figure_out_scope(options.mangle);
|
toplevel.figure_out_scope(options.mangle);
|
||||||
toplevel.expand_names(options.mangle);
|
toplevel.expand_names(options.mangle);
|
||||||
}
|
}
|
||||||
if (timings) timings.compress = Date.now();
|
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 (timings) timings.scope = Date.now();
|
||||||
if (options.mangle) toplevel.figure_out_scope(options.mangle);
|
if (options.mangle) toplevel.figure_out_scope(options.mangle);
|
||||||
if (timings) timings.mangle = Date.now();
|
if (timings) timings.mangle = Date.now();
|
||||||
@@ -193,9 +197,7 @@ function minify(files, options) {
|
|||||||
toplevel.mangle_names(options.mangle);
|
toplevel.mangle_names(options.mangle);
|
||||||
}
|
}
|
||||||
if (timings) timings.properties = Date.now();
|
if (timings) timings.properties = Date.now();
|
||||||
if (options.mangle && options.mangle.properties) {
|
if (options.mangle && options.mangle.properties) mangle_properties(toplevel, options.mangle.properties);
|
||||||
toplevel = mangle_properties(toplevel, options.mangle.properties);
|
|
||||||
}
|
|
||||||
if (timings) timings.output = Date.now();
|
if (timings) timings.output = Date.now();
|
||||||
var result = {};
|
var result = {};
|
||||||
if (options.output.ast) {
|
if (options.output.ast) {
|
||||||
|
|||||||
385
lib/output.js
385
lib/output.js
@@ -100,7 +100,7 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var indentation = 0;
|
var indentation = options.indent_start;
|
||||||
var current_col = 0;
|
var current_col = 0;
|
||||||
var current_line = 1;
|
var current_line = 1;
|
||||||
var current_pos = 0;
|
var current_pos = 0;
|
||||||
@@ -191,10 +191,6 @@ function OutputStream(options) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_indent(back) {
|
|
||||||
return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -----[ beautification/minification ]----- */
|
/* -----[ beautification/minification ]----- */
|
||||||
|
|
||||||
var has_parens = false;
|
var has_parens = false;
|
||||||
@@ -345,9 +341,7 @@ function OutputStream(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var indent = options.beautify ? function(half) {
|
var indent = options.beautify ? function(half) {
|
||||||
if (options.beautify) {
|
print(repeat_string(" ", half ? indentation - (options.indent_level >> 1) : indentation));
|
||||||
print(make_indent(half ? 0.5 : 0));
|
|
||||||
}
|
|
||||||
} : noop;
|
} : noop;
|
||||||
|
|
||||||
var with_indent = options.beautify ? function(col, cont) {
|
var with_indent = options.beautify ? function(col, cont) {
|
||||||
@@ -575,9 +569,9 @@ function OutputStream(options) {
|
|||||||
get : get,
|
get : get,
|
||||||
toString : get,
|
toString : get,
|
||||||
indent : indent,
|
indent : indent,
|
||||||
indentation : function() { return indentation },
|
should_break : readonly ? noop : function() {
|
||||||
current_width : function() { return current_col - indentation },
|
return options.width && current_col - indentation >= options.width;
|
||||||
should_break : function() { return options.width && this.current_width() >= options.width },
|
},
|
||||||
has_parens : function() { return has_parens },
|
has_parens : function() { return has_parens },
|
||||||
newline : newline,
|
newline : newline,
|
||||||
print : print,
|
print : print,
|
||||||
@@ -630,13 +624,7 @@ function OutputStream(options) {
|
|||||||
var use_asm = false;
|
var use_asm = false;
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print", function(stream, force_parens) {
|
AST_Node.DEFMETHOD("print", function(stream, force_parens) {
|
||||||
var self = this, generator = self._codegen;
|
var self = this;
|
||||||
function doit() {
|
|
||||||
stream.prepend_comments(self);
|
|
||||||
self.add_source_map(stream);
|
|
||||||
generator(self, stream);
|
|
||||||
stream.append_comments(self);
|
|
||||||
}
|
|
||||||
stream.push_node(self);
|
stream.push_node(self);
|
||||||
if (force_parens || self.needs_parens(stream)) {
|
if (force_parens || self.needs_parens(stream)) {
|
||||||
stream.with_parens(doit);
|
stream.with_parens(doit);
|
||||||
@@ -644,9 +632,14 @@ function OutputStream(options) {
|
|||||||
doit();
|
doit();
|
||||||
}
|
}
|
||||||
stream.pop_node();
|
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) {
|
AST_Node.DEFMETHOD("print_to_string", function(options) {
|
||||||
var s = OutputStream(options);
|
var s = OutputStream(options);
|
||||||
this.print(s);
|
this.print(s);
|
||||||
@@ -689,78 +682,66 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
PARENS(AST_Unary, function(output) {
|
PARENS(AST_Unary, function(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
return p instanceof AST_PropAccess && p.expression === this
|
return (p instanceof AST_Call || p instanceof AST_PropAccess) && p.expression === this;
|
||||||
|| p instanceof AST_Call && p.expression === this;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Sequence, function(output) {
|
PARENS(AST_Sequence, function(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// (foo, bar)() or foo(1, (2, 3), 4)
|
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||||
return p instanceof AST_Call
|
return p instanceof AST_Array
|
||||||
// !(foo, bar, baz)
|
|
||||||
|| p instanceof AST_Unary
|
|
||||||
// 1 + (2, 3) + 4 ==> 8
|
// 1 + (2, 3) + 4 ==> 8
|
||||||
|| p instanceof AST_Binary
|
|| p instanceof AST_Binary
|
||||||
// var a = (1, 2), b = a + a; ==> b == 4
|
// new (foo, bar) or foo(1, (2, 3), 4)
|
||||||
|| p instanceof AST_VarDef
|
|| p instanceof AST_Call
|
||||||
// (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
|
|
||||||
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||||
// ==> 20 (side effect, set a := 10 and b := 20)
|
// ==> 20 (side effect, set a := 10 and b := 20)
|
||||||
|| p instanceof AST_Conditional;
|
|| 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) {
|
PARENS(AST_Binary, function(output) {
|
||||||
var p = output.parent();
|
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)
|
// this deals with precedence: 3 * (2 + 1)
|
||||||
if (p instanceof AST_Binary) {
|
if (p instanceof AST_Binary) {
|
||||||
var po = p.operator, pp = PRECEDENCE[po];
|
var po = p.operator, pp = PRECEDENCE[po];
|
||||||
var so = this.operator, sp = PRECEDENCE[so];
|
var so = this.operator, sp = PRECEDENCE[so];
|
||||||
if (pp > sp
|
return pp > sp || (pp == sp && this === p.right);
|
||||||
|| (pp == sp
|
|
||||||
&& this === p.right)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// (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) {
|
PARENS(AST_PropAccess, function(output) {
|
||||||
|
var node = this;
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_New && p.expression === this) {
|
if (p instanceof AST_New && p.expression === node) {
|
||||||
// i.e. new (foo.bar().baz)
|
// i.e. new (foo().bar)
|
||||||
//
|
//
|
||||||
// if there's one call into this subtree, then we need
|
// if there's one call into this subtree, then we need
|
||||||
// parens around it too, otherwise the call will be
|
// parens around it too, otherwise the call will be
|
||||||
// interpreted as passing the arguments to the upper New
|
// interpreted as passing the arguments to the upper New
|
||||||
// expression.
|
// expression.
|
||||||
var parens = false;
|
do {
|
||||||
this.walk(new TreeWalker(function(node) {
|
node = node.expression;
|
||||||
if (parens || node instanceof AST_Scope) return true;
|
} while (node instanceof AST_PropAccess);
|
||||||
if (node instanceof AST_Call) {
|
return node.TYPE == "Call";
|
||||||
parens = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
return parens;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Call, function(output) {
|
PARENS(AST_Call, function(output) {
|
||||||
var p = output.parent();
|
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
|
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||||
if (output.option('webkit')) {
|
if (output.option('webkit')) {
|
||||||
var g = output.parent(1);
|
var g = output.parent(1);
|
||||||
@@ -773,11 +754,12 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_New, function(output) {
|
PARENS(AST_New, function(output) {
|
||||||
|
if (need_constructor_parens(this, output)) return false;
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (!need_constructor_parens(this, output)
|
// (new foo)(bar)
|
||||||
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
if (p instanceof AST_Call) return p.expression === this;
|
||||||
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
// (new Date).getTime(), (new Date)["getTime"]()
|
||||||
return true;
|
return p instanceof AST_PropAccess;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Number, function(output) {
|
PARENS(AST_Number, function(output) {
|
||||||
@@ -786,36 +768,29 @@ function OutputStream(options) {
|
|||||||
var value = this.value;
|
var value = this.value;
|
||||||
// https://github.com/mishoo/UglifyJS/issues/115
|
// https://github.com/mishoo/UglifyJS/issues/115
|
||||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||||
if (value < 0 || /^0/.test(make_num(value))) {
|
return value < 0 || /^0/.test(make_num(value));
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS([ AST_Assign, AST_Conditional ], function(output) {
|
PARENS([ AST_Assign, AST_Conditional ], function(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// !(a = false) → true
|
|
||||||
if (p instanceof AST_Unary)
|
|
||||||
return true;
|
|
||||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||||
if (p instanceof AST_Binary && !(p instanceof AST_Assign))
|
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
||||||
return true;
|
|
||||||
// (a = func)() —or— new (a = Object)()
|
// (a = func)() —or— new (a = Object)()
|
||||||
if (p instanceof AST_Call && p.expression === this)
|
if (p instanceof AST_Call) return p.expression === this;
|
||||||
return true;
|
|
||||||
// (a = foo) ? bar : baz
|
// (a = foo) ? bar : baz
|
||||||
if (p instanceof AST_Conditional && p.condition === this)
|
if (p instanceof AST_Conditional) return p.condition === this;
|
||||||
return true;
|
|
||||||
// (a = foo)["prop"] —or— (a = foo).prop
|
// (a = foo)["prop"] —or— (a = foo).prop
|
||||||
if (p instanceof AST_PropAccess && p.expression === this)
|
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||||
return true;
|
// !(a = false) → true
|
||||||
|
if (p instanceof AST_Unary) return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ PRINTERS ]----- */
|
/* -----[ PRINTERS ]----- */
|
||||||
|
|
||||||
DEFPRINT(AST_Directive, function(self, output) {
|
DEFPRINT(AST_Directive, function(output) {
|
||||||
var quote = self.quote;
|
var quote = this.quote;
|
||||||
var value = self.value;
|
var value = this.value;
|
||||||
switch (output.option("quote_style")) {
|
switch (output.option("quote_style")) {
|
||||||
case 0:
|
case 0:
|
||||||
case 2:
|
case 2:
|
||||||
@@ -828,7 +803,7 @@ function OutputStream(options) {
|
|||||||
output.print(quote + value + quote);
|
output.print(quote + value + quote);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Debugger, function(self, output) {
|
DEFPRINT(AST_Debugger, function(output) {
|
||||||
output.print("debugger");
|
output.print("debugger");
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
@@ -864,21 +839,21 @@ function OutputStream(options) {
|
|||||||
force_statement(this.body, output);
|
force_statement(this.body, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFPRINT(AST_Statement, function(self, output) {
|
DEFPRINT(AST_Statement, function(output) {
|
||||||
self.body.print(output);
|
this.body.print(output);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Toplevel, function(self, output) {
|
DEFPRINT(AST_Toplevel, function(output) {
|
||||||
display_body(self.body, true, output, true);
|
display_body(this.body, true, output, true);
|
||||||
output.print("");
|
output.print("");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_LabeledStatement, function(self, output) {
|
DEFPRINT(AST_LabeledStatement, function(output) {
|
||||||
self.label.print(output);
|
this.label.print(output);
|
||||||
output.colon();
|
output.colon();
|
||||||
self.body.print(output);
|
this.body.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_SimpleStatement, function(self, output) {
|
DEFPRINT(AST_SimpleStatement, function(output) {
|
||||||
self.body.print(output);
|
this.body.print(output);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
function print_braced_empty(self, output) {
|
function print_braced_empty(self, output) {
|
||||||
@@ -895,13 +870,14 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
} else print_braced_empty(self, output);
|
} else print_braced_empty(self, output);
|
||||||
}
|
}
|
||||||
DEFPRINT(AST_BlockStatement, function(self, output) {
|
DEFPRINT(AST_BlockStatement, function(output) {
|
||||||
print_braced(self, output);
|
print_braced(this, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_EmptyStatement, function(self, output) {
|
DEFPRINT(AST_EmptyStatement, function(output) {
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Do, function(self, output) {
|
DEFPRINT(AST_Do, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("do");
|
output.print("do");
|
||||||
output.space();
|
output.space();
|
||||||
make_block(self.body, output);
|
make_block(self.body, output);
|
||||||
@@ -913,7 +889,8 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_While, function(self, output) {
|
DEFPRINT(AST_While, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("while");
|
output.print("while");
|
||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function() {
|
output.with_parens(function() {
|
||||||
@@ -922,7 +899,8 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
self._do_print_body(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_For, function(self, output) {
|
DEFPRINT(AST_For, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("for");
|
output.print("for");
|
||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function() {
|
output.with_parens(function() {
|
||||||
@@ -951,7 +929,8 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
self._do_print_body(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ForIn, function(self, output) {
|
DEFPRINT(AST_ForIn, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("for");
|
output.print("for");
|
||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function() {
|
output.with_parens(function() {
|
||||||
@@ -964,7 +943,8 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
self._do_print_body(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_With, function(self, output) {
|
DEFPRINT(AST_With, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("with");
|
output.print("with");
|
||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function() {
|
output.with_parens(function() {
|
||||||
@@ -975,7 +955,7 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ functions ]----- */
|
/* -----[ functions ]----- */
|
||||||
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
|
DEFPRINT(AST_Lambda, function(output, nokeyword) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (!nokeyword) {
|
if (!nokeyword) {
|
||||||
output.print("function");
|
output.print("function");
|
||||||
@@ -993,32 +973,23 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
print_braced(self, output, true);
|
print_braced(self, output, true);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Lambda, function(self, output) {
|
|
||||||
self._do_print(output);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -----[ jumps ]----- */
|
/* -----[ jumps ]----- */
|
||||||
function print_jump(output, kind, target) {
|
function print_jump(kind, prop) {
|
||||||
output.print(kind);
|
return function(output) {
|
||||||
if (target) {
|
output.print(kind);
|
||||||
output.space();
|
var target = this[prop];
|
||||||
target.print(output);
|
if (target) {
|
||||||
}
|
output.space();
|
||||||
output.semicolon();
|
target.print(output);
|
||||||
|
}
|
||||||
|
output.semicolon();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
DEFPRINT(AST_Return, print_jump("return", "value"));
|
||||||
DEFPRINT(AST_Return, function(self, output) {
|
DEFPRINT(AST_Throw, print_jump("throw", "value"));
|
||||||
print_jump(output, "return", self.value);
|
DEFPRINT(AST_Break, print_jump("break", "label"));
|
||||||
});
|
DEFPRINT(AST_Continue, print_jump("continue", "label"));
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -----[ if ]----- */
|
/* -----[ if ]----- */
|
||||||
function make_then(self, output) {
|
function make_then(self, output) {
|
||||||
@@ -1047,7 +1018,8 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
force_statement(self.body, output);
|
force_statement(self.body, output);
|
||||||
}
|
}
|
||||||
DEFPRINT(AST_If, function(self, output) {
|
DEFPRINT(AST_If, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("if");
|
output.print("if");
|
||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function() {
|
output.with_parens(function() {
|
||||||
@@ -1069,7 +1041,8 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ switch ]----- */
|
/* -----[ switch ]----- */
|
||||||
DEFPRINT(AST_Switch, function(self, output) {
|
DEFPRINT(AST_Switch, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("switch");
|
output.print("switch");
|
||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function() {
|
output.with_parens(function() {
|
||||||
@@ -1087,28 +1060,30 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
|
function print_branch_body(self, output) {
|
||||||
output.newline();
|
output.newline();
|
||||||
this.body.forEach(function(stmt) {
|
self.body.forEach(function(stmt) {
|
||||||
output.indent();
|
output.indent();
|
||||||
stmt.print(output);
|
stmt.print(output);
|
||||||
output.newline();
|
output.newline();
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
DEFPRINT(AST_Default, function(self, output) {
|
DEFPRINT(AST_Default, function(output) {
|
||||||
output.print("default:");
|
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.print("case");
|
||||||
output.space();
|
output.space();
|
||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
output.print(":");
|
output.print(":");
|
||||||
self._do_print_body(output);
|
print_branch_body(self, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ exceptions ]----- */
|
/* -----[ exceptions ]----- */
|
||||||
DEFPRINT(AST_Try, function(self, output) {
|
DEFPRINT(AST_Try, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("try");
|
output.print("try");
|
||||||
output.space();
|
output.space();
|
||||||
print_braced(self, output);
|
print_braced(self, output);
|
||||||
@@ -1121,7 +1096,8 @@ function OutputStream(options) {
|
|||||||
self.bfinally.print(output);
|
self.bfinally.print(output);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Catch, function(self, output) {
|
DEFPRINT(AST_Catch, function(output) {
|
||||||
|
var self = this;
|
||||||
output.print("catch");
|
output.print("catch");
|
||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function() {
|
output.with_parens(function() {
|
||||||
@@ -1130,13 +1106,14 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
print_braced(self, output);
|
print_braced(self, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Finally, function(self, output) {
|
DEFPRINT(AST_Finally, function(output) {
|
||||||
output.print("finally");
|
output.print("finally");
|
||||||
output.space();
|
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.print("var");
|
||||||
output.space();
|
output.space();
|
||||||
self.definitions.forEach(function(def, i) {
|
self.definitions.forEach(function(def, i) {
|
||||||
@@ -1161,7 +1138,8 @@ function OutputStream(options) {
|
|||||||
node.print(output, parens);
|
node.print(output, parens);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFPRINT(AST_VarDef, function(self, output) {
|
DEFPRINT(AST_VarDef, function(output) {
|
||||||
|
var self = this;
|
||||||
self.name.print(output);
|
self.name.print(output);
|
||||||
if (self.value) {
|
if (self.value) {
|
||||||
output.space();
|
output.space();
|
||||||
@@ -1174,10 +1152,7 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ other expressions ]----- */
|
/* -----[ other expressions ]----- */
|
||||||
DEFPRINT(AST_Call, function(self, output) {
|
function print_call_args(self, output) {
|
||||||
self.expression.print(output);
|
|
||||||
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
|
||||||
return;
|
|
||||||
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
||||||
output.add_mapping(self.start);
|
output.add_mapping(self.start);
|
||||||
}
|
}
|
||||||
@@ -1187,14 +1162,20 @@ function OutputStream(options) {
|
|||||||
expr.print(output);
|
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.print("new");
|
||||||
output.space();
|
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) {
|
DEFPRINT(AST_Sequence, function(output) {
|
||||||
self.expressions.forEach(function(node, index) {
|
this.expressions.forEach(function(node, index) {
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
output.comma();
|
output.comma();
|
||||||
if (output.should_break()) {
|
if (output.should_break()) {
|
||||||
@@ -1205,7 +1186,8 @@ function OutputStream(options) {
|
|||||||
node.print(output);
|
node.print(output);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Dot, function(self, output) {
|
DEFPRINT(AST_Dot, function(output) {
|
||||||
|
var self = this;
|
||||||
var expr = self.expression;
|
var expr = self.expression;
|
||||||
expr.print(output);
|
expr.print(output);
|
||||||
var prop = self.property;
|
var prop = self.property;
|
||||||
@@ -1226,35 +1208,38 @@ function OutputStream(options) {
|
|||||||
output.print_name(prop);
|
output.print_name(prop);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Sub, function(self, output) {
|
DEFPRINT(AST_Sub, function(output) {
|
||||||
self.expression.print(output);
|
this.expression.print(output);
|
||||||
output.print("[");
|
output.print("[");
|
||||||
self.property.print(output);
|
this.property.print(output);
|
||||||
output.print("]");
|
output.print("]");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_UnaryPrefix, function(self, output) {
|
DEFPRINT(AST_UnaryPrefix, function(output) {
|
||||||
var op = self.operator;
|
var op = this.operator;
|
||||||
|
var exp = this.expression;
|
||||||
output.print(op);
|
output.print(op);
|
||||||
if (/^[a-z]/i.test(op)
|
if (/^[a-z]/i.test(op)
|
||||||
|| (/[+-]$/.test(op)
|
|| (/[+-]$/.test(op)
|
||||||
&& self.expression instanceof AST_UnaryPrefix
|
&& exp instanceof AST_UnaryPrefix
|
||||||
&& /^[+-]/.test(self.expression.operator))) {
|
&& /^[+-]/.test(exp.operator))) {
|
||||||
output.space();
|
output.space();
|
||||||
}
|
}
|
||||||
self.expression.print(output);
|
exp.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_UnaryPostfix, function(self, output) {
|
DEFPRINT(AST_UnaryPostfix, function(output) {
|
||||||
self.expression.print(output);
|
this.expression.print(output);
|
||||||
output.print(self.operator);
|
output.print(this.operator);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Binary, function(self, output) {
|
DEFPRINT(AST_Binary, function(output) {
|
||||||
|
var self = this;
|
||||||
self.left.print(output);
|
self.left.print(output);
|
||||||
output.space();
|
output.space();
|
||||||
output.print(self.operator);
|
output.print(self.operator);
|
||||||
output.space();
|
output.space();
|
||||||
self.right.print(output);
|
self.right.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Conditional, function(self, output) {
|
DEFPRINT(AST_Conditional, function(output) {
|
||||||
|
var self = this;
|
||||||
self.condition.print(output);
|
self.condition.print(output);
|
||||||
output.space();
|
output.space();
|
||||||
output.print("?");
|
output.print("?");
|
||||||
@@ -1266,10 +1251,10 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ literals ]----- */
|
/* -----[ literals ]----- */
|
||||||
DEFPRINT(AST_Array, function(self, output) {
|
DEFPRINT(AST_Array, function(output) {
|
||||||
output.with_square(function() {
|
var a = this.elements, len = a.length;
|
||||||
var a = self.elements, len = a.length;
|
output.with_square(len > 0 ? function() {
|
||||||
if (len > 0) output.space();
|
output.space();
|
||||||
a.forEach(function(exp, i) {
|
a.forEach(function(exp, i) {
|
||||||
if (i) output.comma();
|
if (i) output.comma();
|
||||||
exp.print(output);
|
exp.print(output);
|
||||||
@@ -1279,12 +1264,13 @@ function OutputStream(options) {
|
|||||||
if (i === len - 1 && exp instanceof AST_Hole)
|
if (i === len - 1 && exp instanceof AST_Hole)
|
||||||
output.comma();
|
output.comma();
|
||||||
});
|
});
|
||||||
if (len > 0) output.space();
|
output.space();
|
||||||
});
|
} : noop);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Object, function(self, output) {
|
DEFPRINT(AST_Object, function(output) {
|
||||||
if (self.properties.length > 0) output.with_block(function() {
|
var props = this.properties;
|
||||||
self.properties.forEach(function(prop, i) {
|
if (props.length > 0) output.with_block(function() {
|
||||||
|
props.forEach(function(prop, i) {
|
||||||
if (i) {
|
if (i) {
|
||||||
output.print(",");
|
output.print(",");
|
||||||
output.newline();
|
output.newline();
|
||||||
@@ -1294,7 +1280,7 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
output.newline();
|
output.newline();
|
||||||
});
|
});
|
||||||
else print_braced_empty(self, output);
|
else print_braced_empty(this, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
function print_property_name(key, quote, output) {
|
function print_property_name(key, quote, output) {
|
||||||
@@ -1313,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);
|
print_property_name(self.key, self.quote, output);
|
||||||
output.colon();
|
output.colon();
|
||||||
self.value.print(output);
|
self.value.print(output);
|
||||||
});
|
});
|
||||||
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, output) {
|
function print_accessor(type) {
|
||||||
output.print(type);
|
return function(output) {
|
||||||
output.space();
|
var self = this;
|
||||||
print_property_name(this.key.name, this.quote, output);
|
output.print(type);
|
||||||
this.value._do_print(output, true);
|
output.space();
|
||||||
});
|
print_property_name(self.key.name, self.quote, output);
|
||||||
DEFPRINT(AST_ObjectSetter, function(self, output) {
|
self.value._codegen(output, true);
|
||||||
self._print_getter_setter("set", output);
|
};
|
||||||
});
|
}
|
||||||
DEFPRINT(AST_ObjectGetter, function(self, output) {
|
DEFPRINT(AST_ObjectGetter, print_accessor("get"));
|
||||||
self._print_getter_setter("get", output);
|
DEFPRINT(AST_ObjectSetter, print_accessor("set"));
|
||||||
});
|
DEFPRINT(AST_Symbol, function(output) {
|
||||||
DEFPRINT(AST_Symbol, function(self, output) {
|
var def = this.definition();
|
||||||
var def = self.definition();
|
output.print_name(def && def.mangled_name || this.name);
|
||||||
output.print_name(def && def.mangled_name || self.name);
|
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Hole, noop);
|
DEFPRINT(AST_Hole, noop);
|
||||||
DEFPRINT(AST_This, function(self, output) {
|
DEFPRINT(AST_This, function(output) {
|
||||||
output.print("this");
|
output.print("this");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Constant, function(self, output) {
|
DEFPRINT(AST_Constant, function(output) {
|
||||||
output.print(self.value);
|
output.print(this.value);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_String, function(self, output) {
|
DEFPRINT(AST_String, function(output) {
|
||||||
output.print_string(self.value, self.quote);
|
output.print_string(this.value, this.quote);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Number, function(self, output) {
|
DEFPRINT(AST_Number, function(output) {
|
||||||
if (use_asm && self.start && self.start.raw != null) {
|
var start = this.start;
|
||||||
output.print(self.start.raw);
|
if (use_asm && start && start.raw != null) {
|
||||||
|
output.print(start.raw);
|
||||||
} else {
|
} else {
|
||||||
output.print(make_num(self.value));
|
output.print(make_num(this.value));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFPRINT(AST_RegExp, function(self, output) {
|
DEFPRINT(AST_RegExp, function(output) {
|
||||||
var regexp = self.value;
|
var regexp = this.value;
|
||||||
var str = regexp.toString();
|
var str = regexp.toString();
|
||||||
var end = str.lastIndexOf("/");
|
var end = str.lastIndexOf("/");
|
||||||
if (regexp.raw_source) {
|
if (regexp.raw_source) {
|
||||||
@@ -1387,7 +1374,7 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
var p = output.parent();
|
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(" ");
|
output.print(" ");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1092,7 +1092,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function switch_body_() {
|
function switch_body_() {
|
||||||
expect("{");
|
expect("{");
|
||||||
var a = [], cur = null, branch = null, tmp;
|
var a = [], branch, cur, default_branch, tmp;
|
||||||
while (!is("punc", "}")) {
|
while (!is("punc", "}")) {
|
||||||
if (is("eof")) expect_token("punc", "}");
|
if (is("eof")) expect_token("punc", "}");
|
||||||
if (is("keyword", "case")) {
|
if (is("keyword", "case")) {
|
||||||
@@ -1107,12 +1107,14 @@ function parse($TEXT, options) {
|
|||||||
expect(":");
|
expect(":");
|
||||||
} else if (is("keyword", "default")) {
|
} else if (is("keyword", "default")) {
|
||||||
if (branch) branch.end = prev();
|
if (branch) branch.end = prev();
|
||||||
|
if (default_branch) croak("More than one default clause in switch statement");
|
||||||
cur = [];
|
cur = [];
|
||||||
branch = new AST_Default({
|
branch = new AST_Default({
|
||||||
start : (tmp = S.token, next(), expect(":"), tmp),
|
start : (tmp = S.token, next(), expect(":"), tmp),
|
||||||
body : cur
|
body : cur
|
||||||
});
|
});
|
||||||
a.push(branch);
|
a.push(branch);
|
||||||
|
default_branch = branch;
|
||||||
} else {
|
} else {
|
||||||
if (!cur) unexpected();
|
if (!cur) unexpected();
|
||||||
cur.push(statement());
|
cur.push(statement());
|
||||||
|
|||||||
@@ -43,7 +43,8 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function find_builtins(reserved) {
|
var builtins = function() {
|
||||||
|
var names = [];
|
||||||
// NaN will be included due to Number.NaN
|
// NaN will be included due to Number.NaN
|
||||||
[
|
[
|
||||||
"null",
|
"null",
|
||||||
@@ -67,19 +68,21 @@ function find_builtins(reserved) {
|
|||||||
].forEach(function(ctor) {
|
].forEach(function(ctor) {
|
||||||
Object.getOwnPropertyNames(ctor).map(add);
|
Object.getOwnPropertyNames(ctor).map(add);
|
||||||
if (ctor.prototype) {
|
if (ctor.prototype) {
|
||||||
|
Object.getOwnPropertyNames(new ctor()).map(add);
|
||||||
Object.getOwnPropertyNames(ctor.prototype).map(add);
|
Object.getOwnPropertyNames(ctor.prototype).map(add);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return makePredicate(names);
|
||||||
|
|
||||||
function add(name) {
|
function add(name) {
|
||||||
push_uniq(reserved, name);
|
names.push(name);
|
||||||
}
|
}
|
||||||
}
|
}();
|
||||||
|
|
||||||
function reserve_quoted_keys(ast, reserved) {
|
function reserve_quoted_keys(ast, reserved) {
|
||||||
ast.walk(new TreeWalker(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_ObjectKeyVal && node.quote) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
add(node.key);
|
if (node.quote) add(node.key);
|
||||||
} else if (node instanceof AST_Sub) {
|
} else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, add);
|
addStrings(node.property, add);
|
||||||
}
|
}
|
||||||
@@ -91,17 +94,14 @@ function reserve_quoted_keys(ast, reserved) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addStrings(node, add) {
|
function addStrings(node, add) {
|
||||||
node.walk(new TreeWalker(function(node) {
|
if (node instanceof AST_Conditional) {
|
||||||
if (node instanceof AST_Sequence) {
|
addStrings(node.consequent, add);
|
||||||
addStrings(node.tail_node(), add);
|
addStrings(node.alternative, add);
|
||||||
} else if (node instanceof AST_String) {
|
} else if (node instanceof AST_Sequence) {
|
||||||
add(node.value);
|
addStrings(node.tail_node(), add);
|
||||||
} else if (node instanceof AST_Conditional) {
|
} else if (node instanceof AST_String) {
|
||||||
addStrings(node.consequent, add);
|
add(node.value);
|
||||||
addStrings(node.alternative, add);
|
}
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mangle_properties(ast, options) {
|
function mangle_properties(ast, options) {
|
||||||
@@ -110,21 +110,21 @@ function mangle_properties(ast, options) {
|
|||||||
cache: null,
|
cache: null,
|
||||||
debug: false,
|
debug: false,
|
||||||
keep_quoted: false,
|
keep_quoted: false,
|
||||||
only_cache: false,
|
|
||||||
regex: null,
|
regex: null,
|
||||||
reserved: null,
|
reserved: null,
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
var reserved = options.reserved;
|
var reserved = Object.create(options.builtins ? null : builtins);
|
||||||
if (!Array.isArray(reserved)) reserved = [];
|
if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) {
|
||||||
if (!options.builtins) find_builtins(reserved);
|
reserved[name] = true;
|
||||||
|
});
|
||||||
|
|
||||||
var cname = -1;
|
var cname = -1;
|
||||||
var cache;
|
var cache;
|
||||||
if (options.cache) {
|
if (options.cache) {
|
||||||
cache = options.cache.props;
|
cache = options.cache.props;
|
||||||
cache.each(function(mangled_name) {
|
cache.each(function(name) {
|
||||||
push_uniq(reserved, mangled_name);
|
reserved[name] = true;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
cache = new Dictionary();
|
cache = new Dictionary();
|
||||||
@@ -139,62 +139,92 @@ function mangle_properties(ast, options) {
|
|||||||
var debug_suffix;
|
var debug_suffix;
|
||||||
if (debug) debug_suffix = options.debug === true ? "" : options.debug;
|
if (debug) debug_suffix = options.debug === true ? "" : options.debug;
|
||||||
|
|
||||||
var names_to_mangle = [];
|
var names_to_mangle = Object.create(null);
|
||||||
var unmangleable = [];
|
var unmangleable = Object.create(reserved);
|
||||||
|
|
||||||
// step 1: find candidates to mangle
|
// step 1: find candidates to mangle
|
||||||
ast.walk(new TreeWalker(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_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);
|
add(node.key);
|
||||||
} else if (node instanceof AST_ObjectProperty) {
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter, since KeyVal is handled above
|
// setter or getter, since KeyVal is handled above
|
||||||
add(node.key.name);
|
add(node.key.name);
|
||||||
} else if (node instanceof AST_Dot) {
|
|
||||||
add(node.property);
|
|
||||||
} else if (node instanceof AST_Sub) {
|
} else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, add);
|
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
|
// step 2: renaming properties
|
||||||
return ast.transform(new TreeTransformer(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
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);
|
node.key = mangle(node.key);
|
||||||
} else if (node instanceof AST_ObjectProperty) {
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter
|
// setter or getter
|
||||||
node.key.name = mangle(node.key.name);
|
node.key.name = mangle(node.key.name);
|
||||||
} else if (node instanceof AST_Dot) {
|
} else if (node instanceof AST_Sub) {
|
||||||
node.property = mangle(node.property);
|
if (!options.keep_quoted) mangleStrings(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]);
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// only function declarations after this line
|
// only function declarations after this line
|
||||||
|
|
||||||
function can_mangle(name) {
|
function can_mangle(name) {
|
||||||
if (unmangleable.indexOf(name) >= 0) return false;
|
if (unmangleable[name]) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
|
||||||
if (options.only_cache) return cache.has(name);
|
|
||||||
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function should_mangle(name) {
|
function should_mangle(name) {
|
||||||
|
if (reserved[name]) return false;
|
||||||
if (regex && !regex.test(name)) return false;
|
if (regex && !regex.test(name)) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
return cache.has(name) || names_to_mangle[name];
|
||||||
return cache.has(name) || names_to_mangle.indexOf(name) >= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(name) {
|
function add(name) {
|
||||||
if (can_mangle(name)) push_uniq(names_to_mangle, name);
|
if (can_mangle(name)) names_to_mangle[name] = true;
|
||||||
if (!should_mangle(name)) push_uniq(unmangleable, name);
|
if (!should_mangle(name)) unmangleable[name] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mangle(name) {
|
function mangle(name) {
|
||||||
@@ -218,17 +248,13 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mangleStrings(node) {
|
function mangleStrings(node) {
|
||||||
return node.transform(new TreeTransformer(function(node) {
|
if (node instanceof AST_Sequence) {
|
||||||
if (node instanceof AST_Sequence) {
|
mangleStrings(node.expressions.tail_node());
|
||||||
var last = node.expressions.length - 1;
|
} else if (node instanceof AST_String) {
|
||||||
node.expressions[last] = mangleStrings(node.expressions[last]);
|
node.value = mangle(node.value);
|
||||||
} else if (node instanceof AST_String) {
|
} else if (node instanceof AST_Conditional) {
|
||||||
node.value = mangle(node.value);
|
mangleStrings(node.consequent);
|
||||||
} else if (node instanceof AST_Conditional) {
|
mangleStrings(node.alternative);
|
||||||
node.consequent = mangleStrings(node.consequent);
|
}
|
||||||
node.alternative = mangleStrings(node.alternative);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
73
lib/scope.js
73
lib/scope.js
@@ -96,8 +96,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
|
|
||||||
// pass 1: setup scope chaining and handle definitions
|
// pass 1: setup scope chaining and handle definitions
|
||||||
var self = this;
|
var self = this;
|
||||||
var scope = self.parent_scope = null;
|
|
||||||
var defun = null;
|
var defun = null;
|
||||||
|
var next_def_id = 0;
|
||||||
|
var scope = self.parent_scope = null;
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
if (node instanceof AST_Catch) {
|
if (node instanceof AST_Catch) {
|
||||||
var save_scope = scope;
|
var save_scope = scope;
|
||||||
@@ -149,7 +150,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
scope.def_variable(node).defun = defun;
|
scope.def_variable(node).defun = defun;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.next_def_id = 0;
|
self.make_def = function(orig, init) {
|
||||||
|
return new SymbolDef(++next_def_id, this, orig, init);
|
||||||
|
};
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
// pass 2: find back references and eval
|
// pass 2: find back references and eval
|
||||||
@@ -230,6 +233,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
} else {
|
} else {
|
||||||
new_def = scope.def_variable(node);
|
new_def = scope.def_variable(node);
|
||||||
}
|
}
|
||||||
|
old_def.defun = new_def.scope;
|
||||||
old_def.orig.concat(old_def.references).forEach(function(node) {
|
old_def.orig.concat(old_def.references).forEach(function(node) {
|
||||||
node.thedef = new_def;
|
node.thedef = new_def;
|
||||||
node.reference(options);
|
node.reference(options);
|
||||||
@@ -239,12 +243,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("make_def", function(orig, init) {
|
|
||||||
var top = this;
|
|
||||||
while (top.parent_scope) top = top.parent_scope;
|
|
||||||
return new SymbolDef(++top.next_def_id, this, orig, init);
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||||
var globals = this.globals, name = node.name;
|
var globals = this.globals, name = node.name;
|
||||||
if (globals.has(name)) {
|
if (globals.has(name)) {
|
||||||
@@ -258,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) {
|
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)
|
init_scope_vars(this, parent_scope);
|
||||||
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
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("init_scope_vars", function() {
|
AST_Lambda.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
init_scope_vars(this, parent_scope);
|
||||||
this.uses_arguments = false;
|
this.uses_arguments = false;
|
||||||
this.def_variable(new AST_SymbolFunarg({
|
this.def_variable(new AST_SymbolFunarg({
|
||||||
name: "arguments",
|
name: "arguments",
|
||||||
start: this.start,
|
start: this.start,
|
||||||
end: this.end
|
end: this.end,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -386,18 +389,10 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options) {
|
|||||||
// labels are always mangleable
|
// labels are always mangleable
|
||||||
AST_Label.DEFMETHOD("unmangleable", return_false);
|
AST_Label.DEFMETHOD("unmangleable", return_false);
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("unreferenced", function() {
|
|
||||||
return !this.definition().references.length && !this.scope.pinned();
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("definition", function() {
|
AST_Symbol.DEFMETHOD("definition", function() {
|
||||||
return this.thedef;
|
return this.thedef;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("global", function() {
|
|
||||||
return this.definition().global;
|
|
||||||
});
|
|
||||||
|
|
||||||
function _default_mangler_options(options) {
|
function _default_mangler_options(options) {
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
eval : false,
|
eval : false,
|
||||||
@@ -557,22 +552,24 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
|
|||||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
||||||
options = _default_mangler_options(options);
|
options = _default_mangler_options(options);
|
||||||
base54.reset();
|
base54.reset();
|
||||||
|
var fn = AST_Symbol.prototype.add_source_map;
|
||||||
try {
|
try {
|
||||||
AST_Node.prototype.print = function(stream, force_parens) {
|
AST_Symbol.prototype.add_source_map = function() {
|
||||||
this._print(stream, force_parens);
|
if (!this.unmangleable(options)) base54.consider(this.name, -1);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
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);
|
base54.consider(this.print_to_string(), 1);
|
||||||
} finally {
|
} 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();
|
base54.sort();
|
||||||
|
|
||||||
|
|||||||
52
lib/utils.js
52
lib/utils.js
@@ -112,51 +112,29 @@ function return_this() { return this; }
|
|||||||
function return_null() { return null; }
|
function return_null() { return null; }
|
||||||
|
|
||||||
var List = (function() {
|
var List = (function() {
|
||||||
function List(a, f, backwards) {
|
function List(a, f) {
|
||||||
var ret = [], top = [], i;
|
var ret = [];
|
||||||
function doit() {
|
for (var i = 0; i < a.length; i++) {
|
||||||
var val = f(a[i], i);
|
var val = f(a[i], i);
|
||||||
var is_last = val instanceof Last;
|
if (val === skip) continue;
|
||||||
if (is_last) val = val.v;
|
if (val instanceof Splice) {
|
||||||
if (val instanceof AtTop) {
|
ret.push.apply(ret, val.v);
|
||||||
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();
|
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < a.length; ++i) if (doit()) break;
|
ret.push(val);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for (i in a) if (HOP(a, i)) if (doit()) break;
|
|
||||||
}
|
}
|
||||||
return top.concat(ret);
|
return ret;
|
||||||
}
|
}
|
||||||
List.is_op = function(val) {
|
List.is_op = function(val) {
|
||||||
return val === skip || val instanceof AtTop || val instanceof Last || val instanceof Splice;
|
return val === skip || val instanceof Splice;
|
||||||
|
};
|
||||||
|
List.splice = function(val) {
|
||||||
|
return new Splice(val);
|
||||||
};
|
};
|
||||||
List.at_top = function(val) { return new AtTop(val); };
|
|
||||||
List.splice = function(val) { return new Splice(val); };
|
|
||||||
List.last = function(val) { return new Last(val); };
|
|
||||||
var skip = List.skip = {};
|
var skip = List.skip = {};
|
||||||
function AtTop(val) { this.v = val; }
|
function Splice(val) {
|
||||||
function Splice(val) { this.v = val; }
|
this.v = val;
|
||||||
function Last(val) { this.v = val; }
|
}
|
||||||
return List;
|
return List;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.10.0",
|
"version": "3.10.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ function test_case(test) {
|
|||||||
quote_style: 3,
|
quote_style: 3,
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
|
input.validate_ast();
|
||||||
U.parse(input_code);
|
U.parse(input_code);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
log([
|
log([
|
||||||
@@ -311,12 +312,10 @@ function test_case(test) {
|
|||||||
if (test.mangle) {
|
if (test.mangle) {
|
||||||
output.compute_char_frequency(test.mangle);
|
output.compute_char_frequency(test.mangle);
|
||||||
output.mangle_names(test.mangle);
|
output.mangle_names(test.mangle);
|
||||||
if (test.mangle.properties) {
|
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
||||||
output = U.mangle_properties(output, test.mangle.properties);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
output = make_code(output, output_options);
|
var output_code = make_code(output, output_options);
|
||||||
if (expect != output) {
|
if (expect != output_code) {
|
||||||
log([
|
log([
|
||||||
"!!! failed",
|
"!!! failed",
|
||||||
"---INPUT---",
|
"---INPUT---",
|
||||||
@@ -329,14 +328,15 @@ function test_case(test) {
|
|||||||
"",
|
"",
|
||||||
].join("\n"), {
|
].join("\n"), {
|
||||||
input: input_formatted,
|
input: input_formatted,
|
||||||
output: output,
|
output: output_code,
|
||||||
expected: expect
|
expected: expect
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// expect == output
|
// expect == output
|
||||||
try {
|
try {
|
||||||
U.parse(output);
|
output.validate_ast();
|
||||||
|
U.parse(output_code);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
log([
|
log([
|
||||||
"!!! Test matched expected result but cannot parse output",
|
"!!! Test matched expected result but cannot parse output",
|
||||||
@@ -350,7 +350,7 @@ function test_case(test) {
|
|||||||
"",
|
"",
|
||||||
].join("\n"), {
|
].join("\n"), {
|
||||||
input: input_formatted,
|
input: input_formatted,
|
||||||
output: output,
|
output: output_code,
|
||||||
error: ex,
|
error: ex,
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
@@ -409,7 +409,7 @@ function test_case(test) {
|
|||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
actual = run_code(output, toplevel);
|
actual = run_code(output_code, toplevel);
|
||||||
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
||||||
log([
|
log([
|
||||||
"!!! failed",
|
"!!! failed",
|
||||||
|
|||||||
@@ -1599,7 +1599,7 @@ collapse_vars_constants: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collapse_vars_arguments: {
|
collapse_vars_arguments_1: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
@@ -1636,6 +1636,78 @@ collapse_vars_arguments: {
|
|||||||
expect_stdout: true
|
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: {
|
collapse_vars_short_circuit: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
@@ -8280,3 +8352,211 @@ issue_3976: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -123,6 +123,29 @@ self_comparison_3: {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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: {
|
issue_2857_1: {
|
||||||
options = {
|
options = {
|
||||||
comparisons: true,
|
comparisons: true,
|
||||||
|
|||||||
@@ -1341,3 +1341,24 @@ issue_3967: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1729,7 +1729,7 @@ chained_3: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(a, b) {
|
console.log(function(a, b) {
|
||||||
var c = 2;
|
var c = b;
|
||||||
b++;
|
b++;
|
||||||
return c;
|
return c;
|
||||||
}(0, 2));
|
}(0, 2));
|
||||||
@@ -2718,7 +2718,7 @@ issue_3962_1: {
|
|||||||
0..toString();
|
0..toString();
|
||||||
} while (0);
|
} while (0);
|
||||||
if (c) console.log("PASS");
|
if (c) console.log("PASS");
|
||||||
})((a--, 1));
|
}((a--, 1)), 0);
|
||||||
void 0;
|
void 0;
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -2751,7 +2751,7 @@ issue_3962_2: {
|
|||||||
0..toString();
|
0..toString();
|
||||||
} while (0);
|
} while (0);
|
||||||
if (c) console.log("PASS");
|
if (c) console.log("PASS");
|
||||||
})((a--, 1));
|
}((a--, 1)), 0);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
@@ -2789,3 +2789,62 @@ issue_3986: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "0"
|
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",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -2833,3 +2833,78 @@ issue_3997: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "string"
|
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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -4747,3 +4747,34 @@ issue_3929: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4006: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
(function() {
|
||||||
|
(function(b, c) {
|
||||||
|
for (var k in console.log(c), 0)
|
||||||
|
return b += 0;
|
||||||
|
})(0, --a);
|
||||||
|
return a ? 0 : --a;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
(function(c) {
|
||||||
|
for (var k in console.log(c), 0)
|
||||||
|
return;
|
||||||
|
})(--a), a || --a;
|
||||||
|
}
|
||||||
|
expect_stdout: "-1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,20 @@ must_replace: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repeated_nodes: {
|
||||||
|
options = {
|
||||||
|
global_defs: {
|
||||||
|
"@N": "rand()",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(N, N);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(rand(), rand());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
keyword: {
|
keyword: {
|
||||||
options = {
|
options = {
|
||||||
global_defs: {
|
global_defs: {
|
||||||
|
|||||||
@@ -1016,3 +1016,28 @@ issue_3945_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2544,12 +2544,12 @@ issue_3999: {
|
|||||||
expect: {
|
expect: {
|
||||||
(function() {
|
(function() {
|
||||||
(function f() {
|
(function f() {
|
||||||
for (var c = 0; c < 2; c++)
|
for (var o = 0; o < 2; o++)
|
||||||
try {
|
try {
|
||||||
f[0];
|
f[0];
|
||||||
} catch (f) {
|
} catch (f) {
|
||||||
var f = 0;
|
var f = 0;
|
||||||
console.log(c);
|
console.log(o);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
})(typeof f);
|
})(typeof f);
|
||||||
@@ -2593,3 +2593,124 @@ issue_4001: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -756,7 +756,37 @@ empty_for_in_side_effects: {
|
|||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unused variable b [test/compress/loops.js:4,16]",
|
"WARN: Dropping unused variable b [test/compress/loops.js:4,16]",
|
||||||
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
|
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
|
||||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]",
|
"WARN: Side effects in object of for-in loop [test/compress/loops.js:2,17]",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
empty_for_in_prop_init: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
var a = "bar";
|
||||||
|
for ((a, f)[a] in console.log("foo"));
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = "bar";
|
||||||
|
console.log("foo");
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
expect_warnings: [
|
||||||
|
"INFO: Dropping unused loop variable f [test/compress/loops.js:3,21]",
|
||||||
|
"WARN: Side effects in object of for-in loop [test/compress/loops.js:3,30]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -933,3 +963,49 @@ issue_3634_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
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 = {
|
mangle = {
|
||||||
properties: {
|
properties: {
|
||||||
keep_quoted: false,
|
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: {
|
mangle_unquoted_properties: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
@@ -2031,6 +2031,7 @@ issue_1670_4: {
|
|||||||
|
|
||||||
issue_1670_5: {
|
issue_1670_5: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
keep_fargs: false,
|
keep_fargs: false,
|
||||||
@@ -2062,6 +2063,7 @@ issue_1670_5: {
|
|||||||
|
|
||||||
issue_1670_6: {
|
issue_1670_6: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
keep_fargs: false,
|
keep_fargs: false,
|
||||||
@@ -7383,3 +7385,46 @@ issue_3974: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "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]"
|
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"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
forin: {
|
forin_1: {
|
||||||
options = {
|
options = {
|
||||||
sequences: true,
|
sequences: true,
|
||||||
}
|
}
|
||||||
@@ -895,6 +895,49 @@ forin: {
|
|||||||
expect_stdout: "PASS"
|
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: {
|
call: {
|
||||||
options = {
|
options = {
|
||||||
sequences: true,
|
sequences: true,
|
||||||
@@ -1112,3 +1155,25 @@ issue_3703: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
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"
|
||||||
|
}
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ operator_in: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_3983: {
|
issue_3983_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -323,7 +323,71 @@ issue_3983: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = "PASS";
|
var a = "PASS";
|
||||||
|
g();
|
||||||
|
function g() {}
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
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: {
|
constant_switch_1: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -19,6 +20,7 @@ constant_switch_1: {
|
|||||||
|
|
||||||
constant_switch_2: {
|
constant_switch_2: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -39,6 +41,7 @@ constant_switch_2: {
|
|||||||
|
|
||||||
constant_switch_3: {
|
constant_switch_3: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -60,6 +63,7 @@ constant_switch_3: {
|
|||||||
|
|
||||||
constant_switch_4: {
|
constant_switch_4: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -86,6 +90,7 @@ constant_switch_4: {
|
|||||||
|
|
||||||
constant_switch_5: {
|
constant_switch_5: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -120,6 +125,7 @@ constant_switch_5: {
|
|||||||
|
|
||||||
constant_switch_6: {
|
constant_switch_6: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -154,6 +160,7 @@ constant_switch_6: {
|
|||||||
|
|
||||||
constant_switch_7: {
|
constant_switch_7: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -197,6 +204,7 @@ constant_switch_7: {
|
|||||||
|
|
||||||
constant_switch_8: {
|
constant_switch_8: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -226,6 +234,7 @@ constant_switch_8: {
|
|||||||
|
|
||||||
constant_switch_9: {
|
constant_switch_9: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -315,6 +324,7 @@ keep_default: {
|
|||||||
|
|
||||||
issue_1663: {
|
issue_1663: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -551,6 +561,7 @@ issue_441_2: {
|
|||||||
|
|
||||||
issue_1674: {
|
issue_1674: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -876,6 +887,7 @@ beautify: {
|
|||||||
|
|
||||||
issue_1758: {
|
issue_1758: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
switches: true,
|
switches: true,
|
||||||
}
|
}
|
||||||
@@ -898,15 +910,16 @@ issue_1758: {
|
|||||||
|
|
||||||
issue_2535: {
|
issue_2535: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
switches: true,
|
switches: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
switch(w(), 42) {
|
switch(w(), 42) {
|
||||||
case 13: x();
|
case 13: x();
|
||||||
case 42: y();
|
case 42: y();
|
||||||
default: z();
|
default: z();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
@@ -919,6 +932,7 @@ issue_2535: {
|
|||||||
|
|
||||||
issue_1750: {
|
issue_1750: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
switches: true,
|
switches: true,
|
||||||
@@ -963,6 +977,7 @@ drop_switch_1: {
|
|||||||
|
|
||||||
drop_switch_2: {
|
drop_switch_2: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
switches: true,
|
switches: true,
|
||||||
}
|
}
|
||||||
@@ -1007,6 +1022,7 @@ drop_switch_3: {
|
|||||||
|
|
||||||
drop_switch_4: {
|
drop_switch_4: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
switches: true,
|
switches: true,
|
||||||
}
|
}
|
||||||
@@ -1028,3 +1044,140 @@ drop_switch_4: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
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"
|
||||||
|
}
|
||||||
|
|||||||
4
test/input/invalid/switch.js
Normal file
4
test/input/invalid/switch.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
switch (0) {
|
||||||
|
default:
|
||||||
|
default:
|
||||||
|
}
|
||||||
@@ -330,7 +330,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should fail with invalid syntax", function(done) {
|
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) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
var lines = stderr.split(/\n/);
|
var lines = stderr.split(/\n/);
|
||||||
@@ -342,7 +342,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should fail with correct marking of tabs", function(done) {
|
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) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
var lines = stderr.split(/\n/);
|
var lines = stderr.split(/\n/);
|
||||||
@@ -354,7 +354,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should fail with correct marking at start of line", function(done) {
|
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) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
var lines = stderr.split(/\n/);
|
var lines = stderr.split(/\n/);
|
||||||
@@ -366,7 +366,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should fail with a missing loop body", function(done) {
|
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) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
var lines = stderr.split(/\n/);
|
var lines = stderr.split(/\n/);
|
||||||
@@ -378,7 +378,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (5--)", function(done) {
|
it("Should throw syntax error (5--)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
|
var command = uglifyjscmd + " test/input/invalid/assign_1.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -392,7 +392,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (Math.random() /= 2)", function(done) {
|
it("Should throw syntax error (Math.random() /= 2)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
|
var command = uglifyjscmd + " test/input/invalid/assign_2.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -406,7 +406,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (++this)", function(done) {
|
it("Should throw syntax error (++this)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
|
var command = uglifyjscmd + " test/input/invalid/assign_3.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -420,7 +420,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (++null)", function(done) {
|
it("Should throw syntax error (++null)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
|
var command = uglifyjscmd + " test/input/invalid/assign_4.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -434,7 +434,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (a.=)", function(done) {
|
it("Should throw syntax error (a.=)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
|
var command = uglifyjscmd + " test/input/invalid/dot_1.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -448,7 +448,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (%.a)", function(done) {
|
it("Should throw syntax error (%.a)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
|
var command = uglifyjscmd + " test/input/invalid/dot_2.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -462,7 +462,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (a./();)", function(done) {
|
it("Should throw syntax error (a./();)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
|
var command = uglifyjscmd + " test/input/invalid/dot_3.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -476,7 +476,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error ({%: 1})", function(done) {
|
it("Should throw syntax error ({%: 1})", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/object.js';
|
var command = uglifyjscmd + " test/input/invalid/object.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -490,7 +490,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (delete x)", function(done) {
|
it("Should throw syntax error (delete x)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/delete.js';
|
var command = uglifyjscmd + " test/input/invalid/delete.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -504,7 +504,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (function g(arguments))", function(done) {
|
it("Should throw syntax error (function g(arguments))", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/function_1.js';
|
var command = uglifyjscmd + " test/input/invalid/function_1.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -518,7 +518,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (function eval())", function(done) {
|
it("Should throw syntax error (function eval())", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/function_2.js';
|
var command = uglifyjscmd + " test/input/invalid/function_2.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -532,7 +532,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (iife arguments())", function(done) {
|
it("Should throw syntax error (iife arguments())", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/function_3.js';
|
var command = uglifyjscmd + " test/input/invalid/function_3.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -546,7 +546,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (catch (eval))", function(done) {
|
it("Should throw syntax error (catch (eval))", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/try.js';
|
var command = uglifyjscmd + " test/input/invalid/try.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -560,7 +560,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (var eval)", function(done) {
|
it("Should throw syntax error (var eval)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/var.js';
|
var command = uglifyjscmd + " test/input/invalid/var.js";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -574,7 +574,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (else)", function(done) {
|
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) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -588,7 +588,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (return)", function(done) {
|
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) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -602,7 +602,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (for-in init)", function(done) {
|
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) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -616,7 +616,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (for-in var)", function(done) {
|
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) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
@@ -629,6 +629,18 @@ describe("bin/uglifyjs", function() {
|
|||||||
done();
|
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) {
|
it("Should handle literal string as source map input", function(done) {
|
||||||
var command = [
|
var command = [
|
||||||
uglifyjscmd,
|
uglifyjscmd,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function createContext() {
|
|||||||
arg.constructor.toString();
|
arg.constructor.toString();
|
||||||
if (level--) for (var key in arg) {
|
if (level--) for (var key in arg) {
|
||||||
var desc = Object.getOwnPropertyDescriptor(arg, key);
|
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;
|
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;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -197,6 +197,7 @@ 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 = BINARY_OPS.concat(BINARY_OPS);
|
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||||
|
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||||
BINARY_OPS.push(" in ");
|
BINARY_OPS.push(" in ");
|
||||||
|
|
||||||
var ASSIGNMENTS = [
|
var ASSIGNMENTS = [
|
||||||
@@ -495,11 +496,16 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
var label = createLabel(canBreak, canContinue);
|
var label = createLabel(canBreak, canContinue);
|
||||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||||
var optElementVar = "";
|
var key = rng(10) ? "key" + loop : getVarName();
|
||||||
if (rng(5) > 1) {
|
return [
|
||||||
optElementVar = "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[key" + loop + "]; ";
|
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||||
}
|
label.target + " for (",
|
||||||
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) + "}}";
|
/^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:
|
case STMT_SEMI:
|
||||||
return use_strict && rng(20) === 0 ? '"use strict";' : ";";
|
return use_strict && rng(20) === 0 ? '"use strict";' : ";";
|
||||||
case STMT_EXPR:
|
case STMT_EXPR:
|
||||||
@@ -1136,18 +1142,6 @@ function log(options) {
|
|||||||
errorln(original_result);
|
errorln(original_result);
|
||||||
errorln("uglified result:");
|
errorln("uglified result:");
|
||||||
errorln(uglify_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 {
|
} else {
|
||||||
errorln("// !!! uglify failed !!!");
|
errorln("// !!! uglify failed !!!");
|
||||||
errorln(uglify_code);
|
errorln(uglify_code);
|
||||||
@@ -1158,6 +1152,20 @@ function log(options) {
|
|||||||
errorln(original_result);
|
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("minify(options):");
|
||||||
errorln(JSON.stringify(JSON.parse(options), null, 2));
|
errorln(JSON.stringify(JSON.parse(options), null, 2));
|
||||||
errorln();
|
errorln();
|
||||||
@@ -1172,7 +1180,8 @@ function log(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sort_globals(code) {
|
function sort_globals(code) {
|
||||||
return "var " + sandbox.run_code("throw Object.keys(this).sort();" + code).join(",") + ";" + 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) {
|
function fuzzy_match(original, uglified) {
|
||||||
@@ -1231,7 +1240,7 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
if (typeof result != "object" || typeof result.name != "string" || typeof result.message != "string") {
|
if (typeof result != "object" || typeof result.name != "string" || typeof result.message != "string") {
|
||||||
if (!stack.filled && match[1]) stack.push({
|
if (!stack.filled && match[1]) stack.push({
|
||||||
code: code,
|
code: code,
|
||||||
index: index,
|
index: index && index - 1,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
tries: JSON.parse(JSON.stringify(tries)),
|
tries: JSON.parse(JSON.stringify(tries)),
|
||||||
});
|
});
|
||||||
|
|||||||
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
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