Compare commits

..

55 Commits

Author SHA1 Message Date
Alex Lam S.L
f54ab16843 harmony-v3.0.27 2017-07-30 15:15:29 +08:00
alexlamsl
69cb459c16 fix-ups for #2258 2017-07-30 04:26:21 +08:00
alexlamsl
1eae8f2dcc Merge branch 'master' into harmony 2017-07-30 01:57:34 +08:00
Alex Lam S.L
c4c2ef44d0 v3.0.27 2017-07-30 01:50:42 +08:00
Alex Lam S.L
a845897758 improve mangle.properties (#2261)
- include dead code when `keep_quoted`
- unify `keep_quoted` & `reserved`
- make `test/run-tests.js` consistent with `minify()`

fixes #2256
2017-07-29 23:02:04 +08:00
kzc
d600c78d7b have keep_quoted respect quoted method names (#2258)
fixes #2257
2017-07-28 19:42:12 +08:00
kzc
32ea2c5530 issue template: describe acceptable JS input (#2255) 2017-07-27 21:38:36 +08:00
Alex Lam S.L
d3df2f985d extend collapse_vars to let and const (#2252)
fixes #2250
2017-07-25 22:07:21 +08:00
Alex Lam S.L
69861824b5 enhance test for #2242 (#2248) 2017-07-24 00:32:33 +08:00
Alex Lam S.L
1e0c7d2bc5 harmony-v3.0.26 2017-07-23 16:54:46 +08:00
alexlamsl
98b850580b fix for #2242 on harmony 2017-07-23 16:20:53 +08:00
alexlamsl
29011ea60a remove ascii_identifiers 2017-07-23 12:54:50 +08:00
alexlamsl
77d18be073 Merge branch 'master' into harmony-v3.0.26 2017-07-23 12:53:13 +08:00
Alex Lam S.L
bc61deeca9 v3.0.26 2017-07-23 12:39:36 +08:00
Alex Lam S.L
6a5e74b44e unescape surrogate pairs only (#2246)
fixes #2242
2017-07-23 12:38:21 +08:00
Alex Lam S.L
54446341ee update dependencies (#2241)
- acorn@5.1.1
- commander@2.11.0
- mocha@3.4.2
2017-07-16 16:20:40 +08:00
Alex Lam S.L
91f8b57b3e harmony-v3.0.25 2017-07-16 12:21:39 +08:00
alexlamsl
3a2b737c42 Merge branch 'master' into harmony-v3.0.25 2017-07-16 11:15:07 +08:00
Alex Lam S.L
4e12a6f740 v3.0.25 2017-07-16 11:05:53 +08:00
Alex Lam S.L
b35dfc2599 reject malformed CLI parameters (#2239)
fixes #2237
2017-07-15 23:50:27 +08:00
Alex Lam S.L
9e1da9235e ensure ie8 works with mangled properties (#2238)
fixes #2234
2017-07-15 22:50:59 +08:00
Alex Lam S.L
a5ffe2c23f drop unused builtin globals under unsafe (#2236)
fixes #2233
2017-07-15 15:16:11 +08:00
Alex Lam S.L
9282e7b0c6 fix unsafe evaluate of Object static methods (#2232)
fixes #2231
2017-07-14 19:52:01 +08:00
Alex Lam S.L
5229cb2b1b drop unused compound assignments (#2230)
fixes #2226
2017-07-14 00:39:34 +08:00
Alex Lam S.L
458e3e15f0 enhance passes (#2229)
- remove hardcoded upper limit
- continue based on node count reduction
- emit verbose statistics

fixes #2226
2017-07-13 02:18:59 +08:00
Alex Lam S.L
c615a1e80a fix gzip stream in test/benchmark.js (#2228) 2017-07-12 02:55:57 +08:00
Alex Lam S.L
10a938cb79 enhance source mapping on IIFEs (#2224)
fixes #2213
2017-07-11 02:34:28 +08:00
kzc
0f4278148d uglify-es: update repository and project tagline (#2221) 2017-07-09 23:55:38 +08:00
Alex Lam S.L
4956ad311b benchmark gzipped output (#2220) 2017-07-09 01:44:59 +08:00
kzc
145874e504 docs: update benchmarks using node 8, add babili (#2218) 2017-07-09 01:06:15 +08:00
kzc
f30375052b docs: update benchmarks using node 8, add babili (#2218) 2017-07-09 00:48:53 +08:00
Alex Lam S.L
3e1a8598bf harmony-v3.0.24 2017-07-08 14:51:47 +08:00
alexlamsl
ef63de6968 handle AST_Arrow IIFEs in collapse_vars 2017-07-08 14:27:06 +08:00
alexlamsl
2539fb8096 inline property access of AST_ConciseMethod 2017-07-08 14:25:58 +08:00
alexlamsl
a556dd2dcb Merge branch 'master' into harmony-v3.0.24 2017-07-08 13:12:54 +08:00
Alex Lam S.L
bd7be07c38 v3.0.24 2017-07-08 12:53:20 +08:00
Alex Lam S.L
71ee91e716 handle duplicate argument names in collapse_vars (#2215) 2017-07-08 04:42:35 +08:00
kzc
e7334b4048 uglify-es: have repository point to harmony branch (#2212) 2017-07-07 11:39:48 +08:00
Alex Lam S.L
4f70d2e28c inlining of static methods & constants (#2211)
- guard by `unsafe`
- support `Array`, `Math`, `Number`, `Object` & `String`

fixes #2207
2017-07-07 05:35:32 +08:00
Alex Lam S.L
4b6ca5e742 inline property access of object literal (#2209)
- only if property value is side-effect-free
- guard by `unsafe`

fixes #2208
2017-07-06 21:51:58 +08:00
Alex Lam S.L
f5c46db738 improve AST_ConciseMethod compression (#2202)
p(){return x;} ---> p:()=>x

Optimization subject to the `compress` option `arrows`.
2017-07-06 01:21:04 +08:00
Alex Lam S.L
9306da3c58 suppress collapse_vars of this as call argument (#2204)
fixes #2203
2017-07-06 01:03:52 +08:00
Alex Lam S.L
1ac25fc032 improve compress granularity through typeofs (#2201)
fixes #2198
2017-07-05 19:20:33 +08:00
kzc
fdbb1d09ef Convert p: function(){} to p(){} in object literals (#2199)
when `compress` option `ecma` is 6 or greater.
2017-07-04 14:35:58 +08:00
Alex Lam S.L
5f046c724b minor clean-ups to evaluate (#2197) 2017-07-03 18:52:39 +08:00
Alex Lam S.L
af0262b7e5 improve parenthesis emission (#2196)
- eliminate `throw` usages
- suppress extraneous parenthesis
  - `new function() {foo.bar()}.baz`
  - `for (function() { "foo" in bar; };;);`
2017-07-03 04:17:37 +08:00
Alex Lam S.L
6b3aeff1d8 clean up TreeWalker.pop() (#2195)
Remove superfluous parameter.
2017-07-03 03:23:38 +08:00
Alex Lam S.L
20e4f8277f refactor throw usage within compress (#2193)
Eliminate exceptional constructs from normal control flow.
2017-07-03 02:10:56 +08:00
kzc
f3a487a368 document fast mangle-only minify mode (#2194) 2017-07-03 01:37:04 +08:00
Alex Lam S.L
33ad0d258c harmony-v3.0.23 2017-07-02 19:04:15 +08:00
alexlamsl
5ea1da2d42 handle AST_Expansion in collapse_vars & inline 2017-07-02 18:15:16 +08:00
alexlamsl
e77b6d525c Merge branch 'master' into harmony-v3.0.23 2017-07-02 17:47:21 +08:00
Alex Lam S.L
2dde41615a v3.0.23 2017-07-02 17:24:22 +08:00
Alex Lam S.L
8b69a3d18e drop argument value after collapse_vars (#2190) 2017-07-02 04:28:11 +08:00
Alex Lam S.L
d40950b741 improve inline efficiency (#2188)
... by teaching `collapse_vars` some new tricks.

fixes #2187
2017-07-02 01:05:14 +08:00
41 changed files with 2258 additions and 641 deletions

View File

@@ -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.**

View File

@@ -1,7 +1,7 @@
uglify-es uglify-es
========= =========
**uglify-es** is an ECMAScript parser, minifier, compressor and beautifier toolkit for ES6+. A JavaScript parser, mangler/compressor and beautifier toolkit for ES6+.
#### Note: #### Note:
- **`uglify-es` is API/CLI compatible with `uglify-js@3`.** - **`uglify-es` is API/CLI compatible with `uglify-js@3`.**
@@ -653,6 +653,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
@@ -726,7 +730,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.
@@ -897,7 +901,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)
@@ -1050,3 +1053,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 });
```

View File

@@ -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.");
@@ -315,7 +315,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 {
@@ -333,7 +333,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);
@@ -356,14 +356,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);

View File

@@ -697,7 +697,7 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul
var AST_VarDef = DEFNODE("VarDef", "name value", { var AST_VarDef = DEFNODE("VarDef", "name value", {
$documentation: "A variable declaration; only appears in a AST_Definitions node", $documentation: "A variable declaration; only appears in a AST_Definitions node",
$propdoc: { $propdoc: {
name: "[AST_SymbolVar|AST_SymbolConst|AST_Destructuring] name of the variable", name: "[AST_Destructuring|AST_SymbolConst|AST_SymbolLet|AST_SymbolVar] name of the variable",
value: "[AST_Node?] initializer, or null of there's no initializer" value: "[AST_Node?] initializer, or null of there's no initializer"
}, },
_walk: function(visitor) { _walk: function(visitor) {
@@ -1160,7 +1160,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) {
@@ -1179,8 +1179,8 @@ TreeWalker.prototype = {
} }
this.stack.push(node); this.stack.push(node);
}, },
pop: function(node) { pop: function() {
this.stack.pop(); var node = this.stack.pop();
if (node instanceof AST_Lambda || node instanceof AST_Class) { if (node instanceof AST_Lambda || node instanceof AST_Class) {
this.directives = Object.getPrototypeOf(this.directives); this.directives = Object.getPrototypeOf(this.directives);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -70,6 +70,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 || {}),
@@ -82,11 +83,16 @@ function minify(files, options) {
safari10: false, safari10: false,
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 || {};
} }
} }
@@ -129,6 +135,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);
} }

View File

@@ -54,7 +54,6 @@ function OutputStream(options) {
options = defaults(options, { options = defaults(options, {
ascii_only : false, ascii_only : false,
ascii_identifiers: undefined,
beautify : false, beautify : false,
bracketize : false, bracketize : false,
comments : false, comments : false,
@@ -78,9 +77,6 @@ function OutputStream(options) {
wrap_iife : false, wrap_iife : false,
}, true); }, true);
if (typeof options.ascii_identifiers === 'undefined')
options.ascii_identifiers = options.ascii_only;
if (options.shorthand === undefined) if (options.shorthand === undefined)
options.shorthand = options.ecma > 5; options.shorthand = options.ecma > 5;
@@ -118,20 +114,16 @@ 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(/[\ud800-\udbff][\udc00-\udfff]|[\u0000-\u001f\u007f-\uffff]/g, function(ch) { if (options.ecma >= 6) {
var code = get_full_char_code(ch, 0).toString(16); str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
var code = get_full_char_code(ch, 0).toString(16);
if ((identifier && code.length === 1 && options.ecma >= 6) || code.length > 4) {
if (options.ecma < 6) {
if (identifier) {
return ch; // no \u{} support
}
return "\\u" + ch.charCodeAt(0).toString(16) + "\\u"
+ ch.charCodeAt(1).toString(16);
}
return "\\u{" + code + "}"; return "\\u{" + code + "}";
} else if (code.length <= 2 && !identifier) { });
}
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = ch.charCodeAt(0).toString(16);
if (code.length <= 2 && !identifier) {
while (code.length < 2) code = "0" + code; while (code.length < 2) code = "0" + code;
return "\\x" + code; return "\\x" + code;
} else { } else {
@@ -139,6 +131,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) {
@@ -172,7 +170,7 @@ function OutputStream(options) {
function quote_template() { function quote_template() {
return '`' + str.replace(/`/g, '\\`') + '`'; return '`' + str.replace(/`/g, '\\`') + '`';
} }
if (options.ascii_only) str = to_ascii(str); str = to_utf8(str);
if (quote === "`") return quote_template(); if (quote === "`") return quote_template();
switch (options.quote_style) { switch (options.quote_style) {
case 1: case 1:
@@ -198,8 +196,7 @@ function OutputStream(options) {
function make_name(name) { function make_name(name) {
name = name.toString(); name = name.toString();
if (options.ascii_identifiers) name = to_utf8(name, true);
name = to_ascii(name, true);
return name; return name;
}; };
@@ -461,7 +458,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);
@@ -745,14 +742,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;
} }
}); });
@@ -1369,19 +1367,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){
@@ -1401,6 +1397,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_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();
@@ -1440,15 +1439,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);
@@ -1703,9 +1710,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)

View File

@@ -85,6 +85,36 @@ 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_ObjectProperty && node.quote) {
add(node.key.name);
} 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,
@@ -94,7 +124,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 = [];
@@ -109,7 +139,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'
@@ -122,12 +151,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
@@ -137,18 +165,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);
}
else if (node instanceof AST_ConciseMethod) {
add(node.name.name);
} }
})); }));
// 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
@@ -157,27 +181,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_ConciseMethod) {
if (should_mangle(node.name.name)) {
node.name.name = mangle(node.name.name);
}
}
// 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
@@ -193,19 +199,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);
@@ -225,19 +225,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);
@@ -245,32 +242,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) {

View File

@@ -116,7 +116,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (node.is_block_scope()) { if (node.is_block_scope()) {
var save_scope = scope; var save_scope = scope;
scope = new AST_Scope(node); node.block_scope = scope = new AST_Scope(node);
scope.init_scope_vars(save_scope); scope.init_scope_vars(save_scope);
if (!(node instanceof AST_Scope)) { if (!(node instanceof AST_Scope)) {
scope.uses_with = save_scope.uses_with; scope.uses_with = save_scope.uses_with;
@@ -461,14 +461,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;
}); });

View File

@@ -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;
}); });
}; };

View File

@@ -1,20 +1,17 @@
{ {
"name": "uglify-es", "name": "uglify-es",
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit for ES6+",
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony", "homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"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.22", "version": "3.0.27",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
"maintainers": [ "maintainers": [
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)" "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
], ],
"repository": { "repository": "git+https://github.com/mishoo/UglifyJS2.git#harmony",
"type": "git",
"url": "https://github.com/mishoo/UglifyJS2.git"
},
"bugs": { "bugs": {
"url": "https://github.com/mishoo/UglifyJS2/issues" "url": "https://github.com/mishoo/UglifyJS2/issues"
}, },
@@ -29,12 +26,12 @@
"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.4.2",
"semver": "~5.3.0" "semver": "~5.3.0"
}, },
"scripts": { "scripts": {
@@ -42,12 +39,16 @@
}, },
"keywords": [ "keywords": [
"uglify", "uglify",
"uglify-js",
"uglify-es", "uglify-es",
"uglify-js",
"minify", "minify",
"minifier", "minifier",
"javascript",
"ecmascript",
"es5", "es5",
"es6", "es6",
"es7",
"es8",
"es2015", "es2015",
"es2016", "es2016",
"es2017", "es2017",

View File

@@ -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();

View File

@@ -287,6 +287,7 @@ issue_2105_1: {
collapse_vars: true, collapse_vars: true,
ecma: 6, ecma: 6,
inline: true, inline: true,
passes: 3,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -312,12 +313,12 @@ issue_2105_1: {
}); });
} }
expect: { expect: {
void (() => { (() => {
var quux = () => { var quux = () => {
console.log("PASS"); console.log("PASS");
}; };
return { return {
prop: () => { prop() {
console.log; console.log;
quux(); quux();
} }
@@ -332,6 +333,7 @@ issue_2105_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
inline: true, inline: true,
passes: 2,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -357,7 +359,7 @@ issue_2105_2: {
}); });
} }
expect: { expect: {
void (() => { (() => {
var quux = () => { var quux = () => {
console.log("PASS"); console.log("PASS");
}; };
@@ -538,3 +540,60 @@ issue_2084: {
expect_stdout: "0" expect_stdout: "0"
node_version: ">=4" node_version: ">=4"
} }
export_default_object_expression: {
options = {
arrows: true,
evaluate: true,
}
input: {
export default {
foo: 1 + 2,
bar() { return 4; },
get baz() { return this.foo; },
};
}
expect_exact: "export default{foo:3,bar:()=>4,get baz(){return this.foo}};"
}
concise_methods_with_computed_property2: {
options = {
arrows: true,
evaluate: true,
}
input: {
var foo = {
[[1]](v) {
return v;
}
};
console.log(foo[[1]]("PASS"));
}
expect_exact: 'var foo={[[1]]:v=>v};console.log(foo[[1]]("PASS"));'
expect_stdout: "PASS"
node_version: ">=4"
}
async_object_literal: {
options = {
arrows: true,
ecma: 6,
evaluate: true,
}
input: {
var obj = {
async a() {
return await foo(1 + 0);
},
anon: async function() {
return await foo(2 + 0);
}
};
}
expect: {
var obj = {
a: async () => await foo(1),
anon: async () => await foo(2)
};
}
}

View File

@@ -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
@@ -2077,10 +2077,10 @@ chained_3: {
} }
expect: { expect: {
console.log(function(a, b) { console.log(function(a, b) {
var c = a, c = b; var c = 1, c = b;
b++; b++;
return c; return c;
}(1, 2)); }(0, 2));
} }
expect_stdout: "2" expect_stdout: "2"
} }
@@ -2330,3 +2330,289 @@ reassign_const_2: {
} }
expect_stdout: true expect_stdout: true
} }
issue_2187_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 1;
!function(foo) {
foo();
var a = 2;
console.log(a);
}(function() {
console.log(a);
});
}
expect: {
var a = 1;
!function(foo) {
foo();
var a = 2;
console.log(a);
}(function() {
console.log(a);
});
}
expect_stdout: [
"1",
"2",
]
}
issue_2187_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var b = 1;
console.log(function(a) {
return a && ++b;
}(b--));
}
expect: {
var b = 1;
console.log(function(a) {
return b-- && ++b;
}());
}
expect_stdout: "1"
}
issue_2187_3: {
options = {
collapse_vars: true,
inline: true,
unused: true,
}
input: {
var b = 1;
console.log(function(a) {
return a && ++b;
}(b--));
}
expect: {
var b = 1;
console.log(b-- && ++b);
}
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"
}
issue_2203_3: {
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"
node_version: ">=4"
}
issue_2203_4: {
options = {
collapse_vars: true,
unused: true,
}
input: {
a = "FAIL";
console.log({
a: "PASS",
b: function() {
return (c => {
return c.a;
})((String, (Object, (() => this)())));
}
}.b());
}
expect: {
a = "FAIL";
console.log({
a: "PASS",
b: function() {
return (c => {
return (String, (Object, (() => this)())).a;
})();
}
}.b());
}
expect_stdout: "PASS"
node_version: ">=4"
}
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_2250_1: {
options = {
collapse_vars: true,
conditionals: true,
reduce_vars: true,
}
input: {
function f(x) {
if (x) {
const a = foo();
x(a);
}
}
function g(x) {
if (x) {
let a = foo();
x(a);
}
}
function h(x) {
if (x) {
var a = foo();
x(a);
}
}
}
expect: {
function f(x) {
x && x(foo());
}
function g(x) {
x && x(foo());
}
function h(x) {
x && x(foo());
}
}
}
issue_2250_2: {
options = {
collapse_vars: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
{
const foo = function(){};
foo(bar());
}
{
let foo = function(){};
foo(bar());
}
{
var foo = function(){};
foo(bar());
}
}
expect: {
bar();
bar();
bar();
}
}

