Compare commits

...

47 Commits

Author SHA1 Message Date
Alex Lam S.L
f72d3029dd v3.3.25 2018-05-12 23:50:40 +00:00
Alex Lam S.L
1a0d6edc81 remove colors dependency (#3133) 2018-05-13 07:50:02 +08:00
Alex Lam S.L
7b59b2f5b2 replace mocha dependency (#3131) 2018-05-11 20:15:34 +08:00
Alex Lam S.L
7bc7704edf fix corner case in reduce_vars (#3129) 2018-05-10 18:45:20 +08:00
Alex Lam S.L
14e712ee80 fix corner case in call binding (#3128)
fixes #3127
2018-05-10 06:16:35 +08:00
Alex Lam S.L
f83adcc995 v3.3.24 2018-05-07 20:17:34 +00:00
Alex Lam S.L
df8a99439a fix various corner cases (#3126)
- augment ufuzz/reminify test options

fixes #3125
2018-05-07 07:36:25 +08:00
Alex Lam S.L
6b91d12ec3 fix corner case in reduce_vars (#3124) 2018-05-06 16:42:35 +08:00
Alex Lam S.L
f37b91879f fix various corner cases (#3123) 2018-05-05 13:17:50 +08:00
Alex Lam S.L
d835c72c80 speed up collapse_vars (#3119) 2018-05-04 18:38:13 +08:00
Alex Lam S.L
c4cebb4b01 fix reduce_vars on nested invocations (#3118) 2018-05-04 06:05:38 +08:00
Alex Lam S.L
d51a00a450 compress AST_Sequence within AST_Call (#3117) 2018-05-03 19:14:56 +08:00
Alex Lam S.L
fc0f168a0c better fix for #3113 (#3115) 2018-05-03 15:51:51 +08:00
Alex Lam S.L
a0ca595c2c fix TreeWalker scan order (#3114)
fixes #3113
2018-05-03 00:27:45 +08:00
Alex Lam S.L
1a314e9f60 improve reduce_vars (#3112)
fixes #3110
2018-05-02 15:11:45 +08:00
Alex Lam S.L
6fcbd5e217 v3.3.23 2018-04-28 17:14:52 +00:00
Alex Lam S.L
22cea023d1 improve numeral compression (#3108) 2018-04-28 02:47:49 +08:00
Alex Lam S.L
70d4477e05 workaround vm context issue in node-chakracore (#3106) 2018-04-27 07:40:34 +08:00
Alex Lam S.L
838f837379 improve general performance (#3104) 2018-04-27 04:30:29 +08:00
Alex Lam S.L
82a8b6f612 improve collapse_vars (#3103) 2018-04-26 19:26:01 +08:00
Alex Lam S.L
69fc7ca8da workaround test failures in Node.js 10 (#3102) 2018-04-26 17:44:37 +08:00
Alex Lam S.L
0a79496e0a workaround stack overflow in ChakraCore (#3101) 2018-04-26 15:02:17 +08:00
Alex Lam S.L
9e87edfc2e better fix for #2506 (#3099) 2018-04-25 04:46:07 +08:00
Alex Lam S.L
27211cf2d5 handle RHS side-effects in collapse_vars (#3097)
fixes #3096
2018-04-24 20:31:50 +08:00
Alex Lam S.L
b5ce199711 improve max_line_len (#3095)
fixes #304
2018-04-24 15:19:45 +08:00
Alex Lam S.L
c71ed91e63 update AST documentation (#3094)
fixes #2622
2018-04-24 14:39:12 +08:00
alexlamsl
f7545d0f1c remove unsupported platform 2018-04-24 13:32:54 +08:00
Alex Lam S.L
59eecb6bf5 v3.3.22 2018-04-20 19:50:16 +00:00
Alex Lam S.L
d83c6490ab fix corner case in strip_func_ids() (#3090) 2018-04-19 04:51:42 +08:00
Alex Lam S.L
7362f57966 improve performance when handling unused variables in collapse_vars (#3084)
fixes #3082
2018-04-15 12:38:31 +08:00
Alex Lam S.L
eaa2c1f6af v3.3.21 2018-04-12 07:08:53 +00:00
Alex Lam S.L
6a916523d4 fix inline of catch-scoped variables (#3077)
fixes #3076
2018-04-11 15:44:43 +08:00
Alex Lam S.L
ba7069d52b suppress hoist_props for embedded assignments (#3074) 2018-04-11 05:19:16 +08:00
Alex Lam S.L
4dd7d0e39b extend hoist_props (#3073)
- handle `AST_Assign` the same way as `AST_VarDef`
- inject `AST_Var` as succeeding statement

fixes #3071
2018-04-11 02:48:15 +08:00
Alex Lam S.L
90199d0a96 extend join_vars on object assignments (#3072) 2018-04-11 01:35:42 +08:00
Alex Lam S.L
b82fd0ad41 handle flow control in loops with reduce_vars (#3069)
fixes #3068
2018-04-10 06:51:03 +08:00
Alex Lam S.L
183da16896 handle pure_funcs under inline & reduce_vars correctly (#3066)
fixes #3065
2018-04-10 02:46:38 +08:00
Alex Lam S.L
87857b0f1b v3.3.20 2018-04-08 03:06:15 +08:00
Alex Lam S.L
e5f6a88233 fix corner case in reuse of mangle options (#3062) 2018-04-08 02:29:37 +08:00
Alex Lam S.L
8d0b00317e v3.3.19 2018-04-07 22:27:55 +08:00
Alex Lam S.L
db49daf365 mangle Object.defineProperty() (#3059)
fixes #869
2018-04-06 17:10:36 +08:00
Alex Lam S.L
923deeff35 support inline source map from multiple files (#3058)
fixes #145
2018-04-06 16:04:15 +08:00
Alex Lam S.L
0b62a28b47 improve usability of includeSources (#3057)
Exclude source contents from input source map if `includeSources=false`

fixes #3041
2018-04-06 13:32:26 +08:00
Alex Lam S.L
44116c6d2b fix AST corruption during inline of simple return (#3056)
fixes #3054
2018-04-06 05:39:07 +08:00
Alex Lam S.L
b5bab254ce speed up has_parens() (take 2) (#3052)
fixes #3050
2018-04-05 04:12:04 +08:00
Alex Lam S.L
81603ecd15 improve performance through makePredicate() (#3048) 2018-04-03 15:15:01 +08:00
Alex Lam S.L
e67553fa55 fix tree traversal on AST_Do (#3047)
fixes #3046
2018-04-02 22:31:23 +08:00
34 changed files with 2181 additions and 659 deletions

View File

@@ -2,10 +2,6 @@
<!-- Note: sub-optimal but correct code is not a bug --> <!-- Note: sub-optimal but correct code is not a bug -->
**ES5 or ES6+ input?**
<!-- Note: for ES6 see: https://github.com/mishoo/UglifyJS2/tree/harmony#harmony -->
**Uglify version (`uglifyjs -V`)** **Uglify version (`uglifyjs -V`)**
**JavaScript input** **JavaScript input**
@@ -24,6 +20,6 @@
**JavaScript output or error produced.** **JavaScript output or error produced.**
<!-- <!--
Note: `uglify-js` only supports ES5. Note: `uglify-js` only supports JavaScript.
Those wishing to minify ES6 should use `uglify-es`. Those wishing to minify ES6+ should transpile first.
--> -->

View File

@@ -685,7 +685,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
pass `pure_funcs: [ 'Math.floor' ]` to let it know that this pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
function won't produce any side effect, in which case the whole function won't produce any side effect, in which case the whole
statement would get discarded. The current implementation adds some statement would get discarded. The current implementation adds some
overhead (compression will be slower). overhead (compression will be slower). Make sure symbols under `pure_funcs`
are also under `mangle.reserved` to avoid mangling.
- `pure_getters` (default: `"strict"`) -- If you pass `true` for - `pure_getters` (default: `"strict"`) -- If you pass `true` for
this, UglifyJS will assume that object property access this, UglifyJS will assume that object property access
@@ -1040,8 +1041,9 @@ var result = UglifyJS.minify(ast, {
### Working with Uglify AST ### Working with Uglify AST
Transversal and transformation of the native AST can be performed through Transversal and transformation of the native AST can be performed through
[`TreeWalker`](http://lisperator.net/uglifyjs/walk) and [`TreeWalker`](https://github.com/mishoo/UglifyJS2/blob/master/lib/ast.js) and
[`TreeTransformer`](http://lisperator.net/uglifyjs/transform) respectively. [`TreeTransformer`](https://github.com/mishoo/UglifyJS2/blob/master/lib/transform.js)
respectively.
### ESTree / SpiderMonkey AST ### ESTree / SpiderMonkey AST

View File

@@ -543,12 +543,11 @@ var AST_Call = DEFNODE("Call", "expression args", {
args: "[AST_Node*] array of arguments" args: "[AST_Node*] array of arguments"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
var args = this.args;
for (var i = 0, len = args.length; i < len; i++) {
args[i]._walk(visitor);
}
this.expression._walk(visitor); this.expression._walk(visitor);
this.args.forEach(function(node) {
node._walk(visitor);
});
}); });
} }
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -7,15 +7,23 @@ var to_base64 = typeof btoa == "undefined" ? function(str) {
return new Buffer(str).toString("base64"); return new Buffer(str).toString("base64");
} : btoa; } : btoa;
function read_source_map(code) { function read_source_map(name, code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code); var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) { if (!match) {
AST_Node.warn("inline source map not found"); AST_Node.warn("inline source map not found: " + name);
return null; return null;
} }
return to_ascii(match[2]); return to_ascii(match[2]);
} }
function parse_source_map(content) {
try {
return JSON.parse(content);
} catch (ex) {
throw new Error("invalid input source map: " + content);
}
}
function set_shorthand(name, options, keys) { function set_shorthand(name, options, keys) {
if (options[name]) { if (options[name]) {
keys.forEach(function(key) { keys.forEach(function(key) {
@@ -113,7 +121,7 @@ function minify(files, options) {
}; };
} }
if (timings) timings.parse = Date.now(); if (timings) timings.parse = Date.now();
var toplevel; var source_maps, toplevel;
if (files instanceof AST_Toplevel) { if (files instanceof AST_Toplevel) {
toplevel = files; toplevel = files;
} else { } else {
@@ -122,13 +130,23 @@ function minify(files, options) {
} }
options.parse = options.parse || {}; options.parse = options.parse || {};
options.parse.toplevel = null; options.parse.toplevel = null;
var source_map_content = options.sourceMap && options.sourceMap.content;
if (typeof source_map_content == "string" && source_map_content != "inline") {
source_map_content = parse_source_map(source_map_content);
}
source_maps = source_map_content && Object.create(null);
for (var name in files) if (HOP(files, name)) { for (var name in files) if (HOP(files, name)) {
options.parse.filename = name; options.parse.filename = name;
options.parse.toplevel = parse(files[name], options.parse); options.parse.toplevel = parse(files[name], options.parse);
if (options.sourceMap && options.sourceMap.content == "inline") { if (source_maps) {
if (Object.keys(files).length > 1) if (source_map_content == "inline") {
throw new Error("inline source map only works with singular input"); var inlined_content = read_source_map(name, files[name]);
options.sourceMap.content = read_source_map(files[name]); if (inlined_content) {
source_maps[name] = parse_source_map(inlined_content);
}
} else {
source_maps[name] = source_map_content;
}
} }
} }
toplevel = options.parse.toplevel; toplevel = options.parse.toplevel;
@@ -164,16 +182,9 @@ function minify(files, options) {
} }
if (!HOP(options.output, "code") || options.output.code) { if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) { if (options.sourceMap) {
if (typeof options.sourceMap.content == "string") {
try {
options.sourceMap.content = JSON.parse(options.sourceMap.content);
} catch (ex) {
throw new Error("invalid input source map: " + options.sourceMap.content);
}
}
options.output.source_map = SourceMap({ options.output.source_map = SourceMap({
file: options.sourceMap.filename, file: options.sourceMap.filename,
orig: options.sourceMap.content, orig: source_maps,
root: options.sourceMap.root root: options.sourceMap.root
}); });
if (options.sourceMap.includeSources) { if (options.sourceMap.includeSources) {
@@ -182,6 +193,8 @@ function minify(files, options) {
} else for (var name in files) if (HOP(files, name)) { } else for (var name in files) if (HOP(files, name)) {
options.output.source_map.get().setSourceContent(name, files[name]); options.output.source_map.get().setSourceContent(name, files[name]);
} }
} else {
options.output.source_map.get()._sourcesContents = null;
} }
} }
delete options.output.ast; delete options.output.ast;

View File

@@ -173,7 +173,7 @@ function OutputStream(options) {
default: default:
return dq > sq ? quote_single() : quote_double(); return dq > sq ? quote_single() : quote_double();
} }
}; }
function encode_string(str, quote) { function encode_string(str, quote) {
var ret = make_string(str, quote); var ret = make_string(str, quote);
@@ -183,20 +183,21 @@ function OutputStream(options) {
ret = ret.replace(/--\x3e/g, "--\\x3e"); ret = ret.replace(/--\x3e/g, "--\\x3e");
} }
return ret; return ret;
}; }
function make_name(name) { function make_name(name) {
name = name.toString(); name = name.toString();
name = to_utf8(name, true); name = to_utf8(name, true);
return name; return name;
}; }
function make_indent(back) { function make_indent(back) {
return repeat_string(" ", options.indent_start + indentation - back * options.indent_level); return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
}; }
/* -----[ beautification/minification ]----- */ /* -----[ beautification/minification ]----- */
var has_parens = false;
var might_need_space = false; var might_need_space = false;
var might_need_semicolon = false; var might_need_semicolon = false;
var might_add_newline = 0; var might_add_newline = 0;
@@ -280,7 +281,7 @@ function OutputStream(options) {
might_need_semicolon = false; might_need_semicolon = false;
if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") { if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") {
if (options.semicolons || requireSemicolonChars(ch)) { if (options.semicolons || requireSemicolonChars[ch]) {
OUTPUT += ";"; OUTPUT += ";";
current_col++; current_col++;
current_pos++; current_pos++;
@@ -340,6 +341,7 @@ function OutputStream(options) {
} }
OUTPUT += str; OUTPUT += str;
has_parens = str[str.length - 1] == "(";
current_pos += str.length; current_pos += str.length;
var a = str.split(/\r?\n/), n = a.length - 1; var a = str.split(/\r?\n/), n = a.length - 1;
current_line += n; current_line += n;
@@ -349,7 +351,7 @@ function OutputStream(options) {
current_col = a[n].length; current_col = a[n].length;
} }
last = str; last = str;
}; }
var space = options.beautify ? function() { var space = options.beautify ? function() {
print(" "); print(" ");
@@ -372,6 +374,11 @@ function OutputStream(options) {
return ret; return ret;
} : function(col, cont) { return cont() }; } : function(col, cont) { return cont() };
var may_add_newline = options.max_line_len ? function() {
ensure_line_len();
might_add_newline = OUTPUT.length;
} : noop;
var newline = options.beautify ? function() { var newline = options.beautify ? function() {
if (newline_insert < 0) return print("\n"); if (newline_insert < 0) return print("\n");
if (OUTPUT[newline_insert] != "\n") { if (OUTPUT[newline_insert] != "\n") {
@@ -380,10 +387,7 @@ function OutputStream(options) {
current_line++; current_line++;
} }
newline_insert++; newline_insert++;
} : options.max_line_len ? function() { } : may_add_newline;
ensure_line_len();
might_add_newline = OUTPUT.length;
} : noop;
var semicolon = options.beautify ? function() { var semicolon = options.beautify ? function() {
print(";"); print(";");
@@ -394,11 +398,11 @@ function OutputStream(options) {
function force_semicolon() { function force_semicolon() {
might_need_semicolon = false; might_need_semicolon = false;
print(";"); print(";");
}; }
function next_indent() { function next_indent() {
return indentation + options.indent_level; return indentation + options.indent_level;
}; }
function with_block(cont) { function with_block(cont) {
var ret; var ret;
@@ -410,34 +414,40 @@ function OutputStream(options) {
indent(); indent();
print("}"); print("}");
return ret; return ret;
}; }
function with_parens(cont) { function with_parens(cont) {
print("("); print("(");
may_add_newline();
//XXX: still nice to have that for argument lists //XXX: still nice to have that for argument lists
//var ret = with_indent(current_col, cont); //var ret = with_indent(current_col, cont);
var ret = cont(); var ret = cont();
may_add_newline();
print(")"); print(")");
return ret; return ret;
}; }
function with_square(cont) { function with_square(cont) {
print("["); print("[");
may_add_newline();
//var ret = with_indent(current_col, cont); //var ret = with_indent(current_col, cont);
var ret = cont(); var ret = cont();
may_add_newline();
print("]"); print("]");
return ret; return ret;
}; }
function comma() { function comma() {
may_add_newline();
print(","); print(",");
may_add_newline();
space(); space();
}; }
function colon() { function colon() {
print(":"); print(":");
space(); space();
}; }
var add_mapping = mappings ? function(token, name) { var add_mapping = mappings ? function(token, name) {
mapping_token = token; mapping_token = token;
@@ -449,7 +459,7 @@ function OutputStream(options) {
ensure_line_len(); ensure_line_len();
} }
return OUTPUT; return OUTPUT;
}; }
function has_nlb() { function has_nlb() {
var index = OUTPUT.lastIndexOf("\n"); var index = OUTPUT.lastIndexOf("\n");
@@ -576,7 +586,7 @@ function OutputStream(options) {
indentation : function() { return indentation }, indentation : function() { return indentation },
current_width : function() { return current_col - indentation }, current_width : function() { return current_col - indentation },
should_break : function() { return options.width && this.current_width() >= options.width }, should_break : function() { return options.width && this.current_width() >= options.width },
has_parens : function() { return OUTPUT[OUTPUT.length - 1] == "(" }, has_parens : function() { return has_parens },
newline : newline, newline : newline,
print : print, print : print,
space : space, space : space,
@@ -617,8 +627,7 @@ function OutputStream(options) {
return stack[stack.length - 2 - (n || 0)]; return stack[stack.length - 2 - (n || 0)];
} }
}; };
}
};
/* -----[ code generators ]----- */ /* -----[ code generators ]----- */
@@ -628,7 +637,7 @@ function OutputStream(options) {
function DEFPRINT(nodetype, generator) { function DEFPRINT(nodetype, generator) {
nodetype.DEFMETHOD("_codegen", generator); nodetype.DEFMETHOD("_codegen", generator);
}; }
var in_directive = false; var in_directive = false;
var active_scope = null; var active_scope = null;
@@ -677,7 +686,7 @@ function OutputStream(options) {
} else { } else {
nodetype.DEFMETHOD("needs_parens", func); nodetype.DEFMETHOD("needs_parens", func);
} }
}; }
PARENS(AST_Node, return_false); PARENS(AST_Node, return_false);
@@ -863,7 +872,7 @@ function OutputStream(options) {
} }
}); });
in_directive = false; in_directive = false;
}; }
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){ AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
force_statement(this.body, output); force_statement(this.body, output);
@@ -899,7 +908,7 @@ function OutputStream(options) {
display_body(self.body, false, output, allow_directives); display_body(self.body, false, output, allow_directives);
}); });
} else print_braced_empty(self, output); } else print_braced_empty(self, output);
}; }
DEFPRINT(AST_BlockStatement, function(self, output){ DEFPRINT(AST_BlockStatement, function(self, output){
print_braced(self, output); print_braced(self, output);
}); });
@@ -1062,7 +1071,7 @@ function OutputStream(options) {
else break; else break;
} }
force_statement(self.body, output); force_statement(self.body, output);
}; }
DEFPRINT(AST_If, function(self, output){ DEFPRINT(AST_If, function(self, output){
output.print("if"); output.print("if");
output.space(); output.space();
@@ -1182,7 +1191,7 @@ function OutputStream(options) {
} }
})); }));
node.print(output, parens); node.print(output, parens);
}; }
DEFPRINT(AST_VarDef, function(self, output){ DEFPRINT(AST_VarDef, function(self, output){
self.name.print(output); self.name.print(output);
@@ -1244,7 +1253,7 @@ function OutputStream(options) {
var expr = self.expression; var expr = self.expression;
expr.print(output); expr.print(output);
var prop = self.property; var prop = self.property;
if (output.option("ie8") && RESERVED_WORDS(prop)) { if (output.option("ie8") && RESERVED_WORDS[prop]) {
output.print("["); output.print("[");
output.add_mapping(self.end); output.add_mapping(self.end);
output.print_string(prop); output.print_string(prop);
@@ -1356,7 +1365,7 @@ function OutputStream(options) {
output.print_string(key); output.print_string(key);
} else if ("" + +key == key && key >= 0) { } else if ("" + +key == key && key >= 0) {
output.print(make_num(key)); output.print(make_num(key));
} else if (RESERVED_WORDS(key) ? !output.option("ie8") : is_identifier_string(key)) { } else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
if (quote && output.option("keep_quoted_props")) { if (quote && output.option("keep_quoted_props")) {
output.print_string(key, quote); output.print_string(key, quote);
} else { } else {
@@ -1428,7 +1437,7 @@ function OutputStream(options) {
else else
stat.print(output); stat.print(output);
} }
}; }
// self should be AST_New. decide if we want to show parens or not. // self should be AST_New. decide if we want to show parens or not.
function need_constructor_parens(self, output) { function need_constructor_parens(self, output) {
@@ -1436,7 +1445,7 @@ function OutputStream(options) {
if (self.args.length > 0) return true; if (self.args.length > 0) return true;
return output.option("beautify"); return output.option("beautify");
}; }
function best_of(a) { function best_of(a) {
var best = a[0], len = best.length; var best = a[0], len = best.length;
@@ -1447,27 +1456,31 @@ function OutputStream(options) {
} }
} }
return best; return best;
}; }
function make_num(num) { function make_num(num) {
var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m; var str = num.toString(10).replace(/^0\./, ".").replace("e+", "e");
var candidates = [ str ];
if (Math.floor(num) === num) { if (Math.floor(num) === num) {
if (num >= 0) { if (num < 0) {
a.push("0x" + num.toString(16).toLowerCase(), // probably pointless candidates.push("-0x" + (-num).toString(16).toLowerCase());
"0" + num.toString(8)); // same.
} else { } else {
a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless candidates.push("0x" + num.toString(16).toLowerCase());
"-0" + (-num).toString(8)); // same.
} }
if ((m = /^(.*?)(0+)$/.exec(num))) {
a.push(m[1] + "e" + m[2].length);
}
} else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
a.push(m[2] + "e-" + (m[1].length + m[2].length),
str.substr(str.indexOf(".")));
} }
return best_of(a); var match, len, digits;
}; if (match = /^\.0+/.exec(str)) {
len = match[0].length;
digits = str.slice(len);
candidates.push(digits + "e-" + (digits.length + len - 1));
} else if (match = /0+$/.exec(str)) {
len = match[0].length;
candidates.push(str.slice(0, -len) + "e" + len);
} else if (match = /^(\d)\.(\d+)e(-?\d+)$/.exec(str)) {
candidates.push(match[1] + match[2] + "e" + (match[3] - match[2].length));
}
return best_of(candidates);
}
function make_block(stmt, output) { function make_block(stmt, output) {
if (!stmt || stmt instanceof AST_EmptyStatement) if (!stmt || stmt instanceof AST_EmptyStatement)
@@ -1479,7 +1492,7 @@ function OutputStream(options) {
stmt.print(output); stmt.print(output);
output.newline(); output.newline();
}); });
}; }
/* -----[ source map generators ]----- */ /* -----[ source map generators ]----- */

View File

@@ -165,7 +165,7 @@ function is_unicode_connector_punctuation(ch) {
}; };
function is_identifier(name) { function is_identifier(name) {
return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name); return !RESERVED_WORDS[name] && /^[a-z_$][a-z0-9_$]*$/i.test(name);
}; };
function is_identifier_start(code) { function is_identifier_start(code) {
@@ -245,7 +245,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var ch = S.text.charAt(S.pos++); var ch = S.text.charAt(S.pos++);
if (signal_eof && !ch) if (signal_eof && !ch)
throw EX_EOF; throw EX_EOF;
if (NEWLINE_CHARS(ch)) { if (NEWLINE_CHARS[ch]) {
S.newline_before = S.newline_before || !in_string; S.newline_before = S.newline_before || !in_string;
++S.line; ++S.line;
S.col = 0; S.col = 0;
@@ -272,7 +272,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var text = S.text; var text = S.text;
for (var i = S.pos, n = S.text.length; i < n; ++i) { for (var i = S.pos, n = S.text.length; i < n; ++i) {
var ch = text[i]; var ch = text[i];
if (NEWLINE_CHARS(ch)) if (NEWLINE_CHARS[ch])
return i; return i;
} }
return -1; return -1;
@@ -292,9 +292,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var prev_was_dot = false; var prev_was_dot = false;
function token(type, value, is_comment) { function token(type, value, is_comment) {
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) || S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX[value]) ||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) || (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION[value]) ||
(type == "punc" && PUNC_BEFORE_EXPRESSION(value))); (type == "punc" && PUNC_BEFORE_EXPRESSION[value]));
if (type == "punc" && value == ".") { if (type == "punc" && value == ".") {
prev_was_dot = true; prev_was_dot = true;
} else if (!is_comment) { } else if (!is_comment) {
@@ -324,7 +324,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}; };
function skip_whitespace() { function skip_whitespace() {
while (WHITESPACE_CHARS(peek())) while (WHITESPACE_CHARS[peek()])
next(); next();
}; };
@@ -424,7 +424,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
for (;;) { for (;;) {
var ch = next(true, true); var ch = next(true, true);
if (ch == "\\") ch = read_escaped_char(true); if (ch == "\\") ch = read_escaped_char(true);
else if (NEWLINE_CHARS(ch)) parse_error("Unterminated string constant"); else if (NEWLINE_CHARS[ch]) parse_error("Unterminated string constant");
else if (ch == quote) break; else if (ch == quote) break;
ret += ch; ret += ch;
} }
@@ -476,7 +476,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
backslash = false; backslash = false;
} }
} }
if (KEYWORDS(name) && escaped) { if (KEYWORDS[name] && escaped) {
hex = name.charCodeAt(0).toString(16).toUpperCase(); hex = name.charCodeAt(0).toString(16).toUpperCase();
name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
} }
@@ -485,7 +485,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var read_regexp = with_eof_error("Unterminated regular expression", function(source) { var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
var prev_backslash = false, ch, in_class = false; var prev_backslash = false, ch, in_class = false;
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) { while ((ch = next(true))) if (NEWLINE_CHARS[ch]) {
parse_error("Unexpected line terminator"); parse_error("Unexpected line terminator");
} else if (prev_backslash) { } else if (prev_backslash) {
source += "\\" + ch; source += "\\" + ch;
@@ -517,7 +517,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function grow(op) { function grow(op) {
if (!peek()) return op; if (!peek()) return op;
var bigger = op + peek(); var bigger = op + peek();
if (OPERATORS(bigger)) { if (OPERATORS[bigger]) {
next(); next();
return grow(bigger); return grow(bigger);
} else { } else {
@@ -550,9 +550,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function read_word() { function read_word() {
var word = read_name(); var word = read_name();
if (prev_was_dot) return token("name", word); if (prev_was_dot) return token("name", word);
return KEYWORDS_ATOM(word) ? token("atom", word) return KEYWORDS_ATOM[word] ? token("atom", word)
: !KEYWORDS(word) ? token("name", word) : !KEYWORDS[word] ? token("name", word)
: OPERATORS(word) ? token("operator", word) : OPERATORS[word] ? token("operator", word)
: token("keyword", word); : token("keyword", word);
}; };
@@ -603,8 +603,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} }
} }
if (is_digit(code)) return read_num(); if (is_digit(code)) return read_num();
if (PUNC_CHARS(ch)) return token("punc", next()); if (PUNC_CHARS[ch]) return token("punc", next());
if (OPERATOR_CHARS(ch)) return read_operator(); if (OPERATOR_CHARS[ch]) return read_operator();
if (code == 92 || is_identifier_start(code)) return read_word(); if (code == 92 || is_identifier_start(code)) return read_word();
break; break;
} }
@@ -1321,7 +1321,7 @@ function parse($TEXT, options) {
func.end = prev(); func.end = prev();
return subscripts(func, allow_calls); return subscripts(func, allow_calls);
} }
if (ATOMIC_START_TOKEN(S.token.type)) { if (ATOMIC_START_TOKEN[S.token.type]) {
return subscripts(as_atom_node(), allow_calls); return subscripts(as_atom_node(), allow_calls);
} }
unexpected(); unexpected();
@@ -1406,7 +1406,7 @@ function parse($TEXT, options) {
var tmp = S.token; var tmp = S.token;
switch (tmp.type) { switch (tmp.type) {
case "operator": case "operator":
if (!KEYWORDS(tmp.value)) unexpected(); if (!KEYWORDS[tmp.value]) unexpected();
case "num": case "num":
case "string": case "string":
case "name": case "name":
@@ -1504,7 +1504,7 @@ function parse($TEXT, options) {
var maybe_unary = function(allow_calls) { var maybe_unary = function(allow_calls) {
var start = S.token; var start = S.token;
if (is("operator") && UNARY_PREFIX(start.value)) { if (is("operator") && UNARY_PREFIX[start.value]) {
next(); next();
handle_regexp(); handle_regexp();
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls)); var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls));
@@ -1513,7 +1513,7 @@ function parse($TEXT, options) {
return ex; return ex;
} }
var val = expr_atom(allow_calls); var val = expr_atom(allow_calls);
while (is("operator") && UNARY_POSTFIX(S.token.value) && !has_newline_before(S.token)) { while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
val = make_unary(AST_UnaryPostfix, S.token, val); val = make_unary(AST_UnaryPostfix, S.token, val);
val.start = start; val.start = start;
val.end = S.token; val.end = S.token;
@@ -1585,7 +1585,7 @@ function parse($TEXT, options) {
var maybe_assign = function(no_in) { var maybe_assign = function(no_in) {
var start = S.token; var start = S.token;
var left = maybe_conditional(no_in), val = S.token.value; var left = maybe_conditional(no_in), val = S.token.value;
if (is("operator") && ASSIGNMENT(val)) { if (is("operator") && ASSIGNMENT[val]) {
if (is_assignable(left)) { if (is_assignable(left)) {
next(); next();
return new AST_Assign({ return new AST_Assign({

View File

@@ -150,6 +150,10 @@ function mangle_properties(ast, options) {
else if (node instanceof AST_Sub) { else if (node instanceof AST_Sub) {
addStrings(node.property, add); addStrings(node.property, add);
} }
else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") {
addStrings(node.args[1], add);
}
})); }));
// step 2: transform the tree, renaming properties // step 2: transform the tree, renaming properties
@@ -167,6 +171,10 @@ function mangle_properties(ast, options) {
else if (!options.keep_quoted && node instanceof AST_Sub) { else if (!options.keep_quoted && node instanceof AST_Sub) {
node.property = mangleStrings(node.property); node.property = mangleStrings(node.property);
} }
else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") {
node.args[1] = mangleStrings(node.args[1]);
}
})); }));
// only function declarations after this line // only function declarations after this line

View File

@@ -55,7 +55,7 @@ function SymbolDef(scope, orig, init) {
this.mangled_name = null; this.mangled_name = null;
this.undeclared = false; this.undeclared = false;
this.id = SymbolDef.next_id++; this.id = SymbolDef.next_id++;
}; }
SymbolDef.next_id = 1; SymbolDef.next_id = 1;
@@ -344,7 +344,7 @@ function next_mangled_name(scope, options, def) {
} }
while (true) { while (true) {
name = base54(++scope.cname); name = base54(++scope.cname);
if (in_use[name] || !is_identifier(name) || member(name, options.reserved)) continue; if (in_use[name] || !is_identifier(name) || options.reserved.has[name]) continue;
if (!names[name]) break; if (!names[name]) break;
holes.push(scope.cname); holes.push(scope.cname);
} }
@@ -387,6 +387,7 @@ function _default_mangler_options(options) {
if (!Array.isArray(options.reserved)) options.reserved = []; if (!Array.isArray(options.reserved)) options.reserved = [];
// Never mangle arguments // Never mangle arguments
push_uniq(options.reserved, "arguments"); push_uniq(options.reserved, "arguments");
options.reserved.has = makePredicate(options.reserved);
return options; return options;
} }
@@ -452,9 +453,8 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
redefined.forEach(mangle); redefined.forEach(mangle);
function mangle(def) { function mangle(def) {
if (!member(def.name, options.reserved)) { if (options.reserved.has[def.name]) return;
def.mangle(options); def.mangle(options);
}
} }
}); });
@@ -504,7 +504,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
function rename(def) { function rename(def) {
if (def.global && options.cache) return; if (def.global && options.cache) return;
if (def.unmangleable(options)) return; if (def.unmangleable(options)) return;
if (member(def.name, options.reserved)) return; if (options.reserved.has[def.name]) return;
var d = def.redefined(); var d = def.redefined();
def.name = d ? d.name : next_name(); def.name = d ? d.name : next_name();
def.orig.forEach(function(sym) { def.orig.forEach(function(sym) {
@@ -556,17 +556,21 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
}); });
var base54 = (function() { var base54 = (function() {
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split(""); var freq = Object.create(null);
var digits = "0123456789".split(""); function init(chars) {
var array = [];
for (var i = 0, len = chars.length; i < len; i++) {
var ch = chars[i];
array.push(ch);
freq[ch] = -1e-2 * i;
}
return array;
}
var digits = init("0123456789");
var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
var chars, frequency; var chars, frequency;
function reset() { function reset() {
frequency = Object.create(null); frequency = Object.create(freq);
leading.forEach(function(ch) {
frequency[ch] = 0;
});
digits.forEach(function(ch) {
frequency[ch] = 0;
});
} }
base54.consider = function(str, delta) { base54.consider = function(str, delta) {
for (var i = str.length; --i >= 0;) { for (var i = str.length; --i >= 0;) {
@@ -577,7 +581,7 @@ var base54 = (function() {
return frequency[b] - frequency[a]; return frequency[b] - frequency[a];
} }
base54.sort = function() { base54.sort = function() {
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare)); chars = leading.sort(compare).concat(digits.sort(compare));
}; };
base54.reset = reset; base54.reset = reset;
reset(); reset();
@@ -591,6 +595,6 @@ var base54 = (function() {
base = 64; base = 64;
} while (num > 0); } while (num > 0);
return ret; return ret;
}; }
return base54; return base54;
})(); })();

View File

@@ -57,26 +57,26 @@ function SourceMap(options) {
file : options.file, file : options.file,
sourceRoot : options.root sourceRoot : options.root
}); });
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig); var maps = options.orig && Object.create(null);
if (maps) for (var source in options.orig) {
if (orig_map && Array.isArray(options.orig.sources)) { var map = new MOZ_SourceMap.SourceMapConsumer(options.orig[source]);
orig_map._sources.toArray().forEach(function(source) { if (Array.isArray(options.orig[source].sources)) {
var sourceContent = orig_map.sourceContentFor(source, true); map._sources.toArray().forEach(function(source) {
if (sourceContent) { var sourceContent = map.sourceContentFor(source, true);
generator.setSourceContent(source, sourceContent); if (sourceContent) generator.setSourceContent(source, sourceContent);
} });
}); }
maps[source] = map;
} }
function add(source, gen_line, gen_col, orig_line, orig_col, name) { function add(source, gen_line, gen_col, orig_line, orig_col, name) {
if (orig_map) { var map = maps && maps[source];
var info = orig_map.originalPositionFor({ if (map) {
var info = map.originalPositionFor({
line: orig_line, line: orig_line,
column: orig_col column: orig_col
}); });
if (info.source === null) { if (info.source === null) return;
return;
}
source = info.source; source = info.source;
orig_line = info.line; orig_line = info.line;
orig_col = info.column; orig_col = info.column;

View File

@@ -93,7 +93,12 @@ TreeTransformer.prototype = new TreeWalker;
self.body = do_list(self.body, tw); self.body = do_list(self.body, tw);
}); });
_(AST_DWLoop, function(self, tw){ _(AST_Do, function(self, tw){
self.body = self.body.transform(tw);
self.condition = self.condition.transform(tw);
});
_(AST_While, function(self, tw){
self.condition = self.condition.transform(tw); self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
}); });

