Merge pull request #1485 from alexlamsl/merge-2.8.0

2.8.0 staging
This commit is contained in:
Alex Lam S.L
2017-02-24 07:33:57 +08:00
committed by GitHub
48 changed files with 4186 additions and 551 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.js text eol=lf

View File

@@ -346,6 +346,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
comparison are switching. Compression only works if both `comparisons` and comparison are switching. Compression only works if both `comparisons` and
`unsafe_comps` are both set to true. `unsafe_comps` are both set to true.
- `unsafe_proto` (default: false) -- optimize expressions like
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
- `conditionals` -- apply optimizations for `if`-s and conditional - `conditionals` -- apply optimizations for `if`-s and conditional
expressions expressions
@@ -361,7 +364,15 @@ to set `true`; it's effectively a shortcut for `foo=true`).
- `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
- `unused` -- drop unreferenced functions and variables - `unused` -- drop unreferenced functions and variables (simple direct variable
assignments do not count as references unless set to `"keep_assign"`)
- `toplevel` -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`)
in the toplevel scope (`false` by default, `true` to drop both unreferenced
functions and variables)
- `top_retain` -- prevent specific toplevel functions and variables from `unused`
removal (can be array, comma-separated, RegExp or function. Implies `toplevel`)
- `hoist_funs` -- hoist function declarations - `hoist_funs` -- hoist function declarations
@@ -446,6 +457,8 @@ if (DEBUG) {
} }
``` ```
You can specify nested constants in the form of `--define env.DEBUG=false`.
UglifyJS will warn about the condition being always false and about dropping UglifyJS will warn about the condition being always false and about dropping
unreachable code; for now there is no option to turn off only this specific unreachable code; for now there is no option to turn off only this specific
warning, you can pass `warnings=false` to turn off *all* warnings. warning, you can pass `warnings=false` to turn off *all* warnings.
@@ -456,8 +469,6 @@ separate file and include it into the build. For example you can have a
```javascript ```javascript
const DEBUG = false; const DEBUG = false;
const PRODUCTION = true; const PRODUCTION = true;
// Alternative for environments that don't support `const`
/** @const */ var STAGING = false;
// etc. // etc.
``` ```
@@ -468,7 +479,8 @@ and build your code like this:
UglifyJS will notice the constants and, since they cannot be altered, it UglifyJS will notice the constants and, since they cannot be altered, it
will evaluate references to them to the value itself and drop unreachable will evaluate references to them to the value itself and drop unreachable
code as usual. The build will contain the `const` declarations if you use code as usual. The build will contain the `const` declarations if you use
them. If you are targeting < ES6 environments, use `/** @const */ var`. them. If you are targeting < ES6 environments which does not support `const`,
using `var` with `reduce_vars` (enabled by default) should suffice.
<a name="codegen-options"></a> <a name="codegen-options"></a>

View File