View File

@@ -377,3 +377,82 @@ accessor: {
} }
expect: {} expect: {}
} }
issue_2233_1: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
Array.isArray;
Boolean;
console.log;
Error.name;
Function.length;
Math.random;
Number.isNaN;
RegExp;
Object.defineProperty;
String.fromCharCode;
}
expect: {}
expect_stdout: true
}
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;
}
}

View File

@@ -1210,6 +1210,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;
@@ -1219,9 +1220,8 @@ var_catch_toplevel: {
} }
expect: { expect: {
!function() { !function() {
a--;
try { try {
a++; x();
} catch(a) { } catch(a) {
var a; var a;
} }
@@ -1299,6 +1299,7 @@ issue_2105: {
options = { options = {
collapse_vars: true, collapse_vars: true,
inline: true, inline: true,
passes: 3,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -1324,7 +1325,7 @@ issue_2105: {
}); });
} }
expect: { expect: {
!void function() { (function() {
var quux = function() { var quux = function() {
console.log("PASS"); console.log("PASS");
}; };
@@ -1334,7 +1335,7 @@ issue_2105: {
quux(); quux();
} }
}; };
}().prop(); })().prop();
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
@@ -1426,3 +1427,89 @@ issue_2163: {
b; b;
} }
} }
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"
}