View File

@@ -45,27 +45,25 @@
function characters(str) { function characters(str) {
return str.split(""); return str.split("");
}; }
function member(name, array) { function member(name, array) {
return array.indexOf(name) >= 0; return array.indexOf(name) >= 0;
}; }
function find_if(func, array) { function find_if(func, array) {
for (var i = 0, n = array.length; i < n; ++i) { for (var i = 0, n = array.length; i < n; ++i) {
if (func(array[i])) if (func(array[i])) return array[i];
return array[i];
} }
}; }
function repeat_string(str, i) { function repeat_string(str, i) {
if (i <= 0) return ""; if (i <= 0) return "";
if (i == 1) return str; if (i == 1) return str;
var d = repeat_string(str, i >> 1); var d = repeat_string(str, i >> 1);
d += d; d += d;
if (i & 1) d += str; return i & 1 ? d + str : d;
return d; }
};
function configure_error_stack(fn) { function configure_error_stack(fn) {
Object.defineProperty(fn.prototype, "stack", { Object.defineProperty(fn.prototype, "stack", {
@@ -84,27 +82,23 @@ function configure_error_stack(fn) {
function DefaultsError(msg, defs) { function DefaultsError(msg, defs) {
this.message = msg; this.message = msg;
this.defs = defs; this.defs = defs;
}; }
DefaultsError.prototype = Object.create(Error.prototype); DefaultsError.prototype = Object.create(Error.prototype);
DefaultsError.prototype.constructor = DefaultsError; DefaultsError.prototype.constructor = DefaultsError;
DefaultsError.prototype.name = "DefaultsError"; DefaultsError.prototype.name = "DefaultsError";
configure_error_stack(DefaultsError); configure_error_stack(DefaultsError);
DefaultsError.croak = function(msg, defs) {
throw new DefaultsError(msg, defs);
};
function defaults(args, defs, croak) { function defaults(args, defs, croak) {
if (args === true) if (args === true) args = {};
args = {};
var ret = args || {}; var ret = args || {};
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
DefaultsError.croak("`" + i + "` is not a supported option", defs); throw new DefaultsError("`" + i + "` is not a supported option", defs);
}
for (var i in defs) if (HOP(defs, i)) { for (var i in defs) if (HOP(defs, i)) {
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
} }
return ret; return ret;
}; }
function merge(obj, ext) { function merge(obj, ext) {
var count = 0; var count = 0;
@@ -113,7 +107,7 @@ function merge(obj, ext) {
count++; count++;
} }
return count; return count;
}; }
function noop() {} function noop() {}
function return_false() { return false; } function return_false() { return false; }
@@ -145,7 +139,7 @@ var MAP = (function(){
} }
return is_last; return is_last;
}; };
if (a instanceof Array) { if (Array.isArray(a)) {
if (backwards) { if (backwards) {
for (i = a.length; --i >= 0;) if (doit()) break; for (i = a.length; --i >= 0;) if (doit()) break;
ret.reverse(); ret.reverse();
@@ -172,101 +166,40 @@ var MAP = (function(){
function push_uniq(array, el) { function push_uniq(array, el) {
if (array.indexOf(el) < 0) if (array.indexOf(el) < 0)
array.push(el); array.push(el);
}; }
function string_template(text, props) { function string_template(text, props) {
return text.replace(/\{(.+?)\}/g, function(str, p){ return text.replace(/\{(.+?)\}/g, function(str, p){
return props && props[p]; return props && props[p];
}); });
}; }
function remove(array, el) { function remove(array, el) {
for (var i = array.length; --i >= 0;) { for (var i = array.length; --i >= 0;) {
if (array[i] === el) array.splice(i, 1); if (array[i] === el) array.splice(i, 1);
} }
}; }
function mergeSort(array, cmp) {
if (array.length < 2) return array.slice();
function merge(a, b) {
var r = [], ai = 0, bi = 0, i = 0;
while (ai < a.length && bi < b.length) {
cmp(a[ai], b[bi]) <= 0
? r[i++] = a[ai++]
: r[i++] = b[bi++];
}
if (ai < a.length) r.push.apply(r, a.slice(ai));
if (bi < b.length) r.push.apply(r, b.slice(bi));
return r;
};
function _ms(a) {
if (a.length <= 1)
return a;
var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
left = _ms(left);
right = _ms(right);
return merge(left, right);
};
return _ms(array);
};
// this function is taken from Acorn [1], written by Marijn Haverbeke
// [1] https://github.com/marijnh/acorn
function makePredicate(words) { function makePredicate(words) {
if (!(words instanceof Array)) words = words.split(" "); if (!Array.isArray(words)) words = words.split(" ");
var f = "", cats = []; var map = Object.create(null);
out: for (var i = 0; i < words.length; ++i) { words.forEach(function(word) {
for (var j = 0; j < cats.length; ++j) map[word] = true;
if (cats[j][0].length == words[i].length) { });
cats[j].push(words[i]); return map;
continue out; }
}
cats.push([words[i]]);
}
function quote(word) {
return JSON.stringify(word).replace(/[\u2028\u2029]/g, function(s) {
switch (s) {
case "\u2028": return "\\u2028";
case "\u2029": return "\\u2029";
}
return s;
});
}
function compareTo(arr) {
if (arr.length == 1) return f += "return str === " + quote(arr[0]) + ";";
f += "switch(str){";
for (var i = 0; i < arr.length; ++i) f += "case " + quote(arr[i]) + ":";
f += "return true}return false;";
}
// When there are more than three length categories, an outer
// switch first dispatches on the lengths, to save on comparisons.
if (cats.length > 3) {
cats.sort(function(a, b) {return b.length - a.length;});
f += "switch(str.length){";
for (var i = 0; i < cats.length; ++i) {
var cat = cats[i];
f += "case " + cat[0].length + ":";
compareTo(cat);
}
f += "}";
// Otherwise, simply generate a flat `switch` statement.
} else {
compareTo(words);
}
return new Function("str", f);
};
function all(array, predicate) { function all(array, predicate) {
for (var i = array.length; --i >= 0;) for (var i = array.length; --i >= 0;)
if (!predicate(array[i])) if (!predicate(array[i]))
return false; return false;
return true; return true;
}; }
function Dictionary() { function Dictionary() {
this._values = Object.create(null); this._values = Object.create(null);
this._size = 0; this._size = 0;
}; }
Dictionary.prototype = { Dictionary.prototype = {
set: function(key, val) { set: function(key, val) {
if (!this.has(key)) ++this._size; if (!this.has(key)) ++this._size;
@@ -327,20 +260,22 @@ function HOP(obj, prop) {
// a statement. // a statement.
function first_in_statement(stack) { function first_in_statement(stack) {
var node = stack.parent(-1); var node = stack.parent(-1);
for (var i = 0, p; p = stack.parent(i); i++) { for (var i = 0, p; p = stack.parent(i++); node = p) {
if (p instanceof AST_Statement && p.body === node) if (p.TYPE == "Call") {
return true; if (p.expression === node) continue;
if ((p instanceof AST_Sequence && p.expressions[0] === node) || } else if (p instanceof AST_Binary) {
(p.TYPE == "Call" && p.expression === node ) || if (p.left === node) continue;
(p instanceof AST_Dot && p.expression === node ) || } else if (p instanceof AST_Conditional) {
(p instanceof AST_Sub && p.expression === node ) || if (p.condition === node) continue;
(p instanceof AST_Conditional && p.condition === node ) || } else if (p instanceof AST_PropAccess) {
(p instanceof AST_Binary && p.left === node ) || if (p.expression === node) continue;
(p instanceof AST_UnaryPostfix && p.expression === node )) } else if (p instanceof AST_Sequence) {
{ if (p.expressions[0] === node) continue;
node = p; } else if (p instanceof AST_Statement) {
} else { return p.body === node;
return false; } else if (p instanceof AST_UnaryPostfix) {
if (p.expression === node) continue;
} }
return false;
} }
} }

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.3.18", "version": "3.3.25",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -28,7 +28,6 @@
}, },
"devDependencies": { "devDependencies": {
"acorn": "~5.5.3", "acorn": "~5.5.3",
"mocha": "~3.5.1",
"semver": "~5.5.0" "semver": "~5.5.0"
}, },
"scripts": { "scripts": {

View File

@@ -4056,6 +4056,36 @@ replace_all_var: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
replace_all_var_scope: {
rename = true;
options = {
collapse_vars: true,
unused: true,
}
mangle = {}
input: {
var a = 100, b = 10;
(function(r, a) {
switch (~a) {
case (b += a):
case a++:
}
})(--b, a);
console.log(a, b);
}
expect: {
var a = 100, b = 10;
(function(c, o) {
switch (~a) {
case (b += a):
case o++:
}
})(--b, a);
console.log(a, b);
}
expect_stdout: "100 109"
}
cascade_statement: { cascade_statement: {
options = { options = {
collapse_vars: true, collapse_vars: true,
@@ -5327,3 +5357,24 @@ issue_3032: {
} }
expect_stdout: "42" expect_stdout: "42"
} }
issue_3096: {
options = {
collapse_vars: true,
}
input: {
console.log(function() {
var ar = ["a", "b"];
var first = ar.pop();
return ar + "" + first;
}());
}
expect: {
console.log(function() {
var ar = ["a", "b"];
var first = ar.pop();
return ar + "" + first;
}());
}
expect_stdout: "ab"
}

View File

@@ -2237,3 +2237,85 @@ issue_3018: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3054: {
options = {
booleans: true,
collapse_vars: true,
inline: 1,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
function f() {
return { a: true };
}
console.log(function(b) {
b = false;
return f();
}().a, f.call().a);
}
expect: {
"use strict";
function f() {
return { a: !0 };
}
console.log(function(b) {
return { a: !(b = !1) };
}().a, f.call().a);
}
expect_stdout: "true true"
}
issue_3076: {
options = {
dead_code: true,
inline: true,
sequences: true,
unused: true,
}
input: {
var c = "PASS";
(function(b) {
var n = 2;
while (--b + function() {
e && (c = "FAIL");
e = 5;
return 1;
try {
var a = 5;
} catch (e) {
var e;
}
}().toString() && --n > 0);
})(2);
console.log(c);
}
expect: {
var c = "PASS";
(function(b) {
var n = 2;
while (--b + (e = void 0, e && (c = "FAIL"), e = 5, 1).toString() && --n > 0);
var e;
})(2),
console.log(c);
}
expect_stdout: "PASS"
}
issue_3125: {
options = {
inline: true,
unsafe: true,
}
input: {
console.log(function() {
return "PASS";
}.call());
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -716,3 +716,143 @@ issue_3021: {
} }
expect_stdout: "2 2" expect_stdout: "2 2"
} }
issue_3046: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
console.log(function(a) {
do {
var b = {
c: a++
};
} while (b.c && a);
return a;
}(0));
}
expect: {
console.log(function(a) {
do {
var b_c = a++;
} while (b_c && a);
return a;
}(0));
}
expect_stdout: "1"
}
issue_3071_1: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function() {
var obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_2: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
var obj;
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_2_toplevel: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function() {
obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
var obj;
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_3: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
var c = 0;
(function(a, b) {
(function f(o) {
var n = 2;
while (--b + (o = {
p: c++,
}) && --n > 0);
})();
})();
console.log(c);
}
expect: {
var c = 0;
(function(a, b) {
(function f(o) {
var n = 2;
while (--b + (o = {
p: c++,
}) && --n > 0);
})();
})();
console.log(c);
}
expect_stdout: "2"
}

View File

@@ -1,11 +1,31 @@
remove_redundant_sequence_items: { remove_sequence: {
options = { side_effects: true }; options = {
side_effects: true,
}
input: { input: {
(0, 1, eval)(); (0, 1, eval)();
(0, 1, logThis)(); (0, 1, logThis)();
(0, 1, _decorators.logThis)(); (0, 1, _decorators.logThis)();
} }
expect: { expect: {
eval();
logThis();
(0, _decorators.logThis)();
}
}
remove_redundant_sequence_items: {
options = {
side_effects: true,
}
input: {
"use strict";
(0, 1, eval)();
(0, 1, logThis)();
(0, 1, _decorators.logThis)();
}
expect: {
"use strict";
(0, eval)(); (0, eval)();
logThis(); logThis();
(0, _decorators.logThis)(); (0, _decorators.logThis)();
@@ -13,13 +33,17 @@ remove_redundant_sequence_items: {
} }
dont_remove_this_binding_sequence: { dont_remove_this_binding_sequence: {
options = { side_effects: true }; options = {
side_effects: true,
}
input: { input: {
"use strict";
(0, eval)(); (0, eval)();
(0, logThis)(); (0, logThis)();
(0, _decorators.logThis)(); (0, _decorators.logThis)();
} }
expect: { expect: {
"use strict";
(0, eval)(); (0, eval)();
logThis(); logThis();
(0, _decorators.logThis)(); (0, _decorators.logThis)();

View File

@@ -3,8 +3,9 @@ this_binding_conditionals: {
conditionals: true, conditionals: true,
evaluate: true, evaluate: true,
side_effects: true, side_effects: true,
}; }
input: { input: {
"use strict";
(1 && a)(); (1 && a)();
(0 || a)(); (0 || a)();
(0 || 1 && a)(); (0 || 1 && a)();
@@ -26,6 +27,7 @@ this_binding_conditionals: {
(1 ? eval : 0)(); (1 ? eval : 0)();
} }
expect: { expect: {
"use strict";
a(); a();
a(); a();
a(); a();
@@ -53,13 +55,15 @@ this_binding_collapse_vars: {
collapse_vars: true, collapse_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
}; }
input: { input: {
"use strict";
var c = a; c(); var c = a; c();
var d = a.b; d(); var d = a.b; d();
var e = eval; e(); var e = eval; e();
} }
expect: { expect: {
"use strict";
a(); a();
(0, a.b)(); (0, a.b)();
(0, eval)(); (0, eval)();
@@ -69,31 +73,88 @@ this_binding_collapse_vars: {
this_binding_side_effects: { this_binding_side_effects: {
options = { options = {
side_effects : true side_effects : true
}; }
input: { input: {
(function (foo) { (function(foo) {
(0, foo)(); (0, foo)();
(0, foo.bar)(); (0, foo.bar)();
(0, eval)('console.log(foo);'); (0, eval)("console.log(foo);");
}()); }());
(function (foo) { (function(foo) {
"use strict";
(0, foo)();
(0, foo.bar)();
(0, eval)("console.log(foo);");
}());
(function(foo) {
var eval = console; var eval = console;
(0, foo)(); (0, foo)();
(0, foo.bar)(); (0, foo.bar)();
(0, eval)('console.log(foo);'); (0, eval)("console.log(foo);");
}()); }());
} }
expect: { expect: {
(function (foo) { (function(foo) {
foo(); foo();
(0, foo.bar)(); (0, foo.bar)();
(0, eval)('console.log(foo);'); eval("console.log(foo);");
}()); }());
(function (foo) { (function(foo) {
"use strict";
foo();
(0, foo.bar)();
(0, eval)("console.log(foo);");
}());
(function(foo) {
var eval = console; var eval = console;
foo(); foo();
(0, foo.bar)(); (0, foo.bar)();
(0, eval)('console.log(foo);'); eval("console.log(foo);");
}()); }());
} }
} }
this_binding_sequences: {
options = {
sequences: true,
side_effects: true,
}
input: {
console.log(typeof function() {
return eval("this");
}());
console.log(typeof function() {
"use strict";
return eval("this");
}());
console.log(typeof function() {
return (0, eval)("this");
}());
console.log(typeof function() {
"use strict";
return (0, eval)("this");
}());
}
expect: {
console.log(typeof function() {
return eval("this");
}()),
console.log(typeof function() {
"use strict";
return eval("this");
}()),
console.log(typeof function() {
return eval("this");
}()),
console.log(typeof function() {
"use strict";
return (0, eval)("this");
}());
}
expect_stdout: [
"object",
"undefined",
"object",
"object",
]
}

View File

@@ -8,14 +8,14 @@ too_short: {
} }
} }
expect_exact: [ expect_exact: [
'function f(a){', "function f(",
'return{', "a){return{",
'c:42,', "c:42,d:a(",
'd:a(),', '),e:"foo"}',
'e:"foo"}}', "}",
] ]
expect_warnings: [ expect_warnings: [
"WARN: Output exceeds 10 characters" "WARN: Output exceeds 10 characters",
] ]
} }
@@ -29,11 +29,25 @@ just_enough: {
} }
} }
expect_exact: [ expect_exact: [
'function f(a){', "function f(a){",
'return{c:42,', "return{c:42,",
'd:a(),e:"foo"}', 'd:a(),e:"foo"}',
'}', "}",
]
expect_warnings: [
] ]
expect_warnings: []
}
issue_304: {
beautify = {
max_line_len: 10,
}
input: {
var a = 0, b = 0, c = 0, d = 0, e = 0;
}
expect_exact: [
"var a=0,",
"b=0,c=0,",
"d=0,e=0;",
]
expect_warnings: []
} }

View File

@@ -1,21 +1,49 @@
hex_numbers_in_parentheses_for_prototype_functions: { hex_numbers_in_parentheses_for_prototype_functions: {
input: { beautify = {
(-2); beautify: true,
(-2).toFixed(0);
(2);
(2).toFixed(0);
(0.2);
(0.2).toFixed(0);
(0.00000002);
(0.00000002).toFixed(0);
(1000000000000000128);
(1000000000000000128).toFixed(0);
} }
expect_exact: "-2;(-2).toFixed(0);2;2..toFixed(0);.2;.2.toFixed(0);2e-8;2e-8.toFixed(0);0xde0b6b3a7640080;(0xde0b6b3a7640080).toFixed(0);" input: {
function f() {
(-2);
(-2).toFixed(0);
(2);
(2).toFixed(0);
(0.2);
(0.2).toFixed(0);
(2.34e20);
(2.34e20).toFixed(0);
(0.00000002);
(0.00000002).toFixed(0);
(1000000000000000128);
(1000000000000000128).toFixed(0);
(-1000000000000000128);
(-1000000000000000128).toFixed(0);
}
}
expect_exact: [
"function f() {",
" -2;",
" (-2).toFixed(0);",
" 2;",
" 2..toFixed(0);",
" .2;",
" .2.toFixed(0);",
" 234e18;",
" 234e18.toFixed(0);",
" 2e-8;",
" 2e-8.toFixed(0);",
" 0xde0b6b3a7640080;",
" (0xde0b6b3a7640080).toFixed(0);",
" -0xde0b6b3a7640080;",
" (-0xde0b6b3a7640080).toFixed(0);",
"}",
]
} }
comparisons: { comparisons: {

View File

@@ -1208,6 +1208,37 @@ join_object_assignments_3: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
join_object_assignments_4: {
options = {
join_vars: true,
sequences: true,
}
input: {
var o;
console.log(o);
o = {};
o.a = "foo";
console.log(o.b);
o.b = "bar";
console.log(o.a);
}
expect: {
var o;
console.log(o),
o = {
a: "foo",
},
console.log(o.b),
o.b = "bar",
console.log(o.a);
}
expect_stdout: [
"undefined",
"undefined",
"foo",
]
}
join_object_assignments_return_1: { join_object_assignments_return_1: {
options = { options = {
join_vars: true, join_vars: true,
@@ -1640,3 +1671,61 @@ issue_2893_2: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_869_1: {
mangle = {
properties: {
reserved: [ "get" ]
},
}
input: {
var o = { p: "FAIL" };
Object.defineProperty(o, "p", {
get: function() {
return "PASS";
}
});
console.log(o.p);
}
expect: {
var o = { o: "FAIL" };
Object.defineProperty(o, "o", {
get: function() {
return "PASS";
}
});
console.log(o.o);
}
expect_stdout: "PASS"
}
issue_869_2: {
mangle = {
properties: {
reserved: [ "get" ]
},
}
input: {
var o = { p: "FAIL" };
Object.defineProperties(o, {
p: {
get: function() {
return "PASS";
}
}
});
console.log(o.p);
}
expect: {
var o = { o: "FAIL" };
Object.defineProperties(o, {
o: {
get: function() {
return "PASS";
}
}
});
console.log(o.o);
}
expect_stdout: "PASS"
}

View File

@@ -535,3 +535,110 @@ issue_2705_6: {
"/* */new(/* */a()||b())(c(),d());", "/* */new(/* */a()||b())(c(),d());",
] ]
} }
issue_3065_1: {
options = {
inline: true,
pure_funcs: [ "pureFunc" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function modifyWrapper(a, f, wrapper) {
wrapper.a = a;
wrapper.f = f;
return wrapper;
}
function pureFunc(fun) {
return modifyWrapper(1, fun, function(a) {
return fun(a);
});
}
var unused = pureFunc(function(x) {
return x;
});
}
expect: {}
}
issue_3065_2: {
rename = true
options = {
inline: true,
pure_funcs: [ "pureFunc" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
mangle = {
reserved: [ "pureFunc" ],
toplevel: true,
}
input: {
function modifyWrapper(a, f, wrapper) {
wrapper.a = a;
wrapper.f = f;
return wrapper;
}
function pureFunc(fun) {
return modifyWrapper(1, fun, function(a) {
return fun(a);
});
}
var unused = pureFunc(function(x) {
return x;
});
}
expect: {}
}
issue_3065_3: {
options = {
pure_funcs: [ "debug" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function debug(msg) {
console.log(msg);
}
debug(function() {
console.log("PASS");
return "FAIL";
}());
}
expect: {
(function() {
console.log("PASS");
})();
}
}
issue_3065_4: {
options = {
pure_funcs: [ "debug" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var debug = function(msg) {
console.log(msg);
};
debug(function() {
console.log("PASS");
return "FAIL";
}());
}
expect: {
(function() {
console.log("PASS");
})();
}
}

View File

@@ -1476,18 +1476,18 @@ defun_redefine: {
}; };
return g() + h(); return g() + h();
} }
console.log(f());
} }
expect: { expect: {
function f() { function f() {
function g() { (function() {
return 1;
}
g = function() {
return 3; return 3;
}; });
return g() + 2; return 3 + 2;
} }
console.log(f());
} }
expect_stdout: "5"
} }
func_inline: { func_inline: {
@@ -1527,23 +1527,37 @@ func_modified: {
} }
input: { input: {
function f(a) { function f(a) {
function a() { return 1; } function a() {
function b() { return 2; } return 1;
function c() { return 3; } }
function b() {
return 2;
}
function c() {
return 3;
}
b.inject = []; b.inject = [];
c = function() { return 4; }; c = function() {
return 4;
};
return a() + b() + c(); return a() + b() + c();
} }
console.log(f());
} }
expect: { expect: {
function f(a) { function f(a) {
function b() { return 2; } function b() {
function c() { return 3; } return 2;
}
b.inject = []; b.inject = [];
c = function() { return 4; }; (function() {
return 1 + 2 + c(); return 4;
});
return 1 + 2 + 4;
} }
console.log(f());
} }
expect_stdout: "7"
} }
defun_label: { defun_label: {
@@ -5054,9 +5068,7 @@ defun_var_1: {
console.log(typeof a, typeof b); console.log(typeof a, typeof b);
} }
expect: { expect: {
var a = 42; console.log("number", "function");
function a() {}
console.log(typeof a, "function");
} }
expect_stdout: "number function" expect_stdout: "number function"
} }
@@ -5076,9 +5088,7 @@ defun_var_2: {
console.log(typeof a, typeof b); console.log(typeof a, typeof b);
} }
expect: { expect: {
function a() {} console.log("number", "function");
var a = 42;
console.log(typeof a, "function");
} }
expect_stdout: "number function" expect_stdout: "number function"
} }
@@ -5654,3 +5664,517 @@ issue_3042_2: {
"true", "true",
] ]
} }
issue_3068_1: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
(function() {
do {
continue;
var b = "defined";
} while (b && b.c);
})();
}
expect: {
(function() {
do {
continue;
var b = "defined";
} while (b && b.c);
})();
}
expect_stdout: true
}
issue_3068_2: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
(function() {
do {
try {
while ("" == typeof a);
} finally {
continue;
}
var b = "defined";
} while (b && b.c);
})();
}
expect: {
(function() {
do {
try {
while ("" == typeof a);
} finally {
continue;
}
var b = "defined";
} while (b && b.c);
})();
}
expect_stdout: true
}
issue_3110_1: {
options = {
conditionals: true,
evaluate: true,
inline: true,
passes: 3,
properties: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
function foo() {
return isDev ? "foo" : "bar";
}
var isDev = true;
var obj = {
foo: foo
};
console.log(foo());
console.log(obj.foo());
})();
}
expect: {
console.log("foo"),
console.log("foo");
}
expect_stdout: [
"foo",
"foo",
]
}
issue_3110_2: {
options = {
conditionals: true,
evaluate: true,
inline: true,
passes: 4,
properties: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
function foo() {
return isDev ? "foo" : "bar";
}
var isDev = true;
console.log(foo());
var obj = {
foo: foo
};
console.log(obj.foo());
})();
}
expect: {
console.log("foo"),
console.log("foo");
}
expect_stdout: [
"foo",
"foo",
]
}
issue_3110_3: {
options = {
conditionals: true,
evaluate: true,
inline: true,
properties: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
function foo() {
return isDev ? "foo" : "bar";
}
console.log(foo());
var isDev = true;
var obj = {
foo: foo
};
console.log(obj.foo());
})();
}
expect: {
(function() {
function foo() {
return isDev ? "foo" : "bar";
}
console.log(foo());
var isDev = true;
var obj = {
foo: foo
};
console.log(obj.foo());
})();
}
expect_stdout: [
"bar",
"foo",
]
}
issue_3113_1: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var c = 0;
(function() {
function f() {
while (g());
}
var a = f();
function g() {
a && a[c++];
}
g(a = 1);
})();
console.log(c);
}
expect: {
var c = 0;
(function() {
function f() {
while (g());
}
var a = f();
function g() {
a && a[c++];
}
g(a = 1);
})();
console.log(c);
}
expect_stdout: "1"
}
issue_3113_2: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var c = 0;
(function() {
function f() {
while (g());
}
var a = f();
function g() {
a && a[c++];
}
a = 1;
g();
})();
console.log(c);
}
expect: {
var c = 0;
(function() {
function f() {
while (g());
}
var a = f();
function g() {
a && a[c++];
}
a = 1;
g();
})();
console.log(c);
}
expect_stdout: "1"
}
issue_3113_3: {
options = {
evaluate: true,
inline: true,
passes: 2,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var c = 0;
(function() {
function f() {
while (g());
}
var a;
function g() {
a && a[c++];
}
g(a = 1);
})();
console.log(c);
}
expect: {
var c = 0;
c++;
console.log(c);
}
expect_stdout: "1"
}
issue_3113_4: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 0, b = 0;
function f() {
b += a;
}
f(f(), ++a);
console.log(a, b);
}
expect: {
var a = 0, b = 0;
function f() {
b += a;
}
f(f(), ++a);
console.log(a, b);
}
expect_stdout: "1 1"
}
issue_3113_5: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f() {
console.log(a);
}
function g() {
f();
}
while (g());
var a = 1;
f();
}
expect: {
function f() {
console.log(a);
}
function g() {
f();
}
while (g());
var a = 1;
f();
}
expect_stdout: [
"undefined",
"1",
]
}
conditional_nested_1: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var a = 1, b = 0;
(function f(c) {
function g() {
c && (c.a = 0);
c && (c.a = 0);
c && (c[b++] *= 0);
}
g(a-- && f(g(c = 42)));
})();
console.log(b);
}
expect: {
var a = 1, b = 0;
(function f(c) {
function g() {
c && (c.a = 0);
c && (c.a = 0);
c && (c[b++] *= 0);
}
g(a-- && f(g(c = 42)));
})();
console.log(b);
}
expect_stdout: "2"
}
conditional_nested_2: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var c = 0;
(function(a) {
function f() {
a && c++;
}
f(!c && f(), a = 1);
})();
console.log(c);
}
expect: {
var c = 0;
(function(a) {
function f() {
a && c++;
}
f(!c && f(), a = 1);
})();
console.log(c);
}
expect_stdout: "1"
}
conditional_nested_3: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var n = 2, c = 0;
(function f(a) {
0 < n-- && g(a = 1);
function g() {
a && c++;
}
g();
0 < n-- && f();
})();
console.log(c);
}
expect: {
var n = 2, c = 0;
(function f(a) {
0 < n-- && g(a = 1);
function g() {
a && c++;
}
g();
0 < n-- && f();
})();
console.log(c);
}
expect_stdout: "2"
}
issue_2436: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var c;
console.log(((c = {
a: 1,
b: 2
}).a = 3, {
x: c.a,
y: c.b
}));
}
expect: {
var c;
console.log(((c = {
a: 1,
b: 2
}).a = 3, {
x: c.a,
y: c.b
}));
}
expect_stdout: true
}
issue_2916: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var c = "FAIL";
(function(b) {
(function(d) {
d[0] = 1;
})(b);
+b && (c = "PASS");
})([]);
console.log(c);
}
expect: {
var c = "FAIL";
(function(b) {
b[0] = 1;
+b && (c = "PASS");
})([]);
console.log(c);
}
expect_stdout: "PASS"
}
issue_3125: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var o;
console.log((function() {
this.p++;
}.call(o = {
p: 6
}), o.p));
}
expect: {
var o;
console.log((function() {
this.p++;
}.call(o = {
p: 6
}), o.p));
}
expect_stdout: "7"
}