@@ -228,9 +228,10 @@ if (ARGS.mangle_props === true) {
} }
var OUTPUT_OPTIONS = { var OUTPUT_OPTIONS = {
beautify : BEAUTIFY ? true : false, beautify : BEAUTIFY ? true : false,
preamble : ARGS.preamble || null, max_line_len : 32000,
quote_style : ARGS.quotes != null ? ARGS.quotes : 0 preamble : ARGS.preamble || null,
quote_style : ARGS.quotes != null ? ARGS.quotes : 0,
}; };
if (ARGS.mangle_props == 2) { if (ARGS.mangle_props == 2) {
@@ -540,7 +541,7 @@ function getOptions(flag, constants) {
ast.walk(new UglifyJS.TreeWalker(function(node){ ast.walk(new UglifyJS.TreeWalker(function(node){
if (node instanceof UglifyJS.AST_Seq) return; // descend if (node instanceof UglifyJS.AST_Seq) return; // descend
if (node instanceof UglifyJS.AST_Assign) { if (node instanceof UglifyJS.AST_Assign) {
var name = node.left.print_to_string({ beautify: false }).replace(/-/g, "_"); var name = node.left.print_to_string().replace(/-/g, "_");
var value = node.right; var value = node.right;
if (constants) if (constants)
value = new Function("return (" + value.print_to_string() + ")")(); value = new Function("return (" + value.print_to_string() + ")")();
@@ -548,7 +549,7 @@ function getOptions(flag, constants) {
return true; // no descend return true; // no descend
} }
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_Binary) { if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_Binary) {
var name = node.print_to_string({ beautify: false }).replace(/-/g, "_"); var name = node.print_to_string().replace(/-/g, "_");
ret[name] = true; ret[name] = true;
return true; // no descend return true; // no descend
} }

File diff suppressed because it is too large Load Diff

View File

@@ -70,7 +70,7 @@ function OutputStream(options) {
unescape_regexps : false, unescape_regexps : false,
inline_script : false, inline_script : false,
width : 80, width : 80,
max_line_len : 32000, max_line_len : false,
beautify : false, beautify : false,
source_map : null, source_map : null,
bracketize : false, bracketize : false,
@@ -198,16 +198,29 @@ function OutputStream(options) {
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 last = null; var last = null;
function last_char() { function last_char() {
return last.charAt(last.length - 1); return last.charAt(last.length - 1);
}; };
function maybe_newline() { var ensure_line_len = options.max_line_len ? function() {
if (options.max_line_len && current_col > options.max_line_len) if (current_col > options.max_line_len) {
print("\n"); if (might_add_newline) {
}; var left = OUTPUT.slice(0, might_add_newline);
var right = OUTPUT.slice(might_add_newline);
OUTPUT = left + "\n" + right;
current_line++;
current_pos++;
current_col = right.length;
}
if (current_col > options.max_line_len) {
AST_Node.warn("Output exceeds {max_line_len} characters", options);
}
}
might_add_newline = 0;
} : noop;
var requireSemicolonChars = makePredicate("( [ + * / - , ."); var requireSemicolonChars = makePredicate("( [ + * / - , .");
@@ -223,6 +236,7 @@ function OutputStream(options) {
current_col++; current_col++;
current_pos++; current_pos++;
} else { } else {
ensure_line_len();
OUTPUT += "\n"; OUTPUT += "\n";
current_pos++; current_pos++;
current_line++; current_line++;
@@ -243,6 +257,7 @@ function OutputStream(options) {
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
var target_line = stack[stack.length - 1].start.line; var target_line = stack[stack.length - 1].start.line;
while (current_line < target_line) { while (current_line < target_line) {
ensure_line_len();
OUTPUT += "\n"; OUTPUT += "\n";
current_pos++; current_pos++;
current_line++; current_line++;
@@ -254,8 +269,9 @@ function OutputStream(options) {
if (might_need_space) { if (might_need_space) {
var prev = last_char(); var prev = last_char();
if ((is_identifier_char(prev) if ((is_identifier_char(prev)
&& (is_identifier_char(ch) || ch == "\\")) && (is_identifier_char(ch) || ch == "\\"))
|| (/^[\+\-\/]$/.test(ch) && ch == prev)) || (ch == "/" && ch == prev)
|| ((ch == "+" || ch == "-") && ch == last))
{ {
OUTPUT += " "; OUTPUT += " ";
current_col++; current_col++;
@@ -263,16 +279,16 @@ function OutputStream(options) {
} }
might_need_space = false; might_need_space = false;
} }
OUTPUT += str;
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;
if (n == 0) { current_col += a[0].length;
current_col += a[n].length; if (n > 0) {
} else { ensure_line_len();
current_col = a[n].length; current_col = a[n].length;
} }
current_pos += str.length;
last = str; last = str;
OUTPUT += str;
}; };
var space = options.beautify ? function() { var space = options.beautify ? function() {
@@ -298,7 +314,10 @@ function OutputStream(options) {
var newline = options.beautify ? function() { var newline = options.beautify ? function() {
print("\n"); print("\n");
} : maybe_newline; } : options.max_line_len ? function() {
ensure_line_len();
might_add_newline = OUTPUT.length;
} : noop;
var semicolon = options.beautify ? function() { var semicolon = options.beautify ? function() {
print(";"); print(";");
@@ -375,6 +394,9 @@ function OutputStream(options) {
} : noop; } : noop;
function get() { function get() {
if (might_add_newline) {
ensure_line_len();
}
return OUTPUT; return OUTPUT;
}; };
@@ -425,7 +447,6 @@ function OutputStream(options) {
pos : function() { return current_pos }, pos : function() { return current_pos },
push_node : function(node) { stack.push(node) }, push_node : function(node) { stack.push(node) },
pop_node : function() { return stack.pop() }, pop_node : function() { return stack.pop() },
stack : function() { return stack },
parent : function(n) { parent : function(n) {
return stack[stack.length - 2 - (n || 0)]; return stack[stack.length - 2 - (n || 0)];
} }
@@ -939,7 +960,10 @@ function OutputStream(options) {
output.space(); output.space();
output.print("else"); output.print("else");
output.space(); output.space();
force_statement(self.alternative, output); if (self.alternative instanceof AST_If)
self.alternative.print(output);
else
force_statement(self.alternative, output);
} else { } else {
self._do_print_body(output); self._do_print_body(output);
} }
@@ -1334,30 +1358,6 @@ function OutputStream(options) {
} }
}; };
// return true if the node at the top of the stack (that means the
// innermost node in the current output) is lexically the first in
// a statement.
function first_in_statement(output) {
var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
while (i > 0) {
if (p instanceof AST_Statement && p.body === node)
return true;
if ((p instanceof AST_Seq && p.car === node ) ||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
(p instanceof AST_Dot && p.expression === node ) ||
(p instanceof AST_Sub && p.expression === node ) ||
(p instanceof AST_Conditional && p.condition === node ) ||
(p instanceof AST_Binary && p.left === node ) ||
(p instanceof AST_UnaryPostfix && p.expression === node ))
{
node = p;
p = a[--i];
} else {
return false;
}
}
};
// 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) {
// Always print parentheses with arguments // Always print parentheses with arguments

View File

@@ -1308,6 +1308,10 @@ function parse($TEXT, options) {
}); });
}); });
var create_accessor = embed_tokens(function() {
return function_(AST_Accessor);
});
var object_ = embed_tokens(function() { var object_ = embed_tokens(function() {
expect("{"); expect("{");
var first = true, a = []; var first = true, a = [];
@@ -1324,7 +1328,7 @@ function parse($TEXT, options) {
a.push(new AST_ObjectGetter({ a.push(new AST_ObjectGetter({
start : start, start : start,
key : as_atom_node(), key : as_atom_node(),
value : function_(AST_Accessor), value : create_accessor(),
end : prev() end : prev()
})); }));
continue; continue;
@@ -1333,7 +1337,7 @@ function parse($TEXT, options) {
a.push(new AST_ObjectSetter({ a.push(new AST_ObjectSetter({
start : start, start : start,
key : as_atom_node(), key : as_atom_node(),
value : function_(AST_Accessor), value : create_accessor(),
end : prev() end : prev()
})); }));
continue; continue;

View File

@@ -97,26 +97,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var scope = self.parent_scope = null; var scope = self.parent_scope = null;
var labels = new Dictionary(); var labels = new Dictionary();
var defun = null; var defun = null;
var last_var_had_const_pragma = false;
var nesting = 0;
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (options.screw_ie8 && node instanceof AST_Catch) { if (options.screw_ie8 && node instanceof AST_Catch) {
var save_scope = scope; var save_scope = scope;
scope = new AST_Scope(node); scope = new AST_Scope(node);
scope.init_scope_vars(nesting); scope.init_scope_vars();
scope.parent_scope = save_scope; scope.parent_scope = save_scope;
descend(); descend();
scope = save_scope; scope = save_scope;
return true; return true;
} }
if (node instanceof AST_Scope) { if (node instanceof AST_Scope) {
node.init_scope_vars(nesting); node.init_scope_vars();
var save_scope = node.parent_scope = scope; var save_scope = node.parent_scope = scope;
var save_defun = defun; var save_defun = defun;
var save_labels = labels; var save_labels = labels;
defun = scope = node; defun = scope = node;
labels = new Dictionary(); labels = new Dictionary();
++nesting; descend(); --nesting; descend();
scope = save_scope; scope = save_scope;
defun = save_defun; defun = save_defun;
labels = save_labels; labels = save_labels;
@@ -155,13 +153,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// later. // later.
(node.scope = defun.parent_scope).def_function(node); (node.scope = defun.parent_scope).def_function(node);
} }
else if (node instanceof AST_Var) {
last_var_had_const_pragma = node.has_const_pragma();
}
else if (node instanceof AST_SymbolVar else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst) { || node instanceof AST_SymbolConst) {
var def = defun.def_variable(node); var def = defun.def_variable(node);
def.constant = node instanceof AST_SymbolConst || last_var_had_const_pragma; def.constant = node instanceof AST_SymbolConst;
def.init = tw.parent().value; def.init = tw.parent().value;
} }
else if (node instanceof AST_SymbolCatch) { else if (node instanceof AST_SymbolCatch) {
@@ -184,17 +179,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var func = null; var func = null;
var globals = self.globals = new Dictionary(); var globals = self.globals = new Dictionary();
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
function isModified(node, level) {
var parent = tw.parent(level);
if (parent instanceof AST_Unary && (parent.operator === "++" || parent.operator === "--")
|| parent instanceof AST_Assign && parent.left === node
|| parent instanceof AST_Call && parent.expression === node) {
return true;
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
return isModified(parent, level + 1);
}
}
if (node instanceof AST_Lambda) { if (node instanceof AST_Lambda) {
var prev_func = func; var prev_func = func;
func = node; func = node;
@@ -218,21 +202,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
node.scope.uses_arguments = true; node.scope.uses_arguments = true;
} }
if (!sym) { if (!sym) {
var g; sym = self.def_global(node);
if (globals.has(name)) {
g = globals.get(name);
} else {
g = new SymbolDef(self, globals.size(), node);
g.undeclared = true;
g.global = true;
globals.set(name, g);
}
sym = g;
} }
node.thedef = sym; node.thedef = sym;
if (isModified(node, 0)) {
sym.modified = true;
}
node.reference(options); node.reference(options);
return true; return true;
} }
@@ -244,7 +216,20 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
} }
}); });
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){ AST_Toplevel.DEFMETHOD("def_global", function(node){
var globals = this.globals, name = node.name;
if (globals.has(name)) {
return globals.get(name);
} else {
var g = new SymbolDef(this, globals.size(), node);
g.undeclared = true;
g.global = true;
globals.set(name, g);
return g;
}
});
AST_Scope.DEFMETHOD("init_scope_vars", function(){
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
@@ -252,7 +237,6 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
this.parent_scope = null; // the parent scope this.parent_scope = null; // the parent scope
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
this.cname = -1; // the current index for mangling functions/variables this.cname = -1; // the current index for mangling functions/variables
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
}); });
AST_Lambda.DEFMETHOD("init_scope_vars", function(){ AST_Lambda.DEFMETHOD("init_scope_vars", function(){
@@ -270,15 +254,14 @@ AST_SymbolRef.DEFMETHOD("reference", function(options) {
var s = this.scope; var s = this.scope;
while (s) { while (s) {
push_uniq(s.enclosed, def); push_uniq(s.enclosed, def);
if (s === def.scope) break;
if (options.keep_fnames) { if (options.keep_fnames) {
s.variables.each(function(d) { s.functions.each(function(d) {
push_uniq(def.scope.enclosed, d); push_uniq(def.scope.enclosed, d);
}); });
} }
if (s === def.scope) break;
s = s.parent_scope; s = s.parent_scope;
} }
this.frame = this.scope.nesting - def.scope.nesting;
}); });
AST_Scope.DEFMETHOD("find_variable", function(name){ AST_Scope.DEFMETHOD("find_variable", function(name){
@@ -382,12 +365,6 @@ AST_Symbol.DEFMETHOD("global", function(){
return this.definition().global; return this.definition().global;
}); });
AST_Var.DEFMETHOD("has_const_pragma", function() {
var comments_before = this.start && this.start.comments_before;
var lastComment = comments_before && comments_before[comments_before.length - 1];
return lastComment && /@const\b/.test(lastComment.value);
});
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
return defaults(options, { return defaults(options, {
except : [], except : [],

View File

@@ -320,3 +320,26 @@ Dictionary.fromObject = function(obj) {
function HOP(obj, prop) { function HOP(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop); return Object.prototype.hasOwnProperty.call(obj, prop);
} }
// return true if the node at the top of the stack (that means the
// innermost node in the current output) is lexically the first in
// a statement.
function first_in_statement(stack) {
var node = stack.parent(-1);
for (var i = 0, p; p = stack.parent(i); i++) {
if (p instanceof AST_Statement && p.body === node)
return true;
if ((p instanceof AST_Seq && p.car === node ) ||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
(p instanceof AST_Dot && p.expression === node ) ||
(p instanceof AST_Sub && p.expression === node ) ||
(p instanceof AST_Conditional && p.condition === node ) ||
(p instanceof AST_Binary && p.left === node ) ||
(p instanceof AST_UnaryPostfix && p.expression === node ))
{
node = p;
} else {
return false;
}
}
}

49
test/benchmark.js Normal file
View File

@@ -0,0 +1,49 @@
#! /usr/bin/env node
// -*- js -*-
"use strict";
var createHash = require("crypto").createHash;
var fork = require("child_process").fork;
var args = process.argv.slice(2);
if (!args.length) {
args.push("-mc", "warnings=false");
}
args.push("--stats");
var urls = [
"https://code.jquery.com/jquery-3.1.1.js",
"https://code.angularjs.org/1.6.1/angular.js",
"https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js",
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
"https://unpkg.com/react@15.3.2/dist/react.js",
"http://builds.emberjs.com/tags/v2.11.0/ember.prod.js",
"https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js",
"https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js",
];
var results = {};
var remaining = 2 * urls.length;
function done() {
if (!--remaining) {
urls.forEach(function(url) {
console.log();
console.log(url);
console.log(results[url].time);
console.log("SHA1:", results[url].sha1);
});
}
}
urls.forEach(function(url) {
results[url] = { time: "" };
require(url.slice(0, url.indexOf(":"))).get(url, function(res) {
var uglifyjs = fork("bin/uglifyjs", args, { silent: true });
res.pipe(uglifyjs.stdin);
uglifyjs.stdout.pipe(createHash("sha1")).on("data", function(data) {
results[url].sha1 = data.toString("hex");
done();
});
uglifyjs.stderr.setEncoding("utf8");
uglifyjs.stderr.on("data", function(data) {
results[url].time += data;
}).on("end", done)
});
});

View File

@@ -21,10 +21,19 @@ constant_join: {
input: { input: {
var a = [ "foo", "bar", "baz" ].join(""); var a = [ "foo", "bar", "baz" ].join("");
var a1 = [ "foo", "bar", "baz" ].join(); var a1 = [ "foo", "bar", "baz" ].join();
var a2 = [ "foo", "bar", "baz" ].join(null);
var a3 = [ "foo", "bar", "baz" ].join(void 0);
var a4 = [ "foo", , "baz" ].join();
var a5 = [ "foo", null, "baz" ].join();
var a6 = [ "foo", void 0, "baz" ].join();
var b = [ "foo", 1, 2, 3, "bar" ].join(""); var b = [ "foo", 1, 2, 3, "bar" ].join("");
var c = [ boo(), "foo", 1, 2, 3, "bar", bar() ].join(""); var c = [ boo(), "foo", 1, 2, 3, "bar", bar() ].join("");
var c1 = [ boo(), bar(), "foo", 1, 2, 3, "bar", bar() ].join(""); var c1 = [ boo(), bar(), "foo", 1, 2, 3, "bar", bar() ].join("");
var c2 = [ 1, 2, "foo", "bar", baz() ].join(""); var c2 = [ 1, 2, "foo", "bar", baz() ].join("");
var c3 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join("");
var c4 = [ 1, 2, null, undefined, "foo", "bar", baz() ].join("");
var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join();
var c6 = [ 1, 2, null, undefined, "foo", "bar", baz() ].join();
var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-"); var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-");
var e = [].join(foo + bar); var e = [].join(foo + bar);
var f = [].join(""); var f = [].join("");
@@ -33,10 +42,19 @@ constant_join: {
expect: { expect: {
var a = "foobarbaz"; var a = "foobarbaz";
var a1 = "foo,bar,baz"; var a1 = "foo,bar,baz";
var a2 = "foonullbarnullbaz";
var a3 = "foo,bar,baz";
var a4 = "foo,,baz";
var a5 = "foo,,baz";
var a6 = "foo,,baz";
var b = "foo123bar"; var b = "foo123bar";
var c = boo() + "foo123bar" + bar(); var c = boo() + "foo123bar" + bar();
var c1 = "" + boo() + bar() + "foo123bar" + bar(); var c1 = "" + boo() + bar() + "foo123bar" + bar();
var c2 = "12foobar" + baz(); var c2 = "12foobar" + baz();
var c3 = boo() + bar() + "foo123bar" + bar() + "foo";
var c4 = "12foobar" + baz();
var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join();
var c6 = [ "1,2,,,foo,bar", baz() ].join();
var d = "foo-3bar-baz"; var d = "foo-3bar-baz";
var e = [].join(foo + bar); var e = [].join(foo + bar);
var f = ""; var f = "";
@@ -73,6 +91,41 @@ constant_join_2: {
} }
} }
constant_join_3: {
options = {
unsafe: true,
evaluate: true,
};
input: {
var a = [ null ].join();
var b = [ , ].join();
var c = [ , 1, , 3 ].join();
var d = [ foo ].join();
var e = [ foo, null, undefined, bar ].join("-");
var f = [ foo, bar ].join("");
var g = [ null, "foo", null, bar + "baz" ].join("");
var h = [ null, "foo", null, bar + "baz" ].join("-");
var i = [ "foo" + bar, null, baz + "moo" ].join("");
var j = [ foo + "bar", baz ].join("");
var k = [ foo, "bar" + baz ].join("");
var l = [ foo, bar + "baz" ].join("");
}
expect: {
var a = "";
var b = "";
var c = ",1,,3";
var d = "" + foo;
var e = [ foo, "-", bar ].join("-");
var f = "" + foo + bar;
var g = "foo" + bar + "baz";
var h = [ "-foo-", bar + "baz" ].join("-");
var i = "foo" + bar + baz + "moo";
var j = foo + "bar" + baz;
var k = foo + "bar" + baz;
var l = foo + (bar + "baz");
}
}
for_loop: { for_loop: {
options = { options = {
unsafe : true, unsafe : true,

View File

@@ -338,8 +338,9 @@ collapse_vars_while: {
collapse_vars_do_while: { collapse_vars_do_while: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:false, loops:false, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:false, loops:false, unused:"keep_assign",
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true,
side_effects:true
} }
input: { input: {
function f1(y) { function f1(y) {
@@ -409,6 +410,79 @@ collapse_vars_do_while: {
} }
} }
collapse_vars_do_while_drop_assign: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:false, loops:false, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
}
input: {
function f1(y) {
// The constant do-while condition `c` will be replaced.
var c = 9;
do { } while (c === 77);
}
function f2(y) {
// The non-constant do-while condition `c` will not be replaced.
var c = 5 - y;
do { } while (c);
}
function f3(y) {
// The constant `x` will be replaced in the do loop body.
function fn(n) { console.log(n); }
var a = 2, x = 7;
do {
fn(a = x);
break;
} while (y);
}
function f4(y) {
// The non-constant `a` will not be replaced in the do loop body.
var a = y / 4;
do {
return a;
} while (y);
}
function f5(y) {
function p(x) { console.log(x); }
do {
// The non-constant `a` will be replaced in p(a)
// because it is declared in same block.
var a = y - 3;
p(a);
} while (--y);
}
}
expect: {
function f1(y) {
do ; while (false);
}
function f2(y) {
var c = 5 - y;
do ; while (c);
}
function f3(y) {
function fn(n) { console.log(n); }
do {
fn(7);
break;
} while (y);
}
function f4(y) {
var a = y / 4;
do
return a;
while (y);
}
function f5(y) {
function p(x) { console.log(x); }
do {
p(y - 3);
} while (--y);
}
}
}
collapse_vars_seq: { collapse_vars_seq: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
@@ -567,8 +641,9 @@ collapse_vars_assignment: {
collapse_vars_lvalues: { collapse_vars_lvalues: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:"keep_assign",
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true,
side_effects:true
} }
input: { input: {
function f0(x) { var i = ++x; return x += i; } function f0(x) { var i = ++x; return x += i; }
@@ -593,7 +668,38 @@ collapse_vars_lvalues: {
function f7(x) { var w = e1(), v = e2(), c = v - x; return (w = x) - c; } function f7(x) { var w = e1(), v = e2(), c = v - x; return (w = x) - c; }
function f8(x) { var w = e1(), v = e2(); return (w = x) - (v - x); } function f8(x) { var w = e1(), v = e2(); return (w = x) - (v - x); }
function f9(x) { var w = e1(); return e2() - x - (w = x); } function f9(x) { var w = e1(); return e2() - x - (w = x); }
}
}
collapse_vars_lvalues_drop_assign: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
}
input: {
function f0(x) { var i = ++x; return x += i; }
function f1(x) { var a = (x -= 3); return x += a; }
function f2(x) { var z = x, a = ++z; return z += a; }
function f3(x) { var a = (x -= 3), b = x + a; return b; }
function f4(x) { var a = (x -= 3); return x + a; }
function f5(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return b - c; }
function f6(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return c - b; }
function f7(x) { var w = e1(), v = e2(), c = v - x, b = w = x; return b - c; }
function f8(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return b - c; }
function f9(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return c - b; }
}
expect: {
function f0(x) { var i = ++x; return x += i; }
function f1(x) { var a = (x -= 3); return x += a; }
function f2(x) { var z = x, a = ++z; return z += a; }
function f3(x) { var a = (x -= 3); return x + a; }
function f4(x) { var a = (x -= 3); return x + a; }
function f5(x) { var v = (e1(), e2()), c = v = --x; return x - c; }
function f6(x) { e1(), e2(); return --x - x; }
function f7(x) { var v = (e1(), e2()), c = v - x; return x - c; }
function f8(x) { var v = (e1(), e2()); return x - (v - x); }
function f9(x) { e1(); return e2() - x - x; }
} }
} }

View File

@@ -24,3 +24,143 @@ concat_1: {
var f = "\x00360\08\0"; var f = "\x00360\08\0";
} }
} }
concat_2: {
options = {};
input: {
console.log(
1 + (2 + 3),
1 + (2 + "3"),
1 + ("2" + 3),
1 + ("2" + "3"),
"1" + (2 + 3),
"1" + (2 + "3"),
"1" + ("2" + 3),
"1" + ("2" + "3")
);
}
expect: {
console.log(
1 + (2 + 3),
1 + (2 + "3"),
1 + "2" + 3,
1 + "2" + "3",
"1" + (2 + 3),
"1" + 2 + "3",
"1" + "2" + 3,
"1" + "2" + "3"
);
}
}
concat_3: {
options = {};
input: {
console.log(
1 + 2 + (3 + 4 + 5),
1 + 2 + (3 + 4 + "5"),
1 + 2 + (3 + "4" + 5),
1 + 2 + (3 + "4" + "5"),
1 + 2 + ("3" + 4 + 5),
1 + 2 + ("3" + 4 + "5"),
1 + 2 + ("3" + "4" + 5),
1 + 2 + ("3" + "4" + "5")
);
}
expect: {
console.log(
1 + 2 + (3 + 4 + 5),
1 + 2 + (3 + 4 + "5"),
1 + 2 + (3 + "4") + 5,
1 + 2 + (3 + "4") + "5",
1 + 2 + "3" + 4 + 5,
1 + 2 + "3" + 4 + "5",
1 + 2 + "3" + "4" + 5,
1 + 2 + "3" + "4" + "5"
);
}
}
concat_4: {
options = {};
input: {
console.log(
1 + "2" + (3 + 4 + 5),
1 + "2" + (3 + 4 + "5"),
1 + "2" + (3 + "4" + 5),
1 + "2" + (3 + "4" + "5"),
1 + "2" + ("3" + 4 + 5),
1 + "2" + ("3" + 4 + "5"),
1 + "2" + ("3" + "4" + 5),
1 + "2" + ("3" + "4" + "5")
);
}
expect: {
console.log(
1 + "2" + (3 + 4 + 5),
1 + "2" + (3 + 4) + "5",
1 + "2" + 3 + "4" + 5,
1 + "2" + 3 + "4" + "5",
1 + "2" + "3" + 4 + 5,
1 + "2" + "3" + 4 + "5",
1 + "2" + "3" + "4" + 5,
1 + "2" + "3" + "4" + "5"
);
}
}
concat_5: {
options = {};
input: {
console.log(
"1" + 2 + (3 + 4 + 5),
"1" + 2 + (3 + 4 + "5"),
"1" + 2 + (3 + "4" + 5),
"1" + 2 + (3 + "4" + "5"),
"1" + 2 + ("3" + 4 + 5),
"1" + 2 + ("3" + 4 + "5"),
"1" + 2 + ("3" + "4" + 5),
"1" + 2 + ("3" + "4" + "5")
);
}
expect: {
console.log(
"1" + 2 + (3 + 4 + 5),
"1" + 2 + (3 + 4) + "5",
"1" + 2 + 3 + "4" + 5,
"1" + 2 + 3 + "4" + "5",
"1" + 2 + "3" + 4 + 5,
"1" + 2 + "3" + 4 + "5",
"1" + 2 + "3" + "4" + 5,
"1" + 2 + "3" + "4" + "5"
);
}
}
concat_6: {
options = {};
input: {
console.log(
"1" + "2" + (3 + 4 + 5),
"1" + "2" + (3 + 4 + "5"),
"1" + "2" + (3 + "4" + 5),
"1" + "2" + (3 + "4" + "5"),
"1" + "2" + ("3" + 4 + 5),
"1" + "2" + ("3" + 4 + "5"),
"1" + "2" + ("3" + "4" + 5),
"1" + "2" + ("3" + "4" + "5")
);
}
expect: {
console.log(
"1" + "2" + (3 + 4 + 5),
"1" + "2" + (3 + 4) + "5",
"1" + "2" + 3 + "4" + 5,
"1" + "2" + 3 + "4" + "5",
"1" + "2" + "3" + 4 + 5,
"1" + "2" + "3" + 4 + "5",
"1" + "2" + "3" + "4" + 5,
"1" + "2" + "3" + "4" + "5"
);
}
}

165
test/compress/const.js Normal file
View File

@@ -0,0 +1,165 @@
issue_1191: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function foo(rot) {
const rotTol = 5;
if (rot < -rotTol || rot > rotTol)
bar();
baz();
}
}
expect: {
function foo(rot) {
(rot < -5 || rot > 5) && bar();
baz();
}
}
}
issue_1194: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function f1() {const a = "X"; return a + a;}
function f2() {const aa = "X"; return aa + aa;}
function f3() {const aaa = "X"; return aaa + aaa;}
}
expect: {
function f1(){return"XX"}
function f2(){return"XX"}
function f3(){return"XX"}
}
}
issue_1396: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function foo(a) {
const VALUE = 1;
console.log(2 | VALUE);
console.log(VALUE + 1);
console.log(VALUE);
console.log(a & VALUE);
}
function bar() {
const s = "01234567890123456789";
console.log(s + s + s + s + s);
const CONSTANT = "abc";
console.log(CONSTANT + CONSTANT + CONSTANT + CONSTANT + CONSTANT);
}
}
expect: {
function foo(a) {
console.log(3);
console.log(2);
console.log(1);
console.log(1 & a);
}
function bar() {
const s = "01234567890123456789";
console.log(s + s + s + s + s);
console.log("abcabcabcabcabc");
}
}
}
unused_regexp_literal: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
}
input: {
function f(){ var a = /b/; }
}
expect: {
function f(){}
}
}
regexp_literal_not_const: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
(function(){
var result;
const s = 'acdabcdeabbb';
const REGEXP_LITERAL = /ab*/g;
while (result = REGEXP_LITERAL.exec(s)) {
console.log(result[0]);
}
})();
}
expect: {
(function() {
var result;
const REGEXP_LITERAL = /ab*/g;
while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]);
})();
}
}

View File

@@ -1,206 +1,208 @@
dead_code_1: { dead_code_1: {
options = { options = {
dead_code: true dead_code: true
}; };
input: { input: {
function f() { function f() {
a(); a();
b(); b();
x = 10; x = 10;
return; return;
if (x) { if (x) {
y(); y();
} }
} }
} }
expect: { expect: {
function f() { function f() {
a(); a();
b(); b();
x = 10; x = 10;
return; return;
} }
} }
} }
dead_code_2_should_warn: { dead_code_2_should_warn: {
options = { options = {
dead_code: true dead_code: true
}; };
input: { input: {
function f() { function f() {
g(); g();
x = 10; x = 10;
throw "foo"; throw "foo";
// completely discarding the `if` would introduce some // completely discarding the `if` would introduce some
// bugs. UglifyJS v1 doesn't deal with this issue; in v2 // bugs. UglifyJS v1 doesn't deal with this issue; in v2
// we copy any declarations to the upper scope. // we copy any declarations to the upper scope.
if (x) { if (x) {
y(); y();
var x; var x;
function g(){}; function g(){};
// but nested declarations should not be kept. // but nested declarations should not be kept.
(function(){ (function(){
var q; var q;
function y(){}; function y(){};
})(); })();
} }
} }
} }
expect: { expect: {
function f() { function f() {
g(); g();
x = 10; x = 10;
throw "foo"; throw "foo";
var x; var x;
function g(){}; function g(){};
} }
} }
} }
dead_code_constant_boolean_should_warn_more: { dead_code_constant_boolean_should_warn_more: {
options = { options = {
dead_code : true, dead_code : true,
loops : true, loops : true,
booleans : true, booleans : true,
conditionals : true, conditionals : true,
evaluate : true evaluate : true
}; };
input: { input: {
while (!((foo && bar) || (x + "0"))) { while (!((foo && bar) || (x + "0"))) {
console.log("unreachable"); console.log("unreachable");
var foo; var foo;
function bar() {} function bar() {}
} }
for (var x = 10, y; x && (y || x) && (!typeof x); ++x) { for (var x = 10, y; x && (y || x) && (!typeof x); ++x) {
asdf(); asdf();
foo(); foo();
var moo; var moo;
} }
} }
expect: { expect: {
var foo; var foo;
function bar() {} function bar() {}
// nothing for the while // nothing for the while
// as for the for, it should keep: // as for the for, it should keep:
var x = 10, y; var x = 10, y;
var moo; var moo;
} }
} }
dead_code_const_declaration: { dead_code_const_declaration: {
options = { options = {
dead_code : true, dead_code : true,
loops : true, loops : true,
booleans : true, booleans : true,
conditionals : true, conditionals : true,
evaluate : true evaluate : true,
}; reduce_vars : true,
input: { };
var unused; input: {
const CONST_FOO = false; var unused;
if (CONST_FOO) { const CONST_FOO = false;
console.log("unreachable"); if (CONST_FOO) {
var moo; console.log("unreachable");
function bar() {} var moo;
} function bar() {}
} }
expect: { }
var unused; expect: {
const CONST_FOO = !1; var unused;
var moo; const CONST_FOO = !1;
function bar() {} var moo;
} function bar() {}
} }
}
dead_code_const_annotation: {
options = { dead_code_const_annotation: {
dead_code : true, options = {
loops : true, dead_code : true,
booleans : true, loops : true,
conditionals : true, booleans : true,
evaluate : true conditionals : true,
}; evaluate : true,
input: { reduce_vars : true,
var unused; };
/** @const */ var CONST_FOO_ANN = false; input: {
if (CONST_FOO_ANN) { var unused;
console.log("unreachable"); /** @const */ var CONST_FOO_ANN = false;
var moo; if (CONST_FOO_ANN) {
function bar() {} console.log("unreachable");
} var moo;
} function bar() {}
expect: { }
var unused; }
var CONST_FOO_ANN = !1; expect: {
var moo; var unused;
function bar() {} var CONST_FOO_ANN = !1;
} var moo;
} function bar() {}
}
dead_code_const_annotation_regex: { }
options = {
dead_code : true, dead_code_const_annotation_regex: {
loops : true, options = {
booleans : true, dead_code : true,
conditionals : true, loops : true,
evaluate : true booleans : true,
}; conditionals : true,
input: { evaluate : true
var unused; };
// @constraint this shouldn't be a constant input: {
var CONST_FOO_ANN = false; var unused;
if (CONST_FOO_ANN) { // @constraint this shouldn't be a constant
console.log("reachable"); var CONST_FOO_ANN = false;
} if (CONST_FOO_ANN) {
} console.log("reachable");
expect: { }
var unused; }
var CONST_FOO_ANN = !1; expect: {
CONST_FOO_ANN && console.log('reachable'); var unused;
} var CONST_FOO_ANN = !1;
} CONST_FOO_ANN && console.log('reachable');
}
dead_code_const_annotation_complex_scope: { }
options = {
dead_code : true, dead_code_const_annotation_complex_scope: {
loops : true, options = {
booleans : true, dead_code : true,
conditionals : true, loops : true,
evaluate : true booleans : true,
}; conditionals : true,
input: { evaluate : true,
var unused_var; reduce_vars : true,
/** @const */ var test = 'test'; };
// @const input: {
var CONST_FOO_ANN = false; var unused_var;
var unused_var_2; /** @const */ var test = 'test';
if (CONST_FOO_ANN) { // @const
console.log("unreachable"); var CONST_FOO_ANN = false;
var moo; var unused_var_2;
function bar() {} if (CONST_FOO_ANN) {
} console.log("unreachable");
if (test === 'test') { var moo;
var beef = 'good'; function bar() {}
/** @const */ var meat = 'beef'; }
var pork = 'bad'; if (test === 'test') {
if (meat === 'pork') { var beef = 'good';
console.log('also unreachable'); /** @const */ var meat = 'beef';
} else if (pork === 'good') { var pork = 'bad';
console.log('reached, not const'); if (meat === 'pork') {
} console.log('also unreachable');
} } else if (pork === 'good') {
} console.log('reached, not const');
expect: { }
var unused_var; }
var test = 'test'; }
var CONST_FOO_ANN = !1; expect: {
var unused_var_2; var unused_var;
var moo; var test = 'test';
function bar() {} var CONST_FOO_ANN = !1;
var beef = 'good'; var unused_var_2;
var meat = 'beef'; var moo;
var pork = 'bad'; function bar() {}
'good' === pork && console.log('reached, not const'); var beef = 'good';
} var meat = 'beef';
} var pork = 'bad';
}
}

