Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55387e8fd0 | ||
|
|
7e3e9da860 | ||
|
|
00f509405b | ||
|
|
aceb0af36b | ||
|
|
4f0953f7e9 | ||
|
|
182a47bfb1 | ||
|
|
cd27f4ec38 | ||
|
|
8158b1bdcf | ||
|
|
aacf3edc68 | ||
|
|
8b89072190 | ||
|
|
395a17ccda | ||
|
|
3f355866cf | ||
|
|
71d52f147d | ||
|
|
eb7adaa6fc | ||
|
|
e5cf7972ea | ||
|
|
f81ff10a9b | ||
|
|
16d40915b4 | ||
|
|
e7c21e87e3 | ||
|
|
c4c2ef44d0 | ||
|
|
a845897758 | ||
|
|
32ea2c5530 | ||
|
|
bc61deeca9 | ||
|
|
6a5e74b44e | ||
|
|
54446341ee | ||
|
|
4e12a6f740 | ||
|
|
b35dfc2599 | ||
|
|
9e1da9235e | ||
|
|
a5ffe2c23f | ||
|
|
9282e7b0c6 | ||
|
|
5229cb2b1b | ||
|
|
458e3e15f0 | ||
|
|
c615a1e80a | ||
|
|
10a938cb79 | ||
|
|
4956ad311b | ||
|
|
145874e504 | ||
|
|
bd7be07c38 | ||
|
|
71ee91e716 | ||
|
|
4f70d2e28c | ||
|
|
4b6ca5e742 | ||
|
|
9306da3c58 | ||
|
|
1ac25fc032 | ||
|
|
5f046c724b | ||
|
|
af0262b7e5 | ||
|
|
6b3aeff1d8 | ||
|
|
20e4f8277f | ||
|
|
f3a487a368 |
9
.github/ISSUE_TEMPLATE.md
vendored
9
.github/ISSUE_TEMPLATE.md
vendored
@@ -8,7 +8,14 @@
|
|||||||
|
|
||||||
**Uglify version (`uglifyjs -V`)**
|
**Uglify version (`uglifyjs -V`)**
|
||||||
|
|
||||||
**JavaScript input** <!-- ideally as small as possible -->
|
**JavaScript input**
|
||||||
|
|
||||||
|
<!--
|
||||||
|
A complete parsable JS program exhibiting the issue with
|
||||||
|
UglifyJS alone - without third party tools or libraries.
|
||||||
|
Ideally the input should be as small as possible.
|
||||||
|
Post a link to a gist if necessary.
|
||||||
|
-->
|
||||||
|
|
||||||
**The `uglifyjs` CLI command executed or `minify()` options used.**
|
**The `uglifyjs` CLI command executed or `minify()` options used.**
|
||||||
|
|
||||||
|
|||||||
48
README.md
48
README.md
@@ -150,19 +150,19 @@ debugging your compressed JavaScript. To get a source map, pass
|
|||||||
|
|
||||||
Additional options:
|
Additional options:
|
||||||
|
|
||||||
- `--source-map filename=<NAME>` to specify the name of the source map.
|
- `--source-map "filename='<NAME>'"` to specify the name of the source map.
|
||||||
|
|
||||||
- `--source-map root=<URL>` to pass the URL where the original files can be found.
|
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
|
||||||
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
|
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
|
||||||
`//# sourceMappingURL=` directive.
|
`//# sourceMappingURL=` directive.
|
||||||
|
|
||||||
- `--source-map url=<URL>` to specify the URL where the source map can be found.
|
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
uglifyjs js/file1.js js/file2.js \
|
uglifyjs js/file1.js js/file2.js \
|
||||||
-o foo.min.js -c -m \
|
-o foo.min.js -c -m \
|
||||||
--source-map root="http://foo.com/src",url=foo.min.js.map
|
--source-map "root='http://foo.com/src',url='foo.min.js.map'"
|
||||||
|
|
||||||
The above will compress and mangle `file1.js` and `file2.js`, will drop the
|
The above will compress and mangle `file1.js` and `file2.js`, will drop the
|
||||||
output in `foo.min.js` and the source map in `foo.min.js.map`. The source
|
output in `foo.min.js` and the source map in `foo.min.js.map`. The source
|
||||||
@@ -181,8 +181,8 @@ CoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript →
|
|||||||
compressed JS by mapping every token in the compiled JS to its original
|
compressed JS by mapping every token in the compiled JS to its original
|
||||||
location.
|
location.
|
||||||
|
|
||||||
To use this feature pass `--source-map content="/path/to/input/source.map"`
|
To use this feature pass `--source-map "content='/path/to/input/source.map'"`
|
||||||
or `--source-map content=inline` if the source map is included inline with
|
or `--source-map "content=inline"` if the source map is included inline with
|
||||||
the sources.
|
the sources.
|
||||||
|
|
||||||
## CLI compress options
|
## CLI compress options
|
||||||
@@ -213,7 +213,7 @@ When mangling is enabled but you want to prevent certain names from being
|
|||||||
mangled, you can declare those names with `--mangle reserved` — pass a
|
mangled, you can declare those names with `--mangle reserved` — pass a
|
||||||
comma-separated list of names. For example:
|
comma-separated list of names. For example:
|
||||||
|
|
||||||
uglifyjs ... -m reserved=[$,require,exports]
|
uglifyjs ... -m reserved=['$','require','exports']
|
||||||
|
|
||||||
to prevent the `require`, `exports` and `$` names from being changed.
|
to prevent the `require`, `exports` and `$` names from being changed.
|
||||||
|
|
||||||
@@ -644,6 +644,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
- `booleans` -- various optimizations for boolean context, for example `!!a
|
- `booleans` -- various optimizations for boolean context, for example `!!a
|
||||||
? b : c → a ? b : c`
|
? b : c → a ? b : c`
|
||||||
|
|
||||||
|
- `typeofs` -- default `true`. Transforms `typeof foo == "undefined"` into
|
||||||
|
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
||||||
|
earlier versions due to known issues.
|
||||||
|
|
||||||
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
||||||
statically determine the condition
|
statically determine the condition
|
||||||
|
|
||||||
@@ -717,7 +721,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
compressor from discarding function names. Useful for code relying on
|
compressor from discarding function names. Useful for code relying on
|
||||||
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
||||||
|
|
||||||
- `passes` -- default `1`. Number of times to run compress with a maximum of 3.
|
- `passes` -- default `1`. The maximum number of times to run compress.
|
||||||
In some cases more than one pass leads to further compressed code. Keep in
|
In some cases more than one pass leads to further compressed code. Keep in
|
||||||
mind more passes will take more time.
|
mind more passes will take more time.
|
||||||
|
|
||||||
@@ -873,7 +877,6 @@ when this flag is on:
|
|||||||
- `new Object()` → `{}`
|
- `new Object()` → `{}`
|
||||||
- `String(exp)` or `exp.toString()` → `"" + exp`
|
- `String(exp)` or `exp.toString()` → `"" + exp`
|
||||||
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
|
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
|
||||||
- `typeof foo == "undefined"` → `foo === void 0`
|
|
||||||
- `void 0` → `undefined` (if there is a variable named "undefined" in
|
- `void 0` → `undefined` (if there is a variable named "undefined" in
|
||||||
scope; we do it because the variable name will be mangled, typically
|
scope; we do it because the variable name will be mangled, typically
|
||||||
reduced to a single character)
|
reduced to a single character)
|
||||||
@@ -1026,3 +1029,30 @@ in total it's a bit more than just using UglifyJS's own parser.
|
|||||||
|
|
||||||
[acorn]: https://github.com/ternjs/acorn
|
[acorn]: https://github.com/ternjs/acorn
|
||||||
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
|
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
|
||||||
|
|
||||||
|
### Uglify Fast Minify Mode
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
comparable minify speeds and gzip sizes to
|
||||||
|
[`butternut`](https://www.npmjs.com/package/butternut):
|
||||||
|
|
||||||
|
| d3.js | minify size | gzip size | minify time (seconds) |
|
||||||
|
| --- | ---: | ---: | ---: |
|
||||||
|
| original | 451,131 | 108,733 | - |
|
||||||
|
| uglify-js@3.0.24 mangle=false, compress=false | 316,600 | 85,245 | 0.70 |
|
||||||
|
| uglify-js@3.0.24 mangle=true, compress=false | 220,216 | 72,730 | 1.13 |
|
||||||
|
| butternut@0.4.6 | 217,568 | 72,738 | 1.41 |
|
||||||
|
| uglify-js@3.0.24 mangle=true, compress=true | 212,511 | 71,560 | 3.36 |
|
||||||
|
| babili@0.1.4 | 210,713 | 72,140 | 12.64 |
|
||||||
|
|
||||||
|
To enable fast minify mode from the CLI use:
|
||||||
|
```
|
||||||
|
uglifyjs file.js -m
|
||||||
|
```
|
||||||
|
To enable fast minify mode with the API use:
|
||||||
|
```js
|
||||||
|
UglifyJS.minify(code, { compress: false, mangle: true });
|
||||||
|
```
|
||||||
|
|||||||
22
bin/uglifyjs
22
bin/uglifyjs
@@ -35,11 +35,11 @@ else if (process.argv.indexOf("options") >= 0) program.helpInformation = functio
|
|||||||
}
|
}
|
||||||
return text.join("\n");
|
return text.join("\n");
|
||||||
};
|
};
|
||||||
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
|
program.option("-p, --parse <options>", "Specify parser options.", parse_js());
|
||||||
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js("compress", true));
|
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js());
|
||||||
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js("mangle", true));
|
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
|
||||||
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js("mangle-props", true));
|
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
|
||||||
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js("beautify", true));
|
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js());
|
||||||
program.option("-o, --output <file>", "Output file (default STDOUT).");
|
program.option("-o, --output <file>", "Output file (default STDOUT).");
|
||||||
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
||||||
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
||||||
@@ -310,7 +310,7 @@ function read_file(path, default_value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse_js(flag, constants) {
|
function parse_js(flag) {
|
||||||
return function(value, options) {
|
return function(value, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
try {
|
try {
|
||||||
@@ -328,7 +328,7 @@ function parse_js(flag, constants) {
|
|||||||
if (node instanceof UglifyJS.AST_Assign) {
|
if (node instanceof UglifyJS.AST_Assign) {
|
||||||
var name = node.left.print_to_string();
|
var name = node.left.print_to_string();
|
||||||
var value = node.right;
|
var value = node.right;
|
||||||
if (!constants) {
|
if (flag) {
|
||||||
options[name] = value;
|
options[name] = value;
|
||||||
} else if (value instanceof UglifyJS.AST_Array) {
|
} else if (value instanceof UglifyJS.AST_Array) {
|
||||||
options[name] = value.elements.map(to_string);
|
options[name] = value.elements.map(to_string);
|
||||||
@@ -351,14 +351,18 @@ function parse_js(flag, constants) {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
options[value] = null;
|
if (flag) {
|
||||||
|
fatal("Error parsing arguments for '" + flag + "': " + value);
|
||||||
|
} else {
|
||||||
|
options[value] = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse_source_map() {
|
function parse_source_map() {
|
||||||
var parse = parse_js("sourceMap", true);
|
var parse = parse_js();
|
||||||
return function(value, options) {
|
return function(value, options) {
|
||||||
var hasContent = options && "content" in options;
|
var hasContent = options && "content" in options;
|
||||||
var settings = parse(value, options);
|
var settings = parse(value, options);
|
||||||
|
|||||||
13
lib/ast.js
13
lib/ast.js
@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
|
|||||||
$documentation: "Represents a debugger statement",
|
$documentation: "Represents a debugger statement",
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_Directive = DEFNODE("Directive", "value scope quote", {
|
var AST_Directive = DEFNODE("Directive", "value quote", {
|
||||||
$documentation: "Represents a directive, like \"use strict\";",
|
$documentation: "Represents a directive, like \"use strict\";",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
||||||
scope: "[AST_Scope/S] The scope that this directive affects",
|
|
||||||
quote: "[string] the original quote character"
|
quote: "[string] the original quote character"
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
@@ -299,10 +298,9 @@ var AST_With = DEFNODE("With", "expression", {
|
|||||||
|
|
||||||
/* -----[ scope and functions ]----- */
|
/* -----[ scope and functions ]----- */
|
||||||
|
|
||||||
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
|
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||||
$documentation: "Base class for all statements introducing a lexical scope",
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
directives: "[string*/S] an array of directives declared in this scope",
|
|
||||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||||
@@ -859,7 +857,7 @@ TreeWalker.prototype = {
|
|||||||
if (!ret && descend) {
|
if (!ret && descend) {
|
||||||
descend.call(node);
|
descend.call(node);
|
||||||
}
|
}
|
||||||
this.pop(node);
|
this.pop();
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
parent: function(n) {
|
parent: function(n) {
|
||||||
@@ -873,9 +871,8 @@ TreeWalker.prototype = {
|
|||||||
}
|
}
|
||||||
this.stack.push(node);
|
this.stack.push(node);
|
||||||
},
|
},
|
||||||
pop: function(node) {
|
pop: function() {
|
||||||
this.stack.pop();
|
if (this.stack.pop() instanceof AST_Lambda) {
|
||||||
if (node instanceof AST_Lambda) {
|
|
||||||
this.directives = Object.getPrototypeOf(this.directives);
|
this.directives = Object.getPrototypeOf(this.directives);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
604
lib/compress.js
604
lib/compress.js
@@ -80,6 +80,7 @@ function Compressor(options, false_by_default) {
|
|||||||
switches : !false_by_default,
|
switches : !false_by_default,
|
||||||
top_retain : null,
|
top_retain : null,
|
||||||
toplevel : !!(options && options["top_retain"]),
|
toplevel : !!(options && options["top_retain"]),
|
||||||
|
typeofs : !false_by_default,
|
||||||
unsafe : false,
|
unsafe : false,
|
||||||
unsafe_comps : false,
|
unsafe_comps : false,
|
||||||
unsafe_Func : false,
|
unsafe_Func : false,
|
||||||
@@ -147,10 +148,20 @@ merge(Compressor.prototype, {
|
|||||||
node.process_expression(true);
|
node.process_expression(true);
|
||||||
}
|
}
|
||||||
var passes = +this.options.passes || 1;
|
var passes = +this.options.passes || 1;
|
||||||
for (var pass = 0; pass < passes && pass < 3; ++pass) {
|
var last_count = 1 / 0;
|
||||||
|
for (var pass = 0; pass < passes; pass++) {
|
||||||
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, true);
|
||||||
node = node.transform(this);
|
node = node.transform(this);
|
||||||
|
if (passes > 1) {
|
||||||
|
var count = 0;
|
||||||
|
node.walk(new TreeWalker(function() {
|
||||||
|
count++;
|
||||||
|
}));
|
||||||
|
this.info("pass " + pass + ": last_count: " + last_count + ", count: " + count);
|
||||||
|
if (count >= last_count) break;
|
||||||
|
last_count = count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.option("expression")) {
|
if (this.option("expression")) {
|
||||||
node.process_expression(false);
|
node.process_expression(false);
|
||||||
@@ -550,6 +561,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function is_lhs_read_only(lhs) {
|
function is_lhs_read_only(lhs) {
|
||||||
|
if (lhs instanceof AST_This) return true;
|
||||||
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
||||||
if (lhs instanceof AST_PropAccess) {
|
if (lhs instanceof AST_PropAccess) {
|
||||||
lhs = lhs.expression;
|
lhs = lhs.expression;
|
||||||
@@ -678,6 +690,16 @@ merge(Compressor.prototype, {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_undeclared_ref(node) {
|
||||||
|
return node instanceof AST_SymbolRef && node.definition().undeclared;
|
||||||
|
}
|
||||||
|
|
||||||
|
var global_names = makePredicate("Array Boolean clearInterval clearTimeout console Date decodeURI decodeURIComponent encodeURI encodeURIComponent Error escape eval EvalError Function isFinite isNaN JSON Math Number parseFloat parseInt RangeError ReferenceError RegExp Object setInterval setTimeout String SyntaxError TypeError unescape URIError");
|
||||||
|
AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
|
||||||
|
return !this.definition().undeclared
|
||||||
|
|| compressor.option("unsafe") && global_names(this.name);
|
||||||
|
});
|
||||||
|
|
||||||
function tighten_body(statements, compressor) {
|
function tighten_body(statements, compressor) {
|
||||||
var CHANGED, max_iter = 10;
|
var CHANGED, max_iter = 10;
|
||||||
do {
|
do {
|
||||||
@@ -724,7 +746,7 @@ merge(Compressor.prototype, {
|
|||||||
while (candidates.length > 0) {
|
while (candidates.length > 0) {
|
||||||
var candidate = candidates.pop();
|
var candidate = candidates.pop();
|
||||||
var lhs = get_lhs(candidate);
|
var lhs = get_lhs(candidate);
|
||||||
if (!lhs || is_lhs_read_only(lhs)) continue;
|
if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
|
||||||
// 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;
|
||||||
@@ -747,7 +769,7 @@ merge(Compressor.prototype, {
|
|||||||
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|
||||||
|| node instanceof AST_Debugger
|
|| node instanceof AST_Debugger
|
||||||
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
||||||
|| node instanceof AST_SymbolRef && node.undeclared()
|
|| node instanceof AST_SymbolRef && !node.is_declared(compressor)
|
||||||
|| node instanceof AST_Try
|
|| node instanceof AST_Try
|
||||||
|| node instanceof AST_With
|
|| node instanceof AST_With
|
||||||
|| parent instanceof AST_For && node !== parent.init) {
|
|| parent instanceof AST_For && node !== parent.init) {
|
||||||
@@ -779,6 +801,7 @@ merge(Compressor.prototype, {
|
|||||||
right: candidate.value
|
right: candidate.value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
candidate.write_only = false;
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
// These node types have child nodes that execute sequentially,
|
// These node types have child nodes that execute sequentially,
|
||||||
@@ -819,24 +842,37 @@ merge(Compressor.prototype, {
|
|||||||
&& !fn.uses_eval
|
&& !fn.uses_eval
|
||||||
&& (iife = compressor.parent()) instanceof AST_Call
|
&& (iife = compressor.parent()) instanceof AST_Call
|
||||||
&& iife.expression === fn) {
|
&& iife.expression === fn) {
|
||||||
fn.argnames.forEach(function(sym, i) {
|
var fn_strict = compressor.has_directive("use strict");
|
||||||
|
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
||||||
|
var names = Object.create(null);
|
||||||
|
for (var i = fn.argnames.length; --i >= 0;) {
|
||||||
|
var sym = fn.argnames[i];
|
||||||
|
if (sym.name in names) continue;
|
||||||
|
names[sym.name] = true;
|
||||||
var arg = iife.args[i];
|
var arg = iife.args[i];
|
||||||
if (!arg) arg = make_node(AST_Undefined, sym);
|
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
|
||||||
else arg.walk(new TreeWalker(function(node) {
|
else {
|
||||||
if (!arg) return true;
|
var tw = new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) {
|
if (!arg) return true;
|
||||||
var s = node.definition().scope;
|
if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) {
|
||||||
if (s !== scope) while (s = s.parent_scope) {
|
var s = node.definition().scope;
|
||||||
if (s === scope) return true;
|
if (s !== scope) while (s = s.parent_scope) {
|
||||||
|
if (s === scope) return true;
|
||||||
|
}
|
||||||
|
arg = null;
|
||||||
}
|
}
|
||||||
arg = null;
|
if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) {
|
||||||
}
|
arg = null;
|
||||||
}));
|
return true;
|
||||||
if (arg) candidates.push(make_node(AST_VarDef, sym, {
|
}
|
||||||
|
});
|
||||||
|
arg.walk(tw);
|
||||||
|
}
|
||||||
|
if (arg) candidates.unshift(make_node(AST_VarDef, sym, {
|
||||||
name: sym,
|
name: sym,
|
||||||
value: arg
|
value: arg
|
||||||
}));
|
}));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1198,21 +1234,21 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = 0, len = statements.length; i < len; i++) {
|
for (var i = 0, len = statements.length; i < len; i++) {
|
||||||
var stat = statements[i];
|
var stat = statements[i];
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (stat instanceof AST_For) {
|
if (stat instanceof AST_For && !(stat.init instanceof AST_Definitions)) {
|
||||||
try {
|
var abort = false;
|
||||||
prev.body.walk(new TreeWalker(function(node){
|
prev.body.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Binary && node.operator == "in")
|
if (abort || node instanceof AST_Scope) return true;
|
||||||
throw cons_seq;
|
if (node instanceof AST_Binary && node.operator == "in") {
|
||||||
}));
|
abort = true;
|
||||||
if (stat.init && !(stat.init instanceof AST_Definitions)) {
|
return true;
|
||||||
stat.init = cons_seq(stat.init);
|
|
||||||
}
|
}
|
||||||
else if (!stat.init) {
|
}));
|
||||||
|
if (!abort) {
|
||||||
|
if (stat.init) stat.init = cons_seq(stat.init);
|
||||||
|
else {
|
||||||
stat.init = prev.body.drop_side_effect_free(compressor);
|
stat.init = prev.body.drop_side_effect_free(compressor);
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
} catch(ex) {
|
|
||||||
if (ex !== cons_seq) throw ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (stat instanceof AST_If) {
|
else if (stat instanceof AST_If) {
|
||||||
@@ -1297,12 +1333,12 @@ merge(Compressor.prototype, {
|
|||||||
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
||||||
(function(def) {
|
(function(def) {
|
||||||
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
|
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
|
||||||
var pure_getters = compressor.option("pure_getters");
|
return !compressor.option("pure_getters")
|
||||||
return !pure_getters || this._throw_on_access(pure_getters);
|
|| this._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
|
|
||||||
function is_strict(pure_getters) {
|
function is_strict(compressor) {
|
||||||
return /strict/.test(pure_getters);
|
return /strict/.test(compressor.option("pure_getters"));
|
||||||
}
|
}
|
||||||
|
|
||||||
def(AST_Node, is_strict);
|
def(AST_Node, is_strict);
|
||||||
@@ -1310,8 +1346,8 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Undefined, return_true);
|
def(AST_Undefined, return_true);
|
||||||
def(AST_Constant, return_false);
|
def(AST_Constant, return_false);
|
||||||
def(AST_Array, return_false);
|
def(AST_Array, return_false);
|
||||||
def(AST_Object, function(pure_getters) {
|
def(AST_Object, function(compressor) {
|
||||||
if (!is_strict(pure_getters)) return false;
|
if (!is_strict(compressor)) return false;
|
||||||
for (var i = this.properties.length; --i >=0;)
|
for (var i = this.properties.length; --i >=0;)
|
||||||
if (this.properties[i].value instanceof AST_Accessor) return true;
|
if (this.properties[i].value instanceof AST_Accessor) return true;
|
||||||
return false;
|
return false;
|
||||||
@@ -1321,37 +1357,38 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_UnaryPrefix, function() {
|
def(AST_UnaryPrefix, function() {
|
||||||
return this.operator == "void";
|
return this.operator == "void";
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(pure_getters) {
|
def(AST_Binary, function(compressor) {
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "&&":
|
case "&&":
|
||||||
return this.left._throw_on_access(pure_getters);
|
return this.left._dot_throw(compressor);
|
||||||
case "||":
|
case "||":
|
||||||
return this.left._throw_on_access(pure_getters)
|
return this.left._dot_throw(compressor)
|
||||||
&& this.right._throw_on_access(pure_getters);
|
&& this.right._dot_throw(compressor);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def(AST_Assign, function(pure_getters) {
|
def(AST_Assign, function(compressor) {
|
||||||
return this.operator == "="
|
return this.operator == "="
|
||||||
&& this.right._throw_on_access(pure_getters);
|
&& this.right._dot_throw(compressor);
|
||||||
})
|
})
|
||||||
def(AST_Conditional, function(pure_getters) {
|
def(AST_Conditional, function(compressor) {
|
||||||
return this.consequent._throw_on_access(pure_getters)
|
return this.consequent._dot_throw(compressor)
|
||||||
|| this.alternative._throw_on_access(pure_getters);
|
|| this.alternative._dot_throw(compressor);
|
||||||
})
|
})
|
||||||
def(AST_Sequence, function(pure_getters) {
|
def(AST_Sequence, function(compressor) {
|
||||||
return this.expressions[this.expressions.length - 1]._throw_on_access(pure_getters);
|
return this.expressions[this.expressions.length - 1]._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(pure_getters) {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
if (this.is_undefined) return true;
|
if (this.is_undefined) return true;
|
||||||
if (!is_strict(pure_getters)) return false;
|
if (!is_strict(compressor)) return false;
|
||||||
|
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
||||||
if (this.is_immutable()) return false;
|
if (this.is_immutable()) return false;
|
||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
return !fixed || fixed._throw_on_access(pure_getters);
|
return !fixed || fixed._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
node.DEFMETHOD("_throw_on_access", func);
|
node.DEFMETHOD("_dot_throw", func);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ boolean/negation helpers ]----- */
|
/* -----[ boolean/negation helpers ]----- */
|
||||||
@@ -1532,13 +1569,8 @@ merge(Compressor.prototype, {
|
|||||||
// descendant of AST_Node.
|
// descendant of AST_Node.
|
||||||
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
||||||
if (!compressor.option("evaluate")) return this;
|
if (!compressor.option("evaluate")) return this;
|
||||||
try {
|
var val = this._eval(compressor);
|
||||||
var val = this._eval(compressor);
|
return !val || val instanceof RegExp || typeof val != "object" ? val : this;
|
||||||
return !val || val instanceof RegExp || typeof val != "object" ? val : this;
|
|
||||||
} catch(ex) {
|
|
||||||
if (ex !== def) throw ex;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
var unaryPrefix = makePredicate("! ~ - + void");
|
var unaryPrefix = makePredicate("! ~ - + void");
|
||||||
AST_Node.DEFMETHOD("is_constant", function(){
|
AST_Node.DEFMETHOD("is_constant", function(){
|
||||||
@@ -1584,27 +1616,28 @@ merge(Compressor.prototype, {
|
|||||||
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));
|
||||||
});
|
});
|
||||||
def(AST_Lambda, function(){
|
def(AST_Lambda, return_this);
|
||||||
throw def;
|
|
||||||
});
|
|
||||||
function ev(node, compressor) {
|
function ev(node, compressor) {
|
||||||
if (!compressor) throw new Error("Compressor must be passed");
|
if (!compressor) throw new Error("Compressor must be passed");
|
||||||
|
|
||||||
return node._eval(compressor);
|
return node._eval(compressor);
|
||||||
};
|
};
|
||||||
def(AST_Node, function(){
|
def(AST_Node, return_this);
|
||||||
throw def; // not constant
|
|
||||||
});
|
|
||||||
def(AST_Constant, function(){
|
def(AST_Constant, function(){
|
||||||
return this.getValue();
|
return this.getValue();
|
||||||
});
|
});
|
||||||
def(AST_Array, function(compressor){
|
def(AST_Array, function(compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
return this.elements.map(function(element) {
|
var elements = [];
|
||||||
return ev(element, compressor);
|
for (var i = 0, len = this.elements.length; i < len; i++) {
|
||||||
});
|
var element = this.elements[i];
|
||||||
|
var value = ev(element, compressor);
|
||||||
|
if (element === value) return this;
|
||||||
|
elements.push(value);
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Object, function(compressor){
|
def(AST_Object, function(compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
@@ -1616,163 +1649,255 @@ merge(Compressor.prototype, {
|
|||||||
key = key.name;
|
key = key.name;
|
||||||
} else if (key instanceof AST_Node) {
|
} else if (key instanceof AST_Node) {
|
||||||
key = ev(key, compressor);
|
key = ev(key, compressor);
|
||||||
|
if (key === prop.key) return this;
|
||||||
}
|
}
|
||||||
if (typeof Object.prototype[key] === 'function') {
|
if (typeof Object.prototype[key] === 'function') {
|
||||||
throw def;
|
return this;
|
||||||
}
|
}
|
||||||
val[key] = ev(prop.value, compressor);
|
val[key] = ev(prop.value, compressor);
|
||||||
|
if (val[key] === prop.value) return this;
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_UnaryPrefix, function(compressor){
|
def(AST_UnaryPrefix, function(compressor){
|
||||||
var e = this.expression;
|
// Function would be evaluated to an array and so typeof would
|
||||||
|
// incorrectly return 'object'. Hence making is a special case.
|
||||||
|
if (this.operator == "typeof" && this.expression instanceof AST_Function) {
|
||||||
|
return typeof function(){};
|
||||||
|
}
|
||||||
|
var e = ev(this.expression, compressor);
|
||||||
|
if (e === this.expression) return this;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "!": return !ev(e, compressor);
|
case "!": return !e;
|
||||||
case "typeof":
|
case "typeof":
|
||||||
// Function would be evaluated to an array and so typeof would
|
|
||||||
// incorrectly return 'object'. Hence making is a special case.
|
|
||||||
if (e instanceof AST_Function) return typeof function(){};
|
|
||||||
|
|
||||||
e = ev(e, compressor);
|
|
||||||
|
|
||||||
// typeof <RegExp> returns "object" or "function" on different platforms
|
// typeof <RegExp> returns "object" or "function" on different platforms
|
||||||
// so cannot evaluate reliably
|
// so cannot evaluate reliably
|
||||||
if (e instanceof RegExp) throw def;
|
if (e instanceof RegExp) return this;
|
||||||
|
|
||||||
return typeof e;
|
return typeof e;
|
||||||
case "void": return void ev(e, compressor);
|
case "void": return void e;
|
||||||
case "~": return ~ev(e, compressor);
|
case "~": return ~e;
|
||||||
case "-": return -ev(e, compressor);
|
case "-": return -e;
|
||||||
case "+": return +ev(e, compressor);
|
case "+": return +e;
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(c){
|
def(AST_Binary, function(compressor){
|
||||||
var left = this.left, right = this.right, result;
|
var left = ev(this.left, compressor);
|
||||||
|
if (left === this.left) return this;
|
||||||
|
var right = ev(this.right, compressor);
|
||||||
|
if (right === this.right) return this;
|
||||||
|
var result;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "&&" : result = ev(left, c) && ev(right, c); break;
|
case "&&" : result = left && right; break;
|
||||||
case "||" : result = ev(left, c) || ev(right, c); break;
|
case "||" : result = left || right; break;
|
||||||
case "|" : result = ev(left, c) | ev(right, c); break;
|
case "|" : result = left | right; break;
|
||||||
case "&" : result = ev(left, c) & ev(right, c); break;
|
case "&" : result = left & right; break;
|
||||||
case "^" : result = ev(left, c) ^ ev(right, c); break;
|
case "^" : result = left ^ right; break;
|
||||||
case "+" : result = ev(left, c) + ev(right, c); break;
|
case "+" : result = left + right; break;
|
||||||
case "*" : result = ev(left, c) * ev(right, c); break;
|
case "*" : result = left * right; break;
|
||||||
case "/" : result = ev(left, c) / ev(right, c); break;
|
case "/" : result = left / right; break;
|
||||||
case "%" : result = ev(left, c) % ev(right, c); break;
|
case "%" : result = left % right; break;
|
||||||
case "-" : result = ev(left, c) - ev(right, c); break;
|
case "-" : result = left - right; break;
|
||||||
case "<<" : result = ev(left, c) << ev(right, c); break;
|
case "<<" : result = left << right; break;
|
||||||
case ">>" : result = ev(left, c) >> ev(right, c); break;
|
case ">>" : result = left >> right; break;
|
||||||
case ">>>" : result = ev(left, c) >>> ev(right, c); break;
|
case ">>>" : result = left >>> right; break;
|
||||||
case "==" : result = ev(left, c) == ev(right, c); break;
|
case "==" : result = left == right; break;
|
||||||
case "===" : result = ev(left, c) === ev(right, c); break;
|
case "===" : result = left === right; break;
|
||||||
case "!=" : result = ev(left, c) != ev(right, c); break;
|
case "!=" : result = left != right; break;
|
||||||
case "!==" : result = ev(left, c) !== ev(right, c); break;
|
case "!==" : result = left !== right; break;
|
||||||
case "<" : result = ev(left, c) < ev(right, c); break;
|
case "<" : result = left < right; break;
|
||||||
case "<=" : result = ev(left, c) <= ev(right, c); break;
|
case "<=" : result = left <= right; break;
|
||||||
case ">" : result = ev(left, c) > ev(right, c); break;
|
case ">" : result = left > right; break;
|
||||||
case ">=" : result = ev(left, c) >= ev(right, c); break;
|
case ">=" : result = left >= right; break;
|
||||||
default:
|
default:
|
||||||
throw def;
|
return this;
|
||||||
}
|
}
|
||||||
if (isNaN(result) && c.find_parent(AST_With)) {
|
if (isNaN(result) && compressor.find_parent(AST_With)) {
|
||||||
// leave original expression as is
|
// leave original expression as is
|
||||||
throw def;
|
return this;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor){
|
def(AST_Conditional, function(compressor){
|
||||||
return ev(this.condition, compressor)
|
var condition = ev(this.condition, compressor);
|
||||||
? ev(this.consequent, compressor)
|
if (condition === this.condition) return this;
|
||||||
: ev(this.alternative, compressor);
|
var node = condition ? this.consequent : this.alternative;
|
||||||
|
var value = ev(node, compressor);
|
||||||
|
return value === node ? this : value;
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor){
|
def(AST_SymbolRef, function(compressor){
|
||||||
if (!compressor.option("reduce_vars") || this._evaluating) throw def;
|
if (!compressor.option("reduce_vars")) return this;
|
||||||
this._evaluating = true;
|
var fixed = this.fixed_value();
|
||||||
try {
|
if (!fixed) return this;
|
||||||
var fixed = this.fixed_value();
|
this._eval = return_this;
|
||||||
if (!fixed) throw def;
|
var value = ev(fixed, compressor);
|
||||||
var value = ev(fixed, compressor);
|
if (value === fixed) {
|
||||||
if (!HOP(fixed, "_eval")) fixed._eval = function() {
|
delete this._eval;
|
||||||
return value;
|
return this;
|
||||||
};
|
|
||||||
if (value && typeof value == "object" && this.definition().escaped) throw def;
|
|
||||||
return value;
|
|
||||||
} finally {
|
|
||||||
this._evaluating = false;
|
|
||||||
}
|
}
|
||||||
|
if (!HOP(fixed, "_eval")) fixed._eval = function() {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
if (value && typeof value == "object" && this.definition().escaped) {
|
||||||
|
delete this._eval;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
this._eval = fixed._eval;
|
||||||
|
return value;
|
||||||
});
|
});
|
||||||
|
var global_objs = {
|
||||||
|
Array: Array,
|
||||||
|
Math: Math,
|
||||||
|
Number: Number,
|
||||||
|
String: String,
|
||||||
|
};
|
||||||
|
function convert_to_predicate(obj) {
|
||||||
|
for (var key in obj) {
|
||||||
|
obj[key] = makePredicate(obj[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var static_values = {
|
||||||
|
Math: [
|
||||||
|
"E",
|
||||||
|
"LN10",
|
||||||
|
"LN2",
|
||||||
|
"LOG2E",
|
||||||
|
"LOG10E",
|
||||||
|
"PI",
|
||||||
|
"SQRT1_2",
|
||||||
|
"SQRT2",
|
||||||
|
],
|
||||||
|
Number: [
|
||||||
|
"MAX_VALUE",
|
||||||
|
"MIN_VALUE",
|
||||||
|
"NaN",
|
||||||
|
"NEGATIVE_INFINITY",
|
||||||
|
"POSITIVE_INFINITY",
|
||||||
|
],
|
||||||
|
};
|
||||||
|
convert_to_predicate(static_values);
|
||||||
def(AST_PropAccess, function(compressor){
|
def(AST_PropAccess, function(compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var key = this.property;
|
var key = this.property;
|
||||||
if (key instanceof AST_Node) {
|
if (key instanceof AST_Node) {
|
||||||
key = ev(key, compressor);
|
key = ev(key, compressor);
|
||||||
|
if (key === this.property) return this;
|
||||||
}
|
}
|
||||||
var val = ev(this.expression, compressor);
|
var exp = this.expression;
|
||||||
if (val && HOP(val, key)) {
|
var val;
|
||||||
return val[key];
|
if (is_undeclared_ref(exp)) {
|
||||||
|
if (!(static_values[exp.name] || return_false)(key)) return this;
|
||||||
|
val = global_objs[exp.name];
|
||||||
|
} else {
|
||||||
|
val = ev(exp, compressor);
|
||||||
|
if (!val || val === exp || !HOP(val, key)) return this;
|
||||||
}
|
}
|
||||||
|
return val[key];
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
});
|
||||||
var object_fns = [
|
var object_fns = [
|
||||||
'constructor',
|
"constructor",
|
||||||
'toString',
|
"toString",
|
||||||
'valueOf',
|
"valueOf",
|
||||||
];
|
];
|
||||||
var native_fns = {
|
var native_fns = {
|
||||||
Array: makePredicate([
|
Array: [
|
||||||
'indexOf',
|
"indexOf",
|
||||||
'join',
|
"join",
|
||||||
'lastIndexOf',
|
"lastIndexOf",
|
||||||
'slice',
|
"slice",
|
||||||
].concat(object_fns)),
|
].concat(object_fns),
|
||||||
Boolean: makePredicate(object_fns),
|
Boolean: object_fns,
|
||||||
Number: makePredicate([
|
Number: [
|
||||||
'toExponential',
|
"toExponential",
|
||||||
'toFixed',
|
"toFixed",
|
||||||
'toPrecision',
|
"toPrecision",
|
||||||
].concat(object_fns)),
|
].concat(object_fns),
|
||||||
RegExp: makePredicate([
|
RegExp: [
|
||||||
'test',
|
"test",
|
||||||
].concat(object_fns)),
|
].concat(object_fns),
|
||||||
String: makePredicate([
|
String: [
|
||||||
'charAt',
|
"charAt",
|
||||||
'charCodeAt',
|
"charCodeAt",
|
||||||
'concat',
|
"concat",
|
||||||
'indexOf',
|
"indexOf",
|
||||||
'italics',
|
"italics",
|
||||||
'lastIndexOf',
|
"lastIndexOf",
|
||||||
'match',
|
"match",
|
||||||
'replace',
|
"replace",
|
||||||
'search',
|
"search",
|
||||||
'slice',
|
"slice",
|
||||||
'split',
|
"split",
|
||||||
'substr',
|
"substr",
|
||||||
'substring',
|
"substring",
|
||||||
'trim',
|
"trim",
|
||||||
].concat(object_fns)),
|
].concat(object_fns),
|
||||||
};
|
};
|
||||||
|
convert_to_predicate(native_fns);
|
||||||
|
var static_fns = {
|
||||||
|
Array: [
|
||||||
|
"isArray",
|
||||||
|
],
|
||||||
|
Math: [
|
||||||
|
"abs",
|
||||||
|
"acos",
|
||||||
|
"asin",
|
||||||
|
"atan",
|
||||||
|
"ceil",
|
||||||
|
"cos",
|
||||||
|
"exp",
|
||||||
|
"floor",
|
||||||
|
"log",
|
||||||
|
"round",
|
||||||
|
"sin",
|
||||||
|
"sqrt",
|
||||||
|
"tan",
|
||||||
|
"atan2",
|
||||||
|
"pow",
|
||||||
|
"max",
|
||||||
|
"min"
|
||||||
|
],
|
||||||
|
Number: [
|
||||||
|
"isFinite",
|
||||||
|
"isNaN",
|
||||||
|
],
|
||||||
|
String: [
|
||||||
|
"fromCharCode",
|
||||||
|
],
|
||||||
|
};
|
||||||
|
convert_to_predicate(static_fns);
|
||||||
def(AST_Call, function(compressor){
|
def(AST_Call, function(compressor){
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
|
if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
|
||||||
var key = exp.property;
|
var key = exp.property;
|
||||||
if (key instanceof AST_Node) {
|
if (key instanceof AST_Node) {
|
||||||
key = ev(key, compressor);
|
key = ev(key, compressor);
|
||||||
|
if (key === exp.property) return this;
|
||||||
}
|
}
|
||||||
var val = ev(exp.expression, compressor);
|
var val;
|
||||||
if ((val && native_fns[val.constructor.name] || return_false)(key)) {
|
var e = exp.expression;
|
||||||
return val[key].apply(val, this.args.map(function(arg) {
|
if (is_undeclared_ref(e)) {
|
||||||
return ev(arg, compressor);
|
if (!(static_fns[e.name] || return_false)(key)) return this;
|
||||||
}));
|
val = global_objs[e.name];
|
||||||
|
} else {
|
||||||
|
val = ev(e, compressor);
|
||||||
|
if (val === e || !(val && native_fns[val.constructor.name] || return_false)(key)) return this;
|
||||||
}
|
}
|
||||||
|
var args = [];
|
||||||
|
for (var i = 0, len = this.args.length; i < len; i++) {
|
||||||
|
var arg = this.args[i];
|
||||||
|
var value = ev(arg, compressor);
|
||||||
|
if (arg === value) return this;
|
||||||
|
args.push(value);
|
||||||
|
}
|
||||||
|
return val[key].apply(val, args);
|
||||||
}
|
}
|
||||||
throw def;
|
return this;
|
||||||
});
|
|
||||||
def(AST_New, function(compressor){
|
|
||||||
throw def;
|
|
||||||
});
|
});
|
||||||
|
def(AST_New, return_this);
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
node.DEFMETHOD("_eval", func);
|
node.DEFMETHOD("_eval", func);
|
||||||
});
|
});
|
||||||
@@ -1858,16 +1983,27 @@ merge(Compressor.prototype, {
|
|||||||
if (!compressor.option("side_effects")) return false;
|
if (!compressor.option("side_effects")) return false;
|
||||||
if (this.pure !== undefined) return this.pure;
|
if (this.pure !== undefined) return this.pure;
|
||||||
var pure = false;
|
var pure = false;
|
||||||
var comments, last_comment;
|
var comments, pure_comment;
|
||||||
if (this.start
|
if (this.start
|
||||||
&& (comments = this.start.comments_before)
|
&& (comments = this.start.comments_before)
|
||||||
&& comments.length
|
&& comments.length
|
||||||
&& /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) {
|
&& (pure_comment = find_if(function (comment) {
|
||||||
pure = last_comment;
|
return /[@#]__PURE__/.test(comment.value);
|
||||||
|
}, comments))) {
|
||||||
|
pure = pure_comment;
|
||||||
}
|
}
|
||||||
return this.pure = pure;
|
return this.pure = pure;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
|
||||||
|
AST_Call.DEFMETHOD("is_expr_pure", function(compressor) {
|
||||||
|
if (compressor.option("unsafe")) {
|
||||||
|
var expr = this.expression;
|
||||||
|
if (is_undeclared_ref(expr) && global_pure_fns(expr.name)) return true;
|
||||||
|
}
|
||||||
|
return this.has_pure_annotation(compressor) || !compressor.pure_funcs(this);
|
||||||
|
});
|
||||||
|
|
||||||
// determine if expression has side effects
|
// determine if expression has side effects
|
||||||
(function(def){
|
(function(def){
|
||||||
def(AST_Node, return_true);
|
def(AST_Node, return_true);
|
||||||
@@ -1877,7 +2013,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_This, return_false);
|
def(AST_This, return_false);
|
||||||
|
|
||||||
def(AST_Call, function(compressor){
|
def(AST_Call, function(compressor){
|
||||||
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return true;
|
if (!this.is_expr_pure(compressor)) return true;
|
||||||
for (var i = this.args.length; --i >= 0;) {
|
for (var i = this.args.length; --i >= 0;) {
|
||||||
if (this.args[i].has_side_effects(compressor))
|
if (this.args[i].has_side_effects(compressor))
|
||||||
return true;
|
return true;
|
||||||
@@ -1936,7 +2072,7 @@ merge(Compressor.prototype, {
|
|||||||
|| this.expression.has_side_effects(compressor);
|
|| this.expression.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor){
|
def(AST_SymbolRef, function(compressor){
|
||||||
return this.undeclared();
|
return !this.is_declared(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolDeclaration, return_false);
|
def(AST_SymbolDeclaration, return_false);
|
||||||
def(AST_Object, function(compressor){
|
def(AST_Object, function(compressor){
|
||||||
@@ -2060,7 +2196,12 @@ merge(Compressor.prototype, {
|
|||||||
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;
|
if (!drop_funcs && !drop_vars) return;
|
||||||
var assign_as_unused = !/keep_assign/.test(compressor.option("unused"));
|
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node) {
|
||||||
|
if (node instanceof AST_Assign && (node.write_only || node.operator == "=")) {
|
||||||
|
return node.left;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Unary && node.write_only) return node.expression;
|
||||||
|
};
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||||
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
||||||
@@ -2110,12 +2251,8 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (assign_as_unused
|
if (assign_as_unused(node) instanceof AST_SymbolRef && scope === self) {
|
||||||
&& node instanceof AST_Assign
|
if (node instanceof AST_Assign) node.right.walk(tw);
|
||||||
&& node.operator == "="
|
|
||||||
&& node.left instanceof AST_SymbolRef
|
|
||||||
&& scope === self) {
|
|
||||||
node.right.walk(tw);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
@@ -2279,14 +2416,17 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (drop_vars && assign_as_unused
|
if (drop_vars) {
|
||||||
&& node instanceof AST_Assign
|
var def = assign_as_unused(node);
|
||||||
&& node.operator == "="
|
if (def instanceof AST_SymbolRef
|
||||||
&& node.left instanceof AST_SymbolRef) {
|
&& !((def = def.definition()).id in in_use_ids)
|
||||||
var def = node.left.definition();
|
|
||||||
if (!(def.id in in_use_ids)
|
|
||||||
&& self.variables.get(def.name) === def) {
|
&& self.variables.get(def.name) === def) {
|
||||||
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
|
if (node instanceof AST_Assign) {
|
||||||
|
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
|
||||||
|
}
|
||||||
|
return make_node(AST_Number, node, {
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// certain combination of unused name + side effect leads to:
|
// certain combination of unused name + side effect leads to:
|
||||||
@@ -2297,17 +2437,18 @@ merge(Compressor.prototype, {
|
|||||||
// We fix it at this stage by moving the `var` outside the `for`.
|
// We fix it at this stage by moving the `var` outside the `for`.
|
||||||
if (node instanceof AST_For) {
|
if (node instanceof AST_For) {
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
|
var block;
|
||||||
if (node.init instanceof AST_BlockStatement) {
|
if (node.init instanceof AST_BlockStatement) {
|
||||||
var block = node.init;
|
block = node.init;
|
||||||
node.init = block.body.pop();
|
node.init = block.body.pop();
|
||||||
block.body.push(node);
|
block.body.push(node);
|
||||||
return in_list ? MAP.splice(block.body) : block;
|
}
|
||||||
} else if (node.init instanceof AST_SimpleStatement) {
|
if (node.init instanceof AST_SimpleStatement) {
|
||||||
node.init = node.init.body;
|
node.init = node.init.body;
|
||||||
} else if (is_empty(node.init)) {
|
} else if (is_empty(node.init)) {
|
||||||
node.init = null;
|
node.init = null;
|
||||||
}
|
}
|
||||||
return node;
|
return !block ? node : in_list ? MAP.splice(block.body) : block;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
|
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
@@ -2491,7 +2632,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Constant, return_null);
|
def(AST_Constant, return_null);
|
||||||
def(AST_This, return_null);
|
def(AST_This, return_null);
|
||||||
def(AST_Call, function(compressor, first_in_statement){
|
def(AST_Call, function(compressor, first_in_statement){
|
||||||
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) {
|
if (!this.is_expr_pure(compressor)) {
|
||||||
if (this.expression instanceof AST_Function
|
if (this.expression instanceof AST_Function
|
||||||
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
|
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
|
||||||
var node = this.clone();
|
var node = this.clone();
|
||||||
@@ -2525,7 +2666,10 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(this, [ left, right ]);
|
return make_sequence(this, [ left, right ]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
def(AST_Assign, return_this);
|
def(AST_Assign, function(compressor){
|
||||||
|
this.write_only = !this.left.has_side_effects(compressor);
|
||||||
|
return this;
|
||||||
|
});
|
||||||
def(AST_Conditional, function(compressor){
|
def(AST_Conditional, function(compressor){
|
||||||
var consequent = this.consequent.drop_side_effect_free(compressor);
|
var consequent = this.consequent.drop_side_effect_free(compressor);
|
||||||
var alternative = this.alternative.drop_side_effect_free(compressor);
|
var alternative = this.alternative.drop_side_effect_free(compressor);
|
||||||
@@ -2546,7 +2690,10 @@ merge(Compressor.prototype, {
|
|||||||
return node;
|
return node;
|
||||||
});
|
});
|
||||||
def(AST_Unary, function(compressor, first_in_statement){
|
def(AST_Unary, function(compressor, first_in_statement){
|
||||||
if (unary_side_effects(this.operator)) return this;
|
if (unary_side_effects(this.operator)) {
|
||||||
|
this.write_only = !this.expression.has_side_effects(compressor);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null;
|
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null;
|
||||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (first_in_statement
|
if (first_in_statement
|
||||||
@@ -2560,8 +2707,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return expression;
|
return expression;
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function() {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
return this.undeclared() ? this : null;
|
return this.is_declared(compressor) ? null : this;
|
||||||
});
|
});
|
||||||
def(AST_Object, function(compressor, first_in_statement){
|
def(AST_Object, function(compressor, first_in_statement){
|
||||||
var values = trim(this.properties, compressor, first_in_statement);
|
var values = trim(this.properties, compressor, first_in_statement);
|
||||||
@@ -2980,6 +3127,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);
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
if (assignments.length == 0) return null;
|
if (assignments.length == 0) return null;
|
||||||
@@ -3023,7 +3171,7 @@ merge(Compressor.prototype, {
|
|||||||
self.args.length = last;
|
self.args.length = last;
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
if (is_undeclared_ref(exp)) {
|
||||||
switch (exp.name) {
|
switch (exp.name) {
|
||||||
case "Array":
|
case "Array":
|
||||||
if (self.args.length != 1) {
|
if (self.args.length != 1) {
|
||||||
@@ -3150,8 +3298,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe_Func")
|
if (compressor.option("unsafe_Func")
|
||||||
&& exp instanceof AST_SymbolRef
|
&& is_undeclared_ref(exp)
|
||||||
&& exp.undeclared()
|
|
||||||
&& exp.name == "Function") {
|
&& exp.name == "Function") {
|
||||||
// new Function() => function(){}
|
// new Function() => function(){}
|
||||||
if (self.args.length == 0) return make_node(AST_Function, self, {
|
if (self.args.length == 0) return make_node(AST_Function, self, {
|
||||||
@@ -3268,9 +3415,7 @@ merge(Compressor.prototype, {
|
|||||||
while (name.expression) {
|
while (name.expression) {
|
||||||
name = name.expression;
|
name = name.expression;
|
||||||
}
|
}
|
||||||
if (name instanceof AST_SymbolRef
|
if (is_undeclared_ref(name) && name.name == "console") {
|
||||||
&& name.name == "console"
|
|
||||||
&& name.undeclared()) {
|
|
||||||
return make_node(AST_Undefined, self).optimize(compressor);
|
return make_node(AST_Undefined, self).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3291,7 +3436,7 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_New, function(self, compressor){
|
OPT(AST_New, function(self, compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
if (is_undeclared_ref(exp)) {
|
||||||
switch (exp.name) {
|
switch (exp.name) {
|
||||||
case "Object":
|
case "Object":
|
||||||
case "RegExp":
|
case "RegExp":
|
||||||
@@ -3354,7 +3499,7 @@ merge(Compressor.prototype, {
|
|||||||
&& (left.operator == "++" || left.operator == "--")) {
|
&& (left.operator == "++" || left.operator == "--")) {
|
||||||
left = left.expression;
|
left = left.expression;
|
||||||
} else left = null;
|
} else left = null;
|
||||||
if (!left || is_lhs_read_only(left)) {
|
if (!left || is_lhs_read_only(left) || left.has_side_effects(compressor)) {
|
||||||
expressions[++i] = cdr;
|
expressions[++i] = cdr;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -3368,6 +3513,8 @@ merge(Compressor.prototype, {
|
|||||||
operator: car.operator,
|
operator: car.operator,
|
||||||
expression: left
|
expression: left
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
car.write_only = false;
|
||||||
}
|
}
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent[field] = car;
|
parent[field] = car;
|
||||||
@@ -3577,12 +3724,13 @@ merge(Compressor.prototype, {
|
|||||||
case "==":
|
case "==":
|
||||||
case "!=":
|
case "!=":
|
||||||
// "undefined" == typeof x => undefined === x
|
// "undefined" == typeof x => undefined === x
|
||||||
if (self.left instanceof AST_String
|
if (compressor.option("typeofs")
|
||||||
|
&& self.left instanceof AST_String
|
||||||
&& self.left.value == "undefined"
|
&& self.left.value == "undefined"
|
||||||
&& self.right instanceof AST_UnaryPrefix
|
&& self.right instanceof AST_UnaryPrefix
|
||||||
&& self.right.operator == "typeof") {
|
&& self.right.operator == "typeof") {
|
||||||
var expr = self.right.expression;
|
var expr = self.right.expression;
|
||||||
if (expr instanceof AST_SymbolRef ? !expr.undeclared()
|
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
|
||||||
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
||||||
self.right = expr;
|
self.right = expr;
|
||||||
self.left = make_node(AST_Undefined, self.left).optimize(compressor);
|
self.left = make_node(AST_Undefined, self.left).optimize(compressor);
|
||||||
@@ -3908,7 +4056,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
// testing against !self.scope.uses_with first is an optimization
|
// testing against !self.scope.uses_with first is an optimization
|
||||||
if (!compressor.option("ie8")
|
if (!compressor.option("ie8")
|
||||||
&& self.undeclared()
|
&& is_undeclared_ref(self)
|
||||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||||
switch (self.name) {
|
switch (self.name) {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
@@ -4263,7 +4411,7 @@ merge(Compressor.prototype, {
|
|||||||
var prop = self.property;
|
var prop = self.property;
|
||||||
if (prop instanceof AST_String && compressor.option("properties")) {
|
if (prop instanceof AST_String && compressor.option("properties")) {
|
||||||
prop = prop.getValue();
|
prop = prop.getValue();
|
||||||
if (RESERVED_WORDS(prop) ? !compressor.option("ie8") : is_identifier_string(prop)) {
|
if (is_identifier_string(prop)) {
|
||||||
return make_node(AST_Dot, self, {
|
return make_node(AST_Dot, self, {
|
||||||
expression : self.expression,
|
expression : self.expression,
|
||||||
property : prop
|
property : prop
|
||||||
@@ -4284,25 +4432,41 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Lambda.DEFMETHOD("contains_this", function() {
|
||||||
|
var result;
|
||||||
|
var self = this;
|
||||||
|
self.walk(new TreeWalker(function(node) {
|
||||||
|
if (result) return true;
|
||||||
|
if (node instanceof AST_This) return result = true;
|
||||||
|
if (node !== self && node instanceof AST_Scope) return true;
|
||||||
|
}));
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
var prop = self.property;
|
if (compressor.option("unsafe") && self.expression instanceof AST_Object) {
|
||||||
if (RESERVED_WORDS(prop) && compressor.option("ie8")) {
|
var values = self.expression.properties;
|
||||||
return make_node(AST_Sub, self, {
|
for (var i = values.length; --i >= 0;) {
|
||||||
expression : self.expression,
|
if (values[i].key === self.property) {
|
||||||
property : make_node(AST_String, self, {
|
var value = values[i].value;
|
||||||
value: prop
|
if (value instanceof AST_Function ? !value.contains_this() : !value.has_side_effects(compressor)) {
|
||||||
})
|
var obj = self.expression.clone();
|
||||||
}).optimize(compressor);
|
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") {
|
||||||
var exp = self.expression.expression;
|
var exp = self.expression.expression;
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) switch (exp.name) {
|
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||||
case "Array":
|
case "Array":
|
||||||
self.expression = make_node(AST_Array, self.expression, {
|
self.expression = make_node(AST_Array, self.expression, {
|
||||||
elements: []
|
elements: []
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ function minify(files, options) {
|
|||||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||||
set_shorthand("warnings", options, [ "compress" ]);
|
set_shorthand("warnings", options, [ "compress" ]);
|
||||||
|
var quoted_props;
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
options.mangle = defaults(options.mangle, {
|
options.mangle = defaults(options.mangle, {
|
||||||
cache: options.nameCache && (options.nameCache.vars || {}),
|
cache: options.nameCache && (options.nameCache.vars || {}),
|
||||||
@@ -78,11 +79,16 @@ function minify(files, options) {
|
|||||||
reserved: [],
|
reserved: [],
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
}, true);
|
}, true);
|
||||||
if (options.nameCache && options.mangle.properties) {
|
if (options.mangle.properties) {
|
||||||
if (typeof options.mangle.properties != "object") {
|
if (typeof options.mangle.properties != "object") {
|
||||||
options.mangle.properties = {};
|
options.mangle.properties = {};
|
||||||
}
|
}
|
||||||
if (!("cache" in options.mangle.properties)) {
|
if (options.mangle.properties.keep_quoted) {
|
||||||
|
quoted_props = options.mangle.properties.reserved;
|
||||||
|
if (!Array.isArray(quoted_props)) quoted_props = [];
|
||||||
|
options.mangle.properties.reserved = quoted_props;
|
||||||
|
}
|
||||||
|
if (options.nameCache && !("cache" in options.mangle.properties)) {
|
||||||
options.mangle.properties.cache = options.nameCache.props || {};
|
options.mangle.properties.cache = options.nameCache.props || {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,6 +131,9 @@ function minify(files, options) {
|
|||||||
}
|
}
|
||||||
toplevel = options.parse.toplevel;
|
toplevel = options.parse.toplevel;
|
||||||
}
|
}
|
||||||
|
if (quoted_props) {
|
||||||
|
reserve_quoted_keys(toplevel, quoted_props);
|
||||||
|
}
|
||||||
if (options.wrap) {
|
if (options.wrap) {
|
||||||
toplevel = toplevel.wrap_commonjs(options.wrap);
|
toplevel = toplevel.wrap_commonjs(options.wrap);
|
||||||
}
|
}
|
||||||
|
|||||||
103
lib/output.js
103
lib/output.js
@@ -109,7 +109,7 @@ function OutputStream(options) {
|
|||||||
var current_pos = 0;
|
var current_pos = 0;
|
||||||
var OUTPUT = "";
|
var OUTPUT = "";
|
||||||
|
|
||||||
function to_ascii(str, identifier) {
|
var to_utf8 = options.ascii_only ? function(str, identifier) {
|
||||||
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
|
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
|
||||||
var code = ch.charCodeAt(0).toString(16);
|
var code = ch.charCodeAt(0).toString(16);
|
||||||
if (code.length <= 2 && !identifier) {
|
if (code.length <= 2 && !identifier) {
|
||||||
@@ -120,6 +120,12 @@ function OutputStream(options) {
|
|||||||
return "\\u" + code;
|
return "\\u" + code;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} : function(str) {
|
||||||
|
return str.replace(/[\ud800-\udbff](?![\udc00-\udfff])/g, function(ch) {
|
||||||
|
return "\\u" + ch.charCodeAt(0).toString(16);
|
||||||
|
}).replace(/(^|[^\ud800-\udbff])([\udc00-\udfff])/g, function(match, prefix, ch) {
|
||||||
|
return prefix + "\\u" + ch.charCodeAt(0).toString(16);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function make_string(str, quote) {
|
function make_string(str, quote) {
|
||||||
@@ -140,7 +146,7 @@ function OutputStream(options) {
|
|||||||
case "\u2029": return "\\u2029";
|
case "\u2029": return "\\u2029";
|
||||||
case "\ufeff": return "\\ufeff";
|
case "\ufeff": return "\\ufeff";
|
||||||
case "\0":
|
case "\0":
|
||||||
return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
|
return /[0-9]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
@@ -150,7 +156,7 @@ function OutputStream(options) {
|
|||||||
function quote_double() {
|
function quote_double() {
|
||||||
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
||||||
}
|
}
|
||||||
if (options.ascii_only) str = to_ascii(str);
|
str = to_utf8(str);
|
||||||
switch (options.quote_style) {
|
switch (options.quote_style) {
|
||||||
case 1:
|
case 1:
|
||||||
return quote_single();
|
return quote_single();
|
||||||
@@ -175,8 +181,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function make_name(name) {
|
function make_name(name) {
|
||||||
name = name.toString();
|
name = name.toString();
|
||||||
if (options.ascii_only)
|
name = to_utf8(name, true);
|
||||||
name = to_ascii(name, true);
|
|
||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -433,7 +438,7 @@ function OutputStream(options) {
|
|||||||
last : function() { return last },
|
last : function() { return last },
|
||||||
semicolon : semicolon,
|
semicolon : semicolon,
|
||||||
force_semicolon : force_semicolon,
|
force_semicolon : force_semicolon,
|
||||||
to_ascii : to_ascii,
|
to_utf8 : to_utf8,
|
||||||
print_name : function(name) { print(make_name(name)) },
|
print_name : function(name) { print(make_name(name)) },
|
||||||
print_string : function(str, quote, escape_directive) {
|
print_string : function(str, quote, escape_directive) {
|
||||||
var encoded = encode_string(str, quote);
|
var encoded = encode_string(str, quote);
|
||||||
@@ -477,13 +482,17 @@ function OutputStream(options) {
|
|||||||
nodetype.DEFMETHOD("_codegen", generator);
|
nodetype.DEFMETHOD("_codegen", generator);
|
||||||
};
|
};
|
||||||
|
|
||||||
var use_asm = false;
|
|
||||||
var in_directive = false;
|
var in_directive = false;
|
||||||
|
var active_scope = null;
|
||||||
|
var use_asm = null;
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
||||||
var self = this, generator = self._codegen, prev_use_asm = use_asm;
|
var self = this, generator = self._codegen;
|
||||||
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
|
if (self instanceof AST_Scope) {
|
||||||
use_asm = true;
|
active_scope = self;
|
||||||
|
}
|
||||||
|
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
|
||||||
|
use_asm = active_scope;
|
||||||
}
|
}
|
||||||
function doit() {
|
function doit() {
|
||||||
self.add_comments(stream);
|
self.add_comments(stream);
|
||||||
@@ -497,8 +506,8 @@ function OutputStream(options) {
|
|||||||
doit();
|
doit();
|
||||||
}
|
}
|
||||||
stream.pop_node();
|
stream.pop_node();
|
||||||
if (self instanceof AST_Scope) {
|
if (self === use_asm) {
|
||||||
use_asm = prev_use_asm;
|
use_asm = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||||
@@ -672,14 +681,15 @@ function OutputStream(options) {
|
|||||||
// parens around it too, otherwise the call will be
|
// parens around it too, otherwise the call will be
|
||||||
// interpreted as passing the arguments to the upper New
|
// interpreted as passing the arguments to the upper New
|
||||||
// expression.
|
// expression.
|
||||||
try {
|
var parens = false;
|
||||||
this.walk(new TreeWalker(function(node){
|
this.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Call) throw p;
|
if (parens || node instanceof AST_Scope) return true;
|
||||||
}));
|
if (node instanceof AST_Call) {
|
||||||
} catch(ex) {
|
parens = true;
|
||||||
if (ex !== p) throw ex;
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
}));
|
||||||
|
return parens;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1073,19 +1083,17 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function parenthesize_for_noin(node, output, noin) {
|
function parenthesize_for_noin(node, output, noin) {
|
||||||
if (!noin) node.print(output);
|
var parens = false;
|
||||||
else try {
|
// need to take some precautions here:
|
||||||
// need to take some precautions here:
|
// https://github.com/mishoo/UglifyJS2/issues/60
|
||||||
// https://github.com/mishoo/UglifyJS2/issues/60
|
if (noin) node.walk(new TreeWalker(function(node) {
|
||||||
node.walk(new TreeWalker(function(node){
|
if (parens || node instanceof AST_Scope) return true;
|
||||||
if (node instanceof AST_Binary && node.operator == "in")
|
if (node instanceof AST_Binary && node.operator == "in") {
|
||||||
throw output;
|
parens = true;
|
||||||
}));
|
return true;
|
||||||
node.print(output);
|
}
|
||||||
} catch(ex) {
|
}));
|
||||||
if (ex !== output) throw ex;
|
node.print(output, parens);
|
||||||
node.print(output, true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFPRINT(AST_VarDef, function(self, output){
|
DEFPRINT(AST_VarDef, function(self, output){
|
||||||
@@ -1105,6 +1113,9 @@ function OutputStream(options) {
|
|||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
||||||
return;
|
return;
|
||||||
|
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
||||||
|
output.add_mapping(self.start);
|
||||||
|
}
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
self.args.forEach(function(expr, i){
|
self.args.forEach(function(expr, i){
|
||||||
if (i) output.comma();
|
if (i) output.comma();
|
||||||
@@ -1144,15 +1155,23 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Dot, function(self, output){
|
DEFPRINT(AST_Dot, function(self, output){
|
||||||
var expr = self.expression;
|
var expr = self.expression;
|
||||||
expr.print(output);
|
expr.print(output);
|
||||||
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
var prop = self.property;
|
||||||
if (!/[xa-f.)]/i.test(output.last())) {
|
if (output.option("ie8") && RESERVED_WORDS(prop)) {
|
||||||
output.print(".");
|
output.print("[");
|
||||||
|
output.add_mapping(self.end);
|
||||||
|
output.print_string(prop);
|
||||||
|
output.print("]");
|
||||||
|
} else {
|
||||||
|
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
||||||
|
if (!/[xa-f.)]/i.test(output.last())) {
|
||||||
|
output.print(".");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
output.print(".");
|
||||||
|
// the name after dot would be mapped about here.
|
||||||
|
output.add_mapping(self.end);
|
||||||
|
output.print_name(prop);
|
||||||
}
|
}
|
||||||
output.print(".");
|
|
||||||
// the name after dot would be mapped about here.
|
|
||||||
output.add_mapping(self.end);
|
|
||||||
output.print_name(self.property);
|
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Sub, function(self, output){
|
DEFPRINT(AST_Sub, function(self, output){
|
||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
@@ -1308,9 +1327,7 @@ function OutputStream(options) {
|
|||||||
if (regexp.raw_source) {
|
if (regexp.raw_source) {
|
||||||
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
|
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
|
||||||
}
|
}
|
||||||
if (output.option("ascii_only")) {
|
str = output.to_utf8(str);
|
||||||
str = output.to_ascii(str);
|
|
||||||
}
|
|
||||||
output.print(str);
|
output.print(str);
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||||
|
|||||||
@@ -67,6 +67,34 @@ function find_builtins(reserved) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reserve_quoted_keys(ast, reserved) {
|
||||||
|
function add(name) {
|
||||||
|
push_uniq(reserved, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast.walk(new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_ObjectKeyVal && node.quote) {
|
||||||
|
add(node.key);
|
||||||
|
} else if (node instanceof AST_Sub) {
|
||||||
|
addStrings(node.property, add);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStrings(node, add) {
|
||||||
|
node.walk(new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_Sequence) {
|
||||||
|
addStrings(node.expressions[node.expressions.length - 1], add);
|
||||||
|
} else if (node instanceof AST_String) {
|
||||||
|
add(node.value);
|
||||||
|
} else if (node instanceof AST_Conditional) {
|
||||||
|
addStrings(node.consequent, add);
|
||||||
|
addStrings(node.alternative, add);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function mangle_properties(ast, options) {
|
function mangle_properties(ast, options) {
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
builtins: false,
|
builtins: false,
|
||||||
@@ -76,7 +104,7 @@ function mangle_properties(ast, options) {
|
|||||||
only_cache: false,
|
only_cache: false,
|
||||||
regex: null,
|
regex: null,
|
||||||
reserved: null,
|
reserved: null,
|
||||||
});
|
}, true);
|
||||||
|
|
||||||
var reserved = options.reserved;
|
var reserved = options.reserved;
|
||||||
if (!Array.isArray(reserved)) reserved = [];
|
if (!Array.isArray(reserved)) reserved = [];
|
||||||
@@ -91,7 +119,6 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var regex = options.regex;
|
var regex = options.regex;
|
||||||
var keep_quoted = options.keep_quoted;
|
|
||||||
|
|
||||||
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
|
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
|
||||||
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
|
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
|
||||||
@@ -104,12 +131,11 @@ function mangle_properties(ast, options) {
|
|||||||
|
|
||||||
var names_to_mangle = [];
|
var names_to_mangle = [];
|
||||||
var unmangleable = [];
|
var unmangleable = [];
|
||||||
var to_keep = {};
|
|
||||||
|
|
||||||
// step 1: find candidates to mangle
|
// step 1: find candidates to mangle
|
||||||
ast.walk(new TreeWalker(function(node){
|
ast.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
add(node.key, keep_quoted && node.quote);
|
add(node.key);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter, since KeyVal is handled above
|
// setter or getter, since KeyVal is handled above
|
||||||
@@ -119,15 +145,14 @@ function mangle_properties(ast, options) {
|
|||||||
add(node.property);
|
add(node.property);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Sub) {
|
else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, keep_quoted);
|
addStrings(node.property, add);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// step 2: transform the tree, renaming properties
|
// step 2: transform the tree, renaming properties
|
||||||
return ast.transform(new TreeTransformer(function(node){
|
return ast.transform(new TreeTransformer(function(node){
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
if (!(keep_quoted && node.quote))
|
node.key = mangle(node.key);
|
||||||
node.key = mangle(node.key);
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter
|
// setter or getter
|
||||||
@@ -136,22 +161,9 @@ function mangle_properties(ast, options) {
|
|||||||
else if (node instanceof AST_Dot) {
|
else if (node instanceof AST_Dot) {
|
||||||
node.property = mangle(node.property);
|
node.property = mangle(node.property);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Sub) {
|
else if (!options.keep_quoted && node instanceof AST_Sub) {
|
||||||
if (!keep_quoted)
|
node.property = mangleStrings(node.property);
|
||||||
node.property = mangleStrings(node.property);
|
|
||||||
}
|
}
|
||||||
// else if (node instanceof AST_String) {
|
|
||||||
// if (should_mangle(node.value)) {
|
|
||||||
// AST_Node.warn(
|
|
||||||
// "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
|
|
||||||
// file : node.start.file,
|
|
||||||
// line : node.start.line,
|
|
||||||
// col : node.start.col,
|
|
||||||
// prop : node.value
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// only function declarations after this line
|
// only function declarations after this line
|
||||||
@@ -167,19 +179,13 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function should_mangle(name) {
|
function should_mangle(name) {
|
||||||
if (keep_quoted && name in to_keep) return false;
|
|
||||||
if (regex && !regex.test(name)) return false;
|
if (regex && !regex.test(name)) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
return cache.props.has(name)
|
return cache.props.has(name)
|
||||||
|| names_to_mangle.indexOf(name) >= 0;
|
|| names_to_mangle.indexOf(name) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(name, keep) {
|
function add(name) {
|
||||||
if (keep) {
|
|
||||||
to_keep[name] = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (can_mangle(name))
|
if (can_mangle(name))
|
||||||
push_uniq(names_to_mangle, name);
|
push_uniq(names_to_mangle, name);
|
||||||
|
|
||||||
@@ -199,19 +205,16 @@ function mangle_properties(ast, options) {
|
|||||||
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
||||||
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
|
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
|
||||||
|
|
||||||
if (can_mangle(debug_mangled) && !(keep_quoted && debug_mangled in to_keep)) {
|
if (can_mangle(debug_mangled)) {
|
||||||
mangled = debug_mangled;
|
mangled = debug_mangled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// either debug mode is off, or it is on and we could not use the mangled name
|
// either debug mode is off, or it is on and we could not use the mangled name
|
||||||
if (!mangled) {
|
if (!mangled) {
|
||||||
// Note: `can_mangle()` does not check if the name collides with the `to_keep` set
|
|
||||||
// (filled with quoted properties when `keep_quoted` is set). Make sure we add this
|
|
||||||
// check so we don't collide with a quoted name.
|
|
||||||
do {
|
do {
|
||||||
mangled = base54(++cache.cname);
|
mangled = base54(++cache.cname);
|
||||||
} while (!can_mangle(mangled) || keep_quoted && mangled in to_keep);
|
} while (!can_mangle(mangled));
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.props.set(name, mangled);
|
cache.props.set(name, mangled);
|
||||||
@@ -219,32 +222,6 @@ function mangle_properties(ast, options) {
|
|||||||
return mangled;
|
return mangled;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addStrings(node, keep) {
|
|
||||||
var out = {};
|
|
||||||
try {
|
|
||||||
(function walk(node){
|
|
||||||
node.walk(new TreeWalker(function(node){
|
|
||||||
if (node instanceof AST_Sequence) {
|
|
||||||
walk(node.expressions[node.expressions.length - 1]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_String) {
|
|
||||||
add(node.value, keep);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Conditional) {
|
|
||||||
walk(node.consequent);
|
|
||||||
walk(node.alternative);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
throw out;
|
|
||||||
}));
|
|
||||||
})(node);
|
|
||||||
} catch(ex) {
|
|
||||||
if (ex !== out) throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mangleStrings(node) {
|
function mangleStrings(node) {
|
||||||
return node.transform(new TreeTransformer(function(node){
|
return node.transform(new TreeTransformer(function(node){
|
||||||
if (node instanceof AST_Sequence) {
|
if (node instanceof AST_Sequence) {
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
ref.reference(options);
|
ref.reference(options);
|
||||||
});
|
});
|
||||||
node.thedef = def;
|
node.thedef = def;
|
||||||
|
node.reference(options);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -373,14 +374,6 @@ AST_Symbol.DEFMETHOD("unreferenced", function(){
|
|||||||
&& !(this.scope.uses_eval || this.scope.uses_with);
|
&& !(this.scope.uses_eval || this.scope.uses_with);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("undeclared", function(){
|
|
||||||
return this.definition().undeclared;
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_LabelRef.DEFMETHOD("undeclared", return_false);
|
|
||||||
|
|
||||||
AST_Label.DEFMETHOD("undeclared", return_false);
|
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("definition", function(){
|
AST_Symbol.DEFMETHOD("definition", function(){
|
||||||
return this.thedef;
|
return this.thedef;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
if (y !== undefined) x = y;
|
if (y !== undefined) x = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tw.pop(this);
|
tw.pop();
|
||||||
return x;
|
return x;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -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.0.23",
|
"version": "3.1.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
@@ -29,13 +29,13 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "~2.9.0",
|
"commander": "~2.11.0",
|
||||||
"source-map": "~0.5.1"
|
"source-map": "~0.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "~5.0.3",
|
"acorn": "~5.1.1",
|
||||||
"mocha": "~2.3.4",
|
"mocha": "~3.5.1",
|
||||||
"semver": "~5.3.0"
|
"semver": "~5.4.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test/run-tests.js"
|
"test": "node test/run-tests.js"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
var createHash = require("crypto").createHash;
|
var createHash = require("crypto").createHash;
|
||||||
var fetch = require("./fetch");
|
var fetch = require("./fetch");
|
||||||
var fork = require("child_process").fork;
|
var fork = require("child_process").fork;
|
||||||
|
var zlib = require("zlib");
|
||||||
var args = process.argv.slice(2);
|
var args = process.argv.slice(2);
|
||||||
if (!args.length) {
|
if (!args.length) {
|
||||||
args.push("-mc");
|
args.push("-mc");
|
||||||
@@ -33,6 +34,7 @@ function done() {
|
|||||||
console.log(info.log);
|
console.log(info.log);
|
||||||
console.log("Original:", info.input, "bytes");
|
console.log("Original:", info.input, "bytes");
|
||||||
console.log("Uglified:", info.output, "bytes");
|
console.log("Uglified:", info.output, "bytes");
|
||||||
|
console.log("GZipped: ", info.gzip, "bytes");
|
||||||
console.log("SHA1 sum:", info.sha1);
|
console.log("SHA1 sum:", info.sha1);
|
||||||
if (info.code) {
|
if (info.code) {
|
||||||
failures.push(url);
|
failures.push(url);
|
||||||
@@ -51,6 +53,7 @@ urls.forEach(function(url) {
|
|||||||
results[url] = {
|
results[url] = {
|
||||||
input: 0,
|
input: 0,
|
||||||
output: 0,
|
output: 0,
|
||||||
|
gzip: 0,
|
||||||
log: ""
|
log: ""
|
||||||
};
|
};
|
||||||
fetch(url, function(err, res) {
|
fetch(url, function(err, res) {
|
||||||
@@ -61,6 +64,10 @@ urls.forEach(function(url) {
|
|||||||
}).pipe(uglifyjs.stdin);
|
}).pipe(uglifyjs.stdin);
|
||||||
uglifyjs.stdout.on("data", function(data) {
|
uglifyjs.stdout.on("data", function(data) {
|
||||||
results[url].output += data.length;
|
results[url].output += data.length;
|
||||||
|
}).pipe(zlib.createGzip({
|
||||||
|
level: zlib.Z_BEST_COMPRESSION
|
||||||
|
})).on("data", function(data) {
|
||||||
|
results[url].gzip += data.length;
|
||||||
}).pipe(createHash("sha1")).on("data", function(data) {
|
}).pipe(createHash("sha1")).on("data", function(data) {
|
||||||
results[url].sha1 = data.toString("hex");
|
results[url].sha1 = data.toString("hex");
|
||||||
done();
|
done();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ascii_only_true: {
|
|||||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
||||||
}
|
}
|
||||||
|
|
||||||
ascii_only_false: {
|
ascii_only_false: {
|
||||||
@@ -31,5 +31,5 @@ ascii_only_false: {
|
|||||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,3 +104,65 @@ asm_mixed: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm_toplevel: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
function f() {
|
||||||
|
0.0;
|
||||||
|
(function(){
|
||||||
|
0.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
|
||||||
|
}
|
||||||
|
|
||||||
|
asm_function_expression: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
0.0;
|
||||||
|
var a = function() {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
function f() {
|
||||||
|
0.0;
|
||||||
|
return function(){
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
|
||||||
|
}
|
||||||
|
|
||||||
|
asm_nested_functions: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
0.0;
|
||||||
|
function a() {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
function b() {
|
||||||
|
0.0;
|
||||||
|
function c(){
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
function d(){
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
|
||||||
|
}
|
||||||
|
|||||||
@@ -863,7 +863,7 @@ collapse_vars_unary: {
|
|||||||
input: {
|
input: {
|
||||||
function f0(o, p) {
|
function f0(o, p) {
|
||||||
var x = o[p];
|
var x = o[p];
|
||||||
delete x;
|
return delete x;
|
||||||
}
|
}
|
||||||
function f1(n) {
|
function f1(n) {
|
||||||
var k = !!n;
|
var k = !!n;
|
||||||
@@ -893,7 +893,7 @@ collapse_vars_unary: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f0(o, p) {
|
function f0(o, p) {
|
||||||
var x = o[p];
|
var x = o[p];
|
||||||
delete x;
|
return delete x;
|
||||||
}
|
}
|
||||||
function f1(n) {
|
function f1(n) {
|
||||||
return n > +!!n
|
return n > +!!n
|
||||||
@@ -2256,3 +2256,268 @@ issue_2187_3: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2203_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a = "FAIL";
|
||||||
|
console.log({
|
||||||
|
a: "PASS",
|
||||||
|
b: function() {
|
||||||
|
return function(c) {
|
||||||
|
return c.a;
|
||||||
|
}((String, (Object, this)));
|
||||||
|
}
|
||||||
|
}.b());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a = "FAIL";
|
||||||
|
console.log({
|
||||||
|
a: "PASS",
|
||||||
|
b: function() {
|
||||||
|
return function(c) {
|
||||||
|
return c.a;
|
||||||
|
}((String, (Object, this)));
|
||||||
|
}
|
||||||
|
}.b());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2203_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a = "PASS";
|
||||||
|
console.log({
|
||||||
|
a: "FAIL",
|
||||||
|
b: function() {
|
||||||
|
return function(c) {
|
||||||
|
return c.a;
|
||||||
|
}((String, (Object, function() {
|
||||||
|
return this;
|
||||||
|
}())));
|
||||||
|
}
|
||||||
|
}.b());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a = "PASS";
|
||||||
|
console.log({
|
||||||
|
a: "FAIL",
|
||||||
|
b: function() {
|
||||||
|
return function(c) {
|
||||||
|
return (String, (Object, function() {
|
||||||
|
return this;
|
||||||
|
}())).a;
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}.b());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_argname: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() { return "PASS"; }
|
||||||
|
console.log(function(a, a) {
|
||||||
|
f++;
|
||||||
|
return a;
|
||||||
|
}("FAIL", f()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() { return "PASS"; }
|
||||||
|
console.log(function(a, a) {
|
||||||
|
f++;
|
||||||
|
return a;
|
||||||
|
}("FAIL", f()));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2298: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function() {
|
||||||
|
function f() {
|
||||||
|
var a = undefined;
|
||||||
|
var undefined = a++;
|
||||||
|
try {
|
||||||
|
!function g(b) {
|
||||||
|
b[1] = "foo";
|
||||||
|
}();
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function() {
|
||||||
|
(function() {
|
||||||
|
var a = undefined;
|
||||||
|
var undefined = a++;
|
||||||
|
try {
|
||||||
|
!function(b) {
|
||||||
|
(void 0)[1] = "foo";
|
||||||
|
}();
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
var foo = {
|
||||||
|
get c() {
|
||||||
|
a++;
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
set c(c) {
|
||||||
|
b++;
|
||||||
|
},
|
||||||
|
d: function() {
|
||||||
|
this.c++;
|
||||||
|
if (this.c) console.log(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo.d();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
var foo = {
|
||||||
|
get c() {
|
||||||
|
a++;
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
set c(c) {
|
||||||
|
b++;
|
||||||
|
},
|
||||||
|
d: function() {
|
||||||
|
this.c++;
|
||||||
|
this.c && console.log(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo.d();
|
||||||
|
}
|
||||||
|
expect_stdout: "2 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
!function a() {
|
||||||
|
a && c++;
|
||||||
|
var a = 0;
|
||||||
|
a && c++;
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
!function a() {
|
||||||
|
a && c++;
|
||||||
|
var a = 0;
|
||||||
|
a && c++;
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2319_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return !function() {
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2319_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
"use strict";
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
"use strict";
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect_stdout: "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2319_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(a) {
|
||||||
|
return !function() {
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ concat_1: {
|
|||||||
var c = 1 + x() + 2 + "boo";
|
var c = 1 + x() + 2 + "boo";
|
||||||
var d = 1 + x() + 2 + 3 + "boo";
|
var d = 1 + x() + 2 + 3 + "boo";
|
||||||
var e = 1 + x() + 2 + "X3boo";
|
var e = 1 + x() + 2 + "X3boo";
|
||||||
var f = "\x00360\08\0";
|
var f = "\x00360\x008\0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -230,3 +230,186 @@ accessor: {
|
|||||||
}
|
}
|
||||||
expect: {}
|
expect: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2233_1: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
Array.isArray;
|
||||||
|
Boolean;
|
||||||
|
console.log;
|
||||||
|
Date;
|
||||||
|
decodeURI;
|
||||||
|
decodeURIComponent;
|
||||||
|
encodeURI;
|
||||||
|
encodeURIComponent;
|
||||||
|
Error.name;
|
||||||
|
escape;
|
||||||
|
eval;
|
||||||
|
EvalError;
|
||||||
|
Function.length;
|
||||||
|
isFinite;
|
||||||
|
isNaN;
|
||||||
|
JSON;
|
||||||
|
Math.random;
|
||||||
|
Number.isNaN;
|
||||||
|
parseFloat;
|
||||||
|
parseInt;
|
||||||
|
RegExp;
|
||||||
|
Object.defineProperty;
|
||||||
|
String.fromCharCode;
|
||||||
|
RangeError;
|
||||||
|
ReferenceError;
|
||||||
|
SyntaxError;
|
||||||
|
TypeError;
|
||||||
|
unescape;
|
||||||
|
URIError;
|
||||||
|
}
|
||||||
|
expect: {}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
global_timeout_and_interval_symbols: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
// These global symbols do not exist in the test sandbox
|
||||||
|
// and must be tested separately.
|
||||||
|
clearInterval;
|
||||||
|
clearTimeout;
|
||||||
|
setInterval;
|
||||||
|
setTimeout;
|
||||||
|
}
|
||||||
|
expect: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2233_2: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var RegExp;
|
||||||
|
Array.isArray;
|
||||||
|
RegExp;
|
||||||
|
UndeclaredGlobal;
|
||||||
|
function foo() {
|
||||||
|
var Number;
|
||||||
|
AnotherUndeclaredGlobal;
|
||||||
|
Math.sin;
|
||||||
|
Number.isNaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var RegExp;
|
||||||
|
UndeclaredGlobal;
|
||||||
|
function foo() {
|
||||||
|
var Number;
|
||||||
|
AnotherUndeclaredGlobal;
|
||||||
|
Number.isNaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2233_3: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var RegExp;
|
||||||
|
Array.isArray;
|
||||||
|
RegExp;
|
||||||
|
UndeclaredGlobal;
|
||||||
|
function foo() {
|
||||||
|
var Number;
|
||||||
|
AnotherUndeclaredGlobal;
|
||||||
|
Math.sin;
|
||||||
|
Number.isNaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
UndeclaredGlobal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_fns: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
Boolean(1, 2);
|
||||||
|
decodeURI(1, 2);
|
||||||
|
decodeURIComponent(1, 2);
|
||||||
|
Date(1, 2);
|
||||||
|
encodeURI(1, 2);
|
||||||
|
encodeURIComponent(1, 2);
|
||||||
|
Error(1, 2);
|
||||||
|
escape(1, 2);
|
||||||
|
EvalError(1, 2);
|
||||||
|
isFinite(1, 2);
|
||||||
|
isNaN(1, 2);
|
||||||
|
Number(1, 2);
|
||||||
|
Object(1, 2);
|
||||||
|
parseFloat(1, 2);
|
||||||
|
parseInt(1, 2);
|
||||||
|
RangeError(1, 2);
|
||||||
|
ReferenceError(1, 2);
|
||||||
|
String(1, 2);
|
||||||
|
SyntaxError(1, 2);
|
||||||
|
TypeError(1, 2);
|
||||||
|
unescape(1, 2);
|
||||||
|
URIError(1, 2);
|
||||||
|
try {
|
||||||
|
Function(1, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
RegExp(1, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Array(NaN);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
Function(1, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
RegExp(1, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Array(NaN);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"SyntaxError",
|
||||||
|
"SyntaxError",
|
||||||
|
"RangeError",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -1090,6 +1090,7 @@ var_catch_toplevel: {
|
|||||||
a--;
|
a--;
|
||||||
try {
|
try {
|
||||||
a++;
|
a++;
|
||||||
|
x();
|
||||||
} catch(a) {
|
} catch(a) {
|
||||||
if (a) var a;
|
if (a) var a;
|
||||||
var a = 10;
|
var a = 10;
|
||||||
@@ -1099,9 +1100,8 @@ var_catch_toplevel: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
!function() {
|
!function() {
|
||||||
a--;
|
|
||||||
try {
|
try {
|
||||||
a++;
|
x();
|
||||||
} catch(a) {
|
} catch(a) {
|
||||||
var a;
|
var a;
|
||||||
}
|
}
|
||||||
@@ -1153,3 +1153,111 @@ issue_2105: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2226_1: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f1() {
|
||||||
|
var a = b;
|
||||||
|
a += c;
|
||||||
|
}
|
||||||
|
function f2(a) {
|
||||||
|
a <<= b;
|
||||||
|
}
|
||||||
|
function f3(a) {
|
||||||
|
--a;
|
||||||
|
}
|
||||||
|
function f4() {
|
||||||
|
var a = b;
|
||||||
|
return a *= c;
|
||||||
|
}
|
||||||
|
function f5(a) {
|
||||||
|
x(a /= b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1() {
|
||||||
|
b;
|
||||||
|
c;
|
||||||
|
}
|
||||||
|
function f2(a) {
|
||||||
|
b;
|
||||||
|
}
|
||||||
|
function f3(a) {
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
function f4() {
|
||||||
|
var a = b;
|
||||||
|
return a *= c;
|
||||||
|
}
|
||||||
|
function f5(a) {
|
||||||
|
x(a /= b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2226_2: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a, b) {
|
||||||
|
a += b;
|
||||||
|
return a;
|
||||||
|
}(1, 2));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a, b) {
|
||||||
|
return a += b;
|
||||||
|
}(1, 2));
|
||||||
|
}
|
||||||
|
expect_stdout: "3"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2226_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a, b) {
|
||||||
|
a += b;
|
||||||
|
return a;
|
||||||
|
}(1, 2));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a, b) {
|
||||||
|
return a += 2;
|
||||||
|
}(1));
|
||||||
|
}
|
||||||
|
expect_stdout: "3"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2288: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo(o) {
|
||||||
|
for (var j = o.a, i = 0; i < 0; i++);
|
||||||
|
for (var i = 0; i < 0; i++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo(o) {
|
||||||
|
o.a;
|
||||||
|
for (i = 0; i < 0; i++);
|
||||||
|
for (var i = 0; i < 0; i++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -250,22 +250,26 @@ unsafe_constant: {
|
|||||||
|
|
||||||
unsafe_object: {
|
unsafe_object: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate: true,
|
||||||
unsafe : true
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
console.log(
|
console.log(
|
||||||
({a:1}) + 1,
|
o + 1,
|
||||||
({a:1}).a + 1,
|
o.a + 1,
|
||||||
({a:1}).b + 1,
|
o.b + 1,
|
||||||
({a:1}).a.b + 1
|
o.a.b + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var o = { a: 1 };
|
||||||
console.log(
|
console.log(
|
||||||
({a:1}) + 1,
|
o + 1,
|
||||||
2,
|
2,
|
||||||
({a:1}).b + 1,
|
o.b + 1,
|
||||||
1..b + 1
|
1..b + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -274,22 +278,26 @@ unsafe_object: {
|
|||||||
|
|
||||||
unsafe_object_nested: {
|
unsafe_object_nested: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate: true,
|
||||||
unsafe : true
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
var o = { a: { b: 1 } };
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1}}) + 1,
|
o + 1,
|
||||||
({a:{b:1}}).a + 1,
|
o.a + 1,
|
||||||
({a:{b:1}}).b + 1,
|
o.b + 1,
|
||||||
({a:{b:1}}).a.b + 1
|
o.a.b + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var o = { a: { b: 1 } };
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1}}) + 1,
|
o + 1,
|
||||||
({a:{b:1}}).a + 1,
|
o.a + 1,
|
||||||
({a:{b:1}}).b + 1,
|
o.b + 1,
|
||||||
2
|
2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -298,21 +306,25 @@ unsafe_object_nested: {
|
|||||||
|
|
||||||
unsafe_object_complex: {
|
unsafe_object_complex: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate: true,
|
||||||
unsafe : true
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
var o = { a: { b: 1 }, b: 1 };
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1},b:1}) + 1,
|
o + 1,
|
||||||
({a:{b:1},b:1}).a + 1,
|
o.a + 1,
|
||||||
({a:{b:1},b:1}).b + 1,
|
o.b + 1,
|
||||||
({a:{b:1},b:1}).a.b + 1
|
o.a.b + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var o = { a: { b: 1 }, b: 1 };
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1},b:1}) + 1,
|
o + 1,
|
||||||
({a:{b:1},b:1}).a + 1,
|
o.a + 1,
|
||||||
2,
|
2,
|
||||||
2
|
2
|
||||||
);
|
);
|
||||||
@@ -322,22 +334,26 @@ unsafe_object_complex: {
|
|||||||
|
|
||||||
unsafe_object_repeated: {
|
unsafe_object_repeated: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate: true,
|
||||||
unsafe : true
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
var o = { a: { b: 1 }, a: 1 };
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1},a:1}) + 1,
|
o + 1,
|
||||||
({a:{b:1},a:1}).a + 1,
|
o.a + 1,
|
||||||
({a:{b:1},a:1}).b + 1,
|
o.b + 1,
|
||||||
({a:{b:1},a:1}).a.b + 1
|
o.a.b + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var o = { a: { b: 1 }, a: 1 };
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1},a:1}) + 1,
|
o + 1,
|
||||||
2,
|
2,
|
||||||
({a:{b:1},a:1}).b + 1,
|
o.b + 1,
|
||||||
1..b + 1
|
1..b + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -386,9 +402,9 @@ unsafe_function: {
|
|||||||
expect: {
|
expect: {
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1},b:function(){}}) + 1,
|
({a:{b:1},b:function(){}}) + 1,
|
||||||
({a:{b:1},b:function(){}}).a + 1,
|
({b:function(){}}, {b:1}) + 1,
|
||||||
({a:{b:1},b:function(){}}).b + 1,
|
({a:{b:1}}, function(){}) + 1,
|
||||||
({a:{b:1},b:function(){}}).a.b + 1
|
({b:function(){}}, {b:1}).b + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
@@ -636,8 +652,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 = ({valueOf: 0}).valueOf();
|
var g = ({}, 0)();
|
||||||
var h = "" + ({toString: 0});
|
var h = ({}, 0)();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1069,3 +1085,103 @@ string_charCodeAt: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
expect_stdout: "NaN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2207_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(String.fromCharCode(65));
|
||||||
|
console.log(Math.max(3, 6, 2, 7, 3, 4));
|
||||||
|
console.log(Math.cos(1.2345));
|
||||||
|
console.log(Math.cos(1.2345) - Math.sin(4.321));
|
||||||
|
console.log(Math.pow(Math.PI, Math.E - Math.LN10));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("A");
|
||||||
|
console.log(7);
|
||||||
|
console.log(Math.cos(1.2345));
|
||||||
|
console.log(1.2543732512566947);
|
||||||
|
console.log(1.6093984514472044);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2207_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(Math.E);
|
||||||
|
console.log(Math.LN10);
|
||||||
|
console.log(Math.LN2);
|
||||||
|
console.log(Math.LOG2E);
|
||||||
|
console.log(Math.LOG10E);
|
||||||
|
console.log(Math.PI);
|
||||||
|
console.log(Math.SQRT1_2);
|
||||||
|
console.log(Math.SQRT2);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(Math.E);
|
||||||
|
console.log(Math.LN10);
|
||||||
|
console.log(Math.LN2);
|
||||||
|
console.log(Math.LOG2E);
|
||||||
|
console.log(Math.LOG10E);
|
||||||
|
console.log(Math.PI);
|
||||||
|
console.log(Math.SQRT1_2);
|
||||||
|
console.log(Math.SQRT2);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2207_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(Number.MAX_VALUE);
|
||||||
|
console.log(Number.MIN_VALUE);
|
||||||
|
console.log(Number.NaN);
|
||||||
|
console.log(Number.NEGATIVE_INFINITY);
|
||||||
|
console.log(Number.POSITIVE_INFINITY);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(Number.MAX_VALUE);
|
||||||
|
console.log(5e-324);
|
||||||
|
console.log(NaN);
|
||||||
|
console.log(-1/0);
|
||||||
|
console.log(1/0);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2231_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(Object.keys(void 0));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(Object.keys(void 0));
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2231_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(Object.getOwnPropertyNames(null));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(Object.getOwnPropertyNames(null));
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ object: {
|
|||||||
VALUE: 42,
|
VALUE: 42,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
side_effects: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -140,9 +141,9 @@ mixed: {
|
|||||||
console.log(CONFIG);
|
console.log(CONFIG);
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:126,22]',
|
|
||||||
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]',
|
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]',
|
||||||
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:129,8]',
|
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:128,22]',
|
||||||
|
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:130,8]',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,3 +88,24 @@ sequences_funs: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2295: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
hoist_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo(o) {
|
||||||
|
var a = o.a;
|
||||||
|
if (a) return a;
|
||||||
|
var a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo(o) {
|
||||||
|
var a = o.a;
|
||||||
|
if (a) return a;
|
||||||
|
a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,11 +71,13 @@ non_hoisted_function_after_return_2a: {
|
|||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]",
|
||||||
|
"WARN: pass 0: last_count: Infinity, count: 37",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
|
||||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
|
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
|
||||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]",
|
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]",
|
||||||
|
"WARN: pass 1: last_count: 37, count: 18",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,11 +111,11 @@ non_hoisted_function_after_return_2b: {
|
|||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
// duplicate warnings no longer emitted
|
// duplicate warnings no longer emitted
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:99,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:99,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:103,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,10 +153,10 @@ non_hoisted_function_after_return_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "8 7"
|
expect_stdout: "8 7"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
'WARN: Dropping unreachable code [test/compress/issue-1034.js:131,16]',
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:133,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:134,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:136,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:137,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:139,12]",
|
||||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:138,21]"
|
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:140,21]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,17 +196,19 @@ non_hoisted_function_after_return_2a_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "5 6"
|
expect_stdout: "5 6"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:173,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:175,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:173,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:175,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:176,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:176,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,16]",
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:173,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:175,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:180,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:182,21]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,12]",
|
"WARN: pass 0: last_count: Infinity, count: 48",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:180,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:181,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:180,12]",
|
||||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:176,20]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:183,12]",
|
||||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:178,16]",
|
"WARN: Dropping unused variable b [test/compress/issue-1034.js:178,20]",
|
||||||
|
"WARN: Dropping unused variable c [test/compress/issue-1034.js:180,16]",
|
||||||
|
"WARN: pass 1: last_count: 48, count: 29",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,10 +247,10 @@ non_hoisted_function_after_return_2b_strict: {
|
|||||||
expect_stdout: "5 6"
|
expect_stdout: "5 6"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
// duplicate warnings no longer emitted
|
// duplicate warnings no longer emitted
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:225,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:229,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:225,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:227,12]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:227,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:231,12]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:235,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,13 @@ pure_function_calls_toplevel: {
|
|||||||
})();
|
})();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// pure top-level calls will be dropped regardless of the leading comments position
|
||||||
|
var MyClass = /*#__PURE__*//*@class*/(function(){
|
||||||
|
function MyClass() {}
|
||||||
|
MyClass.prototype.method = function() {};
|
||||||
|
return MyClass;
|
||||||
|
})();
|
||||||
|
|
||||||
// comment #__PURE__ comment
|
// comment #__PURE__ comment
|
||||||
bar(), baz(), quux();
|
bar(), baz(), quux();
|
||||||
a.b(), /* @__PURE__ */ c.d.e(), f.g();
|
a.b(), /* @__PURE__ */ c.d.e(), f.g();
|
||||||
@@ -110,10 +117,12 @@ pure_function_calls_toplevel: {
|
|||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
|
||||||
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
|
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:107,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:108,31]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
|
||||||
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
|
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,45]",
|
||||||
|
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:100,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,29 +157,29 @@ should_warn: {
|
|||||||
baz();
|
baz();
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,61]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,61]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,23]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:128,23]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:137,23]",
|
||||||
"WARN: Boolean || always true [test/compress/issue-1261.js:129,23]",
|
"WARN: Boolean || always true [test/compress/issue-1261.js:138,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:129,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:138,23]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:129,23]",
|
"WARN: Condition always true [test/compress/issue-1261.js:138,23]",
|
||||||
"WARN: Condition left of || always true [test/compress/issue-1261.js:130,8]",
|
"WARN: Condition left of || always true [test/compress/issue-1261.js:139,8]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:130,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:139,8]",
|
||||||
"WARN: Boolean && always false [test/compress/issue-1261.js:131,23]",
|
"WARN: Boolean && always false [test/compress/issue-1261.js:140,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:131,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:140,23]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:131,23]",
|
"WARN: Condition always false [test/compress/issue-1261.js:140,23]",
|
||||||
"WARN: Condition left of && always false [test/compress/issue-1261.js:132,8]",
|
"WARN: Condition left of && always false [test/compress/issue-1261.js:141,8]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:132,8]",
|
"WARN: Condition always false [test/compress/issue-1261.js:141,8]",
|
||||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:133,23]",
|
"WARN: + in boolean context always true [test/compress/issue-1261.js:142,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:133,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:142,23]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:133,23]",
|
"WARN: Condition always true [test/compress/issue-1261.js:142,23]",
|
||||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:134,8]",
|
"WARN: + in boolean context always true [test/compress/issue-1261.js:143,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:134,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,31]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:134,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:143,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:144,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,24]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:145,24]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:136,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:145,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:146,31]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:137,8]",
|
"WARN: Condition always false [test/compress/issue-1261.js:146,8]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
issue_1321_no_debug: {
|
issue_1321_no_debug: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: true
|
properties: {
|
||||||
|
keep_quoted: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = {};
|
var x = {};
|
||||||
@@ -10,17 +12,19 @@ issue_1321_no_debug: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.o = 1;
|
x.x = 1;
|
||||||
x["a"] = 2 * x.o;
|
x["a"] = 2 * x.x;
|
||||||
console.log(x.o, x["a"]);
|
console.log(x.x, x["a"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1321_debug: {
|
issue_1321_debug: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: true,
|
properties: {
|
||||||
debug: ""
|
debug: "",
|
||||||
|
keep_quoted: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = {};
|
var x = {};
|
||||||
@@ -30,16 +34,18 @@ issue_1321_debug: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.o = 1;
|
x.x = 1;
|
||||||
x["_$foo$_"] = 2 * x.o;
|
x["_$foo$_"] = 2 * x.x;
|
||||||
console.log(x.o, x["_$foo$_"]);
|
console.log(x.x, x["_$foo$_"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1321_with_quoted: {
|
issue_1321_with_quoted: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: false
|
properties: {
|
||||||
|
keep_quoted: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = {};
|
var x = {};
|
||||||
@@ -49,9 +55,9 @@ issue_1321_with_quoted: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.o = 1;
|
x.x = 1;
|
||||||
x["x"] = 2 * x.o;
|
x["o"] = 2 * x.x;
|
||||||
console.log(x.o, x["x"]);
|
console.log(x.x, x["o"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
typeof_eq_undefined: {
|
typeof_eq_undefined: {
|
||||||
options = {
|
options = {
|
||||||
comparisons: true
|
comparisons: true,
|
||||||
|
typeofs: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = typeof b != "undefined";
|
var a = typeof b != "undefined";
|
||||||
@@ -24,6 +25,7 @@ typeof_eq_undefined_ie8: {
|
|||||||
options = {
|
options = {
|
||||||
comparisons: true,
|
comparisons: true,
|
||||||
ie8: true,
|
ie8: true,
|
||||||
|
typeofs: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = typeof b != "undefined";
|
var a = typeof b != "undefined";
|
||||||
@@ -45,7 +47,8 @@ typeof_eq_undefined_ie8: {
|
|||||||
|
|
||||||
undefined_redefined: {
|
undefined_redefined: {
|
||||||
options = {
|
options = {
|
||||||
comparisons: true
|
comparisons: true,
|
||||||
|
typeofs: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f(undefined) {
|
function f(undefined) {
|
||||||
@@ -58,7 +61,8 @@ undefined_redefined: {
|
|||||||
|
|
||||||
undefined_redefined_mangle: {
|
undefined_redefined_mangle: {
|
||||||
options = {
|
options = {
|
||||||
comparisons: true
|
comparisons: true,
|
||||||
|
typeofs: true,
|
||||||
}
|
}
|
||||||
mangle = {}
|
mangle = {}
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
mangle_props: {
|
mangle_props: {
|
||||||
mangle_props = {}
|
mangle = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
var obj = {
|
var obj = {
|
||||||
undefined: 1,
|
undefined: 1,
|
||||||
@@ -54,10 +56,12 @@ mangle_props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
numeric_literal: {
|
numeric_literal: {
|
||||||
|
mangle = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
beautify: true,
|
beautify: true,
|
||||||
}
|
}
|
||||||
mangle_props = {}
|
|
||||||
input: {
|
input: {
|
||||||
var obj = {
|
var obj = {
|
||||||
0: 0,
|
0: 0,
|
||||||
@@ -105,7 +109,9 @@ numeric_literal: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
identifier: {
|
identifier: {
|
||||||
mangle_props = {}
|
mangle = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
var obj = {
|
var obj = {
|
||||||
abstract: 1,
|
abstract: 1,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
dont_reuse_prop: {
|
dont_reuse_prop: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
regex: /asd/
|
properties: {
|
||||||
|
regex: /asd/,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
"aaaaaaaaaabbbbb";
|
"aaaaaaaaaabbbbb";
|
||||||
@@ -20,8 +22,10 @@ dont_reuse_prop: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unmangleable_props_should_always_be_reserved: {
|
unmangleable_props_should_always_be_reserved: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
regex: /asd/
|
properties: {
|
||||||
|
regex: /asd/,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
"aaaaaaaaaabbbbb";
|
"aaaaaaaaaabbbbb";
|
||||||
|
|||||||
@@ -436,3 +436,17 @@ do_switch: {
|
|||||||
} while (false);
|
} while (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
in_parenthesis_1: {
|
||||||
|
input: {
|
||||||
|
for (("foo" in {});0;);
|
||||||
|
}
|
||||||
|
expect_exact: 'for(("foo"in{});0;);'
|
||||||
|
}
|
||||||
|
|
||||||
|
in_parenthesis_2: {
|
||||||
|
input: {
|
||||||
|
for ((function(){ "foo" in {}; });0;);
|
||||||
|
}
|
||||||
|
expect_exact: 'for(function(){"foo"in{}};0;);'
|
||||||
|
}
|
||||||
|
|||||||
@@ -82,3 +82,19 @@ new_with_unary_prefix: {
|
|||||||
}
|
}
|
||||||
expect_exact: 'var bar=(+new Date).toString(32);';
|
expect_exact: 'var bar=(+new Date).toString(32);';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dot_parenthesis_1: {
|
||||||
|
input: {
|
||||||
|
console.log(new (Math.random().constructor) instanceof Number);
|
||||||
|
}
|
||||||
|
expect_exact: "console.log(new(Math.random().constructor)instanceof Number);"
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
dot_parenthesis_2: {
|
||||||
|
input: {
|
||||||
|
console.log(typeof new function(){Math.random()}.constructor);
|
||||||
|
}
|
||||||
|
expect_exact: "console.log(typeof new function(){Math.random()}.constructor);"
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ keep_properties: {
|
|||||||
dot_properties: {
|
dot_properties: {
|
||||||
options = {
|
options = {
|
||||||
properties: true,
|
properties: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
ie8: true,
|
ie8: true,
|
||||||
};
|
}
|
||||||
input: {
|
input: {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
a["if"] = "if";
|
a["if"] = "if";
|
||||||
@@ -36,8 +38,10 @@ dot_properties: {
|
|||||||
dot_properties_es5: {
|
dot_properties_es5: {
|
||||||
options = {
|
options = {
|
||||||
properties: true,
|
properties: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
ie8: false,
|
ie8: false,
|
||||||
};
|
}
|
||||||
input: {
|
input: {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
a["if"] = "if";
|
a["if"] = "if";
|
||||||
@@ -124,9 +128,11 @@ evaluate_string_length: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mangle_properties: {
|
mangle_properties: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: false
|
properties: {
|
||||||
};
|
keep_quoted: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
a.color = "red";
|
a.color = "red";
|
||||||
@@ -135,11 +141,11 @@ mangle_properties: {
|
|||||||
a['run']({color: "blue", foo: "baz"});
|
a['run']({color: "blue", foo: "baz"});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
a["o"] = "bar";
|
a["a"] = "bar";
|
||||||
a.a = "red";
|
a.b = "red";
|
||||||
x = {r: 10};
|
x = {o: 10};
|
||||||
a.b(x.r, a.o);
|
a.r(x.o, a.a);
|
||||||
a['b']({a: "blue", o: "baz"});
|
a['r']({b: "blue", a: "baz"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,8 +153,10 @@ mangle_unquoted_properties: {
|
|||||||
options = {
|
options = {
|
||||||
properties: false
|
properties: false
|
||||||
}
|
}
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: true
|
properties: {
|
||||||
|
keep_quoted: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
beautify: false,
|
beautify: false,
|
||||||
@@ -177,24 +185,26 @@ mangle_unquoted_properties: {
|
|||||||
function f1() {
|
function f1() {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
a.color = "red";
|
a.color = "red";
|
||||||
a.o = 2;
|
a.r = 2;
|
||||||
x = {"bar": 10, f: 7};
|
x = {"bar": 10, b: 7};
|
||||||
a.f = 9;
|
a.b = 9;
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
a['color'] = "red";
|
a['color'] = "red";
|
||||||
x = {bar: 10, f: 7};
|
x = {bar: 10, b: 7};
|
||||||
a.f = 9;
|
a.b = 9;
|
||||||
a.o = 3;
|
a.r = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mangle_debug: {
|
mangle_debug: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
debug: ""
|
properties: {
|
||||||
};
|
debug: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
x = { baz: "ban" };
|
x = { baz: "ban" };
|
||||||
@@ -206,9 +216,11 @@ mangle_debug: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mangle_debug_true: {
|
mangle_debug_true: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
debug: true
|
properties: {
|
||||||
};
|
debug: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
x = { baz: "ban" };
|
x = { baz: "ban" };
|
||||||
@@ -220,9 +232,11 @@ mangle_debug_true: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mangle_debug_suffix: {
|
mangle_debug_suffix: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
debug: "XYZ"
|
properties: {
|
||||||
};
|
debug: "XYZ",
|
||||||
|
},
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
x = { baz: "ban" };
|
x = { baz: "ban" };
|
||||||
@@ -237,10 +251,12 @@ mangle_debug_suffix_keep_quoted: {
|
|||||||
options = {
|
options = {
|
||||||
properties: false
|
properties: false
|
||||||
}
|
}
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: true,
|
properties: {
|
||||||
debug: "XYZ",
|
debug: "XYZ",
|
||||||
reserved: []
|
keep_quoted: true,
|
||||||
|
reserved: [],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
beautify: false,
|
beautify: false,
|
||||||
@@ -657,3 +673,134 @@ accessor_this: {
|
|||||||
expect_exact: 'var a=1;var b={get this(){return a},set this(c){a=c}};console.log(b.this,b.this=2,b.this);'
|
expect_exact: 'var a=1;var b={get this(){return a},set this(c){a=c}};console.log(b.this,b.this=2,b.this);'
|
||||||
expect_stdout: "1 2 2"
|
expect_stdout: "1 2 2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2208_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
p: function() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}.p());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2208_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
a: 42,
|
||||||
|
p: function() {
|
||||||
|
return this.a;
|
||||||
|
}
|
||||||
|
}.p());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
a: 42,
|
||||||
|
p: function() {
|
||||||
|
return this.a;
|
||||||
|
}
|
||||||
|
}.p());
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2208_3: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a = 42;
|
||||||
|
console.log({
|
||||||
|
p: function() {
|
||||||
|
return function() {
|
||||||
|
return this.a;
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}.p());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a = 42;
|
||||||
|
console.log(function() {
|
||||||
|
return this.a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2208_4: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo() {}
|
||||||
|
console.log({
|
||||||
|
a: foo(),
|
||||||
|
p: function() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}.p());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {}
|
||||||
|
console.log((foo(), function() {
|
||||||
|
return 42;
|
||||||
|
})());
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2208_5: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
p: "FAIL",
|
||||||
|
p: function() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}.p());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2256: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
properties: {
|
||||||
|
keep_quoted: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({ "keep": 1 });
|
||||||
|
g.keep = g.change;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
g.keep = g.g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -385,3 +385,217 @@ set_mutable_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2313_1: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
if (x().y().z) {
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
return console.log(1), {
|
||||||
|
y: function() {
|
||||||
|
return console.log(2), {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++,
|
||||||
|
x().y().z && console.log(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_2: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
if (x().y().z) {
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
return console.log(1), {
|
||||||
|
y: function() {
|
||||||
|
return console.log(2), {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++,
|
||||||
|
x().y().z && console.log(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
if (x().y().z) {
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
x().y().z && console.log(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_4: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
if (x().y().z) {
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
x().y().z && console.log(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_5: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
x().y++;
|
||||||
|
x().y;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x().y++;
|
||||||
|
x().y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_6: {
|
||||||
|
options = {
|
||||||
|
pure_getters: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
x().y++;
|
||||||
|
x().y;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x().y++;
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1469,6 +1469,7 @@ issue_1670_1: {
|
|||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
switches: true,
|
switches: true,
|
||||||
|
typeofs: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -1532,6 +1533,7 @@ issue_1670_3: {
|
|||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
switches: true,
|
switches: true,
|
||||||
|
typeofs: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
@@ -325,3 +325,69 @@ issue_2120_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2254_1: {
|
||||||
|
mangle = {
|
||||||
|
ie8: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"eeeeee";
|
||||||
|
try {
|
||||||
|
console.log(f("PASS"));
|
||||||
|
} catch (e) {}
|
||||||
|
function f(s) {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"eeeeee";
|
||||||
|
try {
|
||||||
|
console.log(f("PASS"));
|
||||||
|
} catch (e) {}
|
||||||
|
function f(e) {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (t) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2254_2: {
|
||||||
|
mangle = {
|
||||||
|
ie8: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"eeeeee";
|
||||||
|
try {
|
||||||
|
console.log(f("PASS"));
|
||||||
|
} catch (e) {}
|
||||||
|
function f(s) {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"eeeeee";
|
||||||
|
try {
|
||||||
|
console.log(f("PASS"));
|
||||||
|
} catch (e) {}
|
||||||
|
function f(t) {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -176,6 +176,11 @@ for_sequences: {
|
|||||||
// 4
|
// 4
|
||||||
x = (foo in bar);
|
x = (foo in bar);
|
||||||
for (y = 5; false;);
|
for (y = 5; false;);
|
||||||
|
// 5
|
||||||
|
x = function() {
|
||||||
|
foo in bar;
|
||||||
|
};
|
||||||
|
for (y = 5; false;);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
// 1
|
// 1
|
||||||
@@ -188,6 +193,10 @@ for_sequences: {
|
|||||||
// 4
|
// 4
|
||||||
x = (foo in bar);
|
x = (foo in bar);
|
||||||
for (y = 5; false;);
|
for (y = 5; false;);
|
||||||
|
// 5
|
||||||
|
for (x = function() {
|
||||||
|
foo in bar;
|
||||||
|
}, y = 5; false;);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,3 +739,44 @@ issue_2062: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2313: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
var foo = {
|
||||||
|
get c() {
|
||||||
|
a++;
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
set c(c) {
|
||||||
|
b++;
|
||||||
|
},
|
||||||
|
d: function() {
|
||||||
|
this.c++;
|
||||||
|
if (this.c) console.log(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo.d();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
var foo = {
|
||||||
|
get c() {
|
||||||
|
return a++, 42;
|
||||||
|
},
|
||||||
|
set c(c) {
|
||||||
|
b++;
|
||||||
|
},
|
||||||
|
d: function() {
|
||||||
|
if (this.c++, this.c) console.log(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo.d();
|
||||||
|
}
|
||||||
|
expect_stdout: "2 1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,3 +15,43 @@ unicode_parse_variables: {
|
|||||||
var l০ = 3;
|
var l০ = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2242_1: {
|
||||||
|
beautify = {
|
||||||
|
ascii_only: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log("\\ud83d","\\ude00","\ud83d\ude00","\\ud83d@\\ude00");'
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2242_2: {
|
||||||
|
beautify = {
|
||||||
|
ascii_only: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log("\\ud83d","\\ude00","\\ud83d\\ude00","\\ud83d@\\ude00");'
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2242_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log("\\ud83d"+"\\ude00","\\ud83d"+"@"+"\\ude00");'
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2242_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log("\ud83d\ude00","\\ud83d@\\ude00");'
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ exports["defaults"] = defaults;
|
|||||||
exports["mangle_properties"] = mangle_properties;
|
exports["mangle_properties"] = mangle_properties;
|
||||||
exports["minify"] = minify;
|
exports["minify"] = minify;
|
||||||
exports["parse"] = parse;
|
exports["parse"] = parse;
|
||||||
|
exports["reserve_quoted_keys"] = reserve_quoted_keys;
|
||||||
exports["string_template"] = string_template;
|
exports["string_template"] = string_template;
|
||||||
exports["tokenizer"] = tokenizer;
|
exports["tokenizer"] = tokenizer;
|
||||||
exports["is_identifier"] = is_identifier;
|
exports["is_identifier"] = is_identifier;
|
||||||
|
|||||||
10
test/input/issue-2310/input.js
Normal file
10
test/input/issue-2310/input.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
function foo() {
|
||||||
|
return function() {
|
||||||
|
console.log("PASS");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var f = foo();
|
||||||
|
f();
|
||||||
|
})();
|
||||||
@@ -63,7 +63,7 @@ describe("bin/uglifyjs", function () {
|
|||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
|
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
|
||||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=\n");
|
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -192,7 +192,7 @@ describe("bin/uglifyjs", function () {
|
|||||||
|
|
||||||
assert.strictEqual(stdout, [
|
assert.strictEqual(stdout, [
|
||||||
"var bar=function(){function foo(bar){return bar}return foo}();",
|
"var bar=function(){function foo(bar){return bar}return foo}();",
|
||||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=",
|
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
|
||||||
"",
|
"",
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
assert.strictEqual(stderr, "WARN: inline source map not found\n");
|
assert.strictEqual(stderr, "WARN: inline source map not found\n");
|
||||||
@@ -573,6 +573,25 @@ describe("bin/uglifyjs", function () {
|
|||||||
return JSON.stringify(map).replace(/"/g, '\\"');
|
return JSON.stringify(map).replace(/"/g, '\\"');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
it("Should include function calls in source map", function(done) {
|
||||||
|
var command = [
|
||||||
|
uglifyjscmd,
|
||||||
|
"test/input/issue-2310/input.js",
|
||||||
|
"-c",
|
||||||
|
"--source-map", "url=inline",
|
||||||
|
].join(" ");
|
||||||
|
|
||||||
|
exec(command, function(err, stdout, stderr) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
assert.strictEqual(stdout, [
|
||||||
|
'function foo(){return function(){console.log("PASS")}}foo()();',
|
||||||
|
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMjMxMC9pbnB1dC5qcyJdLCJuYW1lcyI6WyJmb28iLCJjb25zb2xlIiwibG9nIiwiZiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsTUFDTCxPQUFPLFdBQ0hDLFFBQVFDLElBQUksU0FLUkYsS0FDUkcifQ==",
|
||||||
|
""
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it("Should dump AST as JSON", function(done) {
|
it("Should dump AST as JSON", function(done) {
|
||||||
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
|
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
@@ -593,8 +612,8 @@ describe("bin/uglifyjs", function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with --mangle reserved=[]", function (done) {
|
it("Should work with --mangle reserved=[]", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/issue-505/input.js -m reserved=[callback]';
|
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=[callback]";
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@@ -603,8 +622,8 @@ describe("bin/uglifyjs", function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with --mangle reserved=false", function (done) {
|
it("Should work with --mangle reserved=false", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/issue-505/input.js -m reserved=false';
|
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=false";
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@@ -613,4 +632,22 @@ describe("bin/uglifyjs", function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should fail with --mangle-props reserved=[in]", function(done) {
|
||||||
|
var command = uglifyjscmd + " test/input/issue-505/input.js --mangle-props reserved=[in]";
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.ok(/^Supported options:\n[\s\S]*?\nERROR: `reserved=\[in]` is not a supported option/.test(stderr), stderr);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should fail with --define a-b", function(done) {
|
||||||
|
var command = uglifyjscmd + " test/input/issue-505/input.js --define a-b";
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr, "Error parsing arguments for 'define': a-b\n");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,16 +2,17 @@ var Uglify = require('../../');
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
|
|
||||||
describe("let", function() {
|
describe("let", function() {
|
||||||
it("Should not produce reserved keywords as variable name in mangle", function(done) {
|
this.timeout(30000);
|
||||||
this.timeout(10000);
|
it("Should not produce reserved keywords as variable name in mangle", function() {
|
||||||
|
|
||||||
// Produce a lot of variables in a function and run it through mangle.
|
// Produce a lot of variables in a function and run it through mangle.
|
||||||
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
||||||
for (var i = 0; i < 18000; i++) {
|
for (var i = 0; i < 18000; i++) {
|
||||||
s += "var v" + i + "=0;";
|
s += "var v" + i + "=0;";
|
||||||
}
|
}
|
||||||
s += '}';
|
s += '}';
|
||||||
var result = Uglify.minify(s, {compress: false});
|
var result = Uglify.minify(s, {
|
||||||
|
compress: false
|
||||||
|
}).code;
|
||||||
|
|
||||||
// Verify that select keywords and reserved keywords not produced
|
// Verify that select keywords and reserved keywords not produced
|
||||||
[
|
[
|
||||||
@@ -19,7 +20,7 @@ describe("let", function() {
|
|||||||
"let",
|
"let",
|
||||||
"var",
|
"var",
|
||||||
].forEach(function(name) {
|
].forEach(function(name) {
|
||||||
assert.strictEqual(result.code.indexOf("var " + name + "="), -1);
|
assert.strictEqual(result.indexOf("var " + name + "="), -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify that the variable names that appeared immediately before
|
// Verify that the variable names that appeared immediately before
|
||||||
@@ -30,9 +31,27 @@ describe("let", function() {
|
|||||||
"eet", "fet",
|
"eet", "fet",
|
||||||
"rar", "oar",
|
"rar", "oar",
|
||||||
].forEach(function(name) {
|
].forEach(function(name) {
|
||||||
assert.ok(result.code.indexOf("var " + name + "=") >= 0);
|
assert.notStrictEqual(result.indexOf("var " + name + "="), -1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should quote mangled properties that are reserved keywords", function() {
|
||||||
|
var s = '"rrrrrnnnnniiiiiaaaaa";';
|
||||||
|
for (var i = 0; i < 18000; i++) {
|
||||||
|
s += "v.b" + i + ";";
|
||||||
|
}
|
||||||
|
var result = Uglify.minify(s, {
|
||||||
|
compress: false,
|
||||||
|
ie8: true,
|
||||||
|
mangle: {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
|
}).code;
|
||||||
|
[
|
||||||
|
"in",
|
||||||
|
"var",
|
||||||
|
].forEach(function(name) {
|
||||||
|
assert.notStrictEqual(result.indexOf(name), -1);
|
||||||
|
assert.notStrictEqual(result.indexOf('v["' + name + '"]'), -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -124,6 +124,17 @@ describe("minify", function() {
|
|||||||
assert.strictEqual(result.code,
|
assert.strictEqual(result.code,
|
||||||
'a["foo"]="bar",a.a="red",x={"bar":10};');
|
'a["foo"]="bar",a.a="red",x={"bar":10};');
|
||||||
});
|
});
|
||||||
|
it("Should not mangle quoted property within dead code", function() {
|
||||||
|
var result = Uglify.minify('({ "keep": 1 }); g.keep = g.change;', {
|
||||||
|
mangle: {
|
||||||
|
properties: {
|
||||||
|
keep_quoted: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, "g.keep=g.g;");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("inSourceMap", function() {
|
describe("inSourceMap", function() {
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ describe("String literals", function() {
|
|||||||
var tests = [
|
var tests = [
|
||||||
['"\\76";', ';">";'],
|
['"\\76";', ';">";'],
|
||||||
['"\\0"', '"\\0";'],
|
['"\\0"', '"\\0";'],
|
||||||
['"\\08"', '"\\08";'],
|
['"\\08"', '"\\x008";'],
|
||||||
['"\\008"', '"\\08";'],
|
['"\\008"', '"\\x008";'],
|
||||||
['"\\0008"', '"\\08";'],
|
['"\\0008"', '"\\x008";'],
|
||||||
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
|
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
|
||||||
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
|
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
|
||||||
];
|
];
|
||||||
@@ -75,7 +75,44 @@ describe("String literals", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Should not throw error when digit is 8 or 9", function() {
|
it("Should not throw error when digit is 8 or 9", function() {
|
||||||
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\08";');
|
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\x008";');
|
||||||
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\09";');
|
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\x009";');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not unescape unpaired surrogates", function() {
|
||||||
|
var code = [];
|
||||||
|
for (var i = 0; i <= 0xF; i++) {
|
||||||
|
code.push("\\u000" + i.toString(16));
|
||||||
|
}
|
||||||
|
for (;i <= 0xFF; i++) {
|
||||||
|
code.push("\\u00" + i.toString(16));
|
||||||
|
}
|
||||||
|
for (;i <= 0xFFF; i++) {
|
||||||
|
code.push("\\u0" + i.toString(16));
|
||||||
|
}
|
||||||
|
for (; i <= 0xFFFF; i++) {
|
||||||
|
code.push("\\u" + i.toString(16));
|
||||||
|
}
|
||||||
|
code = '"' + code.join() + '"';
|
||||||
|
var normal = UglifyJS.minify(code, {
|
||||||
|
compress: false,
|
||||||
|
mangle: false,
|
||||||
|
output: {
|
||||||
|
ascii_only: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (normal.error) throw normal.error;
|
||||||
|
assert.ok(code.length > normal.code.length);
|
||||||
|
assert.strictEqual(eval(code), eval(normal.code));
|
||||||
|
var ascii = UglifyJS.minify(code, {
|
||||||
|
compress: false,
|
||||||
|
mangle: false,
|
||||||
|
output: {
|
||||||
|
ascii_only: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (ascii.error) throw ascii.error;
|
||||||
|
assert.ok(code.length > ascii.code.length);
|
||||||
|
assert.strictEqual(eval(code), eval(ascii.code));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -111,18 +111,22 @@ function run_compress_tests() {
|
|||||||
};
|
};
|
||||||
if (!options.warnings) options.warnings = true;
|
if (!options.warnings) options.warnings = true;
|
||||||
}
|
}
|
||||||
|
if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
|
||||||
|
var quoted_props = test.mangle.properties.reserved;
|
||||||
|
if (!Array.isArray(quoted_props)) quoted_props = [];
|
||||||
|
test.mangle.properties.reserved = quoted_props;
|
||||||
|
U.reserve_quoted_keys(input, quoted_props);
|
||||||
|
}
|
||||||
var cmp = new U.Compressor(options, true);
|
var cmp = new U.Compressor(options, true);
|
||||||
var output = cmp.compress(input);
|
var output = cmp.compress(input);
|
||||||
output.figure_out_scope(test.mangle);
|
output.figure_out_scope(test.mangle);
|
||||||
if (test.mangle || test.mangle_props) {
|
if (test.mangle) {
|
||||||
U.base54.reset();
|
U.base54.reset();
|
||||||
output.compute_char_frequency(test.mangle);
|
output.compute_char_frequency(test.mangle);
|
||||||
}
|
|
||||||
if (test.mangle) {
|
|
||||||
output.mangle_names(test.mangle);
|
output.mangle_names(test.mangle);
|
||||||
}
|
if (test.mangle.properties) {
|
||||||
if (test.mangle_props) {
|
output = U.mangle_properties(output, test.mangle.properties);
|
||||||
output = U.mangle_properties(output, test.mangle_props);
|
}
|
||||||
}
|
}
|
||||||
output = make_code(output, output_options);
|
output = make_code(output, output_options);
|
||||||
if (expect != output) {
|
if (expect != output) {
|
||||||
|
|||||||
Reference in New Issue
Block a user