View File

@@ -876,3 +876,59 @@ forin: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
call: {
options = {
sequences: true,
}
input: {
var a = function() {
return this;
}();
function b() {
console.log("foo");
}
b.c = function() {
console.log(this === b ? "bar" : "baz");
};
(a, b)();
(a, b.c)();
(a, function() {
console.log(this === a);
})();
new (a, b)();
new (a, b.c)();
new (a, function() {
console.log(this === a);
})();
}
expect: {
var a = function() {
return this;
}();
function b() {
console.log("foo");
}
b.c = function() {
console.log(this === b ? "bar" : "baz");
},
a, b(),
(a, b.c)(),
a, function() {
console.log(this === a);
}(),
a, new b(),
a, new b.c(),
a, new function() {
console.log(this === a);
}();
}
expect_stdout: [
"foo",
"baz",
"true",
"foo",
"baz",
"false",
]
}

View File

@@ -90,17 +90,11 @@ typeof_defun_1: {
"function" == typeof h && h(); "function" == typeof h && h();
} }
expect: { expect: {
function g() {
h = 42;
console.log("NOPE");
}
function h() { function h() {
console.log("YUP"); console.log("YUP");
} }
g = 42;
console.log("YES"); console.log("YES");
"function" == typeof g && g(); h();
"function" == typeof h && h();
} }
expect_stdout: [ expect_stdout: [
"YES", "YES",

View File

@@ -1,5 +1,5 @@
function test(a){ function test(a){
"aaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaa"
;a(err,data),a(err,data) ;a(err,data),a(err,
} data)}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7QUFDVjtDQUNBQSxFQUFTQyxJQUFLQyxNQUNkRixFQUFTQyxJQUFLQyJ9 //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7QUFDVjtDQUNBQSxFQUFTQyxJQUFLQyxNQUNkRixFQUFTQztBQUFLQyJ9

View File

@@ -1,24 +1,109 @@
var fs = require("fs"); var fs = require("fs");
var Mocha = require("mocha");
var path = require("path");
// Instantiate a Mocha instance var config = {
var mocha = new Mocha({ limit: 5000,
timeout: 5000 timeout: function(limit) {
}); this.limit = limit;
var testDir = __dirname + "/mocha/"; }
};
var tasks = [];
var titles = [];
describe = function(title, fn) {
config = Object.create(config);
titles.push(title);
fn.call(config);
titles.pop();
config = Object.getPrototypeOf(config);
};
it = function(title, fn) {
fn.limit = config.limit;
fn.titles = titles.slice();
fn.titles.push(title);
tasks.push(fn);
};
// Add each .js file to the Mocha instance fs.readdirSync("test/mocha").filter(function(file) {
fs.readdirSync(testDir).filter(function(file) {
return /\.js$/.test(file); return /\.js$/.test(file);
}).forEach(function(file) { }).forEach(function(file) {
mocha.addFile(path.join(testDir, file)); require("./mocha/" + file);
}); });
module.exports = function() { function log_titles(log, current, marker) {
mocha.run(function(failures) { var indent = "";
if (failures) process.on("exit", function() { var writing = false;
process.exit(failures); for (var i = 0; i < current.length; i++, indent += " ") {
if (titles[i] != current[i]) writing = true;
if (writing) log(indent + (i == current.length - 1 && marker || "") + current[i]);
}
titles = current;
}
function red(text) {
return "\u001B[31m" + text + "\u001B[39m";
}
function green(text) {
return "\u001B[32m" + text + "\u001B[39m";
}
var errors = [];
var total = tasks.length;
titles = [];
process.nextTick(function run() {
var task = tasks.shift();
if (task) try {
var elapsed = Date.now();
var timer;
var done = function() {
clearTimeout(timer);
done = function() {};
elapsed = Date.now() - elapsed;
if (elapsed > task.limit) {
throw new Error("Timed out: " + elapsed + "ms > " + task.limit + "ms");
}
log_titles(console.log, task.titles, green('\u221A '));
process.nextTick(run);
};
if (task.length) {
task.timeout = function(limit) {
clearTimeout(timer);
task.limit = limit;
timer = setTimeout(function() {
raise(new Error("Timed out: exceeds " + limit + "ms"));
}, limit);
};
task.timeout(task.limit);
task.call(task, done);
} else {
task.timeout = config.timeout;
task.call(task);
done();
}
} catch (err) {
raise(err);
} else if (errors.length) {
console.error();
console.log(red(errors.length + " test(s) failed!"));
titles = [];
errors.forEach(function(titles, index) {
console.error();
log_titles(console.error, titles, (index + 1) + ") ");
var lines = titles.error.stack.split('\n');
console.error(red(lines[0]));
console.error(lines.slice(1).join("\n"));
}); });
}); process.exit(1);
}; } else {
console.log();
console.log(green(total + " test(s) passed."));
}
function raise(err) {
clearTimeout(timer);
done = function() {};
task.titles.error = err;
errors.push(task.titles);
log_titles(console.log, task.titles, red('\u00D7 '));
process.nextTick(run);
}
});