View File

@@ -344,22 +344,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
); );
} }
@@ -368,22 +372,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
); );
} }
@@ -392,21 +400,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
); );
@@ -416,22 +428,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
); );
} }
@@ -480,9 +496,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
@@ -730,8 +746,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)();
} }
} }
@@ -1162,3 +1178,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
}

View File

@@ -468,11 +468,9 @@ issue_2114_1: {
} }
expect: { expect: {
var c = 0; var c = 0;
!function() { c = 1 + (c += 1), function() {
0;
}((c += 1, c = 1 + c, function() {
var b = void (b && (b.b += (c += 1, 0))); var b = void (b && (b.b += (c += 1, 0)));
}())); }();
console.log(c); console.log(c);
} }
expect_stdout: "2" expect_stdout: "2"

View File

@@ -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]',
] ]
} }

View File

@@ -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]",
] ]
} }

View File

@@ -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
} }

View File

@@ -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: {

View File

@@ -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,

View File

@@ -419,7 +419,7 @@ wrap_iife_in_return_call: {
expect_exact: '(void console.log("test"))();' expect_exact: '(void console.log("test"))();'
} }
pure_annotation: { pure_annotation_1: {
options = { options = {
inline: true, inline: true,
side_effects: true, side_effects: true,
@@ -432,6 +432,20 @@ pure_annotation: {
expect_exact: "" expect_exact: ""
} }
pure_annotation_2: {
options = {
collapse_vars: true,
inline: true,
side_effects: true,
}
input: {
/*@__PURE__*/(function(n) {
console.log("hello", n);
}(42));
}
expect_exact: ""
}
drop_fargs: { drop_fargs: {
options = { options = {
cascade: true, cascade: true,
@@ -449,9 +463,7 @@ drop_fargs: {
} }
expect: { expect: {
var a = 1; var a = 1;
!function() { ++a && a.var, a++;
a++;
}(++a && a.var);
console.log(a); console.log(a);
} }
expect_stdout: "3" expect_stdout: "3"
@@ -474,9 +486,7 @@ keep_fargs: {
} }
expect: { expect: {
var a = 1; var a = 1;
!function(a_1) { ++a && a.var, a++;
a++;
}(++a && a.var);
console.log(a); console.log(a);
} }
expect_stdout: "3" expect_stdout: "3"

View File

@@ -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";

View File

@@ -480,3 +480,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;);'
}

View File

@@ -98,3 +98,19 @@ new_with_assignement_expression: {
new y([a, b] = [3, 4]); new y([a, b] = [3, 4]);
} }
} }
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"
}