View File

@@ -1,24 +1,24 @@
drop_console_1: { drop_console_1: {
options = {}; options = {};
input: { input: {
console.log('foo'); console.log('foo');
console.log.apply(console, arguments); console.log.apply(console, arguments);
} }
expect: { expect: {
console.log('foo'); console.log('foo');
console.log.apply(console, arguments); console.log.apply(console, arguments);
} }
} }
drop_console_1: { drop_console_2: {
options = { drop_console: true }; options = { drop_console: true };
input: { input: {
console.log('foo'); console.log('foo');
console.log.apply(console, arguments); console.log.apply(console, arguments);
} }
expect: { expect: {
// with regular compression these will be stripped out as well // with regular compression these will be stripped out as well
void 0; void 0;
void 0; void 0;
} }
} }

View File

@@ -177,3 +177,505 @@ keep_fnames: {
} }
} }
} }
drop_assign: {
options = { unused: true };
input: {
function f1() {
var a;
a = 1;
}
function f2() {
var a = 1;
a = 2;
}
function f3(a) {
a = 1;
}
function f4() {
var a;
return a = 1;
}
function f5() {
var a;
return function() {
a = 1;
}
}
}
expect: {
function f1() {
1;
}
function f2() {
2;
}
function f3(a) {
1;
}
function f4() {
return 1;
}
function f5() {
var a;
return function() {
a = 1;
}
}
}
}
keep_assign: {
options = { unused: "keep_assign" };
input: {
function f1() {
var a;
a = 1;
}
function f2() {
var a = 1;
a = 2;
}
function f3(a) {
a = 1;
}
function f4() {
var a;
return a = 1;
}
function f5() {
var a;
return function() {
a = 1;
}
}
}
expect: {
function f1() {
var a;
a = 1;
}
function f2() {
var a = 1;
a = 2;
}
function f3(a) {
a = 1;
}
function f4() {
var a;
return a = 1;
}
function f5() {
var a;
return function() {
a = 1;
}
}
}
}
drop_toplevel_funcs: {
options = { toplevel: "funcs", unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var a, b = 1, c = g;
a = 2;
function g() {}
console.log(b = 3);
}
}
drop_toplevel_vars: {
options = { toplevel: "vars", unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var c = g;
function f(d) {
return function() {
c = 2;
}
}
2;
function g() {}
function h() {}
console.log(3);
}
}
drop_toplevel_vars_fargs: {
options = { keep_fargs: false, toplevel: "vars", unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var c = g;
function f() {
return function() {
c = 2;
}
}
2;
function g() {}
function h() {}
console.log(3);
}
}
drop_toplevel_all: {
options = { toplevel: true, unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
2;
console.log(3);
}
}
drop_toplevel_retain: {
options = { top_retain: "f,a,o", unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var a, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
console.log(3);
}
}
drop_toplevel_retain_array: {
options = { top_retain: [ "f", "a", "o" ], unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var a, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
console.log(3);
}
}
drop_toplevel_retain_regex: {
options = { top_retain: /^[fao]$/, unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var a, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
console.log(3);
}
}
drop_toplevel_all_retain: {
options = { toplevel: true, top_retain: "f,a,o", unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var a, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
console.log(3);
}
}
drop_toplevel_funcs_retain: {
options = { toplevel: "funcs", top_retain: "f,a,o", unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
console.log(b = 3);
}
}
drop_toplevel_vars_retain: {
options = { toplevel: "vars", top_retain: "f,a,o", unused: true };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var a, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(3);
}
}
drop_toplevel_keep_assign: {
options = { toplevel: true, unused: "keep_assign" };
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
}
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
var a, b = 1;
a = 2;
console.log(b = 3);
}
}
drop_fargs: {
options = {
keep_fargs: false,
unused: true,
}
input: {
function f(a) {
var b = a;
}
}
expect: {
function f() {}
}
}
drop_fnames: {
options = {
keep_fnames: false,
unused: true,
}
input: {
function f() {
return function g() {
var a = g;
};
}
}
expect: {
function f() {
return function() {};
}
}
}
global_var: {
options = {
side_effects: true,
unused: true,
}
input: {
var a;
function foo(b) {
a;
b;
c;
typeof c === "undefined";
c + b + a;
b && b.ar();
return b;
}
}
expect: {
var a;
function foo(b) {
c;
c;
b && b.ar();
return b;
}
}
}
iife: {
options = {
side_effects: true,
unused: true,
}
input: {
function f() {
var a;
~function() {}(b);
}
}
expect: {
function f() {
~function() {}(b);
}
}
}
drop_value: {
options = {
side_effects: true,
}
input: {
(1, [2, foo()], 3, {a:1, b:bar()});
}
expect: {
foo(), bar();
}
}
const_assign: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
const b = 2;
return 1 + b;
}
function g() {
const b = 2;
b = 3;
return 1 + b;
}
}
expect: {
function f() {
return 3;
}
function g() {
const b = 2;
b = 3;
return 1 + b;
}
}
}