View File

@@ -100,8 +100,8 @@ describe("bin/uglifyjs", function () {
exec(command, function (err, stdout, stderr) { exec(command, function (err, stdout, stderr) {
if (err) throw err; if (err) throw err;
var stderrLines = stderr.split('\n'); var stderrLines = stderr.split("\n");
assert.strictEqual(stderrLines[0], 'INFO: Using input source map: test/input/issue-2082/sample.js.map'); assert.strictEqual(stderrLines[0], "INFO: Using input source map: test/input/issue-2082/sample.js.map");
assert.notStrictEqual(stderrLines[1], 'INFO: Using input source map: {"version": 3,"sources": ["index.js"],"mappings": ";"}'); assert.notStrictEqual(stderrLines[1], 'INFO: Using input source map: {"version": 3,"sources": ["index.js"],"mappings": ";"}');
done(); done();
}); });
@@ -121,7 +121,8 @@ describe("bin/uglifyjs", function () {
var command = [ var command = [
uglifyjscmd, uglifyjscmd,
"--source-map", "content=" + mapFile, "--source-map", "content=" + mapFile,
"--source-map", "url=inline" "--source-map", "includeSources=true",
"--source-map", "url=inline",
].join(" "); ].join(" ");
var child = exec(command, function(err, stdout) { var child = exec(command, function(err, stdout) {
@@ -216,7 +217,14 @@ describe("bin/uglifyjs", function () {
}); });
}); });
it("Should process inline source map", function(done) { it("Should process inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js -mc toplevel --source-map content=inline,url=inline"; var command = [
uglifyjscmd,
"test/input/issue-520/input.js",
"-mc", "toplevel",
"--source-map", "content=inline",
"--source-map", "includeSources=true",
"--source-map", "url=inline",
].join(" ");
exec(command, function (err, stdout) { exec(command, function (err, stdout) {
if (err) throw err; if (err) throw err;
@@ -236,16 +244,29 @@ describe("bin/uglifyjs", function () {
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==", "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"", "",
].join("\n")); ].join("\n"));
assert.strictEqual(stderr, "WARN: inline source map not found\n"); var stderrLines = stderr.split("\n");
assert.strictEqual(stderrLines[0], "WARN: inline source map not found: test/input/issue-1323/sample.js");
done(); done();
}); });
}); });
it("Should fail with multiple input and inline source map", function(done) { it("Should handle multiple input and inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js test/input/issue-520/output.js --source-map content=inline,url=inline"; var command = [
uglifyjscmd,
"test/input/issue-520/input.js",
"test/input/issue-1323/sample.js",
"--source-map", "content=inline,url=inline",
].join(" ");
exec(command, function (err, stdout, stderr) { exec(command, function (err, stdout, stderr) {
assert.ok(err); if (err) throw err;
assert.strictEqual(stderr.split(/\n/)[0], "ERROR: inline source map only works with singular input");
assert.strictEqual(stdout, [
"var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUFBLE1BQWdCQyxRQUFRQyxJQUFJLEVBQUUsSUFBTyxJQUFJRixJQ0FuRCxJQUFJRyxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"",
].join("\n"));
var stderrLines = stderr.split("\n");
assert.strictEqual(stderrLines[0], "WARN: inline source map not found: test/input/issue-1323/sample.js");
done(); done();
}); });
}); });