View File

@@ -284,9 +284,11 @@ concise_methods_with_various_property_names: {
} }
concise_methods_and_mangle_props: { concise_methods_and_mangle_props: {
mangle_props = { mangle = {
regex: /_/ properties: {
}; regex: /_/,
},
}
input: { input: {
function x() { function x() {
obj = { obj = {
@@ -510,3 +512,235 @@ variable_as_computed_property: {
} }
expect_exact: "function getLine(header){return{[header]:{}}}" expect_exact: "function getLine(header){return{[header]:{}}}"
} }
prop_func_to_concise_method: {
options = {
ecma: 6,
}
input: {
({
emit: function NamedFunctionExpression() {
console.log("PASS");
},
run: function() {
this.emit();
}
}).run();
}
expect: {
({
emit: function NamedFunctionExpression() {
console.log("PASS");
},
run() {
this.emit();
}
}).run();
}
expect_stdout: "PASS"
node_version: ">=6"
}
prop_arrow_to_concise_method: {
options = {
ecma: 6,
}
input: {
({
run: () => {
console.log("PASS");
}
}).run();
}
expect: {
({
run() {
console.log("PASS");
}
}).run();
}
expect_stdout: "PASS"
node_version: ">=6"
}
concise_method_to_prop_arrow: {
options = {
arrows: true,
ecma: 6,
}
input: {
console.log(({ a: () => 1 }).a());
console.log(({ a: () => { return 2; } }).a());
console.log(({ a() { return 3; } }).a());
console.log(({ a() { return this.b; }, b: 4 }).a());
}
expect: {
console.log({ a: () => 1 }.a());
console.log({ a: () => 2 }.a());
console.log({ a: () => 3 }.a());
console.log({ a() { return this.b; }, b: 4 }.a());
}
expect_stdout: [
"1",
"2",
"3",
"4",
]
node_version: ">=4"
}
prop_func_to_async_concise_method: {
options = {
ecma: 8,
}
input: {
({
run: async function() {
console.log("PASS");
}
}).run();
}
expect: {
({
async run() {
console.log("PASS");
}
}).run();
}
expect_stdout: "PASS"
node_version: ">=8"
}
prop_func_to_concise_method_various: {
options = {
ecma: 6,
}
input: {
({
null: function(x, y){ x(y); },
123: function(x, y){ x(y); },
"A B": function(x, y){ x(y); },
p1: function(x, y){ x(y); },
p2: function*(x, y){ yield x(y); },
p3: async function(x, y){ await x(y); },
[c1]: function(x, y){ x(y); },
[c2]: function*(x, y){ yield x(y); },
[c3]: async function(x, y){ await x(y); },
});
}
expect: {
({
null(x, y) { x(y); },
123(x, y) { x(y); },
"A B"(x, y) { x(y); },
p1(x, y) { x(y); },
*p2(x, y) { yield x(y); },
async p3(x, y) { await x(y); },
[c1](x, y) { x(y); },
*[c2](x, y) { yield x(y); },
async [c3](x, y) { await x(y); },
});
}
}
prop_arrows_to_concise_method_various: {
options = {
ecma: 6,
}
input: {
({
null: (x, y) => { x(y); },
123: (x, y) => { x(y); },
"A B": (x, y) => { x(y); },
p1: (x, y) => { x(y); },
p3: async (x, y) => { await x(y); },
[c1]: (x, y) => { x(y); },
[c3]: async (x, y) => { await x(y); },
});
}
expect: {
({
null(x, y) { x(y); },
123(x, y) { x(y); },
"A B"(x, y) { x(y); },
p1(x, y) { x(y); },
async p3(x, y) { await x(y); },
[c1](x, y) { x(y); },
async [c3](x, y) { await x(y); },
});
}
}
prop_arrow_with_this: {
options = {
ecma: 6,
}
input: {
function run(arg) {
console.log(arg === this ? "global" : arg === foo ? "foo" : arg);
}
var foo = {
func_no_this: function() { run(); },
func_with_this: function() { run(this); },
arrow_no_this: () => { run(); },
arrow_with_this: () => { run(this); },
};
for (var key in foo) foo[key]();
}
expect: {
function run(arg) {
console.log(arg === this ? "global" : arg === foo ? "foo" : arg);
}
var foo = {
func_no_this() { run(); },
func_with_this() { run(this); },
arrow_no_this() { run(); },
arrow_with_this: () => { run(this); },
};
for (var key in foo) foo[key]();
}
expect_stdout: [
"undefined",
"foo",
"undefined",
"global",
]
node_version: ">=4"
}
prop_arrow_with_nested_this: {
options = {
ecma: 6,
}
input: {
function run(arg) {
console.log(arg === this ? "global" : arg === foo ? "foo" : arg);
}
var foo = {
func_func_this: function() { (function() { run(this); })(); },
func_arrow_this: function() { (() => { run(this); })(); },
arrow_func_this: () => { (function() { run(this); })(); },
arrow_arrow_this: () => { (() => { run(this); })(); },
};
for (var key in foo) foo[key]();
}
expect: {
function run(arg) {
console.log(arg === this ? "global" : arg === foo ? "foo" : arg);
}
var foo = {
func_func_this() { (function() { run(this); })(); },
func_arrow_this() { (() => { run(this); })(); },
arrow_func_this() { (function() { run(this); })(); },
arrow_arrow_this: () => { (() => { run(this); })(); },
};
for (var key in foo) foo[key]();
}
expect_stdout: [
"global",
"foo",
"global",
"global",
]
node_version: ">=4"
}

View File

@@ -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,9 +153,11 @@ mangle_unquoted_properties: {
options = { options = {
properties: false properties: false
} }
mangle_props = { mangle = {
builtins: true, properties: {
keep_quoted: true builtins: true,
keep_quoted: true,
},
} }
beautify = { beautify = {
beautify: false, beautify: false,
@@ -178,24 +186,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" };
@@ -207,9 +217,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" };
@@ -221,9 +233,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" };
@@ -238,11 +252,13 @@ mangle_debug_suffix_keep_quoted: {
options = { options = {
properties: false properties: false
} }
mangle_props = { mangle = {
builtins: true, properties: {
keep_quoted: true, builtins: true,
debug: "XYZ", debug: "XYZ",
reserved: [] keep_quoted: true,
reserved: [],
},
} }
beautify = { beautify = {
beautify: false, beautify: false,
@@ -659,3 +675,292 @@ 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_2208_6: {
options = {
inline: true,
side_effects: true,
unsafe: true,
}
input: {
console.log({
p: () => 42
}.p());
}
expect: {
console.log(42);
}
expect_stdout: "42"
node_version: ">=4"
}
issue_2208_7: {
options = {
inline: true,
side_effects: true,
unsafe: true,
}
input: {
console.log({
p() {
return 42;
}
}.p());
}
expect: {
console.log(42);
}
expect_stdout: "42"
node_version: ">=4"
}
issue_2208_8: {
options = {
inline: true,
side_effects: true,
unsafe: true,
}
input: {
console.log({
*p() {
return x();
}
}.p());
console.log({
async p() {
return await x();
}
}.p());
}
expect: {
console.log({
*p() {
return x();
}
}.p());
console.log(async function() {
return await x();
}());
}
}
issue_2208_9: {
options = {
inline: true,
side_effects: true,
unsafe: true,
}
input: {
a = 42;
console.log({
p: () => {
return function() {
return this.a;
}();
}
}.p());
}
expect: {
a = 42;
console.log(function() {
return this.a;
}());
}
expect_stdout: "42"
node_version: ">=4"
}
methods_keep_quoted_true: {
options = {
arrows: true,
ecma: 6,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
class C { "Quoted"(){} Unquoted(){} }
f1({ "Quoted"(){}, Unquoted(){}, "Prop": 3 });
f2({ "Quoted": function(){} });
f3({ "Quoted": ()=>{} });
}
expect_exact: "class C{Quoted(){}o(){}}f1({Quoted(){},o(){},Prop:3});f2({Quoted(){}});f3({Quoted(){}});"
}
methods_keep_quoted_false: {
options = {
arrows: true,
ecma: 6,
}
mangle = {
properties: {
keep_quoted: false,
},
}
input: {
class C { "Quoted"(){} Unquoted(){} }
f1({ "Quoted"(){}, Unquoted(){}, "Prop": 3 });
f2({ "Quoted": function(){} });
f3({ "Quoted": ()=>{} });
}
expect_exact: "class C{o(){}d(){}}f1({o(){},d(){},e:3});f2({o(){}});f3({o(){}});"
}
methods_keep_quoted_from_dead_code: {
options = {
arrows: true,
booleans: true,
conditionals: true,
dead_code: true,
ecma: 6,
evaluate: true,
reduce_vars: true,
side_effects: true,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
class C { Quoted(){} Unquoted(){} }
f1({ Quoted(){}, Unquoted(){}, "Prop": 3 });
f2({ Quoted: function(){} });
f3({ Quoted: ()=>{} });
0 && obj["Quoted"];
}
expect_exact: "class C{Quoted(){}o(){}}f1({Quoted(){},o(){},Prop:3});f2({Quoted(){}});f3({Quoted(){}});"
}
issue_2256: {
options = {
side_effects: true,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
({ "keep": 1 });
g.keep = g.change;
}
expect: {
g.keep = g.g;
}
}

View File

@@ -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: {

View File

@@ -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;);
} }
} }

View File

@@ -43,15 +43,6 @@ unicode_string_literals: {
expect_exact: 'var a="6 length unicode character: \\u{101111}";' expect_exact: 'var a="6 length unicode character: \\u{101111}";'
} }
// Don't escape identifiers below es6 (or in this case double escaped in expect_exact)
unicode_output_es5_surrogates: {
beautify = {ascii_only: true, ecma: 5}
input: {
var \u{10000} = "6 length unicode character: \u{10FFFF}";
}
expect_exact: 'var \u{10000}="6 length unicode character: \\udbff\\udfff";'
}
check_escape_style: { check_escape_style: {
beautify = {ascii_only: true, ecma: 6} beautify = {ascii_only: true, ecma: 6}
input: { input: {
@@ -65,20 +56,6 @@ check_escape_style: {
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \\u{10000}="\\u{10000}";var \\u{2f800}="\\u{100000}";' expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \\u{10000}="\\u{10000}";var \\u{2f800}="\\u{100000}";'
} }
// Don't escape identifiers below es6, no escaped identifiers support and no \u{} syntax
check_escape_style_es5: {
beautify = {ascii_only: true, ecma: 5}
input: {
var a = "\x01";
var \ua0081 = "\x10"; // \u0081 only in ID_Continue
var \u0100 = "\u0100";
var \u1000 = "\u1000";
var \u{10000} = "\u{10000}"; // Identifier won't be escaped in es 5.1
var \u{2f800} = "\u{100000}"; // Same
}
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \ud800\udc00="\\ud800\\udc00";var \ud87e\udc00="\\udbc0\\udc00";'
}
ID_continue_with_surrogate_pair: { ID_continue_with_surrogate_pair: {
beautify = {ascii_only: true, ecma: 6} beautify = {ascii_only: true, ecma: 6}
input: { input: {
@@ -103,18 +80,42 @@ non_escape_2_non_escape: {
expect_exact: 'var µþ="µþ";' expect_exact: 'var µþ="µþ";'
} }
non_escape_2_half_escape1: { issue_2242_1: {
beautify = {ascii_only: false, ascii_identifiers: true, ecma: 6} beautify = {
input: { ascii_only: false,
var µþ = "µþ";
} }
expect_exact: 'var \\u00b5\\u00fe="µþ";' input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\ud83d\ude00","\\ud83d@\\ude00");'
} }
non_escape_2_half_escape2: { issue_2242_2: {
beautify = {ascii_only: true, ascii_identifiers: false, ecma: 6} beautify = {
input: { ascii_only: true,
var µþ = "µþ";
} }
expect_exact: 'var µþ="\\xb5\\xfe";' 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");'
} }

View File

@@ -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;

View File

@@ -66,7 +66,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();
}); });
}); });
@@ -195,7 +195,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");
@@ -686,8 +686,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;
@@ -696,8 +696,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;
@@ -706,4 +706,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();
});
});
}); });