View File

@@ -598,3 +598,51 @@ unsafe_prototype_function: {
var h = "" + ({toString: 0}); var h = "" + ({toString: 0});
} }
} }
call_args: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
const a = 1;
console.log(a);
+function(a) {
return a;
}(a);
}
expect: {
const a = 1;
console.log(1);
+function(a) {
return a;
}(1);
}
}
in_boolean_context: {
options = {
booleans: true,
evaluate: true,
}
input: {
!42;
!"foo";
![1, 2];
!/foo/;
!b(42);
!b("foo");
!b([1, 2]);
!b(/foo/);
}
expect: {
!1;
!1;
!1;
!1;
!b(42);
!b("foo");
!b([1, 2]);
!b(/foo/);
}
}

View File

@@ -0,0 +1,147 @@
must_replace: {
options = {
global_defs: {
D: "foo bar",
}
}
input: {
console.log(D);
}
expect: {
console.log("foo bar");
}
}
keyword: {
options = {
global_defs: {
undefined: 0,
NaN: 1,
Infinity: 2,
},
}
input: {
console.log(undefined, NaN, Infinity);
}
expect: {
console.log(0, 1, 2);
}
}
object: {
options = {
evaluate: true,
global_defs: {
CONFIG: {
DEBUG: [ 0 ],
VALUE: 42,
},
},
unsafe: true,
}
input: {
function f(CONFIG) {
// CONFIG not global - do not replace
return CONFIG.VALUE;
}
function g() {
var CONFIG = { VALUE: 1 };
// CONFIG not global - do not replace
return CONFIG.VALUE;
}
function h() {
return CONFIG.VALUE;
}
if (CONFIG.DEBUG[0])
console.debug("foo");
}
expect: {
function f(CONFIG) {
return CONFIG.VALUE;
}
function g() {
var CONFIG = { VALUE: 1 };
return CONFIG.VALUE;
}
function h() {
return 42;
}
if (0)
console.debug("foo");
}
}
expanded: {
options = {
global_defs: {
"CONFIG.DEBUG": [ 0 ],
"CONFIG.VALUE": 42,
},
}
input: {
function f(CONFIG) {
// CONFIG not global - do not replace
return CONFIG.VALUE;
}
function g() {
var CONFIG = { VALUE: 1 };
// CONFIG not global - do not replace
return CONFIG.VALUE;
}
function h() {
return CONFIG.VALUE;
}
if (CONFIG.DEBUG[0])
console.debug("foo");
}
expect: {
function f(CONFIG) {
return CONFIG.VALUE;
}
function g() {
var CONFIG = { VALUE: 1 };
return CONFIG.VALUE;
}
function h() {
return 42;
}
if ([0][0])
console.debug("foo");
}
}
mixed: {
options = {
evaluate: true,
global_defs: {
"CONFIG.VALUE": 42,
"FOO.BAR": "moo",
},
properties: true,
}
input: {
const FOO = { BAR: 0 };
console.log(FOO.BAR);
console.log(++CONFIG.DEBUG);
console.log(++CONFIG.VALUE);
console.log(++CONFIG["VAL" + "UE"]);
console.log(++DEBUG[CONFIG.VALUE]);
CONFIG.VALUE.FOO = "bar";
console.log(CONFIG);
}
expect: {
const FOO = { BAR: 0 };
console.log("moo");
console.log(++CONFIG.DEBUG);
console.log(++CONFIG.VALUE);
console.log(++CONFIG.VALUE);
console.log(++DEBUG[42]);
CONFIG.VALUE.FOO = "bar";
console.log(CONFIG);
}
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:129,8]',
]
}

View File

@@ -0,0 +1,90 @@
statements: {
options = {
hoist_funs: false,
hoist_vars: true,
}
input: {
function f() {
var a = 1;
var b = 2;
var c = 3;
function g() {}
return g(a, b, c);
}
}
expect: {
function f() {
var a = 1, b = 2, c = 3;
function g() {}
return g(a, b, c);
}
}
}
statements_funs: {
options = {
hoist_funs: true,
hoist_vars: true,
}
input: {
function f() {
var a = 1;
var b = 2;
var c = 3;
function g() {}
return g(a, b, c);
}
}
expect: {
function f() {
function g() {}
var a = 1, b = 2, c = 3;
return g(a, b, c);
}
}
}
sequences: {
options = {
hoist_funs: false,
hoist_vars: true,
}
input: {
function f() {
var a = 1, b = 2;
function g() {}
var c = 3;
return g(a, b, c);
}
}
expect: {
function f() {
var c, a = 1, b = 2;
function g() {}
c = 3;
return g(a, b, c);
}
}
}
sequences_funs: {
options = {
hoist_funs: true,
hoist_vars: true,
}
input: {
function f() {
var a = 1, b = 2;
function g() {}
var c = 3;
return g(a, b, c);
}
}
expect: {
function f() {
function g() {}
var a = 1, b = 2, c = 3;
return g(a, b, c);
}
}
}

View File

@@ -170,8 +170,51 @@ if_return_7: {
} }
} }
expect: { expect: {
// suboptimal function f(x){if(x)return!0;foo(),bar()}
function f(x){return!!x||(foo(),void bar())} }
}
if_return_8: {
options = {
if_return: true,
sequences: true,
conditionals: true,
side_effects : true,
}
input: {
function f(e) {
if (2 == e) return foo();
if (3 == e) return bar();
if (4 == e) return baz();
fail(e);
}
function g(e) {
if (a(e)) return foo();
if (b(e)) return bar();
if (c(e)) return baz();
fail(e);
}
function h(e) {
if (a(e)) return foo();
else if (b(e)) return bar();
else if (c(e)) return baz();
else fail(e);
}
function i(e) {
if (a(e)) return foo();
else if (b(e)) return bar();
else if (c(e)) return baz();
fail(e);
}
}
expect: {
function f(e){return 2==e?foo():3==e?bar():4==e?baz():void fail(e)}
function g(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)}
function h(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)}
function i(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)}
} }
} }
@@ -205,3 +248,57 @@ issue_1089: {
} }
} }
} }
issue_1437: {
options = {
if_return : true,
sequences : true,
conditionals : false
}
input: {
function x() {
if (a())
return b();
if (c())
return d();
else
e();
f();
}
}
expect: {
function x() {
if (a())
return b();
if (c())
return d();
else
e()
f();
}
}
}
issue_1437_conditionals: {
options = {
conditionals : true,
if_return : true,
sequences : true
}
input: {
function x() {
if (a())
return b();
if (c())
return d();
else
e();
f();
}
}
expect: {
function x() {
return a() ? b() : c() ? d() : (e(), f(), void 0);
}
}
}

View File