View File

@@ -1,66 +1,68 @@
var Uglify = require('../../');
var assert = require("assert"); var assert = require("assert");
var Uglify = require("../../");
var SourceMapConsumer = require("source-map").SourceMapConsumer; var SourceMapConsumer = require("source-map").SourceMapConsumer;
function getMap() {
return {
"version": 3,
"sources": ["index.js"],
"names": [],
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
"file": "bundle.js",
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
};
}
function prepareMap(sourceMap) {
var code = [
'"use strict";',
"",
"var foo = function foo(x) {",
' return "foo " + x;',
"};",
'console.log(foo("bar"));',
"",
"//# sourceMappingURL=bundle.js.map",
].join("\n");
var result = Uglify.minify(code, {
sourceMap: {
content: sourceMap,
includeSources: true,
}
});
if (result.error) throw result.error;
return new SourceMapConsumer(result.map);
}
describe("input sourcemaps", function() { describe("input sourcemaps", function() {
var transpilemap, map;
function getMap() {
return {
"version": 3,
"sources": ["index.js"],
"names": [],
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
"file": "bundle.js",
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
};
}
function prepareMap(sourceMap) {
var transpiled = '"use strict";\n\n' +
'var foo = function foo(x) {\n return "foo " + x;\n};\n' +
'console.log(foo("bar"));\n\n' +
'//# sourceMappingURL=bundle.js.map';
transpilemap = sourceMap || getMap();
var result = Uglify.minify(transpiled, {
sourceMap: {
content: transpilemap
}
});
map = new SourceMapConsumer(result.map);
}
beforeEach(function () {
prepareMap();
});
it("Should copy over original sourcesContent", function() { it("Should copy over original sourcesContent", function() {
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]); var orig = getMap();
var map = prepareMap(orig);
assert.equal(map.sourceContentFor("index.js"), orig.sourcesContent[0]);
}); });
it("Should copy sourcesContent if sources are relative", function () { it("Should copy sourcesContent if sources are relative", function() {
var relativeMap = getMap(); var relativeMap = getMap();
relativeMap.sources = ['./index.js']; relativeMap.sources = ['./index.js'];
var map = prepareMap(relativeMap);
prepareMap(relativeMap);
assert.notEqual(map.sourcesContent, null); assert.notEqual(map.sourcesContent, null);
assert.equal(map.sourcesContent.length, 1); assert.equal(map.sourcesContent.length, 1);
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]); assert.equal(map.sourceContentFor("index.js"), relativeMap.sourcesContent[0]);
}); });
it("Final sourcemap should not have invalid mappings from inputSourceMap (issue #882)", function() { it("Should not have invalid mappings from inputSourceMap (issue #882)", function() {
var map = prepareMap(getMap());
// The original source has only 2 lines, check that mappings don't have more lines // The original source has only 2 lines, check that mappings don't have more lines
var msg = "Mapping should not have higher line number than the original file had"; var msg = "Mapping should not have higher line number than the original file had";
map.eachMapping(function(mapping) { map.eachMapping(function(mapping) {
assert.ok(mapping.originalLine <= 2, msg) assert.ok(mapping.originalLine <= 2, msg);
}); });
map.allGeneratedPositionsFor({
map.allGeneratedPositionsFor({source: "index.js", line: 1, column: 1}).forEach(function(pos) { source: "index.js",
line: 1,
column: 1
}).forEach(function(pos) {
assert.ok(pos.line <= 2, msg); assert.ok(pos.line <= 2, msg);
}) });
}); });
}); });