View File

@@ -26,12 +26,12 @@ describe("bin/uglifyjs with input file globs", function() {
}); });
}); });
it("bin/uglifyjs with multiple input file globs.", function(done) { it("bin/uglifyjs with multiple input file globs.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel'; var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=2';
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",2*11);\n'); assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",22);\n');
done(); done();
}); });
}); });

View File

@@ -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();
}); });
}); });

View File

@@ -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() {

View File

@@ -4,7 +4,11 @@ var assert = require("assert");
describe("Object", function() { describe("Object", function() {
it("Should allow objects to have a methodDefinition as property", function() { it("Should allow objects to have a methodDefinition as property", function() {
var code = "var a = {test() {return true;}}"; var code = "var a = {test() {return true;}}";
assert.equal(Uglify.minify(code).code, "var a={test(){return!0}};"); assert.equal(Uglify.minify(code, {
compress: {
arrows: false
}
}).code, "var a={test(){return!0}};");
}); });
it("Should not allow objects to use static keywords like in classes", function() { it("Should not allow objects to use static keywords like in classes", function() {

View File

@@ -78,4 +78,41 @@ describe("String literals", 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";"\\08";');
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";"\\09";');
}); });
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));
});
}); });

View File

@@ -1,4 +1,5 @@
var assert = require("assert"); var assert = require("assert");
var semver = require("semver");
var uglify = require("../node"); var uglify = require("../node");
describe("Unicode", function() { describe("Unicode", function() {
@@ -138,8 +139,33 @@ describe("Unicode", function() {
it("Should parse raw characters correctly", function() { it("Should parse raw characters correctly", function() {
var ast = uglify.parse('console.log("\\udbff");'); var ast = uglify.parse('console.log("\\udbff");');
assert.strictEqual(ast.print_to_string(), 'console.log("\udbff");'); assert.strictEqual(ast.print_to_string(), 'console.log("\\udbff");');
ast = uglify.parse(ast.print_to_string()); ast = uglify.parse(ast.print_to_string());
assert.strictEqual(ast.print_to_string(), 'console.log("\udbff");'); assert.strictEqual(ast.print_to_string(), 'console.log("\\udbff");');
}); });
if (semver.satisfies(process.version, ">=4")) {
it("Should not unescape unpaired surrogates", function() {
var code = [];
for (var i = 0; i <= 0x20001; i++) {
code.push("\\u{" + i.toString(16) + "}");
}
code = '"' + code.join() + '"';
[true, false].forEach(function(ascii_only) {
[5, 6].forEach(function(ecma) {
var result = uglify.minify(code, {
compress: false,
mangle: false,
output: {
ascii_only: ascii_only
},
ecma: ecma
});
if (result.error) throw result.error;
if (ecma > 5) assert.ok(code.length > result.code.length);
assert.strictEqual(eval(code), eval(result.code));
});
});
});
}
}); });

View File

@@ -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) {