@@ -13,7 +13,8 @@ const_declaration: {
const_pragma: { const_pragma: {
options = { options = {
evaluate: true evaluate: true,
reduce_vars: true,
}; };
input: { input: {
@@ -27,7 +28,8 @@ const_pragma: {
// for completeness' sake // for completeness' sake
not_const: { not_const: {
options = { options = {
evaluate: true evaluate: true,
reduce_vars: true,
}; };
input: { input: {

View File

@@ -1,25 +0,0 @@
typeof_eq_undefined: {
options = {
comparisons: true
};
input: { a = typeof b.c != "undefined" }
expect: { a = "undefined" != typeof b.c }
}
typeof_eq_undefined_unsafe: {
options = {
comparisons: true,
unsafe: true
};
input: { a = typeof b.c != "undefined" }
expect: { a = void 0 !== b.c }
}
typeof_eq_undefined_unsafe2: {
options = {
comparisons: true,
unsafe: true
};
input: { a = "undefined" != typeof b.c }
expect: { a = void 0 !== b.c }
}

118
test/compress/issue-1261.js Normal file
View File

@@ -0,0 +1,118 @@
pure_function_calls: {
options = {
evaluate : true,
conditionals : true,
comparisons : true,
side_effects : true,
booleans : true,
unused : true,
if_return : true,
join_vars : true,
cascade : true,
negate_iife : true,
}
input: {
// pure top-level IIFE will be dropped
// @__PURE__ - comment
(function() {
console.log("iife0");
})();
// pure top-level IIFE assigned to unreferenced var will not be dropped
var iife1 = /*@__PURE__*/(function() {
console.log("iife1");
function iife1() {}
return iife1;
})();
(function(){
// pure IIFE in function scope assigned to unreferenced var will be dropped
var iife2 = /*#__PURE__*/(function() {
console.log("iife2");
function iife2() {}
return iife2;
})();
})();
// comment #__PURE__ comment
bar(), baz(), quux();
a.b(), /* @__PURE__ */ c.d.e(), f.g();
}
expect: {
var iife1 = function() {
console.log("iife1");
function iife1() {}
return iife1;
}();
baz(), quux();
a.b(), f.g();
}
expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:17,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:17,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:30,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:30,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:28,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:39,31]",
]
}
pure_function_calls_toplevel: {
options = {
evaluate : true,
conditionals : true,
comparisons : true,
side_effects : true,
booleans : true,
unused : true,
if_return : true,
join_vars : true,
cascade : true,
negate_iife : true,
toplevel : true,
}
input: {
// pure top-level IIFE will be dropped
// @__PURE__ - comment
(function() {
console.log("iife0");
})();
// pure top-level IIFE assigned to unreferenced var will be dropped
var iife1 = /*@__PURE__*/(function() {
console.log("iife1");
function iife1() {}
return iife1;
})();
(function(){
// pure IIFE in function scope assigned to unreferenced var will be dropped
var iife2 = /*#__PURE__*/(function() {
console.log("iife2");
function iife2() {}
return iife2;
})();
})();
// comment #__PURE__ comment
bar(), baz(), quux();
a.b(), /* @__PURE__ */ c.d.e(), f.g();
}
expect: {
baz(), quux();
a.b(), f.g();
}
expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:79,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:79,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
]
}

View File

@@ -1,3 +1,32 @@
level_zero: {
options = {
keep_fnames: true
}
mangle = {
keep_fnames: true
}
input: {
function f(x) {
function n(a) {
return a * a;
}
return function() {
return x;
};
}
}
expect: {
function f(r) {
function n(n) {
return n * n;
}
return function() {
return r;
};
}
}
}
level_one: { level_one: {
options = { options = {
keep_fnames: true keep_fnames: true

View File

@@ -0,0 +1,69 @@
// tests assume that variable `undefined` not redefined and has `void 0` as value
unsafe_undefined: {
options = {
if_return: true,
unsafe: true
}
mangle = {}
input: {
function f(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}
}
expect: {
function f(n) {
return function() {
if (a)
return b;
if (c)
return d;
else
return n;
};
}
}
}
keep_fnames: {
options = {
if_return: true,
unsafe: true
}
mangle = {
keep_fnames: true
}
input: {
function f(undefined) {
return function() {
function n(a) {
return a * a;
}
if (a)
return b;
if (c)
return d;
};
}
}
expect: {
function f(r) {
return function() {
function n(n) {
return n * n;
}
if (a)
return b;
if (c)
return d;
else
return r;
};
}
}
}

View File

@@ -0,0 +1,71 @@
typeof_eq_undefined: {
options = {
comparisons: true
}
input: {
var a = typeof b != "undefined";
b = typeof a != "undefined";
var c = typeof d.e !== "undefined";
var f = "undefined" === typeof g;
g = "undefined" === typeof f;
var h = "undefined" == typeof i.j;
}
expect: {
var a = "undefined" != typeof b;
b = void 0 !== a;
var c = void 0 !== d.e;
var f = "undefined" == typeof g;
g = void 0 === f;
var h = void 0 === i.j;
}
}
typeof_eq_undefined_ie8: {
options = {
comparisons: true,
screw_ie8: false
}
input: {
var a = typeof b != "undefined";
b = typeof a != "undefined";
var c = typeof d.e !== "undefined";
var f = "undefined" === typeof g;
g = "undefined" === typeof f;
var h = "undefined" == typeof i.j;
}
expect: {
var a = "undefined" != typeof b;
b = void 0 !== a;
var c = "undefined" != typeof d.e;
var f = "undefined" == typeof g;
g = void 0 === f;
var h = "undefined" == typeof i.j;
}
}
undefined_redefined: {
options = {
comparisons: true
}
input: {
function f(undefined) {
var n = 1;
return typeof n == "undefined";
}
}
expect_exact: "function f(undefined){var n=1;return void 0===n}"
}
undefined_redefined_mangle: {
options = {
comparisons: true
}
mangle = {}
input: {
function f(undefined) {
var n = 1;
return typeof n == "undefined";
}
}
expect_exact: "function f(n){var r=1;return void 0===r}"
}

View File

@@ -0,0 +1,45 @@
else_with_empty_block: {
options = {}
input: {
if (x)
yes();
else {
}
}
expect_exact: "if(x)yes();"
}
else_with_empty_statement: {
options = {}
input: {
if (x)
yes();
else
;
}
expect_exact: "if(x)yes();"
}
conditional_false_stray_else_in_loop: {
options = {
evaluate : true,
comparisons : true,
booleans : true,
unused : true,
loops : true,
side_effects : true,
dead_code : true,
hoist_vars : true,
join_vars : true,
if_return : true,
cascade : true,
conditionals : false,
}
input: {
for (var i = 1; i <= 4; ++i) {
if (i <= 2) continue;
console.log(i);
}
}
expect_exact: "for(var i=1;i<=4;++i)if(!(i<=2))console.log(i);"
}

View File

@@ -27,3 +27,44 @@ do_update_rhs: {
MY_DEBUG += 0; MY_DEBUG += 0;
} }
} }
mixed: {
options = {
evaluate: true,
global_defs: {
DEBUG: 0,
ENV: 1,
FOO: 2,
}
}
input: {
const ENV = 3;
var FOO = 4;
f(ENV * 10);
--FOO;
DEBUG = 1;
DEBUG++;
DEBUG += 1;
f(DEBUG);
x = DEBUG;
}
expect: {
const ENV = 3;
var FOO = 4;
f(10);
--FOO;
DEBUG = 1;
DEBUG++;
DEBUG += 1;
f(0);
x = 0;
}
expect_warnings: [
'WARN: global_defs ENV redefined [test/compress/issue-208.js:41,14]',
'WARN: global_defs FOO redefined [test/compress/issue-208.js:42,12]',
'WARN: global_defs FOO redefined [test/compress/issue-208.js:44,10]',
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:45,8]',
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:46,8]',
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:47,8]',
]
}

View File

@@ -82,7 +82,7 @@ issue979_test_negated_is_best: {
1!=a||2!=b||foo(); 1!=a||2!=b||foo();
} }
function f7() { function f7() {
return 1!=a&&2!=b?bar():void foo(); if(1!=a&&2!=b)return bar();foo()
} }
} }
} }

View File

@@ -187,3 +187,32 @@ keep_collapse_const_in_own_block_scope_2: {
console.log(c); console.log(c);
} }
} }
evaluate: {
options = {
loops: true,
dead_code: true,
evaluate: true,
};
input: {
while (true) {
a();
}
while (false) {
b();
}
do {
c();
} while (true);
do {
d();
} while (false);
}
expect: {
for(;;)
a();
for(;;)
c();
d();
}
}

View File

@@ -0,0 +1,28 @@
too_short: {
beautify = {
max_line_len: 10,
}
input: {
function f(a) {
return { c: 42, d: a(), e: "foo"};
}
}
expect_exact: 'function f(a){\nreturn{\nc:42,\nd:a(),\ne:"foo"}}'
expect_warnings: [
"WARN: Output exceeds 10 characters"
]
}
just_enough: {
beautify = {
max_line_len: 14,
}
input: {
function f(a) {
return { c: 42, d: a(), e: "foo"};
}
}
expect_exact: 'function f(a){\nreturn{c:42,\nd:a(),e:"foo"}\n}'
expect_warnings: [
]
}

View File

@@ -10,6 +10,16 @@ negate_iife_1: {
} }
} }
negate_iife_1_off: {
options = {
negate_iife: false,
};
input: {
(function(){ stuff() })();
}
expect_exact: '(function(){stuff()})();'
}
negate_iife_2: { negate_iife_2: {
options = { options = {
negate_iife: true negate_iife: true
@@ -25,6 +35,7 @@ negate_iife_2: {
negate_iife_3: { negate_iife_3: {
options = { options = {
negate_iife: true, negate_iife: true,
conditionals: true
}; };
input: { input: {
(function(){ return true })() ? console.log(true) : console.log(false); (function(){ return true })() ? console.log(true) : console.log(false);
@@ -34,9 +45,23 @@ negate_iife_3: {
} }
} }
negate_iife_3: { negate_iife_3_off: {
options = {
negate_iife: false,
conditionals: true,
};
input: {
(function(){ return true })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return true }() ? console.log(false) : console.log(true);
}
}
negate_iife_4: {
options = { options = {
negate_iife: true, negate_iife: true,
conditionals: true,
sequences: true sequences: true
}; };
input: { input: {
@@ -52,7 +77,42 @@ negate_iife_3: {
} }
} }
negate_iife_4: { sequence_off: {
options = {
negate_iife: false,
conditionals: true,
sequences: true,
passes: 2,
};
input: {
function f() {
(function(){ return true })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
}
function g() {
(function(){
console.log("something");
})();
(function(){ return true })() ? console.log(true) : console.log(false);
}
}
expect: {
function f() {
!function(){ return true }() ? console.log(false) : console.log(true), function(){
console.log("something");
}();
}
function g() {
(function(){
console.log("something");
})(), function(){ return true }() ? console.log(true) : console.log(false);
}
}
}
negate_iife_5: {
options = { options = {
negate_iife: true, negate_iife: true,
sequences: true, sequences: true,
@@ -75,6 +135,29 @@ negate_iife_4: {
} }
} }
negate_iife_5_off: {
options = {
negate_iife: false,
sequences: true,
conditionals: true,
};
input: {
if ((function(){ return true })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
!function(){ return true }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}
}
negate_iife_nested: { negate_iife_nested: {
options = { options = {
negate_iife: true, negate_iife: true,
@@ -107,6 +190,38 @@ negate_iife_nested: {
} }
} }
negate_iife_nested_off: {
options = {
negate_iife: false,
sequences: true,
conditionals: true,
};
input: {
function Foo(f) {
this.f = f;
}
new Foo(function() {
(function(x) {
(function(y) {
console.log(y);
})(x);
})(7);
}).f();
}
expect: {
function Foo(f) {
this.f = f;
}
new Foo(function() {
(function(x) {
(function(y) {
console.log(y);
})(x);
})(7);
}).f();
}
}
negate_iife_issue_1073: { negate_iife_issue_1073: {
options = { options = {
negate_iife: true, negate_iife: true,
@@ -172,3 +287,36 @@ issue_1254_negate_iife_nested: {
} }
expect_exact: '!function(){return function(){console.log("test")}}()()()()();' expect_exact: '!function(){return function(){console.log("test")}}()()()()();'
} }
issue_1288: {
options = {
negate_iife: true,
conditionals: true,
};
input: {
if (w) ;
else {
(function f() {})();
}
if (!x) {
(function() {
x = {};
})();
}
if (y)
(function() {})();
else
(function(z) {
return z;
})(0);
}
expect: {
w || function f() {}();
x || function() {
x = {};
}();
y ? function() {}() : function(z) {
return z;
}(0);
}
}

View File

@@ -539,3 +539,19 @@ first_256_hex_chars_as_properties: {
}; };
} }
} }
native_prototype: {
options = {
unsafe_proto: true,
}
input: {
Array.prototype.splice.apply(a, [1, 2, b, c]);
Object.prototype.hasOwnProperty.call(d, "foo");
String.prototype.indexOf.call(e, "bar");
}
expect: {
[].splice.apply(a, [1, 2, b, c]);
({}).hasOwnProperty.call(d, "foo");
"".indexOf.call(e, "bar");
}
}

295
test/compress/pure_funcs.js Normal file
View File

@@ -0,0 +1,295 @@
array: {
options = {
pure_funcs: [ "Math.floor" ],
side_effects: true,
}
input: {
var a;
function f(b) {
Math.floor(a / b);
Math.floor(c / b);
}
}
expect: {
var a;
function f(b) {
c;
}
}
}
func: {
options = {
pure_funcs: function(node) {
return !~node.args[0].print_to_string().indexOf("a");
},
side_effects: true,
}
input: {
function f(a, b) {
Math.floor(a / b);
Math.floor(c / b);
}
}
expect: {
function f(a, b) {
Math.floor(c / b);
}
}
}
side_effects: {
options = {
pure_funcs: [ "console.log" ],
side_effects: true,
}
input: {
function f(a, b) {
console.log(a());
console.log(b);
}
}
expect: {
function f(a, b) {
a();
}
}
}
unused: {
options = {
pure_funcs: [ "pure" ],
side_effects: true,
unused: true,
}
input: {
function foo() {
var u = pure(1);
var x = pure(2);
var y = pure(x);
var z = pure(pure(side_effects()));
return pure(3);
}
}
expect: {
function foo() {
side_effects();
return pure(3);
}
}
}
babel: {
options = {
pure_funcs: [ "_classCallCheck" ],
side_effects: true,
unused: true,
}
input: {
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor))
throw new TypeError("Cannot call a class as a function");
}
var Foo = function Foo() {
_classCallCheck(this, Foo);
};
}
expect: {
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor))
throw new TypeError("Cannot call a class as a function");
}
var Foo = function() {
};
}
}
conditional: {
options = {
pure_funcs: [ "pure" ],
side_effects: true,
}
input: {
pure(1 | a() ? 2 & b() : 7 ^ c());
pure(1 | a() ? 2 & b() : 5);
pure(1 | a() ? 4 : 7 ^ c());
pure(1 | a() ? 4 : 5);
pure(3 ? 2 & b() : 7 ^ c());
pure(3 ? 2 & b() : 5);
pure(3 ? 4 : 7 ^ c());
pure(3 ? 4 : 5);
}
expect: {
1 | a() ? b() : c();
1 | a() && b();
1 | a() || c();
a();
3 ? b() : c();
3 && b();
3 || c();
}
}
relational: {
options = {
pure_funcs: [ "foo" ],
side_effects :true,
}
input: {
foo() in foo();
foo() instanceof bar();
foo() < "bar";
bar() > foo();
bar() != bar();
bar() !== "bar";
"bar" == foo();
"bar" === bar();
"bar" >= "bar";
}
expect: {
bar();
bar();
bar(), bar();
bar();
bar();
}
}
arithmetic: {
options = {
pure_funcs: [ "foo" ],
side_effects :true,
}
input: {
foo() + foo();
foo() - bar();
foo() * "bar";
bar() / foo();
bar() & bar();
bar() | "bar";
"bar" >> foo();
"bar" << bar();
"bar" >>> "bar";
}
expect: {
bar();
bar();
bar(), bar();
bar();
bar();
}
}
boolean_and: {
options = {
pure_funcs: [ "foo" ],
side_effects :true,
}
input: {
foo() && foo();
foo() && bar();
foo() && "bar";
bar() && foo();
bar() && bar();
bar() && "bar";
"bar" && foo();
"bar" && bar();
"bar" && "bar";
}
expect: {
foo() && bar();
bar();
bar() && bar();
bar();
"bar" && bar();
}
}
boolean_or: {
options = {
pure_funcs: [ "foo" ],
side_effects :true,
}
input: {
foo() || foo();
foo() || bar();
foo() || "bar";
bar() || foo();
bar() || bar();
bar() || "bar";
"bar" || foo();
"bar" || bar();
"bar" || "bar";
}
expect: {
foo() || bar();
bar();
bar() || bar();
bar();
"bar" || bar();
}
}
assign: {
options = {
pure_funcs: [ "foo" ],
side_effects :true,
}
input: {
var a;
function f(b) {
a = foo();
b *= 4 + foo();
c >>= 0 | foo();
}
}
expect: {
var a;
function f(b) {
a = foo();
b *= 4 + foo();
c >>= 0 | foo();
}
}
}
unary: {
options = {
pure_funcs: [ "foo" ],
side_effects :true,
}
input: {
typeof foo();
typeof bar();
typeof "bar";
void foo();
void bar();
void "bar";
delete a[foo()];
delete a[bar()];
delete a["bar"];
a[foo()]++;
a[bar()]++;
a["bar"]++;
--a[foo()];
--a[bar()];
--a["bar"];
~foo();
~bar();
~"bar";
}
expect: {
bar();
bar();
delete a[foo()];
delete a[bar()];
delete a["bar"];
a[foo()]++;
a[bar()]++;
a["bar"]++;
--a[foo()];
--a[bar()];
--a["bar"];
bar();
}
}