View File

@@ -1,7 +1,7 @@
var assert = require("assert"); var assert = require("assert");
var uglify = require("../../"); var uglify = require("../../");
describe("New", function() { describe("parentheses", function() {
it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() { it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() {
var tests = [ var tests = [
"new x(1);", "new x(1);",
@@ -83,4 +83,23 @@ describe("New", function() {
); );
} }
}); });
it("Should compress leading parenthesis with reasonable performance", function() {
this.timeout(30000);
var code = [
"({}?0:1)&&x();",
"(function(){}).name;",
];
for (var i = 16; --i >= 0;) {
code = code.concat(code);
}
code = code.join("");
var result = uglify.minify(code, {
compress: false,
mangle: false,
});
if (result.error) throw result.error;
// Dismal performance for `assert.strictEqual()` in Node.js 6
assert.ok(result.code === code);
});
}); });

View File

@@ -70,6 +70,7 @@ describe("sourcemaps", function() {
compress: { toplevel: true }, compress: { toplevel: true },
sourceMap: { sourceMap: {
content: "inline", content: "inline",
includeSources: true,
url: "inline" url: "inline"
} }
}).code + "\n"; }).code + "\n";
@@ -90,24 +91,60 @@ describe("sourcemaps", function() {
}); });
assert.strictEqual(result.code, "var bar=function(bar){return bar};"); assert.strictEqual(result.code, "var bar=function(bar){return bar};");
assert.strictEqual(warnings.length, 1); assert.strictEqual(warnings.length, 1);
assert.strictEqual(warnings[0], "inline source map not found"); assert.strictEqual(warnings[0], "inline source map not found: 0");
} finally { } finally {
Uglify.AST_Node.warn_function = warn_function; Uglify.AST_Node.warn_function = warn_function;
} }
}); });
it("Should fail with multiple input and inline source map", function() { it("Should handle multiple input and inline source map", function() {
var result = Uglify.minify([ var warn_function = Uglify.AST_Node.warn_function;
read("./test/input/issue-520/input.js"), var warnings = [];
read("./test/input/issue-520/output.js") Uglify.AST_Node.warn_function = function(txt) {
], { warnings.push(txt);
};
try {
var result = Uglify.minify([
read("./test/input/issue-520/input.js"),
read("./test/input/issue-1323/sample.js"),
], {
sourceMap: {
content: "inline",
url: "inline",
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"var Foo=function(){console.log(3)};new Foo;var bar=function(o){return o};",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwiMSJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFdBQWdCQyxRQUFRQyxJQUFJLElBQVMsSUFBSUYsSUNBbkQsSUFBSUcsSUFDQSxTQUFjQSxHQUNWLE9BQU9BIn0=",
].join("\n"));
assert.strictEqual(warnings.length, 1);
assert.strictEqual(warnings[0], "inline source map not found: 1");
} finally {
Uglify.AST_Node.warn_function = warn_function;
}
});
it("Should drop source contents for includeSources=false", function() {
var result = Uglify.minify(read("./test/input/issue-520/input.js"), {
compress: false,
mangle: false,
sourceMap: { sourceMap: {
content: "inline", content: "inline",
url: "inline" includeSources: true,
} },
}); });
var err = result.error; if (result.error) throw result.error;
assert.ok(err instanceof Error); var map = JSON.parse(result.map);
assert.strictEqual(err.stack.split(/\n/)[0], "Error: inline source map only works with singular input"); assert.strictEqual(map.sourcesContent.length, 1);
result = Uglify.minify(result.code, {
compress: false,
mangle: false,
sourceMap: {
content: result.map,
},
});
if (result.error) throw result.error;
map = JSON.parse(result.map);
assert.ok(!("sourcesContent" in map));
}); });
}); });

