Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38bfb73f06 | ||
|
|
bbedbf4ea0 | ||
|
|
2cfb5aa7da | ||
|
|
6c45101870 | ||
|
|
2c2fd89e34 | ||
|
|
f46281e2b7 | ||
|
|
25a18883f5 | ||
|
|
5b4b07e9a7 | ||
|
|
a8aa28a7a6 | ||
|
|
fe5a68f9d5 | ||
|
|
71e61153b1 | ||
|
|
c8b6f4733d | ||
|
|
a48f87abf2 | ||
|
|
2fd927a7cc | ||
|
|
8428326ea1 | ||
|
|
31f8209193 | ||
|
|
9b0f86f5a1 | ||
|
|
ee082ace1b | ||
|
|
ae67a49850 | ||
|
|
4178289c38 | ||
|
|
74ae16f9f8 | ||
|
|
1968203d83 | ||
|
|
86ea38a259 | ||
|
|
8a713e449f | ||
|
|
24aa07855b | ||
|
|
5fd723f143 | ||
|
|
516eaef50c | ||
|
|
4ae1fb3ed8 | ||
|
|
011123223b | ||
|
|
96439ca246 | ||
|
|
c927cea632 | ||
|
|
9f4b98f8e4 | ||
|
|
0f2ef3367c | ||
|
|
7e5b5cac97 | ||
|
|
c1346e06b7 | ||
|
|
0d2fe8e3ef | ||
|
|
f2b9c11e2a | ||
|
|
fe647b083e |
32
README.md
32
README.md
@@ -221,7 +221,7 @@ to prevent the `require`, `exports` and `$` names from being changed.
|
|||||||
is a separate step, different from variable name mangling. Pass
|
is a separate step, different from variable name mangling. Pass
|
||||||
`--mangle-props` to enable it. It will mangle all properties in the
|
`--mangle-props` to enable it. It will mangle all properties in the
|
||||||
input code with the exception of built in DOM properties and properties
|
input code with the exception of built in DOM properties and properties
|
||||||
in core javascript classes. For example:
|
in core JavaScript classes. For example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// example.js
|
// example.js
|
||||||
@@ -236,7 +236,7 @@ x.bar_ = 2;
|
|||||||
x["baz_"] = 3;
|
x["baz_"] = 3;
|
||||||
console.log(x.calc());
|
console.log(x.calc());
|
||||||
```
|
```
|
||||||
Mangle all properties (except for javascript `builtins`):
|
Mangle all properties (except for JavaScript `builtins`):
|
||||||
```bash
|
```bash
|
||||||
$ uglifyjs example.js -c -m --mangle-props
|
$ uglifyjs example.js -c -m --mangle-props
|
||||||
```
|
```
|
||||||
@@ -515,7 +515,6 @@ if (result.error) throw result.error;
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
warnings: false,
|
|
||||||
parse: {
|
parse: {
|
||||||
// parse options
|
// parse options
|
||||||
},
|
},
|
||||||
@@ -538,6 +537,7 @@ if (result.error) throw result.error;
|
|||||||
nameCache: null, // or specify a name cache object
|
nameCache: null, // or specify a name cache object
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
ie8: false,
|
ie8: false,
|
||||||
|
warnings: false,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -632,6 +632,12 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
|
|
||||||
- `hoist_funs` (default: `true`) -- hoist function declarations
|
- `hoist_funs` (default: `true`) -- hoist function declarations
|
||||||
|
|
||||||
|
- `hoist_props` (default: `false`) -- hoist properties from constant object and
|
||||||
|
array literals into regular variables subject to a set of constraints. For example:
|
||||||
|
`var o={p:1, q:2}; f(o.p, o.q);` is converted to `f(1, 2);`. Note: `hoist_props`
|
||||||
|
works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher,
|
||||||
|
and the `compress` option `toplevel` enabled.
|
||||||
|
|
||||||
- `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)
|
||||||
|
|
||||||
@@ -645,6 +651,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
compressor from discarding unused function arguments. You need this
|
compressor from discarding unused function arguments. You need this
|
||||||
for code which relies on `Function.length`.
|
for code which relies on `Function.length`.
|
||||||
|
|
||||||
|
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
|
||||||
|
compressor from discarding function names. Useful for code relying on
|
||||||
|
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
||||||
|
|
||||||
- `keep_infinity` (default: `false`) -- default `false`. Pass `true` to prevent `Infinity` from
|
- `keep_infinity` (default: `false`) -- default `false`. Pass `true` to prevent `Infinity` from
|
||||||
being compressed into `1/0`, which may cause performance issues on Chrome.
|
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||||
|
|
||||||
@@ -709,6 +719,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
||||||
earlier versions due to known issues.
|
earlier versions due to known issues.
|
||||||
|
|
||||||
|
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
|
||||||
|
|
||||||
- `unsafe_comps` (default: `false`) -- Reverse `<` and `<=` to `>` and `>=` to
|
- `unsafe_comps` (default: `false`) -- Reverse `<` and `<=` to `>` and `>=` to
|
||||||
allow improved compression. This might be unsafe when an at least one of two
|
allow improved compression. This might be unsafe when an at least one of two
|
||||||
operands is an object with computed values due the use of methods like `get`,
|
operands is an object with computed values due the use of methods like `get`,
|
||||||
@@ -716,8 +728,6 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
comparison are switching. Compression only works if both `comparisons` and
|
comparison are switching. Compression only works if both `comparisons` and
|
||||||
`unsafe_comps` are both set to true.
|
`unsafe_comps` are both set to true.
|
||||||
|
|
||||||
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
|
|
||||||
|
|
||||||
- `unsafe_Func` (default: `false`) -- compress and mangle `Function(args, code)`
|
- `unsafe_Func` (default: `false`) -- compress and mangle `Function(args, code)`
|
||||||
when both `args` and `code` are string literals.
|
when both `args` and `code` are string literals.
|
||||||
|
|
||||||
@@ -738,15 +748,19 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
|
|
||||||
## Mangle options
|
## Mangle options
|
||||||
|
|
||||||
|
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
|
||||||
|
where `eval` or `with` are used.
|
||||||
|
|
||||||
|
- `keep_fnames` (default `false`). Pass `true` to not mangle function names.
|
||||||
|
Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
|
||||||
|
[compress option](#compress-options).
|
||||||
|
|
||||||
- `reserved` (default `[]`). Pass an array of identifiers that should be
|
- `reserved` (default `[]`). Pass an array of identifiers that should be
|
||||||
excluded from mangling. Example: `["foo", "bar"]`.
|
excluded from mangling. Example: `["foo", "bar"]`.
|
||||||
|
|
||||||
- `toplevel` (default `false`). Pass `true` to mangle names declared in the
|
- `toplevel` (default `false`). Pass `true` to mangle names declared in the
|
||||||
top level scope.
|
top level scope.
|
||||||
|
|
||||||
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
|
|
||||||
where `eval` or `with` are used.
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -1052,7 +1066,7 @@ in total it's a bit more than just using UglifyJS's own parser.
|
|||||||
### Uglify Fast Minify Mode
|
### Uglify Fast Minify Mode
|
||||||
|
|
||||||
It's not well known, but whitespace removal and symbol mangling accounts
|
It's not well known, but whitespace removal and symbol mangling accounts
|
||||||
for 95% of the size reduction in minified code for most javascript - not
|
for 95% of the size reduction in minified code for most JavaScript - not
|
||||||
elaborate code transforms. One can simply disable `compress` to speed up
|
elaborate code transforms. One can simply disable `compress` to speed up
|
||||||
Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has
|
Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has
|
||||||
comparable minify speeds and gzip sizes to
|
comparable minify speeds and gzip sizes to
|
||||||
|
|||||||
563
lib/compress.js
563
lib/compress.js
@@ -60,6 +60,7 @@ function Compressor(options, false_by_default) {
|
|||||||
expression : false,
|
expression : false,
|
||||||
global_defs : {},
|
global_defs : {},
|
||||||
hoist_funs : !false_by_default,
|
hoist_funs : !false_by_default,
|
||||||
|
hoist_props : false,
|
||||||
hoist_vars : false,
|
hoist_vars : false,
|
||||||
ie8 : false,
|
ie8 : false,
|
||||||
if_return : !false_by_default,
|
if_return : !false_by_default,
|
||||||
@@ -149,9 +150,11 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var passes = +this.options.passes || 1;
|
var passes = +this.options.passes || 1;
|
||||||
var last_count = 1 / 0;
|
var last_count = 1 / 0;
|
||||||
|
var mangle = { ie8: this.option("ie8") };
|
||||||
for (var pass = 0; pass < passes; pass++) {
|
for (var pass = 0; pass < passes; pass++) {
|
||||||
|
node.figure_out_scope(mangle);
|
||||||
if (pass > 0 || this.option("reduce_vars"))
|
if (pass > 0 || this.option("reduce_vars"))
|
||||||
node.reset_opt_flags(this, true);
|
node.reset_opt_flags(this);
|
||||||
node = node.transform(this);
|
node = node.transform(this);
|
||||||
if (passes > 1) {
|
if (passes > 1) {
|
||||||
var count = 0;
|
var count = 0;
|
||||||
@@ -190,6 +193,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node._squeezed) return node;
|
if (node._squeezed) return node;
|
||||||
var was_scope = false;
|
var was_scope = false;
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
|
node = node.hoist_properties(this);
|
||||||
node = node.hoist_declarations(this);
|
node = node.hoist_declarations(this);
|
||||||
was_scope = true;
|
was_scope = true;
|
||||||
}
|
}
|
||||||
@@ -283,8 +287,9 @@ merge(Compressor.prototype, {
|
|||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
|
AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
|
||||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
var reduce_vars = compressor.option("reduce_vars");
|
||||||
|
var unused = compressor.option("unused");
|
||||||
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
||||||
// properly assigned before use:
|
// properly assigned before use:
|
||||||
// - `push()` & `pop()` when visiting conditional branches
|
// - `push()` & `pop()` when visiting conditional branches
|
||||||
@@ -308,16 +313,31 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var d = node.definition();
|
var d = node.definition();
|
||||||
d.references.push(node);
|
d.references.push(node);
|
||||||
if (d.fixed === undefined || !safe_to_read(d)
|
if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") {
|
||||||
|| is_modified(node, 0, is_immutable(node))) {
|
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
|
} else if (d.fixed) {
|
||||||
|
var value = node.fixed_value();
|
||||||
|
if (value && ref_once(d)) {
|
||||||
|
if (value instanceof AST_Lambda) {
|
||||||
|
d.single_use = d.scope === node.scope
|
||||||
|
&& !(d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
|
|| value.is_constant_expression(node.scope);
|
||||||
} else {
|
} else {
|
||||||
var parent = tw.parent();
|
d.single_use = d.scope === node.scope
|
||||||
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|
&& loop_ids[d.id] === in_loop
|
||||||
|| parent instanceof AST_Call && node !== parent.expression
|
&& value.is_constant_expression();
|
||||||
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|
}
|
||||||
|| parent instanceof AST_VarDef && node === parent.value) {
|
} else {
|
||||||
d.escaped = true;
|
d.single_use = false;
|
||||||
|
}
|
||||||
|
if (is_modified(node, value, 0, is_immutable(value))) {
|
||||||
|
if (d.single_use) {
|
||||||
|
d.single_use = "m";
|
||||||
|
} else {
|
||||||
|
d.fixed = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mark_escaped(d, node, value, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,6 +385,10 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
d.fixed = node;
|
d.fixed = node;
|
||||||
mark(d, true);
|
mark(d, true);
|
||||||
|
if (ref_once(d)) {
|
||||||
|
d.single_use = d.scope === d.references[0].scope
|
||||||
|
|| node.is_constant_expression(d.references[0].scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var save_ids = safe_ids;
|
var save_ids = safe_ids;
|
||||||
safe_ids = Object.create(null);
|
safe_ids = Object.create(null);
|
||||||
@@ -404,8 +428,7 @@ merge(Compressor.prototype, {
|
|||||||
pop();
|
pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Binary
|
if (node instanceof AST_Binary && lazy_op(node.operator)) {
|
||||||
&& (node.operator == "&&" || node.operator == "||")) {
|
|
||||||
node.left.walk(tw);
|
node.left.walk(tw);
|
||||||
push();
|
push();
|
||||||
node.right.walk(tw);
|
node.right.walk(tw);
|
||||||
@@ -516,6 +539,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return def.fixed instanceof AST_Defun;
|
||||||
}
|
}
|
||||||
|
|
||||||
function safe_to_assign(def, value) {
|
function safe_to_assign(def, value) {
|
||||||
@@ -538,8 +562,9 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reset_def(def) {
|
function reset_def(def) {
|
||||||
|
def.direct_access = false;
|
||||||
def.escaped = false;
|
def.escaped = false;
|
||||||
if (def.scope.uses_eval) {
|
if (def.scope.uses_eval || def.scope.uses_with) {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
} else if (!compressor.exposed(def)) {
|
} else if (!compressor.exposed(def)) {
|
||||||
def.fixed = undefined;
|
def.fixed = undefined;
|
||||||
@@ -551,34 +576,72 @@ merge(Compressor.prototype, {
|
|||||||
def.single_use = undefined;
|
def.single_use = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_immutable(node) {
|
function ref_once(def) {
|
||||||
var value = node.fixed_value();
|
return unused && !def.scope.uses_eval && !def.scope.uses_with && def.references.length == 1;
|
||||||
if (!value) return false;
|
|
||||||
if (value.is_constant()) return true;
|
|
||||||
if (compressor.option("unused")) {
|
|
||||||
var d = node.definition();
|
|
||||||
if (d.single_use === undefined) {
|
|
||||||
d.single_use = loop_ids[d.id] === in_loop
|
|
||||||
&& d.scope === node.scope
|
|
||||||
&& value.is_constant_expression();
|
|
||||||
}
|
|
||||||
if (d.references.length == 1 && d.single_use) return true;
|
|
||||||
}
|
|
||||||
return value instanceof AST_Lambda;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_modified(node, level, immutable) {
|
function is_immutable(value) {
|
||||||
|
if (!value) return false;
|
||||||
|
return value.is_constant()
|
||||||
|
|| value instanceof AST_Lambda
|
||||||
|
|| value instanceof AST_This;
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_property(obj, key) {
|
||||||
|
if (key instanceof AST_Constant) key = key.getValue();
|
||||||
|
if (key instanceof AST_Node) return null;
|
||||||
|
var value;
|
||||||
|
if (obj instanceof AST_Array) {
|
||||||
|
var elements = obj.elements;
|
||||||
|
if (key == "length") return make_node_from_constant(elements.length, obj);
|
||||||
|
if (typeof key == "number" && key in elements) value = elements[key];
|
||||||
|
} else if (obj instanceof AST_Object) {
|
||||||
|
var props = obj.properties;
|
||||||
|
for (var i = props.length; --i >= 0;) {
|
||||||
|
var prop = props[i];
|
||||||
|
if (!(prop instanceof AST_ObjectKeyVal)) return;
|
||||||
|
if (!value && props[i].key === key) value = props[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value instanceof AST_SymbolRef && value.fixed_value() || value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_modified(node, value, level, immutable) {
|
||||||
var parent = tw.parent(level);
|
var parent = tw.parent(level);
|
||||||
if (is_lhs(node, parent)
|
if (is_lhs(node, parent)
|
||||||
|| !immutable && parent instanceof AST_Call && parent.expression === node) {
|
|| !immutable
|
||||||
|
&& parent instanceof AST_Call
|
||||||
|
&& parent.expression === node
|
||||||
|
&& (!(value instanceof AST_Function) || value.contains_this(parent))) {
|
||||||
return true;
|
return true;
|
||||||
|
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
|
||||||
|
return is_modified(parent, parent, level + 1);
|
||||||
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||||
return !immutable && is_modified(parent, level + 1);
|
return !immutable && is_modified(parent, read_property(value, parent.property), level + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mark_escaped(d, node, value, level) {
|
||||||
|
var parent = tw.parent(level);
|
||||||
|
if (value instanceof AST_Constant || value instanceof AST_Function) return;
|
||||||
|
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|
||||||
|
|| parent instanceof AST_Call && node !== parent.expression
|
||||||
|
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|
||||||
|
|| parent instanceof AST_VarDef && node === parent.value) {
|
||||||
|
d.escaped = true;
|
||||||
|
return;
|
||||||
|
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
|
||||||
|
mark_escaped(d, parent, parent, level + 1);
|
||||||
|
} else if (parent instanceof AST_PropAccess && node === parent.expression) {
|
||||||
|
value = read_property(value, parent.property);
|
||||||
|
mark_escaped(d, parent, value, level + 1);
|
||||||
|
if (value) return;
|
||||||
|
}
|
||||||
|
if (level == 0) d.direct_access = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_SymbolRef.DEFMETHOD("fixed_value", function() {
|
AST_Symbol.DEFMETHOD("fixed_value", function() {
|
||||||
var fixed = this.definition().fixed;
|
var fixed = this.definition().fixed;
|
||||||
if (!fixed || fixed instanceof AST_Node) return fixed;
|
if (!fixed || fixed instanceof AST_Node) return fixed;
|
||||||
return fixed();
|
return fixed();
|
||||||
@@ -729,6 +792,14 @@ merge(Compressor.prototype, {
|
|||||||
|| compressor.option("unsafe") && global_names(this.name);
|
|| compressor.option("unsafe") && global_names(this.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function drop_decl(def) {
|
||||||
|
def._eliminiated = (def._eliminiated || 0) + 1;
|
||||||
|
if (def.orig.length == def._eliminiated) {
|
||||||
|
def.scope.functions.del(def.name);
|
||||||
|
def.scope.variables.del(def.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function tighten_body(statements, compressor) {
|
function tighten_body(statements, compressor) {
|
||||||
var CHANGED, max_iter = 10;
|
var CHANGED, max_iter = 10;
|
||||||
do {
|
do {
|
||||||
@@ -762,6 +833,7 @@ merge(Compressor.prototype, {
|
|||||||
function collapse(statements, compressor) {
|
function collapse(statements, compressor) {
|
||||||
var scope = compressor.find_parent(AST_Scope);
|
var scope = compressor.find_parent(AST_Scope);
|
||||||
if (scope.uses_eval || scope.uses_with) return statements;
|
if (scope.uses_eval || scope.uses_with) return statements;
|
||||||
|
var args;
|
||||||
var candidates = [];
|
var candidates = [];
|
||||||
var stat_index = statements.length;
|
var stat_index = statements.length;
|
||||||
while (--stat_index >= 0) {
|
while (--stat_index >= 0) {
|
||||||
@@ -779,9 +851,10 @@ merge(Compressor.prototype, {
|
|||||||
// 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);
|
||||||
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
||||||
|
var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
|
||||||
var side_effects = value_has_side_effects(candidate);
|
var side_effects = value_has_side_effects(candidate);
|
||||||
var hit = candidate.name instanceof AST_SymbolFunarg;
|
var hit = candidate.name instanceof AST_SymbolFunarg;
|
||||||
var abort = false, replaced = false;
|
var abort = false, replaced = false, can_replace = !args || !hit;
|
||||||
var tt = new TreeTransformer(function(node, descend) {
|
var tt = new TreeTransformer(function(node, descend) {
|
||||||
if (abort) return node;
|
if (abort) return node;
|
||||||
// Skip nodes before `candidate` as quickly as possible
|
// Skip nodes before `candidate` as quickly as possible
|
||||||
@@ -806,7 +879,8 @@ merge(Compressor.prototype, {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
// Replace variable with assignment when found
|
// Replace variable with assignment when found
|
||||||
if (!(node instanceof AST_SymbolDeclaration)
|
if (can_replace
|
||||||
|
&& !(node instanceof AST_SymbolDeclaration)
|
||||||
&& !is_lhs(node, parent)
|
&& !is_lhs(node, parent)
|
||||||
&& lhs.equivalent_to(node)) {
|
&& lhs.equivalent_to(node)) {
|
||||||
CHANGED = replaced = abort = true;
|
CHANGED = replaced = abort = true;
|
||||||
@@ -838,17 +912,18 @@ merge(Compressor.prototype, {
|
|||||||
var sym;
|
var sym;
|
||||||
if (node instanceof AST_Call
|
if (node instanceof AST_Call
|
||||||
|| node instanceof AST_Exit
|
|| node instanceof AST_Exit
|
||||||
|| node instanceof AST_PropAccess && node.has_side_effects(compressor)
|
|| node instanceof AST_PropAccess
|
||||||
|
&& (side_effects || node.expression.may_throw_on_access(compressor))
|
||||||
|| node instanceof AST_SymbolRef
|
|| node instanceof AST_SymbolRef
|
||||||
&& (lvalues[node.name]
|
&& (lvalues[node.name]
|
||||||
|| side_effects && !references_in_scope(node.definition()))
|
|| side_effects && !references_in_scope(node.definition()))
|
||||||
|| (sym = lhs_or_def(node)) && get_symbol(sym).name in lvalues
|
|| (sym = lhs_or_def(node))
|
||||||
|| parent instanceof AST_Binary
|
&& (sym instanceof AST_PropAccess || sym.name in lvalues)
|
||||||
&& (parent.operator == "&&" || parent.operator == "||")
|
|| (side_effects || !one_off)
|
||||||
|
&& (parent instanceof AST_Binary && lazy_op(parent.operator)
|
||||||
|| parent instanceof AST_Case
|
|| parent instanceof AST_Case
|
||||||
|| parent instanceof AST_Conditional
|
|| parent instanceof AST_Conditional
|
||||||
|| parent instanceof AST_For
|
|| parent instanceof AST_If)) {
|
||||||
|| parent instanceof AST_If) {
|
|
||||||
if (!(node instanceof AST_Scope)) descend(node, tt);
|
if (!(node instanceof AST_Scope)) descend(node, tt);
|
||||||
abort = true;
|
abort = true;
|
||||||
return node;
|
return node;
|
||||||
@@ -856,6 +931,12 @@ merge(Compressor.prototype, {
|
|||||||
// Skip (non-executed) functions and (leading) default case in switch statements
|
// Skip (non-executed) functions and (leading) default case in switch statements
|
||||||
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
||||||
});
|
});
|
||||||
|
if (!can_replace) {
|
||||||
|
for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; j < args.length; j++) {
|
||||||
|
args[j].transform(tt);
|
||||||
|
}
|
||||||
|
can_replace = true;
|
||||||
|
}
|
||||||
for (var i = stat_index; !abort && i < statements.length; i++) {
|
for (var i = stat_index; !abort && i < statements.length; i++) {
|
||||||
statements[i].transform(tt);
|
statements[i].transform(tt);
|
||||||
}
|
}
|
||||||
@@ -873,12 +954,18 @@ merge(Compressor.prototype, {
|
|||||||
&& iife.expression === fn) {
|
&& iife.expression === fn) {
|
||||||
var fn_strict = compressor.has_directive("use strict");
|
var fn_strict = compressor.has_directive("use strict");
|
||||||
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
||||||
|
var len = fn.argnames.length;
|
||||||
|
args = iife.args.slice(len);
|
||||||
var names = Object.create(null);
|
var names = Object.create(null);
|
||||||
for (var i = fn.argnames.length; --i >= 0;) {
|
for (var i = len; --i >= 0;) {
|
||||||
var sym = fn.argnames[i];
|
var sym = fn.argnames[i];
|
||||||
|
var arg = iife.args[i];
|
||||||
|
args.unshift(make_node(AST_VarDef, sym, {
|
||||||
|
name: sym,
|
||||||
|
value: arg
|
||||||
|
}));
|
||||||
if (sym.name in names) continue;
|
if (sym.name in names) continue;
|
||||||
names[sym.name] = true;
|
names[sym.name] = true;
|
||||||
var arg = iife.args[i];
|
|
||||||
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
|
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
|
||||||
else {
|
else {
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
@@ -925,7 +1012,8 @@ merge(Compressor.prototype, {
|
|||||||
function get_lhs(expr) {
|
function get_lhs(expr) {
|
||||||
if (expr instanceof AST_VarDef) {
|
if (expr instanceof AST_VarDef) {
|
||||||
var def = expr.name.definition();
|
var def = expr.name.definition();
|
||||||
if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg)
|
if (def.orig.length - (def._eliminiated || 0) > 1
|
||||||
|
&& !(expr.name instanceof AST_SymbolFunarg)
|
||||||
|| def.references.length == 1 && !compressor.exposed(def)) {
|
|| def.references.length == 1 && !compressor.exposed(def)) {
|
||||||
return make_node(AST_SymbolRef, expr.name, expr.name);
|
return make_node(AST_SymbolRef, expr.name, expr.name);
|
||||||
}
|
}
|
||||||
@@ -934,30 +1022,21 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_symbol(node) {
|
function get_rvalue(expr) {
|
||||||
while (node instanceof AST_PropAccess) node = node.expression;
|
return expr[expr instanceof AST_Assign ? "right" : "value"];
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_lvalues(expr) {
|
function get_lvalues(expr) {
|
||||||
var lvalues = Object.create(null);
|
var lvalues = Object.create(null);
|
||||||
if (expr instanceof AST_Unary) return lvalues;
|
if (expr instanceof AST_Unary) return lvalues;
|
||||||
var scope;
|
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
if (node instanceof AST_Scope) {
|
var sym = node;
|
||||||
var save_scope = scope;
|
while (sym instanceof AST_PropAccess) sym = sym.expression;
|
||||||
descend();
|
if (sym instanceof AST_SymbolRef || sym instanceof AST_This) {
|
||||||
scope = save_scope;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_SymbolRef || node instanceof AST_PropAccess) {
|
|
||||||
var sym = get_symbol(node);
|
|
||||||
if (sym instanceof AST_SymbolRef) {
|
|
||||||
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
|
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw);
|
get_rvalue(expr).walk(tw);
|
||||||
return lvalues;
|
return lvalues;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,7 +1060,9 @@ merge(Compressor.prototype, {
|
|||||||
if (node === expr) {
|
if (node === expr) {
|
||||||
found = true;
|
found = true;
|
||||||
if (node instanceof AST_VarDef) {
|
if (node instanceof AST_VarDef) {
|
||||||
remove(node.name.definition().orig, node.name);
|
drop_decl(node.name.definition());
|
||||||
|
node.value = null;
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
return in_list ? MAP.skip : null;
|
return in_list ? MAP.skip : null;
|
||||||
}
|
}
|
||||||
@@ -990,16 +1071,13 @@ merge(Compressor.prototype, {
|
|||||||
case 0: return null;
|
case 0: return null;
|
||||||
case 1: return node.expressions[0];
|
case 1: return node.expressions[0];
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && node.definitions.length == 0
|
if (node instanceof AST_SimpleStatement && !node.body) return null;
|
||||||
|| node instanceof AST_SimpleStatement && !node.body) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function value_has_side_effects(expr) {
|
function value_has_side_effects(expr) {
|
||||||
if (expr instanceof AST_Unary) return false;
|
if (expr instanceof AST_Unary) return false;
|
||||||
return expr[expr instanceof AST_Assign ? "right" : "value"].has_side_effects(compressor);
|
return get_rvalue(expr).has_side_effects(compressor);
|
||||||
}
|
}
|
||||||
|
|
||||||
function references_in_scope(def) {
|
function references_in_scope(def) {
|
||||||
@@ -1431,9 +1509,10 @@ merge(Compressor.prototype, {
|
|||||||
return member(this.operator, unary_bool);
|
return member(this.operator, unary_bool);
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(){
|
def(AST_Binary, function(){
|
||||||
return member(this.operator, binary_bool) ||
|
return member(this.operator, binary_bool)
|
||||||
( (this.operator == "&&" || this.operator == "||") &&
|
|| lazy_op(this.operator)
|
||||||
this.left.is_boolean() && this.right.is_boolean() );
|
&& this.left.is_boolean()
|
||||||
|
&& this.right.is_boolean();
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(){
|
def(AST_Conditional, function(){
|
||||||
return this.consequent.is_boolean() && this.alternative.is_boolean();
|
return this.consequent.is_boolean() && this.alternative.is_boolean();
|
||||||
@@ -1502,6 +1581,7 @@ merge(Compressor.prototype, {
|
|||||||
node.DEFMETHOD("is_string", func);
|
node.DEFMETHOD("is_string", func);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var lazy_op = makePredicate("&& ||");
|
||||||
var unary_side_effects = makePredicate("delete ++ --");
|
var unary_side_effects = makePredicate("delete ++ --");
|
||||||
|
|
||||||
function is_lhs(node, parent) {
|
function is_lhs(node, parent) {
|
||||||
@@ -1613,35 +1693,6 @@ merge(Compressor.prototype, {
|
|||||||
&& unaryPrefix(this.operator);
|
&& unaryPrefix(this.operator);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Obtain the constant value of an expression already known to be constant.
|
|
||||||
// Result only valid iff this.is_constant() is true.
|
|
||||||
AST_Node.DEFMETHOD("constant_value", function(compressor){
|
|
||||||
// Accomodate when option evaluate=false.
|
|
||||||
if (this instanceof AST_Constant && !(this instanceof AST_RegExp)) {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
// Accomodate the common constant expressions !0 and -1 when option evaluate=false.
|
|
||||||
if (this instanceof AST_UnaryPrefix
|
|
||||||
&& this.expression instanceof AST_Constant) switch (this.operator) {
|
|
||||||
case "!":
|
|
||||||
return !this.expression.value;
|
|
||||||
case "~":
|
|
||||||
return ~this.expression.value;
|
|
||||||
case "-":
|
|
||||||
return -this.expression.value;
|
|
||||||
case "+":
|
|
||||||
return +this.expression.value;
|
|
||||||
default:
|
|
||||||
throw new Error(string_template("Cannot evaluate unary expression {value}", {
|
|
||||||
value: this.print_to_string()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
var result = this.evaluate(compressor);
|
|
||||||
if (result !== this) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
throw new Error(string_template("Cannot evaluate constant [{file}:{line},{col}]", this.start));
|
|
||||||
});
|
|
||||||
def(AST_Statement, function(){
|
def(AST_Statement, function(){
|
||||||
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
||||||
});
|
});
|
||||||
@@ -1660,6 +1711,7 @@ merge(Compressor.prototype, {
|
|||||||
var elements = [];
|
var elements = [];
|
||||||
for (var i = 0, len = this.elements.length; i < len; i++) {
|
for (var i = 0, len = this.elements.length; i < len; i++) {
|
||||||
var element = this.elements[i];
|
var element = this.elements[i];
|
||||||
|
if (element instanceof AST_Function) continue;
|
||||||
var value = ev(element, compressor);
|
var value = ev(element, compressor);
|
||||||
if (element === value) return this;
|
if (element === value) return this;
|
||||||
elements.push(value);
|
elements.push(value);
|
||||||
@@ -1683,6 +1735,7 @@ merge(Compressor.prototype, {
|
|||||||
if (typeof Object.prototype[key] === 'function') {
|
if (typeof Object.prototype[key] === 'function') {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
if (prop.value instanceof AST_Function) continue;
|
||||||
val[key] = ev(prop.value, compressor);
|
val[key] = ev(prop.value, compressor);
|
||||||
if (val[key] === prop.value) return this;
|
if (val[key] === prop.value) return this;
|
||||||
}
|
}
|
||||||
@@ -2141,18 +2194,22 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
def(AST_Node, return_false);
|
def(AST_Node, return_false);
|
||||||
def(AST_Constant, return_true);
|
def(AST_Constant, return_true);
|
||||||
def(AST_Function, function(){
|
def(AST_Lambda, function(scope){
|
||||||
var self = this;
|
var self = this;
|
||||||
var result = true;
|
var result = true;
|
||||||
self.walk(new TreeWalker(function(node) {
|
self.walk(new TreeWalker(function(node) {
|
||||||
if (!result) return true;
|
if (!result) return true;
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
if (self.enclosed.indexOf(def) >= 0
|
if (member(def, self.enclosed)
|
||||||
&& self.variables.get(def.name) !== def) {
|
&& !self.variables.has(def.name)) {
|
||||||
result = false;
|
if (scope) {
|
||||||
return true;
|
var scope_def = scope.find_variable(node);
|
||||||
|
if (def.undeclared ? !scope_def : scope_def === def) return true;
|
||||||
}
|
}
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
return result;
|
return result;
|
||||||
@@ -2240,7 +2297,6 @@ merge(Compressor.prototype, {
|
|||||||
if (self.uses_eval || self.uses_with) return;
|
if (self.uses_eval || self.uses_with) return;
|
||||||
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
|
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
|
||||||
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
|
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||||
if (!drop_funcs && !drop_vars) return;
|
|
||||||
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node) {
|
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node) {
|
||||||
if (node instanceof AST_Assign && (node.write_only || node.operator == "=")) {
|
if (node instanceof AST_Assign && (node.write_only || node.operator == "=")) {
|
||||||
return node.left;
|
return node.left;
|
||||||
@@ -2263,7 +2319,7 @@ merge(Compressor.prototype, {
|
|||||||
// this scope (not in nested scopes).
|
// this scope (not in nested scopes).
|
||||||
var scope = this;
|
var scope = this;
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node !== self) {
|
if (node === self) return;
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
if (!drop_funcs && scope === self) {
|
if (!drop_funcs && scope === self) {
|
||||||
var node_def = node.name.definition();
|
var node_def = node.name.definition();
|
||||||
@@ -2275,6 +2331,9 @@ merge(Compressor.prototype, {
|
|||||||
initializations.add(node.name.name, node);
|
initializations.add(node.name.name, node);
|
||||||
return true; // don't go in nested scopes
|
return true; // don't go in nested scopes
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_SymbolFunarg && scope === self) {
|
||||||
|
var_defs_by_id.add(node.definition().id, node);
|
||||||
|
}
|
||||||
if (node instanceof AST_Definitions && scope === self) {
|
if (node instanceof AST_Definitions && scope === self) {
|
||||||
node.definitions.forEach(function(def){
|
node.definitions.forEach(function(def){
|
||||||
var node_def = def.name.definition();
|
var node_def = def.name.definition();
|
||||||
@@ -2296,7 +2355,10 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (assign_as_unused(node) instanceof AST_SymbolRef && scope === self) {
|
var sym;
|
||||||
|
if (scope === self
|
||||||
|
&& (sym = assign_as_unused(node)) instanceof AST_SymbolRef
|
||||||
|
&& self.variables.get(sym.name) === sym.definition()) {
|
||||||
if (node instanceof AST_Assign) node.right.walk(tw);
|
if (node instanceof AST_Assign) node.right.walk(tw);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2315,7 +2377,6 @@ merge(Compressor.prototype, {
|
|||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
// pass 2: for every used symbol we need to walk its
|
// pass 2: for every used symbol we need to walk its
|
||||||
@@ -2369,13 +2430,16 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
||||||
if (!(node.name.definition().id in in_use_ids)) {
|
var def = node.name.definition();
|
||||||
|
if (!(def.id in in_use_ids)) {
|
||||||
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
||||||
|
drop_decl(def);
|
||||||
return make_node(AST_EmptyStatement, node);
|
return make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (drop_vars && node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn && tt.parent().init === node)) {
|
var parent = tt.parent();
|
||||||
|
if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
|
||||||
// place uninitialized names at the start
|
// place uninitialized names at the start
|
||||||
var body = [], head = [], tail = [];
|
var body = [], head = [], tail = [];
|
||||||
// for unused names whose initialization has
|
// for unused names whose initialization has
|
||||||
@@ -2385,13 +2449,13 @@ merge(Compressor.prototype, {
|
|||||||
node.definitions.forEach(function(def) {
|
node.definitions.forEach(function(def) {
|
||||||
if (def.value) def.value = def.value.transform(tt);
|
if (def.value) def.value = def.value.transform(tt);
|
||||||
var sym = def.name.definition();
|
var sym = def.name.definition();
|
||||||
if (sym.id in in_use_ids) {
|
if (!drop_vars || sym.id in in_use_ids) {
|
||||||
if (def.name instanceof AST_SymbolVar) {
|
if (def.name instanceof AST_SymbolVar) {
|
||||||
var var_defs = var_defs_by_id.get(sym.id);
|
var var_defs = var_defs_by_id.get(sym.id);
|
||||||
if (var_defs.length > 1 && !def.value) {
|
if (var_defs.length > 1 && !def.value) {
|
||||||
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
remove(var_defs, def);
|
remove(var_defs, def);
|
||||||
remove(sym.orig, def.name);
|
drop_decl(sym);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2424,7 +2488,7 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
|
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
}
|
}
|
||||||
remove(sym.orig, def.name);
|
drop_decl(sym);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
|
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
|
||||||
@@ -2433,7 +2497,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = tail.pop();
|
var def = tail.pop();
|
||||||
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
|
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
|
||||||
remove(var_defs, def);
|
remove(var_defs, def);
|
||||||
remove(def.name.definition().orig, def.name);
|
drop_decl(def.name.definition());
|
||||||
side_effects.unshift(make_node(AST_Assign, def, {
|
side_effects.unshift(make_node(AST_Assign, def, {
|
||||||
operator: "=",
|
operator: "=",
|
||||||
left: make_node(AST_SymbolRef, def.name, def.name),
|
left: make_node(AST_SymbolRef, def.name, def.name),
|
||||||
@@ -2462,12 +2526,11 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (drop_vars) {
|
if (drop_vars) {
|
||||||
var def = assign_as_unused(node);
|
var sym = assign_as_unused(node);
|
||||||
if (def instanceof AST_SymbolRef
|
if (sym instanceof AST_SymbolRef
|
||||||
&& !((def = def.definition()).id in in_use_ids)
|
&& !(sym.definition().id in in_use_ids)) {
|
||||||
&& self.variables.get(def.name) === def) {
|
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
|
return maintain_this_binding(parent, node, node.right.transform(tt));
|
||||||
}
|
}
|
||||||
return make_node(AST_Number, node, {
|
return make_node(AST_Number, node, {
|
||||||
value: 0
|
value: 0
|
||||||
@@ -2651,6 +2714,71 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Scope.DEFMETHOD("hoist_properties", function(compressor){
|
||||||
|
var self = this;
|
||||||
|
if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self;
|
||||||
|
var defs_by_id = Object.create(null);
|
||||||
|
var var_names = Object.create(null);
|
||||||
|
self.enclosed.forEach(function(def) {
|
||||||
|
var_names[def.name] = true;
|
||||||
|
});
|
||||||
|
self.variables.each(function(def, name) {
|
||||||
|
var_names[name] = true;
|
||||||
|
});
|
||||||
|
return self.transform(new TreeTransformer(function(node) {
|
||||||
|
if (node instanceof AST_VarDef) {
|
||||||
|
var sym = node.name, def, value;
|
||||||
|
if (sym.scope === self
|
||||||
|
&& !(def = sym.definition()).escaped
|
||||||
|
&& !def.single_use
|
||||||
|
&& !def.direct_access
|
||||||
|
&& (value = sym.fixed_value()) === node.value
|
||||||
|
&& value instanceof AST_Object) {
|
||||||
|
var defs = new Dictionary();
|
||||||
|
var assignments = [];
|
||||||
|
value.properties.forEach(function(prop) {
|
||||||
|
assignments.push(make_node(AST_VarDef, node, {
|
||||||
|
name: make_sym(prop.key),
|
||||||
|
value: prop.value
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
defs_by_id[def.id] = defs;
|
||||||
|
return MAP.splice(assignments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node instanceof AST_PropAccess && node.expression instanceof AST_SymbolRef) {
|
||||||
|
var defs = defs_by_id[node.expression.definition().id];
|
||||||
|
if (defs) {
|
||||||
|
var key = node.property;
|
||||||
|
if (key instanceof AST_Node) key = key.getValue();
|
||||||
|
var def = defs.get(key);
|
||||||
|
var sym = make_node(AST_SymbolRef, node, {
|
||||||
|
name: def.name,
|
||||||
|
scope: node.expression.scope,
|
||||||
|
thedef: def
|
||||||
|
});
|
||||||
|
sym.reference({});
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_sym(key) {
|
||||||
|
var prefix = sym.name + "_" + key.toString().replace(/[^a-z_$]+/ig, "_");
|
||||||
|
var name = prefix;
|
||||||
|
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
|
||||||
|
var new_var = make_node(sym.CTOR, sym, {
|
||||||
|
name: name,
|
||||||
|
scope: self
|
||||||
|
});
|
||||||
|
var def = self.def_variable(new_var);
|
||||||
|
defs.set(key, def);
|
||||||
|
self.enclosed.push(def);
|
||||||
|
var_names[name] = true;
|
||||||
|
return new_var;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
// drop_side_effect_free()
|
// drop_side_effect_free()
|
||||||
// remove side-effect-free parts which only affects return value
|
// remove side-effect-free parts which only affects return value
|
||||||
(function(def){
|
(function(def){
|
||||||
@@ -2698,14 +2826,12 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Binary, function(compressor, first_in_statement){
|
def(AST_Binary, function(compressor, first_in_statement){
|
||||||
var right = this.right.drop_side_effect_free(compressor);
|
var right = this.right.drop_side_effect_free(compressor);
|
||||||
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||||
switch (this.operator) {
|
if (lazy_op(this.operator)) {
|
||||||
case "&&":
|
|
||||||
case "||":
|
|
||||||
if (right === this.right) return this;
|
if (right === this.right) return this;
|
||||||
var node = this.clone();
|
var node = this.clone();
|
||||||
node.right = right;
|
node.right = right;
|
||||||
return node;
|
return node;
|
||||||
default:
|
} else {
|
||||||
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
|
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||||
return make_sequence(this, [ left, right ]);
|
return make_sequence(this, [ left, right ]);
|
||||||
@@ -3172,7 +3298,7 @@ merge(Compressor.prototype, {
|
|||||||
}));
|
}));
|
||||||
if (reduce_vars) name.definition().fixed = false;
|
if (reduce_vars) name.definition().fixed = false;
|
||||||
}
|
}
|
||||||
remove(def.name.definition().orig, def.name);
|
drop_decl(def.name.definition());
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
if (assignments.length == 0) return null;
|
if (assignments.length == 0) return null;
|
||||||
@@ -3414,6 +3540,7 @@ merge(Compressor.prototype, {
|
|||||||
&& !exp.uses_arguments
|
&& !exp.uses_arguments
|
||||||
&& !exp.uses_eval
|
&& !exp.uses_eval
|
||||||
&& exp.body.length == 1
|
&& exp.body.length == 1
|
||||||
|
&& !exp.contains_this()
|
||||||
&& all(exp.argnames, function(arg) {
|
&& all(exp.argnames, function(arg) {
|
||||||
return arg.__unused;
|
return arg.__unused;
|
||||||
})
|
})
|
||||||
@@ -3427,23 +3554,6 @@ merge(Compressor.prototype, {
|
|||||||
expression: stat.body
|
expression: stat.body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (value) {
|
|
||||||
var tw = new TreeWalker(function(node) {
|
|
||||||
if (!value) return true;
|
|
||||||
if (node instanceof AST_SymbolRef) {
|
|
||||||
var ref = node.scope.find_variable(node);
|
|
||||||
if (ref && ref.scope.parent_scope === fn.parent_scope) {
|
|
||||||
value = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
|
|
||||||
value = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
value.walk(tw);
|
|
||||||
}
|
|
||||||
if (value) {
|
if (value) {
|
||||||
var args = self.args.concat(value);
|
var args = self.args.concat(value);
|
||||||
return make_sequence(self, args).optimize(compressor);
|
return make_sequence(self, args).optimize(compressor);
|
||||||
@@ -3571,7 +3681,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) {
|
if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) {
|
||||||
if (cdr.left.is_constant()) {
|
if (cdr.left.is_constant()) {
|
||||||
if (cdr.operator == "||" || cdr.operator == "&&") {
|
if (lazy_op(cdr.operator)) {
|
||||||
expressions[++i] = expressions[j];
|
expressions[++i] = expressions[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3727,6 +3837,11 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
|
function is_object(node) {
|
||||||
|
return node instanceof AST_Array
|
||||||
|
|| node instanceof AST_Lambda
|
||||||
|
|| node instanceof AST_Object;
|
||||||
|
}
|
||||||
|
|
||||||
OPT(AST_Binary, function(self, compressor){
|
OPT(AST_Binary, function(self, compressor){
|
||||||
function reversible() {
|
function reversible() {
|
||||||
@@ -3762,7 +3877,8 @@ merge(Compressor.prototype, {
|
|||||||
case "!==":
|
case "!==":
|
||||||
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
||||||
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
||||||
(self.left.is_boolean() && self.right.is_boolean())) {
|
(self.left.is_boolean() && self.right.is_boolean()) ||
|
||||||
|
self.left.equivalent_to(self.right)) {
|
||||||
self.operator = self.operator.substr(0, 2);
|
self.operator = self.operator.substr(0, 2);
|
||||||
}
|
}
|
||||||
// XXX: intentionally falling down to the next case
|
// XXX: intentionally falling down to the next case
|
||||||
@@ -3782,6 +3898,13 @@ merge(Compressor.prototype, {
|
|||||||
if (self.operator.length == 2) self.operator += "=";
|
if (self.operator.length == 2) self.operator += "=";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// obj !== obj => false
|
||||||
|
else if (self.left instanceof AST_SymbolRef
|
||||||
|
&& self.right instanceof AST_SymbolRef
|
||||||
|
&& self.left.definition() === self.right.definition()
|
||||||
|
&& is_object(self.left.fixed_value())) {
|
||||||
|
return make_node(self.operator[0] == "=" ? AST_True : AST_False, self);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (compressor.option("booleans") && self.operator == "+" && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && self.operator == "+" && compressor.in_boolean_context()) {
|
||||||
@@ -4071,8 +4194,7 @@ merge(Compressor.prototype, {
|
|||||||
// "x" + (y + "z")==> "x" + y + "z"
|
// "x" + (y + "z")==> "x" + y + "z"
|
||||||
if (self.right instanceof AST_Binary
|
if (self.right instanceof AST_Binary
|
||||||
&& self.right.operator == self.operator
|
&& self.right.operator == self.operator
|
||||||
&& (self.operator == "&&"
|
&& (lazy_op(self.operator)
|
||||||
|| self.operator == "||"
|
|
||||||
|| (self.operator == "+"
|
|| (self.operator == "+"
|
||||||
&& (self.right.left.is_string(compressor)
|
&& (self.right.left.is_string(compressor)
|
||||||
|| (self.left.is_string(compressor)
|
|| (self.left.is_string(compressor)
|
||||||
@@ -4119,20 +4241,37 @@ merge(Compressor.prototype, {
|
|||||||
if (fixed instanceof AST_Defun) {
|
if (fixed instanceof AST_Defun) {
|
||||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||||
}
|
}
|
||||||
if (compressor.option("unused")
|
if (fixed && d.single_use) {
|
||||||
&& d.references.length == 1
|
var recurse;
|
||||||
&& (d.single_use || fixed instanceof AST_Function
|
if (fixed instanceof AST_Function) {
|
||||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
for (var i = 0; recurse = compressor.parent(i); i++) {
|
||||||
&& !d.scope.uses_eval
|
if (recurse instanceof AST_Lambda) {
|
||||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope)) {
|
var name = recurse.name;
|
||||||
|
if (name && name.definition() === d) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!recurse) {
|
||||||
var value = fixed.optimize(compressor);
|
var value = fixed.optimize(compressor);
|
||||||
return value === fixed ? fixed.clone(true) : value;
|
return value === fixed ? fixed.clone(true) : value;
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate") && fixed) {
|
}
|
||||||
if (d.should_replace === undefined) {
|
if (fixed && d.should_replace === undefined) {
|
||||||
var init = fixed.evaluate(compressor);
|
var init;
|
||||||
if (init !== fixed && (compressor.option("unsafe_regexp") || !(init instanceof RegExp))) {
|
if (fixed instanceof AST_This) {
|
||||||
init = make_node_from_constant(init, fixed);
|
if (!(d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
|
&& all(d.references, function(ref) {
|
||||||
|
return d.scope === ref.scope;
|
||||||
|
})) {
|
||||||
|
init = fixed;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var ev = fixed.evaluate(compressor);
|
||||||
|
if (ev !== fixed && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))) {
|
||||||
|
init = make_node_from_constant(ev, fixed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (init) {
|
||||||
var value_length = init.optimize(compressor).print_to_string().length;
|
var value_length = init.optimize(compressor).print_to_string().length;
|
||||||
var fn;
|
var fn;
|
||||||
if (has_symbol_ref(fixed)) {
|
if (has_symbol_ref(fixed)) {
|
||||||
@@ -4161,7 +4300,6 @@ merge(Compressor.prototype, {
|
|||||||
return d.should_replace();
|
return d.should_replace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
function has_symbol_ref(value) {
|
function has_symbol_ref(value) {
|
||||||
@@ -4454,19 +4592,69 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Sub, function(self, compressor){
|
OPT(AST_Sub, function(self, compressor){
|
||||||
|
var expr = self.expression;
|
||||||
var prop = self.property;
|
var prop = self.property;
|
||||||
if (prop instanceof AST_String && compressor.option("properties")) {
|
if (compressor.option("properties")) {
|
||||||
prop = prop.getValue();
|
var key = prop.evaluate(compressor);
|
||||||
if (is_identifier_string(prop)) {
|
if (key !== prop) {
|
||||||
|
var property = "" + key;
|
||||||
|
if (is_identifier_string(property)
|
||||||
|
&& property.length <= prop.print_to_string().length + 1) {
|
||||||
return make_node(AST_Dot, self, {
|
return make_node(AST_Dot, self, {
|
||||||
expression : self.expression,
|
expression: expr,
|
||||||
property : prop
|
property: property
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
var v = parseFloat(prop);
|
if (!(prop instanceof AST_Number)) {
|
||||||
if (!isNaN(v) && v.toString() == prop) {
|
var value = parseFloat(property);
|
||||||
self.property = make_node(AST_Number, self.property, {
|
if (value.toString() == property) {
|
||||||
value: v
|
prop = self.property = make_node(AST_Number, prop, {
|
||||||
|
value: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_lhs(self, compressor.parent())) return self;
|
||||||
|
if (key !== prop) {
|
||||||
|
var sub = self.flatten_object(property, compressor);
|
||||||
|
if (sub) {
|
||||||
|
expr = self.expression = sub.expression;
|
||||||
|
prop = self.property = sub.property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (compressor.option("properties") && compressor.option("side_effects")
|
||||||
|
&& prop instanceof AST_Number && expr instanceof AST_Array) {
|
||||||
|
var index = prop.getValue();
|
||||||
|
var elements = expr.elements;
|
||||||
|
if (index in elements) {
|
||||||
|
var flatten = true;
|
||||||
|
var values = [];
|
||||||
|
for (var i = elements.length; --i > index;) {
|
||||||
|
var value = elements[i].drop_side_effect_free(compressor);
|
||||||
|
if (value) {
|
||||||
|
values.unshift(value);
|
||||||
|
if (flatten && value.has_side_effects(compressor)) flatten = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var retValue = elements[index];
|
||||||
|
retValue = retValue instanceof AST_Hole ? make_node(AST_Undefined, retValue) : retValue;
|
||||||
|
if (!flatten) values.unshift(retValue);
|
||||||
|
while (--i >= 0) {
|
||||||
|
var value = elements[i].drop_side_effect_free(compressor);
|
||||||
|
if (value) values.unshift(value);
|
||||||
|
else index--;
|
||||||
|
}
|
||||||
|
if (flatten) {
|
||||||
|
values.push(retValue);
|
||||||
|
return make_sequence(self, values).optimize(compressor);
|
||||||
|
} else return make_node(AST_Sub, self, {
|
||||||
|
expression: make_node(AST_Array, expr, {
|
||||||
|
elements: values
|
||||||
|
}),
|
||||||
|
property: make_node(AST_Number, prop, {
|
||||||
|
value: index
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4478,7 +4666,8 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("contains_this", function() {
|
AST_Lambda.DEFMETHOD("contains_this", function(grandparent) {
|
||||||
|
if (grandparent instanceof AST_New) return false;
|
||||||
var result;
|
var result;
|
||||||
var self = this;
|
var self = this;
|
||||||
self.walk(new TreeWalker(function(node) {
|
self.walk(new TreeWalker(function(node) {
|
||||||
@@ -4489,25 +4678,40 @@ merge(Compressor.prototype, {
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
|
||||||
|
if (!compressor.option("properties")) return;
|
||||||
|
var expr = this.expression;
|
||||||
|
if (expr instanceof AST_Object) {
|
||||||
|
var props = expr.properties;
|
||||||
|
for (var i = props.length; --i >= 0;) {
|
||||||
|
var prop = props[i];
|
||||||
|
if ("" + prop.key == key) {
|
||||||
|
if (!all(props, function(prop) {
|
||||||
|
return prop instanceof AST_ObjectKeyVal;
|
||||||
|
})) break;
|
||||||
|
var value = prop.value;
|
||||||
|
if (value instanceof AST_Function
|
||||||
|
&& value.contains_this(compressor.parent())) break;
|
||||||
|
return make_node(AST_Sub, this, {
|
||||||
|
expression: make_node(AST_Array, expr, {
|
||||||
|
elements: props.map(function(prop) {
|
||||||
|
return prop.value;
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
property: make_node(AST_Number, this, {
|
||||||
|
value: i
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
OPT(AST_Dot, function(self, compressor){
|
OPT(AST_Dot, function(self, compressor){
|
||||||
var def = self.resolve_defines(compressor);
|
var def = self.resolve_defines(compressor);
|
||||||
if (def) {
|
if (def) {
|
||||||
return def.optimize(compressor);
|
return def.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe") && self.expression instanceof AST_Object) {
|
|
||||||
var values = self.expression.properties;
|
|
||||||
for (var i = values.length; --i >= 0;) {
|
|
||||||
if (values[i].key === self.property) {
|
|
||||||
var value = values[i].value;
|
|
||||||
if (value instanceof AST_Function ? !value.contains_this() : !value.has_side_effects(compressor)) {
|
|
||||||
var obj = self.expression.clone();
|
|
||||||
obj.properties = obj.properties.slice();
|
|
||||||
obj.properties.splice(i, 1);
|
|
||||||
return make_sequence(self, [ obj, value ]).optimize(compressor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (compressor.option("unsafe_proto")
|
if (compressor.option("unsafe_proto")
|
||||||
&& self.expression instanceof AST_Dot
|
&& self.expression instanceof AST_Dot
|
||||||
&& self.expression.property == "prototype") {
|
&& self.expression.property == "prototype") {
|
||||||
@@ -4530,6 +4734,9 @@ merge(Compressor.prototype, {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (is_lhs(self, compressor.parent())) return self;
|
||||||
|
var sub = self.flatten_object(self.property, compressor);
|
||||||
|
if (sub) return sub.optimize(compressor);
|
||||||
var ev = self.evaluate(compressor);
|
var ev = self.evaluate(compressor);
|
||||||
if (ev !== self) {
|
if (ev !== self) {
|
||||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||||
|
|||||||
@@ -137,11 +137,9 @@ function minify(files, options) {
|
|||||||
if (options.wrap) {
|
if (options.wrap) {
|
||||||
toplevel = toplevel.wrap_commonjs(options.wrap);
|
toplevel = toplevel.wrap_commonjs(options.wrap);
|
||||||
}
|
}
|
||||||
if (timings) timings.scope1 = Date.now();
|
|
||||||
if (options.compress) toplevel.figure_out_scope(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 (timings) timings.scope2 = 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();
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
@@ -199,9 +197,9 @@ function minify(files, options) {
|
|||||||
if (timings) {
|
if (timings) {
|
||||||
timings.end = Date.now();
|
timings.end = Date.now();
|
||||||
result.timings = {
|
result.timings = {
|
||||||
parse: 1e-3 * (timings.scope1 - timings.parse),
|
parse: 1e-3 * (timings.compress - timings.parse),
|
||||||
scope: 1e-3 * (timings.compress - timings.scope1 + timings.mangle - timings.scope2),
|
compress: 1e-3 * (timings.scope - timings.compress),
|
||||||
compress: 1e-3 * (timings.scope2 - timings.compress),
|
scope: 1e-3 * (timings.mangle - timings.scope),
|
||||||
mangle: 1e-3 * (timings.properties - timings.mangle),
|
mangle: 1e-3 * (timings.properties - timings.mangle),
|
||||||
properties: 1e-3 * (timings.output - timings.properties),
|
properties: 1e-3 * (timings.output - timings.properties),
|
||||||
output: 1e-3 * (timings.end - timings.output),
|
output: 1e-3 * (timings.end - timings.output),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.1.4",
|
"version": "3.1.8",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -128,50 +128,110 @@ constant_join_3: {
|
|||||||
|
|
||||||
for_loop: {
|
for_loop: {
|
||||||
options = {
|
options = {
|
||||||
unsafe : true,
|
evaluate: true,
|
||||||
unused : true,
|
reduce_vars: true,
|
||||||
evaluate : true,
|
unsafe: true,
|
||||||
reduce_vars : true
|
unused: true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
function f0() {
|
function f0() {
|
||||||
var a = [1, 2, 3];
|
var a = [1, 2, 3];
|
||||||
for (var i = 0; i < a.length; i++) {
|
var b = 0;
|
||||||
console.log(a[i]);
|
for (var i = 0; i < a.length; i++)
|
||||||
|
b += a[i];
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function f1() {
|
function f1() {
|
||||||
var a = [1, 2, 3];
|
var a = [1, 2, 3];
|
||||||
for (var i = 0, len = a.length; i < len; i++) {
|
var b = 0;
|
||||||
console.log(a[i]);
|
for (var i = 0, len = a.length; i < len; i++)
|
||||||
|
b += a[i];
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function f2() {
|
|
||||||
var a = [1, 2, 3];
|
|
||||||
for (var i = 0; i < a.length; i++) {
|
|
||||||
a[i]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function f0() {
|
|
||||||
var a = [1, 2, 3];
|
|
||||||
for (var i = 0; i < 3; i++)
|
|
||||||
console.log(a[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function f1() {
|
|
||||||
var a = [1, 2, 3];
|
|
||||||
for (var i = 0; i < 3; i++)
|
|
||||||
console.log(a[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function f2() {
|
function f2() {
|
||||||
var a = [1, 2, 3];
|
var a = [1, 2, 3];
|
||||||
for (var i = 0; i < a.length; i++)
|
for (var i = 0; i < a.length; i++)
|
||||||
a[i]++;
|
a[i]++;
|
||||||
|
return a[2];
|
||||||
}
|
}
|
||||||
|
console.log(f0(), f1(), f2());
|
||||||
}
|
}
|
||||||
|
expect: {
|
||||||
|
function f0() {
|
||||||
|
var a = [1, 2, 3];
|
||||||
|
var b = 0;
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
b += a[i];
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
function f1() {
|
||||||
|
var a = [1, 2, 3];
|
||||||
|
var b = 0;
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
b += a[i];
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
var a = [1, 2, 3];
|
||||||
|
for (var i = 0; i < a.length; i++)
|
||||||
|
a[i]++;
|
||||||
|
return a[2];
|
||||||
|
}
|
||||||
|
console.log(f0(), f1(), f2());
|
||||||
|
}
|
||||||
|
expect_stdout: "6 6 4"
|
||||||
|
}
|
||||||
|
|
||||||
|
index: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ 1, 2 ];
|
||||||
|
console.log(a[0], a[1]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 2);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2"
|
||||||
|
}
|
||||||
|
|
||||||
|
length: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ 1, 2 ];
|
||||||
|
console.log(a.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
index_length: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ 1, 2 ];
|
||||||
|
console.log(a[0], a.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 2);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1388,6 +1388,7 @@ issue_1605_1: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function foo(x) {
|
function foo(x) {
|
||||||
@@ -1410,6 +1411,7 @@ issue_1605_2: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: "vars",
|
toplevel: "vars",
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function foo(x) {
|
function foo(x) {
|
||||||
@@ -1537,6 +1539,7 @@ issue_1631_3: {
|
|||||||
var_side_effects_1: {
|
var_side_effects_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var print = console.log.bind(console);
|
var print = console.log.bind(console);
|
||||||
@@ -1559,6 +1562,7 @@ var_side_effects_1: {
|
|||||||
var_side_effects_2: {
|
var_side_effects_2: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var print = console.log.bind(console);
|
var print = console.log.bind(console);
|
||||||
@@ -1584,6 +1588,7 @@ var_side_effects_3: {
|
|||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
pure_getters: true,
|
pure_getters: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var print = console.log.bind(console);
|
var print = console.log.bind(console);
|
||||||
@@ -1659,6 +1664,7 @@ iife_2: {
|
|||||||
}(foo);
|
}(foo);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var foo;
|
||||||
!function(x) {
|
!function(x) {
|
||||||
console.log(x);
|
console.log(x);
|
||||||
}(bar());
|
}(bar());
|
||||||
@@ -1945,6 +1951,7 @@ ref_scope: {
|
|||||||
chained_1: {
|
chained_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = 2;
|
var a = 2;
|
||||||
@@ -1961,6 +1968,7 @@ chained_1: {
|
|||||||
chained_2: {
|
chained_2: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a;
|
var a;
|
||||||
@@ -2051,7 +2059,7 @@ inner_lvalues: {
|
|||||||
console.log(null, a, b);
|
console.log(null, a, b);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a, b = 10;
|
var b = 10;
|
||||||
var a = (--b || a || 3).toString(), c = --b + -a;
|
var a = (--b || a || 3).toString(), c = --b + -a;
|
||||||
console.log(null, a, b);
|
console.log(null, a, b);
|
||||||
}
|
}
|
||||||
@@ -2061,6 +2069,7 @@ inner_lvalues: {
|
|||||||
double_def: {
|
double_def: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = x, a = a && y;
|
var a = x, a = a && y;
|
||||||
@@ -2075,6 +2084,7 @@ double_def: {
|
|||||||
toplevel_single_reference: {
|
toplevel_single_reference: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a;
|
var a;
|
||||||
@@ -2084,10 +2094,11 @@ toplevel_single_reference: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
for (var b in x) {
|
||||||
var a;
|
var a;
|
||||||
for (var b in x)
|
|
||||||
b(a = b);
|
b(a = b);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unused_orig: {
|
unused_orig: {
|
||||||
@@ -2534,69 +2545,535 @@ issue_2319_3: {
|
|||||||
expect_stdout: "true"
|
expect_stdout: "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
prop_side_effects_1: {
|
issue_2365: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
evaluate: true,
|
pure_getters: true,
|
||||||
pure_getters: "strict",
|
|
||||||
reduce_vars: true,
|
|
||||||
toplevel: true,
|
|
||||||
unsafe: true,
|
|
||||||
unused: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var C = 1;
|
console.log(function(a) {
|
||||||
console.log(C);
|
var b = a.f;
|
||||||
var obj = {
|
a.f++;
|
||||||
bar: function() {
|
return b;
|
||||||
return C + C;
|
}({ f: 1 }));
|
||||||
|
console.log(function() {
|
||||||
|
var a = { f: 1 }, b = a.f;
|
||||||
|
a.f++;
|
||||||
|
return b;
|
||||||
|
}());
|
||||||
|
console.log({
|
||||||
|
f: 1,
|
||||||
|
g: function() {
|
||||||
|
var b = this.f;
|
||||||
|
this.f++;
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
};
|
}.g());
|
||||||
console.log(obj.bar());
|
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(1);
|
console.log(function(a) {
|
||||||
|
var b = a.f;
|
||||||
|
a.f++;
|
||||||
|
return b;
|
||||||
|
}({ f: 1 }));
|
||||||
|
console.log(function() {
|
||||||
|
var a = { f: 1 }, b = a.f;
|
||||||
|
a.f++;
|
||||||
|
return b;
|
||||||
|
}());
|
||||||
console.log({
|
console.log({
|
||||||
bar: function() {
|
f: 1,
|
||||||
return 2;
|
g: function() {
|
||||||
|
var b = this.f;
|
||||||
|
this.f++;
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
}.bar());
|
}.g());
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"1",
|
"1",
|
||||||
"2",
|
"1",
|
||||||
|
"1",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
prop_side_effects_2: {
|
issue_2364_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo() {
|
||||||
|
var first = arguments[0];
|
||||||
|
var result = inc(first);
|
||||||
|
return foo.amount = first.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo() {
|
||||||
|
var first = arguments[0];
|
||||||
|
var result = inc(first);
|
||||||
|
return foo.amount = first.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0
|
||||||
|
};
|
||||||
|
var answer = foo(data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function callValidate() {
|
||||||
|
var validate = compilation.validate;
|
||||||
|
var result = validate.apply(null, arguments);
|
||||||
|
return callValidate.errors = validate.errors, result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function callValidate() {
|
||||||
|
var validate = compilation.validate;
|
||||||
|
var result = validate.apply(null, arguments);
|
||||||
|
return callValidate.errors = validate.errors, result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo(bar) {
|
||||||
|
var result = inc(bar);
|
||||||
|
return foo.amount = bar.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo(bar) {
|
||||||
|
var result = inc(bar);
|
||||||
|
return foo.amount = bar.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_4: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo(bar, baz) {
|
||||||
|
var result = inc(bar);
|
||||||
|
return foo.amount = baz.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data, data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo(bar, baz) {
|
||||||
|
var result = inc(bar);
|
||||||
|
return foo.amount = baz.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data, data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_5: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
inline: true,
|
pure_getters: true,
|
||||||
passes: 2,
|
properties: true,
|
||||||
pure_getters: "strict",
|
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
side_effects: true,
|
|
||||||
toplevel: true,
|
|
||||||
unsafe: true,
|
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var C = 1;
|
function f0(o, a, h) {
|
||||||
console.log(C);
|
var b = 3 - a;
|
||||||
var obj = {
|
var obj = o;
|
||||||
bar: function() {
|
var seven = 7;
|
||||||
return C + C;
|
var prop = 'run';
|
||||||
|
var t = obj[prop](b)[seven] = h;
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
console.log(obj.bar());
|
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(1);
|
function f0(o, a, h) {
|
||||||
console.log(2);
|
return o.run(3 - a)[7] = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_6: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a.p;
|
||||||
|
b.p = "FAIL";
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
p: "PASS"
|
||||||
|
}
|
||||||
|
console.log(f(o, o));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a.p;
|
||||||
|
b.p = "FAIL";
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
p: "PASS"
|
||||||
|
}
|
||||||
|
console.log(f(o, o));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_7: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a.p;
|
||||||
|
b.f();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
p: "PASS",
|
||||||
|
f: function() {
|
||||||
|
this.p = "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f(o, o));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a.p;
|
||||||
|
b.f();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
p: "PASS",
|
||||||
|
f: function() {
|
||||||
|
this.p = "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f(o, o));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_8: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b, c) {
|
||||||
|
var d = a[b.f = function() {
|
||||||
|
return "PASS";
|
||||||
|
}];
|
||||||
|
return c.f(d);
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(f({}, o, o));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b, c) {
|
||||||
|
var d = a[b.f = function() {
|
||||||
|
return "PASS";
|
||||||
|
}];
|
||||||
|
return c.f(d);
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(f({}, o, o));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_9: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var d = a();
|
||||||
|
return b.f(d);
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(f(function() {
|
||||||
|
o.f = function() {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
}, o));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
var d = a();
|
||||||
|
return b.f(d);
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(f(function() {
|
||||||
|
o.f = function() {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
}, o));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
pure_getters_chain: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function o(t, r) {
|
||||||
|
var a = t[1], s = t[2], o = t[3], i = t[5];
|
||||||
|
return a <= 23 && s <= 59 && o <= 59 && (!r || i);
|
||||||
|
}
|
||||||
|
console.log(o([ , 23, 59, 59, , 42], 1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function o(t, r) {
|
||||||
|
return t[1] <= 23 && t[2] <= 59 && t[3] <= 59 && (!r || t[5]);
|
||||||
|
}
|
||||||
|
console.log(o([ , 23, 59, 59, , 42], 1));
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
conditional_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = "";
|
||||||
|
var d = b ? ">" : "<";
|
||||||
|
if (a) c += "=";
|
||||||
|
return c += d;
|
||||||
|
}
|
||||||
|
console.log(f(0, 0), f(0, 1), f(1, 0), f(1, 1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = "";
|
||||||
|
if (a) c += "=";
|
||||||
|
return c += b ? ">" : "<";
|
||||||
|
}
|
||||||
|
console.log(f(0, 0), f(0, 1), f(1, 0), f(1, 1));
|
||||||
|
}
|
||||||
|
expect_stdout: "< > =< =>"
|
||||||
|
}
|
||||||
|
|
||||||
|
conditional_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a + 1, d = a + 2;
|
||||||
|
return b ? c : d;
|
||||||
|
}
|
||||||
|
console.log(f(3, 0), f(4, 1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
return b ? a + 1 : a + 2;
|
||||||
|
}
|
||||||
|
console.log(f(3, 0), f(4, 1));
|
||||||
|
}
|
||||||
|
expect_stdout: "5 5"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2425_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "15"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2425_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b, c) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b, c) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "15"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2425_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b, b) {
|
||||||
|
b.toString();
|
||||||
|
})(--a, a |= 10);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 8;
|
||||||
|
(function(b, b) {
|
||||||
|
(a |= 10).toString();
|
||||||
|
})(--a);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "15"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2437: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
inline: true,
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
sequences: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
if (xhrDesc) {
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
var result = !!req.onreadystatechange;
|
||||||
|
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
var detectFunc = function () { };
|
||||||
|
req.onreadystatechange = detectFunc;
|
||||||
|
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
|
||||||
|
req.onreadystatechange = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function() {
|
||||||
|
if (xhrDesc)
|
||||||
|
return result = !!(req = new XMLHttpRequest()).onreadystatechange,
|
||||||
|
Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
|
||||||
|
result;
|
||||||
|
var req = new XMLHttpRequest(), detectFunc = function() {};
|
||||||
|
req.onreadystatechange = detectFunc;
|
||||||
|
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
|
||||||
|
req.onreadystatechange = null;
|
||||||
|
}();
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
|
||||||
"1",
|
|
||||||
"2",
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,3 +74,40 @@ dont_change_in_or_instanceof_expressions: {
|
|||||||
null instanceof null;
|
null instanceof null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self_comparison_1: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a === a;
|
||||||
|
a !== b;
|
||||||
|
b.c === a.c;
|
||||||
|
b.c !== b.c;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a == a;
|
||||||
|
a !== b;
|
||||||
|
b.c === a.c;
|
||||||
|
b.c != b.c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self_comparison_2: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {}
|
||||||
|
var o = {};
|
||||||
|
console.log(f != f, o === o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {}
|
||||||
|
var o = {};
|
||||||
|
console.log(false, true);
|
||||||
|
}
|
||||||
|
expect_stdout: "false true"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1109,11 +1109,11 @@ var_catch_toplevel: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_2105: {
|
issue_2105_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 3,
|
passes: 2,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -1139,17 +1139,50 @@ issue_2105: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function() {
|
({
|
||||||
var quux = function() {
|
|
||||||
console.log("PASS");
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
prop: function() {
|
prop: function() {
|
||||||
console.log;
|
console.log;
|
||||||
quux();
|
console.log("PASS");
|
||||||
}
|
}
|
||||||
|
}).prop();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2105_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function(factory) {
|
||||||
|
factory();
|
||||||
|
}( function() {
|
||||||
|
return function(fn) {
|
||||||
|
fn()().prop();
|
||||||
|
}( function() {
|
||||||
|
function bar() {
|
||||||
|
var quux = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}, foo = function() {
|
||||||
|
console.log;
|
||||||
|
quux();
|
||||||
};
|
};
|
||||||
})().prop();
|
return { prop: foo };
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
} );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -386,10 +386,11 @@ unsafe_object_accessor: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_function: {
|
prop_function: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate: true,
|
||||||
unsafe : true
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
@@ -402,9 +403,9 @@ unsafe_function: {
|
|||||||
expect: {
|
expect: {
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1},b:function(){}}) + 1,
|
({a:{b:1},b:function(){}}) + 1,
|
||||||
({b:function(){}}, {b:1}) + 1,
|
({b:1}) + 1,
|
||||||
({a:{b:1}}, function(){}) + 1,
|
function(){} + 1,
|
||||||
({b:function(){}}, {b:1}).b + 1
|
2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
@@ -630,10 +631,11 @@ unsafe_string_bad_index: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_prototype_function: {
|
prototype_function: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate: true,
|
||||||
unsafe : true
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = ({valueOf: 0}) < 1;
|
var a = ({valueOf: 0}) < 1;
|
||||||
@@ -652,8 +654,8 @@ unsafe_prototype_function: {
|
|||||||
var d = ({toString: 0}) + "";
|
var d = ({toString: 0}) + "";
|
||||||
var e = (({valueOf: 0}) + "")[2];
|
var e = (({valueOf: 0}) + "")[2];
|
||||||
var f = (({toString: 0}) + "")[2];
|
var f = (({toString: 0}) + "")[2];
|
||||||
var g = ({}, 0)();
|
var g = 0();
|
||||||
var h = ({}, 0)();
|
var h = 0();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1195,3 +1197,40 @@ issue_2231_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self_comparison_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { n: NaN };
|
||||||
|
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(false, false, true, true, "number");
|
||||||
|
}
|
||||||
|
expect_stdout: "false false true true 'number'"
|
||||||
|
}
|
||||||
|
|
||||||
|
self_comparison_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { n: NaN };
|
||||||
|
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(false, false, true, true, "number");
|
||||||
|
}
|
||||||
|
expect_stdout: "false false true true 'number'"
|
||||||
|
}
|
||||||
|
|||||||
@@ -151,13 +151,13 @@ issue_1841_2: {
|
|||||||
|
|
||||||
function_returning_constant_literal: {
|
function_returning_constant_literal: {
|
||||||
options = {
|
options = {
|
||||||
reduce_vars: true,
|
|
||||||
unsafe: true,
|
|
||||||
toplevel: true,
|
|
||||||
evaluate: true,
|
|
||||||
cascade: true,
|
|
||||||
unused: true,
|
|
||||||
inline: true,
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function greeter() {
|
function greeter() {
|
||||||
@@ -508,3 +508,41 @@ issue_2114_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "2"
|
expect_stdout: "2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2428: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function bar(k) {
|
||||||
|
console.log(k);
|
||||||
|
}
|
||||||
|
function foo(x) {
|
||||||
|
return bar(x);
|
||||||
|
}
|
||||||
|
function baz(a) {
|
||||||
|
foo(a);
|
||||||
|
}
|
||||||
|
baz(42);
|
||||||
|
baz("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function baz(a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
baz(42);
|
||||||
|
baz("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"42",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
399
test/compress/hoist_props.js
Normal file
399
test/compress/hoist_props.js
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
issue_2377_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj_foo = 1, obj_cube = function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
};
|
||||||
|
console.log(obj_foo, obj_cube(3));
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2377_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
}(3));
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2377_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 3,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 27);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_access_1: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
var obj = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in obj) a++;
|
||||||
|
console.log(a, obj.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
var obj = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in obj) a++;
|
||||||
|
console.log(a, obj.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_access_2: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
var f = function(k) {
|
||||||
|
if (o[k]) return "PASS";
|
||||||
|
};
|
||||||
|
console.log(f("a"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
console.log(function(k) {
|
||||||
|
if (o[k]) return "PASS";
|
||||||
|
}("a"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_access_3: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
o.b;
|
||||||
|
console.log(o.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
o.b;
|
||||||
|
console.log(o.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
bar: function() {
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
}.bar());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name_collision_1: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj_foo = 1;
|
||||||
|
var obj_bar = 2;
|
||||||
|
function f() {
|
||||||
|
var obj = {
|
||||||
|
foo: 3,
|
||||||
|
bar: 4,
|
||||||
|
"b-r": 5,
|
||||||
|
"b+r": 6,
|
||||||
|
"b!r": 7,
|
||||||
|
};
|
||||||
|
console.log(obj_foo, obj.foo, obj.bar, obj["b-r"], obj["b+r"], obj["b!r"]);
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj_foo = 1;
|
||||||
|
var obj_bar = 2;
|
||||||
|
function f() {
|
||||||
|
var obj_foo$0 = 3,
|
||||||
|
obj_bar = 4,
|
||||||
|
obj_b_r = 5,
|
||||||
|
obj_b_r$0 = 6,
|
||||||
|
obj_b_r$1 = 7;
|
||||||
|
console.log(obj_foo, obj_foo$0, obj_bar, obj_b_r, obj_b_r$0, obj_b_r$1);
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "1 3 4 5 6 7"
|
||||||
|
}
|
||||||
|
|
||||||
|
name_collision_2: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
p: 1,
|
||||||
|
0: function(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
1: function(x) {
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
}, o__$0 = 2, o__$1 = 3;
|
||||||
|
console.log(o.p === o.p, o[0](4), o[1](5), o__$0, o__$1);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o_p = 1,
|
||||||
|
o__ = function(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
o__$2 = function(x) {
|
||||||
|
return x + 1;
|
||||||
|
},
|
||||||
|
o__$0 = 2,
|
||||||
|
o__$1 = 3;
|
||||||
|
console.log(o_p === o_p, o__(4), o__$2(5), o__$0, o__$1);
|
||||||
|
}
|
||||||
|
expect_stdout: "true 4 6 2 3"
|
||||||
|
}
|
||||||
|
|
||||||
|
name_collision_3: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
p: 1,
|
||||||
|
0: function(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
1: function(x) {
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
}, o__$0 = 2, o__$1 = 3;
|
||||||
|
console.log(o.p === o.p, o[0](4), o[1](5));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o_p = 1,
|
||||||
|
o__ = function(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
o__$2 = function(x) {
|
||||||
|
return x + 1;
|
||||||
|
},
|
||||||
|
o__$0 = 2,
|
||||||
|
o__$1 = 3;
|
||||||
|
console.log(o_p === o_p, o__(4), o__$2(5));
|
||||||
|
}
|
||||||
|
expect_stdout: "true 4 6"
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_this_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
u: function() {
|
||||||
|
return this === this;
|
||||||
|
},
|
||||||
|
p: 1
|
||||||
|
};
|
||||||
|
console.log(o.p, o.p);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 1);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_this_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
u: function() {
|
||||||
|
return this === this;
|
||||||
|
},
|
||||||
|
p: 1
|
||||||
|
};
|
||||||
|
console.log(o.p, o.p, o.u);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 1, function() {
|
||||||
|
return this === this;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_this_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
u: function() {
|
||||||
|
return this === this;
|
||||||
|
},
|
||||||
|
p: 1
|
||||||
|
};
|
||||||
|
console.log(o.p, o.p, o.u());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
u: function() {
|
||||||
|
return this === this;
|
||||||
|
},
|
||||||
|
p: 1
|
||||||
|
};
|
||||||
|
console.log(o.p, o.p, o.u());
|
||||||
|
}
|
||||||
|
expect_stdout: "1 1 true"
|
||||||
|
}
|
||||||
|
|
||||||
|
new_this: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
f: function(a) {
|
||||||
|
this.b = a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(new o.f(o.a).b, o.b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(new function(a) {
|
||||||
|
this.b = a;
|
||||||
|
}(1).b, 2);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2"
|
||||||
|
}
|
||||||
@@ -51,6 +51,7 @@ this_binding_collapse_vars: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
var c = a; c();
|
var c = a; c();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
keep_properties: {
|
keep_properties: {
|
||||||
options = {
|
options = {
|
||||||
properties: false
|
evaluate: true,
|
||||||
};
|
properties: false,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
}
|
}
|
||||||
@@ -12,6 +13,7 @@ keep_properties: {
|
|||||||
|
|
||||||
dot_properties: {
|
dot_properties: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
properties: true,
|
properties: true,
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
@@ -37,6 +39,7 @@ dot_properties: {
|
|||||||
|
|
||||||
dot_properties_es5: {
|
dot_properties_es5: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
properties: true,
|
properties: true,
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
@@ -61,8 +64,8 @@ dot_properties_es5: {
|
|||||||
sub_properties: {
|
sub_properties: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
properties: true
|
properties: true,
|
||||||
};
|
}
|
||||||
input: {
|
input: {
|
||||||
a[0] = 0;
|
a[0] = 0;
|
||||||
a["0"] = 1;
|
a["0"] = 1;
|
||||||
@@ -81,18 +84,18 @@ sub_properties: {
|
|||||||
a[3.14] = 3;
|
a[3.14] = 3;
|
||||||
a.if = 4;
|
a.if = 4;
|
||||||
a["foo bar"] = 5;
|
a["foo bar"] = 5;
|
||||||
a[NaN] = 6;
|
a.NaN = 6;
|
||||||
a[null] = 7;
|
a.null = 7;
|
||||||
a[void 0] = 8;
|
a[void 0] = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluate_array_length: {
|
evaluate_array_length: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
properties: true,
|
properties: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
evaluate: true
|
}
|
||||||
};
|
|
||||||
input: {
|
input: {
|
||||||
a = [1, 2, 3].length;
|
a = [1, 2, 3].length;
|
||||||
a = [1, 2, 3].join()["len" + "gth"];
|
a = [1, 2, 3].join()["len" + "gth"];
|
||||||
@@ -109,10 +112,10 @@ evaluate_array_length: {
|
|||||||
|
|
||||||
evaluate_string_length: {
|
evaluate_string_length: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
properties: true,
|
properties: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
evaluate: true
|
}
|
||||||
};
|
|
||||||
input: {
|
input: {
|
||||||
a = "foo".length;
|
a = "foo".length;
|
||||||
a = ("foo" + "bar")["len" + "gth"];
|
a = ("foo" + "bar")["len" + "gth"];
|
||||||
@@ -151,7 +154,8 @@ mangle_properties: {
|
|||||||
|
|
||||||
mangle_unquoted_properties: {
|
mangle_unquoted_properties: {
|
||||||
options = {
|
options = {
|
||||||
properties: false
|
evaluate: true,
|
||||||
|
properties: false,
|
||||||
}
|
}
|
||||||
mangle = {
|
mangle = {
|
||||||
properties: {
|
properties: {
|
||||||
@@ -249,7 +253,8 @@ mangle_debug_suffix: {
|
|||||||
|
|
||||||
mangle_debug_suffix_keep_quoted: {
|
mangle_debug_suffix_keep_quoted: {
|
||||||
options = {
|
options = {
|
||||||
properties: false
|
evaluate: true,
|
||||||
|
properties: false,
|
||||||
}
|
}
|
||||||
mangle = {
|
mangle = {
|
||||||
properties: {
|
properties: {
|
||||||
@@ -677,8 +682,8 @@ accessor_this: {
|
|||||||
issue_2208_1: {
|
issue_2208_1: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log({
|
console.log({
|
||||||
@@ -696,8 +701,8 @@ issue_2208_1: {
|
|||||||
issue_2208_2: {
|
issue_2208_2: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log({
|
console.log({
|
||||||
@@ -721,8 +726,8 @@ issue_2208_2: {
|
|||||||
issue_2208_3: {
|
issue_2208_3: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
a = 42;
|
a = 42;
|
||||||
@@ -746,8 +751,8 @@ issue_2208_3: {
|
|||||||
issue_2208_4: {
|
issue_2208_4: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function foo() {}
|
function foo() {}
|
||||||
@@ -770,8 +775,8 @@ issue_2208_4: {
|
|||||||
issue_2208_5: {
|
issue_2208_5: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log({
|
console.log({
|
||||||
@@ -804,3 +809,219 @@ issue_2256: {
|
|||||||
g.keep = g.g;
|
g.keep = g.g;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lhs_prop_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(++{
|
||||||
|
a: 1
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(++{
|
||||||
|
a: 1
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs_prop_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
[1][0] = 42;
|
||||||
|
(function(a) {
|
||||||
|
a.b = "g";
|
||||||
|
})("abc");
|
||||||
|
(function(a) {
|
||||||
|
a[2] = "g";
|
||||||
|
})("def");
|
||||||
|
(function(a) {
|
||||||
|
a[""] = "g";
|
||||||
|
})("ghi");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
[1][0] = 42;
|
||||||
|
"abc".b = "g";
|
||||||
|
"def"[2] = "g";
|
||||||
|
"ghi"[""] = "g";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
literal_duplicate_key_side_effects: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
a: "FAIL",
|
||||||
|
a: console.log ? "PASS" : "FAIL"
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(console.log ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_side_effects_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
console.log(C);
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_side_effects_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
console.log(C);
|
||||||
|
var obj = {
|
||||||
|
"": function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj[""]());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
accessor_1: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
a: "FAIL",
|
||||||
|
get a() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
a: "FAIL",
|
||||||
|
get a() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
accessor_2: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get a() {
|
||||||
|
return "PASS";
|
||||||
|
},
|
||||||
|
set a(v) {},
|
||||||
|
a: "FAIL"
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get a() {
|
||||||
|
return "PASS";
|
||||||
|
},
|
||||||
|
set a(v) {},
|
||||||
|
a: "FAIL"
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
array_hole: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(
|
||||||
|
[ 1, 2, , 3][1],
|
||||||
|
[ 1, 2, , 3][2],
|
||||||
|
[ 1, 2, , 3][3]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2, void 0, 3);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 undefined 3"
|
||||||
|
}
|
||||||
|
|
||||||
|
new_this: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
new {
|
||||||
|
f: function(a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
}.f(42);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
new function(a) {
|
||||||
|
this.a = a;
|
||||||
|
}(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -162,6 +162,7 @@ var VALUES = [
|
|||||||
'"object"',
|
'"object"',
|
||||||
'"number"',
|
'"number"',
|
||||||
'"function"',
|
'"function"',
|
||||||
|
'this',
|
||||||
];
|
];
|
||||||
|
|
||||||
var BINARY_OPS_NO_COMMA = [
|
var BINARY_OPS_NO_COMMA = [
|
||||||
@@ -349,10 +350,10 @@ function createParams() {
|
|||||||
return params.join(', ');
|
return params.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
function createArgs() {
|
function createArgs(recurmax, stmtDepth, canThrow) {
|
||||||
var args = [];
|
var args = [];
|
||||||
for (var n = rng(4); --n >= 0;) {
|
for (var n = rng(4); --n >= 0;) {
|
||||||
args.push(createValue());
|
args.push(rng(2) ? createValue() : createExpression(recurmax - 1, COMMA_OK, stmtDepth, canThrow));
|
||||||
}
|
}
|
||||||
return args.join(', ');
|
return args.join(', ');
|
||||||
}
|
}
|
||||||
@@ -390,9 +391,10 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
|
|||||||
|
|
||||||
VAR_NAMES.length = namesLenBefore;
|
VAR_NAMES.length = namesLenBefore;
|
||||||
|
|
||||||
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s + '(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ');';
|
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s;
|
||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');';
|
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name;
|
||||||
|
s += '(' + createArgs(recurmax, stmtDepth, canThrow) + ');';
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -626,6 +628,9 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
return createValue();
|
return createValue();
|
||||||
|
case p++:
|
||||||
|
case p++:
|
||||||
|
return getVarName();
|
||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
|
|||||||
@@ -16,11 +16,9 @@
|
|||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
"compress": {
|
"compress": {
|
||||||
"toplevel": true
|
"hoist_props": true
|
||||||
},
|
},
|
||||||
"mangle": {
|
|
||||||
"toplevel": true
|
"toplevel": true
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compress": {
|
"compress": {
|
||||||
|
|||||||
Reference in New Issue
Block a user