View File

@@ -108,8 +108,6 @@ modified: {
} }
console.log(a + b); console.log(a + b);
console.log(b + c); console.log(b + c);
// TODO: as "modified" is determined in "figure_out_scope",
// even "passes" wouldn't improve this any further
console.log(a + c); console.log(a + c);
console.log(a + b + c); console.log(a + b + c);
} }
@@ -350,3 +348,125 @@ unsafe_evaluate_equality: {
} }
} }
} }
passes: {
options = {
conditionals: true,
evaluate: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
function f() {
var a = 1, b = 2, c = 3;
if (a) {
b = c;
} else {
c = b;
}
console.log(a + b);
console.log(b + c);
console.log(a + c);
console.log(a + b + c);
}
}
expect: {
function f() {
var b = 2, c = 3;
b = c;
console.log(1 + b);
console.log(b + 3);
console.log(4);
console.log(1 + b + 3);
}
}
}
iife: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
!function(a, b, c) {
b++;
console.log(a - 1, b * 1, c + 2);
}(1, 2, 3);
}
expect: {
!function(a, b, c) {
b++;
console.log(0, 1 * b, 5);
}(1, 2, 3);
}
}
iife_new: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var A = new function(a, b, c) {
b++;
console.log(a - 1, b * 1, c + 2);
}(1, 2, 3);
}
expect: {
var A = new function(a, b, c) {
b++;
console.log(0, 1 * b, 5);
}(1, 2, 3);
}
}
multi_def: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
function f(a) {
if (a)
var b = 1;
else
var b = 2
console.log(b + 1);
}
}
expect: {
function f(a) {
if (a)
var b = 1;
else
var b = 2
console.log(b + 1);
}
}
}
multi_def_2: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
if (code == 16)
var bitsLength = 2, bitsOffset = 3, what = len;
else if (code == 17)
var bitsLength = 3, bitsOffset = 3, what = (len = 0);
else if (code == 18)
var bitsLength = 7, bitsOffset = 11, what = (len = 0);
var repeatLength = this.getBits(bitsLength) + bitsOffset;
}
expect: {
if (16 == code)
var bitsLength = 2, bitsOffset = 3, what = len;
else if (17 == code)
var bitsLength = 3, bitsOffset = 3, what = (len = 0);
else if (18 == code)
var bitsLength = 7, bitsOffset = 11, what = (len = 0);
var repeatLength = this.getBits(bitsLength) + bitsOffset;
}
}

View File

@@ -169,3 +169,85 @@ for_sequences: {
for (y = 5; false;); for (y = 5; false;);
} }
} }
limit_1: {
options = {
sequences: 3,
};
input: {
a;
b;
c;
d;
e;
f;
g;
h;
i;
j;
k;
}
expect: {
a, b, c;
d, e, f;
g, h, i;
j, k;
}
}
limit_2: {
options = {
sequences: 3,
};
input: {
a, b;
c, d;
e, f;
g, h;
i, j;
k;
}
expect: {
a, b, c, d;
e, f, g, h;
i, j, k;
}
}
negate_iife_for: {
options = {
sequences: true,
negate_iife: true,
};
input: {
(function() {})();
for (i = 0; i < 5; i++) console.log(i);
(function() {})();
for (; i < 5; i++) console.log(i);
}
expect: {
for (!function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 5; i++) console.log(i);
}
}
iife: {
options = {
sequences: true,
};
input: {
x = 42;
(function a() {})();
!function b() {}();
~function c() {}();
+function d() {}();
-function e() {}();
void function f() {}();
typeof function g() {}();
}
expect: {
x = 42, function a() {}(), function b() {}(), function c() {}(),
function d() {}(), function e() {}(), function f() {}(), function g() {}()
}
}

View File

@@ -0,0 +1 @@
console.log(C.V, C.D);

View File

@@ -0,0 +1 @@
console.log(D);

View File

@@ -0,0 +1,73 @@
if (x) {
foo();
}
if (x) {
foo();
} else {
baz();
}
if (x) {
foo();
} else if (y) {
bar();
} else {
baz();
}
if (x) {
if (y) {
foo();
} else {
bar();
}
} else {
baz();
}
if (x) {
foo();
} else if (y) {
bar();
} else if (z) {
baz();
} else {
moo();
}
function f() {
if (x) {
foo();
}
if (x) {
foo();
} else {
baz();
}
if (x) {
foo();
} else if (y) {
bar();
} else {
baz();
}
if (x) {
if (y) {
foo();
} else {
bar();
}
} else {
baz();
}
if (x) {
foo();
} else if (y) {
bar();
} else if (z) {
baz();
} else {
moo();
}
}

View File

@@ -0,0 +1,17 @@
if (x) foo();
if (x) foo(); else baz();
if (x) foo(); else if (y) bar(); else baz();
if (x) if (y) foo(); else bar(); else baz();
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
function f() {
if (x) foo();
if (x) foo(); else baz();
if (x) foo(); else if (y) bar(); else baz();
if (x) if (y) foo(); else bar(); else baz();
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
}

View File

@@ -0,0 +1,12 @@
if (x) foo();
if (x) foo(); else baz();
if (x) foo(); else if (y) bar(); else baz();
if (x) if (y) foo(); else bar(); else baz();
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
function f() {
if (x) foo();
if (x) foo(); else baz();
if (x) foo(); else if (y) bar(); else baz();
if (x) if (y) foo(); else bar(); else baz();
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
}

87
test/jetstream.js Normal file
View File

@@ -0,0 +1,87 @@
#! /usr/bin/env node
// -*- js -*-
"use strict";
var site = "http://browserbench.org/JetStream/";
if (typeof phantom == "undefined") {
// workaround for tty output truncation upon process.exit()
[process.stdout, process.stderr].forEach(function(stream){
if (stream._handle && stream._handle.setBlocking)
stream._handle.setBlocking(true);
});
var args = process.argv.slice(2);
if (!args.length) {
args.push("-mc", "warnings=false");
}
args.push("--stats");
var child_process = require("child_process");
try {
require("phantomjs-prebuilt");
} catch(e) {
child_process.execSync("npm install phantomjs-prebuilt@2.1.14");
}
var http = require("http");
var server = http.createServer(function(request, response) {
request.resume();
var url = decodeURIComponent(request.url.slice(1));
var stderr = "";
var uglifyjs = child_process.fork("bin/uglifyjs", args, {
silent: true
}).on("exit", function(code) {
console.log("uglifyjs", url.indexOf(site) == 0 ? url.slice(site.length) : url, args.join(" "));
console.log(stderr);
if (code) throw new Error("uglifyjs failed with code " + code);
});
uglifyjs.stderr.on("data", function(data) {
stderr += data;
}).setEncoding("utf8");
uglifyjs.stdout.pipe(response);
http.get(url, function(res) {
res.pipe(uglifyjs.stdin);
});
}).listen().on("listening", function() {
var phantomjs = require("phantomjs-prebuilt");
var program = phantomjs.exec(process.argv[1], server.address().port);
program.stdout.pipe(process.stdout);
program.stderr.pipe(process.stderr);
program.on("exit", function(code) {
server.close();
if (code) throw new Error("JetStream failed!");
console.log("JetStream completed successfully.");
});
});
server.timeout = 0;
} else {
var page = require("webpage").create();
page.onError = function(msg, trace) {
var body = [ msg ];
if (trace) trace.forEach(function(t) {
body.push(" " + (t.function || "Anonymous function") + " (" + t.file + ":" + t.line + ")");
});
console.error(body.join("\n"));
phantom.exit(1);
};
var url = "http://localhost:" + require("system").args[1] + "/";
page.onResourceRequested = function(requestData, networkRequest) {
if (/\.js$/.test(requestData.url))
networkRequest.changeUrl(url + encodeURIComponent(requestData.url));
}
page.onConsoleMessage = function(msg) {
if (/Error:/i.test(msg)) {
console.error(msg);
phantom.exit(1);
}
console.log(msg);
if (~msg.indexOf("Raw results:")) {
phantom.exit();
}
};
page.open(site, function(status) {
if (status != "success") phantomjs.exit(1);
page.evaluate(function() {
JetStream.switchToQuick();
JetStream.start();
});
});
}

View File

@@ -0,0 +1,32 @@
var UglifyJS = require('../../');
var assert = require("assert");
describe("Accessor tokens", function() {
it("Should fill the token information for accessors (issue #1492)", function() {
// location 0 1 2 3 4
// 01234567890123456789012345678901234567890123456789
var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }");
// test all AST_ObjectProperty tokens are set as expected
var checkedAST_ObjectProperty = false;
var checkWalker = new UglifyJS.TreeWalker(function(node, descend) {
if (node instanceof UglifyJS.AST_ObjectProperty) {
checkedAST_ObjectProperty = true;
assert.equal(node.start.pos, 12);
assert.equal(node.end.endpos, 46);
assert(node.key instanceof UglifyJS.AST_SymbolRef);
assert.equal(node.key.start.pos, 16);
assert.equal(node.key.end.endpos, 22);
assert(node.value instanceof UglifyJS.AST_Accessor);
assert.equal(node.value.start.pos, 22);
assert.equal(node.value.end.endpos, 46);
}
});
ast.walk(checkWalker);
assert(checkedAST_ObjectProperty, "AST_ObjectProperty not found");
});
});

View File

@@ -1,10 +1,11 @@
var assert = require("assert"); var assert = require("assert");
var exec = require("child_process").exec; var exec = require("child_process").exec;
var readFileSync = require("fs").readFileSync;
describe("bin/uglifyjs", function () { describe("bin/uglifyjs", function () {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs'; var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
it("should produce a functional build when using --self", function (done) { it("should produce a functional build when using --self", function (done) {
this.timeout(5000); this.timeout(15000);
var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS'; var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
@@ -100,4 +101,54 @@ describe("bin/uglifyjs", function () {
done(); done();
}); });
}); });
it("Should work with --define (simple)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(5);\n");
done();
});
});
it("Should work with --define (nested)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(3,5);\n");
done();
});
});
it("Should work with --define (AST_Node)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "stdout.println(D);\n");
done();
});
});
it("Should work with `--beautify`", function (done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, readFileSync("test/input/issue-1482/default.js", "utf8"));
done();
});
});
it("Should work with `--beautify bracketize`", function (done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, readFileSync("test/input/issue-1482/bracketize.js", "utf8"));
done();
});
});
}); });

View File

@@ -95,4 +95,19 @@ describe("minify", function() {
assert.strictEqual(code, "var a=function(n){return n};"); assert.strictEqual(code, "var a=function(n){return n};");
}); });
}); });
describe("#__PURE__", function() {
it("should drop #__PURE__ hint after use", function() {
var result = Uglify.minify('//@__PURE__ comment1 #__PURE__ comment2\n foo(), bar();', {
fromString: true,
output: {
comments: "all",
beautify: false,
}
});
var code = result.code;
assert.strictEqual(code, "// comment1 comment2\nbar();");
});
});
}); });

489
test/mocha/operator.js Normal file
View File