View File

@@ -18,9 +18,8 @@ if (failures) {
console.error("!!! " + Object.keys(failed_files).join(", ")); console.error("!!! " + Object.keys(failed_files).join(", "));
process.exit(1); process.exit(1);
} }
console.log();
var mocha_tests = require("./mocha.js"); require("./mocha.js");
mocha_tests();
/* -----[ utils ]----- */ /* -----[ utils ]----- */
@@ -172,7 +171,7 @@ function run_compress_tests() {
} }
if (test.expect_stdout if (test.expect_stdout
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) { && (!test.node_version || semver.satisfies(process.version, test.node_version))) {
var stdout = sandbox.run_code(input_code, true); var stdout = run_code(input_code);
if (test.expect_stdout === true) { if (test.expect_stdout === true) {
test.expect_stdout = stdout; test.expect_stdout = stdout;
} }
@@ -186,7 +185,7 @@ function run_compress_tests() {
}); });
return false; return false;
} }
stdout = sandbox.run_code(output, true); stdout = run_code(output);
if (!sandbox.same_stdout(test.expect_stdout, stdout)) { if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", { log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
input: input_formatted, input: input_formatted,
@@ -344,6 +343,11 @@ function evaluate(code) {
return new Function("return(" + code + ")")(); return new Function("return(" + code + ")")();
} }
function run_code(code) {
var result = sandbox.run_code(code, true);
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
}
// Try to reminify original input with standard options // Try to reminify original input with standard options
// to see if it matches expect_stdout. // to see if it matches expect_stdout.
function reminify(orig_options, input_code, input_formatted, expect_stdout) { function reminify(orig_options, input_code, input_formatted, expect_stdout) {
@@ -367,7 +371,7 @@ function reminify(orig_options, input_code, input_formatted, expect_stdout) {
}); });
return false; return false;
} else { } else {
var stdout = sandbox.run_code(result.code, true); var stdout = run_code(result.code);
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) { if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
stdout = expect_stdout; stdout = expect_stdout;
} }

View File

@@ -2,24 +2,18 @@ var semver = require("semver");
var vm = require("vm"); var vm = require("vm");
function createContext() { function createContext() {
var context = Object.create(null); return vm.createContext(Object.defineProperty({}, "console", {
Object.defineProperty(context, "console", { value: {
value: function() { log: function(msg) {
var con = Object.create(null); if (arguments.length == 1 && typeof msg == "string") {
Object.defineProperty(con, "log", { return console.log("%s", msg);
value: function(msg) {
if (arguments.length == 1 && typeof msg == "string") {
return console.log("%s", msg);
}
return console.log.apply(console, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
} }
}); return console.log.apply(console, [].map.call(arguments, function(arg) {
return con; return safe_log(arg, 3);
}() }));
}); }
return vm.createContext(context); }
}));
} }
function safe_log(arg, level) { function safe_log(arg, level) {
@@ -40,7 +34,7 @@ function safe_log(arg, level) {
} }
function strip_func_ids(text) { function strip_func_ids(text) {
return text.toString().replace(/F[0-9]{6}N/g, "<F<>N>"); return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");
} }
var context; var context;

View File

@@ -18,6 +18,13 @@
{ {
"toplevel": true "toplevel": true
}, },
{
"compress": {
"passes": 1e6,
"unsafe": true
},
"toplevel": true
},
{ {
"compress": { "compress": {
"keep_fargs": false, "keep_fargs": false,