@@ -0,0 +1,489 @@
var UglifyJS = require("../../");
var assert = require("assert");
describe("operator", function() {
it("Should handle mixing of ++/+/--/- correctly", function() {
function evaluate(exp) {
return new Function("var a=1,b=2,c=" + exp + ";return{a:a,b:b,c:c}")();
}
[ "", "+", "-" ].forEach(function(p) {
[ "++a", "--a", "a", "a--", "a++" ].forEach(function(a) {
[ "+", "-" ].forEach(function(o) {
[ "", "+", "-" ].forEach(function(q) {
[ "++b", "--b", "b", "b--", "b++" ].forEach(function(b) {
var exp = [p, a, o, q, b].join(" ");
var orig = evaluate(exp);
var uglify = evaluate(UglifyJS.parse(exp).print_to_string());
assert.strictEqual(orig.a, uglify.a);
assert.strictEqual(orig.b, uglify.b);
assert.strictEqual(orig.c, uglify.c);
var beautify = evaluate(UglifyJS.parse(exp).print_to_string({
beautify: true
}));
assert.strictEqual(orig.a, beautify.a);
assert.strictEqual(orig.b, beautify.b);
assert.strictEqual(orig.c, beautify.c);
});
});
});
});
});
});
it("Should remove extraneous spaces", function() {
[
[ "++a + ++b", "++a+ ++b" ],
[ "++a + --b", "++a+--b" ],
[ "++a + b", "++a+b" ],
[ "++a + b--", "++a+b--" ],
[ "++a + b++", "++a+b++" ],
[ "++a + + ++b", "++a+ + ++b" ],
[ "++a + + --b", "++a+ +--b" ],
[ "++a + + b", "++a+ +b" ],
[ "++a + + b--", "++a+ +b--" ],
[ "++a + + b++", "++a+ +b++" ],
[ "++a + - ++b", "++a+-++b" ],
[ "++a + - --b", "++a+- --b" ],
[ "++a + - b", "++a+-b" ],
[ "++a + - b--", "++a+-b--" ],
[ "++a + - b++", "++a+-b++" ],
[ "++a - ++b", "++a-++b" ],
[ "++a - --b", "++a- --b" ],
[ "++a - b", "++a-b" ],
[ "++a - b--", "++a-b--" ],
[ "++a - b++", "++a-b++" ],
[ "++a - + ++b", "++a-+ ++b" ],
[ "++a - + --b", "++a-+--b" ],
[ "++a - + b", "++a-+b" ],
[ "++a - + b--", "++a-+b--" ],
[ "++a - + b++", "++a-+b++" ],
[ "++a - - ++b", "++a- -++b" ],
[ "++a - - --b", "++a- - --b" ],
[ "++a - - b", "++a- -b" ],
[ "++a - - b--", "++a- -b--" ],
[ "++a - - b++", "++a- -b++" ],
[ "--a + ++b", "--a+ ++b" ],
[ "--a + --b", "--a+--b" ],
[ "--a + b", "--a+b" ],
[ "--a + b--", "--a+b--" ],
[ "--a + b++", "--a+b++" ],
[ "--a + + ++b", "--a+ + ++b" ],
[ "--a + + --b", "--a+ +--b" ],
[ "--a + + b", "--a+ +b" ],
[ "--a + + b--", "--a+ +b--" ],
[ "--a + + b++", "--a+ +b++" ],
[ "--a + - ++b", "--a+-++b" ],
[ "--a + - --b", "--a+- --b" ],
[ "--a + - b", "--a+-b" ],
[ "--a + - b--", "--a+-b--" ],
[ "--a + - b++", "--a+-b++" ],
[ "--a - ++b", "--a-++b" ],
[ "--a - --b", "--a- --b" ],
[ "--a - b", "--a-b" ],
[ "--a - b--", "--a-b--" ],
[ "--a - b++", "--a-b++" ],
[ "--a - + ++b", "--a-+ ++b" ],
[ "--a - + --b", "--a-+--b" ],
[ "--a - + b", "--a-+b" ],
[ "--a - + b--", "--a-+b--" ],
[ "--a - + b++", "--a-+b++" ],
[ "--a - - ++b", "--a- -++b" ],
[ "--a - - --b", "--a- - --b" ],
[ "--a - - b", "--a- -b" ],
[ "--a - - b--", "--a- -b--" ],
[ "--a - - b++", "--a- -b++" ],
[ "a + ++b", "a+ ++b" ],
[ "a + --b", "a+--b" ],
[ "a + b", "a+b" ],
[ "a + b--", "a+b--" ],
[ "a + b++", "a+b++" ],
[ "a + + ++b", "a+ + ++b" ],
[ "a + + --b", "a+ +--b" ],
[ "a + + b", "a+ +b" ],
[ "a + + b--", "a+ +b--" ],
[ "a + + b++", "a+ +b++" ],
[ "a + - ++b", "a+-++b" ],
[ "a + - --b", "a+- --b" ],
[ "a + - b", "a+-b" ],
[ "a + - b--", "a+-b--" ],
[ "a + - b++", "a+-b++" ],
[ "a - ++b", "a-++b" ],
[ "a - --b", "a- --b" ],
[ "a - b", "a-b" ],
[ "a - b--", "a-b--" ],
[ "a - b++", "a-b++" ],
[ "a - + ++b", "a-+ ++b" ],
[ "a - + --b", "a-+--b" ],
[ "a - + b", "a-+b" ],
[ "a - + b--", "a-+b--" ],
[ "a - + b++", "a-+b++" ],
[ "a - - ++b", "a- -++b" ],
[ "a - - --b", "a- - --b" ],
[ "a - - b", "a- -b" ],
[ "a - - b--", "a- -b--" ],
[ "a - - b++", "a- -b++" ],
[ "a-- + ++b", "a--+ ++b" ],
[ "a-- + --b", "a--+--b" ],
[ "a-- + b", "a--+b" ],
[ "a-- + b--", "a--+b--" ],
[ "a-- + b++", "a--+b++" ],
[ "a-- + + ++b", "a--+ + ++b" ],
[ "a-- + + --b", "a--+ +--b" ],
[ "a-- + + b", "a--+ +b" ],
[ "a-- + + b--", "a--+ +b--" ],
[ "a-- + + b++", "a--+ +b++" ],
[ "a-- + - ++b", "a--+-++b" ],
[ "a-- + - --b", "a--+- --b" ],
[ "a-- + - b", "a--+-b" ],
[ "a-- + - b--", "a--+-b--" ],
[ "a-- + - b++", "a--+-b++" ],
[ "a-- - ++b", "a---++b" ],
[ "a-- - --b", "a--- --b" ],
[ "a-- - b", "a---b" ],
[ "a-- - b--", "a---b--" ],
[ "a-- - b++", "a---b++" ],
[ "a-- - + ++b", "a---+ ++b" ],
[ "a-- - + --b", "a---+--b" ],
[ "a-- - + b", "a---+b" ],
[ "a-- - + b--", "a---+b--" ],
[ "a-- - + b++", "a---+b++" ],
[ "a-- - - ++b", "a--- -++b" ],
[ "a-- - - --b", "a--- - --b" ],
[ "a-- - - b", "a--- -b" ],
[ "a-- - - b--", "a--- -b--" ],
[ "a-- - - b++", "a--- -b++" ],
[ "a++ + ++b", "a+++ ++b" ],
[ "a++ + --b", "a+++--b" ],
[ "a++ + b", "a+++b" ],
[ "a++ + b--", "a+++b--" ],
[ "a++ + b++", "a+++b++" ],
[ "a++ + + ++b", "a+++ + ++b" ],
[ "a++ + + --b", "a+++ +--b" ],
[ "a++ + + b", "a+++ +b" ],
[ "a++ + + b--", "a+++ +b--" ],
[ "a++ + + b++", "a+++ +b++" ],
[ "a++ + - ++b", "a+++-++b" ],
[ "a++ + - --b", "a+++- --b" ],
[ "a++ + - b", "a+++-b" ],
[ "a++ + - b--", "a+++-b--" ],
[ "a++ + - b++", "a+++-b++" ],
[ "a++ - ++b", "a++-++b" ],
[ "a++ - --b", "a++- --b" ],
[ "a++ - b", "a++-b" ],
[ "a++ - b--", "a++-b--" ],
[ "a++ - b++", "a++-b++" ],
[ "a++ - + ++b", "a++-+ ++b" ],
[ "a++ - + --b", "a++-+--b" ],
[ "a++ - + b", "a++-+b" ],
[ "a++ - + b--", "a++-+b--" ],
[ "a++ - + b++", "a++-+b++" ],
[ "a++ - - ++b", "a++- -++b" ],
[ "a++ - - --b", "a++- - --b" ],
[ "a++ - - b", "a++- -b" ],
[ "a++ - - b--", "a++- -b--" ],
[ "a++ - - b++", "a++- -b++" ],
[ "+ ++a + ++b", "+ ++a+ ++b" ],
[ "+ ++a + --b", "+ ++a+--b" ],
[ "+ ++a + b", "+ ++a+b" ],
[ "+ ++a + b--", "+ ++a+b--" ],
[ "+ ++a + b++", "+ ++a+b++" ],
[ "+ ++a + + ++b", "+ ++a+ + ++b" ],
[ "+ ++a + + --b", "+ ++a+ +--b" ],
[ "+ ++a + + b", "+ ++a+ +b" ],
[ "+ ++a + + b--", "+ ++a+ +b--" ],
[ "+ ++a + + b++", "+ ++a+ +b++" ],
[ "+ ++a + - ++b", "+ ++a+-++b" ],
[ "+ ++a + - --b", "+ ++a+- --b" ],
[ "+ ++a + - b", "+ ++a+-b" ],
[ "+ ++a + - b--", "+ ++a+-b--" ],
[ "+ ++a + - b++", "+ ++a+-b++" ],
[ "+ ++a - ++b", "+ ++a-++b" ],
[ "+ ++a - --b", "+ ++a- --b" ],
[ "+ ++a - b", "+ ++a-b" ],
[ "+ ++a - b--", "+ ++a-b--" ],
[ "+ ++a - b++", "+ ++a-b++" ],
[ "+ ++a - + ++b", "+ ++a-+ ++b" ],
[ "+ ++a - + --b", "+ ++a-+--b" ],
[ "+ ++a - + b", "+ ++a-+b" ],
[ "+ ++a - + b--", "+ ++a-+b--" ],
[ "+ ++a - + b++", "+ ++a-+b++" ],
[ "+ ++a - - ++b", "+ ++a- -++b" ],
[ "+ ++a - - --b", "+ ++a- - --b" ],
[ "+ ++a - - b", "+ ++a- -b" ],
[ "+ ++a - - b--", "+ ++a- -b--" ],
[ "+ ++a - - b++", "+ ++a- -b++" ],
[ "+ --a + ++b", "+--a+ ++b" ],
[ "+ --a + --b", "+--a+--b" ],
[ "+ --a + b", "+--a+b" ],
[ "+ --a + b--", "+--a+b--" ],
[ "+ --a + b++", "+--a+b++" ],
[ "+ --a + + ++b", "+--a+ + ++b" ],
[ "+ --a + + --b", "+--a+ +--b" ],
[ "+ --a + + b", "+--a+ +b" ],
[ "+ --a + + b--", "+--a+ +b--" ],
[ "+ --a + + b++", "+--a+ +b++" ],
[ "+ --a + - ++b", "+--a+-++b" ],
[ "+ --a + - --b", "+--a+- --b" ],
[ "+ --a + - b", "+--a+-b" ],
[ "+ --a + - b--", "+--a+-b--" ],
[ "+ --a + - b++", "+--a+-b++" ],
[ "+ --a - ++b", "+--a-++b" ],
[ "+ --a - --b", "+--a- --b" ],
[ "+ --a - b", "+--a-b" ],
[ "+ --a - b--", "+--a-b--" ],
[ "+ --a - b++", "+--a-b++" ],
[ "+ --a - + ++b", "+--a-+ ++b" ],
[ "+ --a - + --b", "+--a-+--b" ],
[ "+ --a - + b", "+--a-+b" ],
[ "+ --a - + b--", "+--a-+b--" ],
[ "+ --a - + b++", "+--a-+b++" ],
[ "+ --a - - ++b", "+--a- -++b" ],
[ "+ --a - - --b", "+--a- - --b" ],
[ "+ --a - - b", "+--a- -b" ],
[ "+ --a - - b--", "+--a- -b--" ],
[ "+ --a - - b++", "+--a- -b++" ],
[ "+ a + ++b", "+a+ ++b" ],
[ "+ a + --b", "+a+--b" ],
[ "+ a + b", "+a+b" ],
[ "+ a + b--", "+a+b--" ],
[ "+ a + b++", "+a+b++" ],
[ "+ a + + ++b", "+a+ + ++b" ],
[ "+ a + + --b", "+a+ +--b" ],
[ "+ a + + b", "+a+ +b" ],
[ "+ a + + b--", "+a+ +b--" ],
[ "+ a + + b++", "+a+ +b++" ],
[ "+ a + - ++b", "+a+-++b" ],
[ "+ a + - --b", "+a+- --b" ],
[ "+ a + - b", "+a+-b" ],
[ "+ a + - b--", "+a+-b--" ],
[ "+ a + - b++", "+a+-b++" ],
[ "+ a - ++b", "+a-++b" ],
[ "+ a - --b", "+a- --b" ],
[ "+ a - b", "+a-b" ],
[ "+ a - b--", "+a-b--" ],
[ "+ a - b++", "+a-b++" ],
[ "+ a - + ++b", "+a-+ ++b" ],
[ "+ a - + --b", "+a-+--b" ],
[ "+ a - + b", "+a-+b" ],
[ "+ a - + b--", "+a-+b--" ],
[ "+ a - + b++", "+a-+b++" ],
[ "+ a - - ++b", "+a- -++b" ],
[ "+ a - - --b", "+a- - --b" ],
[ "+ a - - b", "+a- -b" ],
[ "+ a - - b--", "+a- -b--" ],
[ "+ a - - b++", "+a- -b++" ],
[ "+ a-- + ++b", "+a--+ ++b" ],
[ "+ a-- + --b", "+a--+--b" ],
[ "+ a-- + b", "+a--+b" ],
[ "+ a-- + b--", "+a--+b--" ],
[ "+ a-- + b++", "+a--+b++" ],
[ "+ a-- + + ++b", "+a--+ + ++b" ],
[ "+ a-- + + --b", "+a--+ +--b" ],
[ "+ a-- + + b", "+a--+ +b" ],
[ "+ a-- + + b--", "+a--+ +b--" ],
[ "+ a-- + + b++", "+a--+ +b++" ],
[ "+ a-- + - ++b", "+a--+-++b" ],
[ "+ a-- + - --b", "+a--+- --b" ],
[ "+ a-- + - b", "+a--+-b" ],
[ "+ a-- + - b--", "+a--+-b--" ],
[ "+ a-- + - b++", "+a--+-b++" ],
[ "+ a-- - ++b", "+a---++b" ],
[ "+ a-- - --b", "+a--- --b" ],
[ "+ a-- - b", "+a---b" ],
[ "+ a-- - b--", "+a---b--" ],
[ "+ a-- - b++", "+a---b++" ],
[ "+ a-- - + ++b", "+a---+ ++b" ],
[ "+ a-- - + --b", "+a---+--b" ],
[ "+ a-- - + b", "+a---+b" ],
[ "+ a-- - + b--", "+a---+b--" ],
[ "+ a-- - + b++", "+a---+b++" ],
[ "+ a-- - - ++b", "+a--- -++b" ],
[ "+ a-- - - --b", "+a--- - --b" ],
[ "+ a-- - - b", "+a--- -b" ],
[ "+ a-- - - b--", "+a--- -b--" ],
[ "+ a-- - - b++", "+a--- -b++" ],
[ "+ a++ + ++b", "+a+++ ++b" ],
[ "+ a++ + --b", "+a+++--b" ],
[ "+ a++ + b", "+a+++b" ],
[ "+ a++ + b--", "+a+++b--" ],
[ "+ a++ + b++", "+a+++b++" ],
[ "+ a++ + + ++b", "+a+++ + ++b" ],
[ "+ a++ + + --b", "+a+++ +--b" ],
[ "+ a++ + + b", "+a+++ +b" ],
[ "+ a++ + + b--", "+a+++ +b--" ],
[ "+ a++ + + b++", "+a+++ +b++" ],
[ "+ a++ + - ++b", "+a+++-++b" ],
[ "+ a++ + - --b", "+a+++- --b" ],
[ "+ a++ + - b", "+a+++-b" ],
[ "+ a++ + - b--", "+a+++-b--" ],
[ "+ a++ + - b++", "+a+++-b++" ],
[ "+ a++ - ++b", "+a++-++b" ],
[ "+ a++ - --b", "+a++- --b" ],
[ "+ a++ - b", "+a++-b" ],
[ "+ a++ - b--", "+a++-b--" ],
[ "+ a++ - b++", "+a++-b++" ],
[ "+ a++ - + ++b", "+a++-+ ++b" ],
[ "+ a++ - + --b", "+a++-+--b" ],
[ "+ a++ - + b", "+a++-+b" ],
[ "+ a++ - + b--", "+a++-+b--" ],
[ "+ a++ - + b++", "+a++-+b++" ],
[ "+ a++ - - ++b", "+a++- -++b" ],
[ "+ a++ - - --b", "+a++- - --b" ],
[ "+ a++ - - b", "+a++- -b" ],
[ "+ a++ - - b--", "+a++- -b--" ],
[ "+ a++ - - b++", "+a++- -b++" ],
[ "- ++a + ++b", "-++a+ ++b" ],
[ "- ++a + --b", "-++a+--b" ],
[ "- ++a + b", "-++a+b" ],
[ "- ++a + b--", "-++a+b--" ],
[ "- ++a + b++", "-++a+b++" ],
[ "- ++a + + ++b", "-++a+ + ++b" ],
[ "- ++a + + --b", "-++a+ +--b" ],
[ "- ++a + + b", "-++a+ +b" ],
[ "- ++a + + b--", "-++a+ +b--" ],
[ "- ++a + + b++", "-++a+ +b++" ],
[ "- ++a + - ++b", "-++a+-++b" ],
[ "- ++a + - --b", "-++a+- --b" ],
[ "- ++a + - b", "-++a+-b" ],
[ "- ++a + - b--", "-++a+-b--" ],
[ "- ++a + - b++", "-++a+-b++" ],
[ "- ++a - ++b", "-++a-++b" ],
[ "- ++a - --b", "-++a- --b" ],
[ "- ++a - b", "-++a-b" ],
[ "- ++a - b--", "-++a-b--" ],
[ "- ++a - b++", "-++a-b++" ],
[ "- ++a - + ++b", "-++a-+ ++b" ],
[ "- ++a - + --b", "-++a-+--b" ],
[ "- ++a - + b", "-++a-+b" ],
[ "- ++a - + b--", "-++a-+b--" ],
[ "- ++a - + b++", "-++a-+b++" ],
[ "- ++a - - ++b", "-++a- -++b" ],
[ "- ++a - - --b", "-++a- - --b" ],
[ "- ++a - - b", "-++a- -b" ],
[ "- ++a - - b--", "-++a- -b--" ],
[ "- ++a - - b++", "-++a- -b++" ],
[ "- --a + ++b", "- --a+ ++b" ],
[ "- --a + --b", "- --a+--b" ],
[ "- --a + b", "- --a+b" ],
[ "- --a + b--", "- --a+b--" ],
[ "- --a + b++", "- --a+b++" ],
[ "- --a + + ++b", "- --a+ + ++b" ],
[ "- --a + + --b", "- --a+ +--b" ],
[ "- --a + + b", "- --a+ +b" ],
[ "- --a + + b--", "- --a+ +b--" ],
[ "- --a + + b++", "- --a+ +b++" ],
[ "- --a + - ++b", "- --a+-++b" ],
[ "- --a + - --b", "- --a+- --b" ],
[ "- --a + - b", "- --a+-b" ],
[ "- --a + - b--", "- --a+-b--" ],
[ "- --a + - b++", "- --a+-b++" ],
[ "- --a - ++b", "- --a-++b" ],
[ "- --a - --b", "- --a- --b" ],
[ "- --a - b", "- --a-b" ],
[ "- --a - b--", "- --a-b--" ],
[ "- --a - b++", "- --a-b++" ],
[ "- --a - + ++b", "- --a-+ ++b" ],
[ "- --a - + --b", "- --a-+--b" ],
[ "- --a - + b", "- --a-+b" ],
[ "- --a - + b--", "- --a-+b--" ],
[ "- --a - + b++", "- --a-+b++" ],
[ "- --a - - ++b", "- --a- -++b" ],
[ "- --a - - --b", "- --a- - --b" ],
[ "- --a - - b", "- --a- -b" ],
[ "- --a - - b--", "- --a- -b--" ],
[ "- --a - - b++", "- --a- -b++" ],
[ "- a + ++b", "-a+ ++b" ],
[ "- a + --b", "-a+--b" ],
[ "- a + b", "-a+b" ],
[ "- a + b--", "-a+b--" ],
[ "- a + b++", "-a+b++" ],
[ "- a + + ++b", "-a+ + ++b" ],
[ "- a + + --b", "-a+ +--b" ],
[ "- a + + b", "-a+ +b" ],
[ "- a + + b--", "-a+ +b--" ],
[ "- a + + b++", "-a+ +b++" ],
[ "- a + - ++b", "-a+-++b" ],
[ "- a + - --b", "-a+- --b" ],
[ "- a + - b", "-a+-b" ],
[ "- a + - b--", "-a+-b--" ],
[ "- a + - b++", "-a+-b++" ],
[ "- a - ++b", "-a-++b" ],
[ "- a - --b", "-a- --b" ],
[ "- a - b", "-a-b" ],
[ "- a - b--", "-a-b--" ],
[ "- a - b++", "-a-b++" ],
[ "- a - + ++b", "-a-+ ++b" ],
[ "- a - + --b", "-a-+--b" ],
[ "- a - + b", "-a-+b" ],
[ "- a - + b--", "-a-+b--" ],
[ "- a - + b++", "-a-+b++" ],
[ "- a - - ++b", "-a- -++b" ],
[ "- a - - --b", "-a- - --b" ],
[ "- a - - b", "-a- -b" ],
[ "- a - - b--", "-a- -b--" ],
[ "- a - - b++", "-a- -b++" ],
[ "- a-- + ++b", "-a--+ ++b" ],
[ "- a-- + --b", "-a--+--b" ],
[ "- a-- + b", "-a--+b" ],
[ "- a-- + b--", "-a--+b--" ],
[ "- a-- + b++", "-a--+b++" ],
[ "- a-- + + ++b", "-a--+ + ++b" ],
[ "- a-- + + --b", "-a--+ +--b" ],
[ "- a-- + + b", "-a--+ +b" ],
[ "- a-- + + b--", "-a--+ +b--" ],
[ "- a-- + + b++", "-a--+ +b++" ],
[ "- a-- + - ++b", "-a--+-++b" ],
[ "- a-- + - --b", "-a--+- --b" ],
[ "- a-- + - b", "-a--+-b" ],
[ "- a-- + - b--", "-a--+-b--" ],
[ "- a-- + - b++", "-a--+-b++" ],
[ "- a-- - ++b", "-a---++b" ],
[ "- a-- - --b", "-a--- --b" ],
[ "- a-- - b", "-a---b" ],
[ "- a-- - b--", "-a---b--" ],
[ "- a-- - b++", "-a---b++" ],
[ "- a-- - + ++b", "-a---+ ++b" ],
[ "- a-- - + --b", "-a---+--b" ],
[ "- a-- - + b", "-a---+b" ],
[ "- a-- - + b--", "-a---+b--" ],
[ "- a-- - + b++", "-a---+b++" ],
[ "- a-- - - ++b", "-a--- -++b" ],
[ "- a-- - - --b", "-a--- - --b" ],
[ "- a-- - - b", "-a--- -b" ],
[ "- a-- - - b--", "-a--- -b--" ],
[ "- a-- - - b++", "-a--- -b++" ],
[ "- a++ + ++b", "-a+++ ++b" ],
[ "- a++ + --b", "-a+++--b" ],
[ "- a++ + b", "-a+++b" ],
[ "- a++ + b--", "-a+++b--" ],
[ "- a++ + b++", "-a+++b++" ],
[ "- a++ + + ++b", "-a+++ + ++b" ],
[ "- a++ + + --b", "-a+++ +--b" ],
[ "- a++ + + b", "-a+++ +b" ],
[ "- a++ + + b--", "-a+++ +b--" ],
[ "- a++ + + b++", "-a+++ +b++" ],
[ "- a++ + - ++b", "-a+++-++b" ],
[ "- a++ + - --b", "-a+++- --b" ],
[ "- a++ + - b", "-a+++-b" ],
[ "- a++ + - b--", "-a+++-b--" ],
[ "- a++ + - b++", "-a+++-b++" ],
[ "- a++ - ++b", "-a++-++b" ],
[ "- a++ - --b", "-a++- --b" ],
[ "- a++ - b", "-a++-b" ],
[ "- a++ - b--", "-a++-b--" ],
[ "- a++ - b++", "-a++-b++" ],
[ "- a++ - + ++b", "-a++-+ ++b" ],
[ "- a++ - + --b", "-a++-+--b" ],
[ "- a++ - + b", "-a++-+b" ],
[ "- a++ - + b--", "-a++-+b--" ],
[ "- a++ - + b++", "-a++-+b++" ],
[ "- a++ - - ++b", "-a++- -++b" ],
[ "- a++ - - --b", "-a++- - --b" ],
[ "- a++ - - b", "-a++- -b" ],
[ "- a++ - - b--", "-a++- -b--" ],
[ "- a++ - - b++", "-a++- -b++" ],
].forEach(function(exp) {
assert.strictEqual(UglifyJS.parse(exp[0]).print_to_string(), exp[1] + ";");
});
});
});

View File

@@ -194,6 +194,9 @@ function parse_test(file) {
if (node instanceof U.AST_LabeledStatement if (node instanceof U.AST_LabeledStatement
&& tw.parent() instanceof U.AST_Toplevel) { && tw.parent() instanceof U.AST_Toplevel) {
var name = node.label.name; var name = node.label.name;
if (name in tests) {
throw new Error('Duplicated test name "' + name + '" in ' + file);
}
tests[name] = get_one_test(name, node.body); tests[name] = get_one_test(name, node.body);
return true; return true;
} }

View File

@@ -115,7 +115,7 @@ exports.minify = function(files, options) {
// 5. output // 5. output
var inMap = options.inSourceMap; var inMap = options.inSourceMap;
var output = {}; var output = { max_line_len: 32000 };
if (typeof options.inSourceMap == "string") { if (typeof options.inSourceMap == "string") {
inMap = JSON.parse(fs.readFileSync(options.inSourceMap, "utf8")); inMap = JSON.parse(fs.readFileSync(options.inSourceMap, "utf8"));
} }