Merge branch 'master' into harmony-2.8.0

This commit is contained in:
alexlamsl
2017-02-27 04:37:48 +08:00
63 changed files with 4471 additions and 480 deletions

View File

@@ -10,6 +10,9 @@ There's also an
[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox,
Chrome and probably Safari).
Note: release versions of `uglify-js` only support ECMAScript 5 (ES5). If you wish to minify
ES2015+ (ES6+) code then please use the [harmony](#harmony) development branch.
Install
-------
@@ -87,10 +90,9 @@ The available options are:
-b, --beautify Beautify output/specify output options.
-m, --mangle Mangle names/pass mangler options.
-r, --reserved Reserved names to exclude from mangling.
-c, --compress Enable compressor/pass compressor options. Pass
options like -c
hoist_vars=false,if_return=false. Use -c with
no argument to use the default compression
-c, --compress Enable compressor/pass compressor options, e.g.
`-c 'if_return=false,pure_funcs=["Math.pow","console.log"]'`
Use `-c` with no argument to enable default compression
options.
-d, --define Global definitions
-e, --enclose Embed everything in a big function, with a
@@ -151,8 +153,10 @@ The available options are:
them explicitly on the command line.
--mangle-regex Only mangle property names matching the regex
--name-cache File to hold mangled names mappings
--pure-funcs List of functions that can be safely removed if
their return value is not used [array]
--pure-funcs Functions that can be safely removed if their
return value is not used, e.g.
`--pure-funcs Math.floor console.info`
(requires `--compress`)
```
Specify `--output` (`-o`) to declare the output file. Otherwise the output
@@ -346,6 +350,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
comparison are switching. Compression only works if both `comparisons` and
`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
expressions
@@ -361,7 +368,15 @@ to set `true`; it's effectively a shortcut for `foo=true`).
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
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
@@ -404,7 +419,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
overhead (compression will be slower).
- `drop_console` -- default `false`. Pass `true` to discard calls to
`console.*` functions.
`console.*` functions. If you wish to drop a specific function call
such as `console.info` and/or retain side effects from function arguments
after dropping the function call then use `pure_funcs` instead.
- `keep_fargs` -- default `true`. Prevents the
compressor from discarding unused function arguments. You need this
@@ -446,6 +463,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
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.
@@ -456,8 +475,6 @@ separate file and include it into the build. For example you can have a
```javascript
const DEBUG = false;
const PRODUCTION = true;
// Alternative for environments that don't support `const`
/** @const */ var STAGING = false;
// etc.
```
@@ -468,7 +485,8 @@ and build your code like this:
UglifyJS will notice the constants and, since they cannot be altered, it
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
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>
@@ -954,3 +972,20 @@ The `source_map_options` (optional) can contain the following properties:
[codegen]: http://lisperator.net/uglifyjs/codegen
[compressor]: http://lisperator.net/uglifyjs/compress
[parser]: http://lisperator.net/uglifyjs/parser
#### Harmony
If you wish to use the experimental [harmony](https://github.com/mishoo/UglifyJS2/commits/harmony)
branch to minify ES2015+ (ES6+) code please use the following in your `package.json` file:
```
"uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony"
```
or to directly install the experimental harmony version of uglify:
```
npm install --save-dev uglify-js@github:mishoo/UglifyJS2#harmony
```
See [#448](https://github.com/mishoo/UglifyJS2/issues/448) for additional details.

View File

@@ -228,9 +228,10 @@ if (ARGS.mangle_props === true) {
}
var OUTPUT_OPTIONS = {
beautify : BEAUTIFY ? true : false,
preamble : ARGS.preamble || null,
quote_style : ARGS.quotes != null ? ARGS.quotes : 0
beautify : BEAUTIFY ? true : false,
max_line_len : 32000,
preamble : ARGS.preamble || null,
quote_style : ARGS.quotes != null ? ARGS.quotes : 0,
};
if (ARGS.mangle_props == 2) {
@@ -281,21 +282,29 @@ if (ARGS.self) {
var ORIG_MAP = ARGS.in_source_map;
if (ORIG_MAP) {
if (ORIG_MAP && ORIG_MAP != "inline") {
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
if (files.length == 0) {
print_error("INFO: Using file from the input source map: " + ORIG_MAP.file);
files = [ ORIG_MAP.file ];
}
if (ARGS.source_map_root == null) {
ARGS.source_map_root = ORIG_MAP.sourceRoot;
}
}
if (files.length == 0) {
files = [ "-" ];
}
if (ORIG_MAP == "inline") {
if (files.length > 1) {
print_error("ERROR: Inline source map only works with singular input");
process.exit(1);
}
if (ARGS.acorn || ARGS.spidermonkey) {
print_error("ERROR: Inline source map only works with built-in parser");
process.exit(1);
}
}
if (files.indexOf("-") >= 0 && ARGS.source_map) {
print_error("ERROR: Source map doesn't work with input from STDIN");
process.exit(1);
@@ -307,37 +316,19 @@ if (files.filter(function(el){ return el == "-" }).length > 1) {
}
var STATS = {};
var OUTPUT_FILE = ARGS.o;
var TOPLEVEL = null;
var P_RELATIVE = ARGS.p && ARGS.p == "relative";
var SOURCES_CONTENT = {};
var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({
file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE,
root: ARGS.source_map_root,
orig: ORIG_MAP,
}) : null;
OUTPUT_OPTIONS.source_map = SOURCE_MAP;
try {
var output = UglifyJS.OutputStream(OUTPUT_OPTIONS);
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
} catch(ex) {
if (ex instanceof UglifyJS.DefaultsError) {
print_error(ex.msg);
print_error("Supported options:");
print_error(sys.inspect(ex.defs));
process.exit(1);
}
}
async.eachLimit(files, 1, function (file, cb) {
read_whole_file(file, function (err, code) {
if (err) {
print_error("ERROR: can't read file: " + file);
process.exit(1);
}
if (ORIG_MAP == "inline") {
ORIG_MAP = read_source_map(code);
}
if (ARGS.p != null) {
if (P_RELATIVE) {
file = path.relative(path.dirname(ARGS.source_map), file).replace(/\\/g, '/');
@@ -373,7 +364,21 @@ async.eachLimit(files, 1, function (file, cb) {
} catch(ex) {
if (ex instanceof UglifyJS.JS_Parse_Error) {
print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
print_error(ex.message);
var col = ex.col;
var line = code.split(/\r?\n/)[ex.line - (col ? 1 : 2)];
if (line) {
if (col > 40) {
line = line.slice(col - 40);
col = 40;
}
if (col) {
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
} else {
print_error(line.slice(-40));
print_error(line.slice(-40).replace(/\S/g, " ") + "^");
}
}
print_error(ex.stack);
process.exit(1);
}
@@ -384,6 +389,28 @@ async.eachLimit(files, 1, function (file, cb) {
cb();
});
}, function () {
var OUTPUT_FILE = ARGS.o;
var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({
file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE,
root: ARGS.source_map_root || ORIG_MAP && ORIG_MAP.sourceRoot,
orig: ORIG_MAP,
}) : null;
OUTPUT_OPTIONS.source_map = SOURCE_MAP;
try {
var output = UglifyJS.OutputStream(OUTPUT_OPTIONS);
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
} catch(ex) {
if (ex instanceof UglifyJS.DefaultsError) {
print_error(ex.message);
print_error("Supported options:");
print_error(sys.inspect(ex.defs));
process.exit(1);
}
}
if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){
TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
});
@@ -540,7 +567,7 @@ function getOptions(flag, constants) {
ast.walk(new UglifyJS.TreeWalker(function(node){
if (node instanceof UglifyJS.AST_Seq) return; // descend
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;
if (constants)
value = new Function("return (" + value.print_to_string() + ")")();
@@ -548,7 +575,7 @@ function getOptions(flag, constants) {
return true; // no descend
}
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;
return true; // no descend
}
@@ -575,6 +602,15 @@ function read_whole_file(filename, cb) {
}
}
function read_source_map(code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
print_error("WARN: inline source map not found");
return null;
}
return JSON.parse(new Buffer(match[2], "base64"));
}
function time_it(name, cont) {
var t1 = new Date().getTime();
var ret = cont();

View File

@@ -81,7 +81,9 @@ function DEFNODE(type, props, methods, base) {
ctor.DEFMETHOD = function(name, method) {
this.prototype[name] = method;
};
exports["AST_" + type] = ctor;
if (typeof exports !== "undefined") {
exports["AST_" + type] = ctor;
}
return ctor;
};
@@ -143,12 +145,13 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
}, AST_Statement);
function walk_body(node, visitor) {
if (node.body instanceof AST_Node) {
node.body._walk(visitor);
var body = node.body;
if (body instanceof AST_Node) {
body._walk(visitor);
}
else for (var i = 0, len = body.length; i < len; i++) {
body[i]._walk(visitor);
}
else node.body.forEach(function(stat){
stat._walk(visitor);
});
};
var AST_Block = DEFNODE("Block", "body", {
@@ -474,9 +477,10 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator",
_walk: function(visitor) {
return visitor._visit(this, function(){
if (this.name) this.name._walk(visitor);
this.argnames.forEach(function(arg){
arg._walk(visitor);
});
var argnames = this.argnames;
for (var i = 0, len = argnames.length; i < len; i++) {
argnames[i]._walk(visitor);
}
walk_body(this, visitor);
});
}
@@ -704,9 +708,10 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.definitions.forEach(function(def){
def._walk(visitor);
});
var definitions = this.definitions;
for (var i = 0, len = definitions.length; i < len; i++) {
definitions[i]._walk(visitor);
}
});
}
}, AST_Statement);
@@ -806,9 +811,10 @@ var AST_Call = DEFNODE("Call", "expression args", {
_walk: function(visitor) {
return visitor._visit(this, function(){
this.expression._walk(visitor);
this.args.forEach(function(arg){
arg._walk(visitor);
});
var args = this.args;
for (var i = 0, len = args.length; i < len; i++) {
args[i]._walk(visitor);
}
});
}
});
@@ -979,9 +985,10 @@ var AST_Array = DEFNODE("Array", "elements", {
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.elements.forEach(function(el){
el._walk(visitor);
});
var elements = this.elements;
for (var i = 0, len = elements.length; i < len; i++) {
elements[i]._walk(visitor);
}
});
}
});
@@ -993,9 +1000,10 @@ var AST_Object = DEFNODE("Object", "properties", {
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.properties.forEach(function(prop){
prop._walk(visitor);
});
var properties = this.properties;
for (var i = 0, len = properties.length; i < len; i++) {
properties[i]._walk(visitor);
}
});
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -71,7 +71,7 @@ function OutputStream(options) {
unescape_regexps : false,
inline_script : false,
width : 80,
max_line_len : 32000,
max_line_len : false,
beautify : false,
source_map : null,
bracketize : false,
@@ -232,6 +232,7 @@ function OutputStream(options) {
var might_need_space = false;
var might_need_semicolon = false;
var might_add_newline = 0;
var last = null;
function last_char() {
@@ -244,10 +245,22 @@ function OutputStream(options) {
return char;
};
function maybe_newline() {
if (options.max_line_len && current_col > options.max_line_len)
print("\n");
};
var ensure_line_len = options.max_line_len ? function() {
if (current_col > options.max_line_len) {
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("( [ + * / - , .");
@@ -263,6 +276,7 @@ function OutputStream(options) {
current_col++;
current_pos++;
} else {
ensure_line_len();
OUTPUT += "\n";
current_pos++;
current_line++;
@@ -283,6 +297,7 @@ function OutputStream(options) {
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
var target_line = stack[stack.length - 1].start.line;
while (current_line < target_line) {
ensure_line_len();
OUTPUT += "\n";
current_pos++;
current_line++;
@@ -294,8 +309,9 @@ function OutputStream(options) {
if (might_need_space) {
var prev = last_char();
if ((is_identifier_char(prev)
&& (is_identifier_char(ch) || ch == "\\"))
|| (/^[\+\-\/]$/.test(ch) && ch == prev))
&& (is_identifier_char(ch) || ch == "\\"))
|| (ch == "/" && ch == prev)
|| ((ch == "+" || ch == "-") && ch == last))
{
OUTPUT += " ";
current_col++;
@@ -303,16 +319,16 @@ function OutputStream(options) {
}
might_need_space = false;
}
OUTPUT += str;
current_pos += str.length;
var a = str.split(/\r?\n/), n = a.length - 1;
current_line += n;
if (n == 0) {
current_col += a[n].length;
} else {
current_col += a[0].length;
if (n > 0) {
ensure_line_len();
current_col = a[n].length;
}
current_pos += str.length;
last = str;
OUTPUT += str;
};
var star = function(){
@@ -342,7 +358,10 @@ function OutputStream(options) {
var newline = options.beautify ? function() {
print("\n");
} : maybe_newline;
} : options.max_line_len ? function() {
ensure_line_len();
might_add_newline = OUTPUT.length;
} : noop;
var semicolon = options.beautify ? function() {
print(";");
@@ -419,6 +438,9 @@ function OutputStream(options) {
} : noop;
function get() {
if (might_add_newline) {
ensure_line_len();
}
return OUTPUT;
};
@@ -474,7 +496,6 @@ function OutputStream(options) {
pos : function() { return current_pos },
push_node : function(node) { stack.push(node) },
pop_node : function() { return stack.pop() },
stack : function() { return stack },
parent : function(n) {
return stack[stack.length - 2 - (n || 0)];
}
@@ -1113,7 +1134,10 @@ function OutputStream(options) {
output.space();
output.print("else");
output.space();
force_statement(self.alternative, output);
if (self.alternative instanceof AST_If)
self.alternative.print(output);
else
force_statement(self.alternative, output);
} else {
self._do_print_body(output);
}
@@ -1669,30 +1693,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.
function need_constructor_parens(self, output) {
// Always print parentheses with arguments

View File

@@ -239,12 +239,11 @@ function JS_Parse_Error(message, filename, line, col, pos) {
this.line = line;
this.col = col;
this.pos = pos;
this.stack = new Error().stack;
};
JS_Parse_Error.prototype.toString = function() {
return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
};
JS_Parse_Error.prototype = Object.create(Error.prototype);
JS_Parse_Error.prototype.constructor = JS_Parse_Error;
JS_Parse_Error.prototype.name = "SyntaxError";
configure_error_stack(JS_Parse_Error);
function js_error(message, filename, line, col, pos) {
throw new JS_Parse_Error(message, filename, line, col, pos);
@@ -404,13 +403,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
});
if (prefix) num = prefix + num;
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
parse_error("SyntaxError: Legacy octal literals are not allowed in strict mode");
parse_error("Legacy octal literals are not allowed in strict mode");
}
var valid = parse_js_number(num);
if (!isNaN(valid)) {
return token("num", valid);
} else {
parse_error("SyntaxError: Invalid syntax: " + num);
parse_error("Invalid syntax: " + num);
}
};
@@ -428,13 +427,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (peek() == "{") {
next(true);
if (peek() === "}")
parse_error("SyntaxError: Expecting hex-character between {}");
parse_error("Expecting hex-character between {}");
while (peek() == "0") next(true); // No significance
var result, length = find("}", true) - S.pos;
// Avoid 32 bit integer overflow (1 << 32 === 1)
// We know first character isn't 0 and thus out of range anyway
if (length > 6 || (result = hex_bytes(length)) > 0x10FFFF) {
parse_error("SyntaxError: Unicode reference out of bounce");
parse_error("Unicode reference out of bounce");
}
next(true);
return from_char_code(result);
@@ -464,7 +463,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
// Parse
if (ch === "0") return "\0";
if (ch.length > 0 && next_token.has_directive("use strict"))
parse_error("SyntaxError: Legacy octal escape sequences are not allowed in strict mode");
parse_error("Legacy octal escape sequences are not allowed in strict mode");
return String.fromCharCode(parseInt(ch, 8));
}
@@ -473,18 +472,18 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
for (; n > 0; --n) {
var digit = parseInt(next(true), 16);
if (isNaN(digit))
parse_error("SyntaxError: Invalid hex-character pattern in string");
parse_error("Invalid hex-character pattern in string");
num = (num << 4) | digit;
}
return num;
};
var read_string = with_eof_error("SyntaxError: Unterminated string constant", function(quote_char){
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
var quote = next(), ret = "";
for (;;) {
var ch = next(true, true);
if (ch == "\\") ch = read_escaped_char(true);
else if (NEWLINE_CHARS(ch)) parse_error("SyntaxError: Unterminated string constant");
else if (NEWLINE_CHARS(ch)) parse_error("Unterminated string constant");
else if (ch == quote) break;
ret += ch;
}
@@ -493,7 +492,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return tok;
});
var read_template_characters = with_eof_error("SyntaxError: Unterminated template", function(begin){
var read_template_characters = with_eof_error("Unterminated template", function(begin){
if (begin) {
S.template_braces.push(S.brace_counter);
}
@@ -543,7 +542,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return next_token;
};
var skip_multiline_comment = with_eof_error("SyntaxError: Unterminated multiline comment", function(){
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
var regex_allowed = S.regex_allowed;
var i = find("*/", true);
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
@@ -555,13 +554,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return next_token;
});
var read_name = with_eof_error("SyntaxError: Unterminated identifier name", function() {
var read_name = with_eof_error("Unterminated identifier name", function() {
var name = "", ch, escaped = false, hex;
var read_escaped_identifier_char = function() {
escaped = true;
next();
if (peek() !== "u") {
parse_error("SyntaxError: Expecting UnicodeEscapeSequence -- uXXXX or u{XXXX}");
parse_error("Expecting UnicodeEscapeSequence -- uXXXX or u{XXXX}");
}
return read_escaped_char();
}
@@ -570,7 +569,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if ((name = peek()) === "\\") {
name = read_escaped_identifier_char();
if (!is_identifier_start(name)) {
parse_error("SyntaxError: First identifier char is an invalid identifier char");
parse_error("First identifier char is an invalid identifier char");
}
} else if (is_identifier_start(name)){
next();
@@ -583,7 +582,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if ((ch = peek()) === "\\") {
ch = read_escaped_identifier_char();
if (!is_identifier_char(ch)) {
parse_error("SyntaxError: Invalid escaped identifier char");
parse_error("Invalid escaped identifier char");
}
} else {
if (!is_identifier_char(ch)) {
@@ -594,15 +593,15 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
name += ch;
}
if (RESERVED_WORDS(name) && escaped) {
parse_error("SyntaxError: Escaped characters are not allowed in keywords");
parse_error("Escaped characters are not allowed in keywords");
}
return name;
});
var read_regexp = with_eof_error("SyntaxError: Unterminated regular expression", function(regexp){
var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
var prev_backslash = false, ch, in_class = false;
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
parse_error("SyntaxError: Unexpected line terminator");
parse_error("Unexpected line terminator");
} else if (prev_backslash) {
regexp += "\\" + ch;
prev_backslash = false;
@@ -623,7 +622,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
try {
return token("regexp", new RegExp(regexp, mods));
} catch(e) {
parse_error("SyntaxError: " + e.message);
parse_error(e.message);
}
});
@@ -752,7 +751,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
break;
}
parse_error("SyntaxError: Unexpected character '" + ch + "'");
parse_error("Unexpected character '" + ch + "'");
};
next_token.next = next;
@@ -914,14 +913,14 @@ function parse($TEXT, options) {
function unexpected(token) {
if (token == null)
token = S.token;
token_error(token, "SyntaxError: Unexpected token: " + token.type + " (" + token.value + ")");
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
};
function expect_token(type, val) {
if (is(type, val)) {
return next();
}
token_error(S.token, "SyntaxError: Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
};
function expect(punc) { return expect_token("punc", punc); };
@@ -1058,7 +1057,7 @@ function parse($TEXT, options) {
case "return":
if (S.in_function == 0 && !options.bare_returns)
croak("SyntaxError: 'return' outside of function");
croak("'return' outside of function");
return new AST_Return({
value: ( is("punc", ";")
? (next(), null)
@@ -1075,7 +1074,7 @@ function parse($TEXT, options) {
case "throw":
if (S.token.nlb)
croak("SyntaxError: Illegal newline after 'throw'");
croak("Illegal newline after 'throw'");
return new AST_Throw({
value: (tmp = expression(true), semicolon(), tmp)
});
@@ -1094,7 +1093,7 @@ function parse($TEXT, options) {
case "with":
if (S.input.has_directive("use strict")) {
croak("SyntaxError: Strict mode may not include a with statement");
croak("Strict mode may not include a with statement");
}
return new AST_With({
expression : parenthesised(),
@@ -1115,14 +1114,14 @@ function parse($TEXT, options) {
var label = as_symbol(AST_Label);
if (label.name === "yield" && is_in_generator()) {
// Ecma-262, 12.1.1 Static Semantics: Early Errors
token_error(S.prev, "SyntaxError: Yield cannot be used as label inside generators");
token_error(S.prev, "Yield cannot be used as label inside generators");
}
if (find_if(function(l){ return l.name == label.name }, S.labels)) {
// ECMA-262, 12.12: An ECMAScript program is considered
// syntactically incorrect if it contains a
// LabelledStatement that is enclosed by a
// LabelledStatement with the same Identifier as label.
croak("SyntaxError: Label " + label.name + " defined twice");
croak("Label " + label.name + " defined twice");
}
expect(":");
S.labels.push(label);
@@ -1135,7 +1134,7 @@ function parse($TEXT, options) {
label.references.forEach(function(ref){
if (ref instanceof AST_Continue) {
ref = ref.label.start;
croak("SyntaxError: Continue label `" + label.name + "` refers to non-IterationStatement.",
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
ref.line, ref.col, ref.pos);
}
});
@@ -1155,11 +1154,11 @@ function parse($TEXT, options) {
if (label != null) {
ldef = find_if(function(l){ return l.name == label.name }, S.labels);
if (!ldef)
croak("SyntaxError: Undefined label " + label.name);
croak("Undefined label " + label.name);
label.thedef = ldef;
}
else if (S.in_loop == 0)
croak("SyntaxError: " + type.TYPE + " not inside a loop or switch");
croak(type.TYPE + " not inside a loop or switch");
semicolon();
var stat = new type({ label: label });
if (ldef) ldef.references.push(stat);
@@ -1180,7 +1179,7 @@ function parse($TEXT, options) {
if (is_in || is_of) {
if ((init instanceof AST_Definitions) &&
init.definitions.length > 1)
croak("SyntaxError: Only one variable declaration allowed in for..in loop");
croak("Only one variable declaration allowed in for..in loop");
next();
if (is_in) {
return for_in(init);
@@ -1232,7 +1231,7 @@ function parse($TEXT, options) {
var arrow_function = function(args) {
if (S.token.nlb) {
croak("SyntaxError: Unexpected newline before arrow (=>)");
croak("Unexpected newline before arrow (=>)");
}
expect_token("arrow", "=>");
@@ -1302,7 +1301,7 @@ function parse($TEXT, options) {
case "eval":
case "yield":
if (strict_mode) {
token_error(token, "SyntaxError: Unexpected " + token.value + " identifier as parameter inside strict mode");
token_error(token, "Unexpected " + token.value + " identifier as parameter inside strict mode");
}
break;
default:
@@ -1331,7 +1330,7 @@ function parse($TEXT, options) {
},
check_strict: function() {
if (tracker.is_strict() && duplicate !== false) {
token_error(duplicate, "SyntaxError: Parameter " + duplicate.value + " was used already");
token_error(duplicate, "Parameter " + duplicate.value + " was used already");
}
}
};
@@ -1457,7 +1456,7 @@ function parse($TEXT, options) {
}));
next();
} else {
croak("SyntaxError: Invalid function parameter");
croak("Invalid function parameter");
}
if (is("operator", "=") && is_expand === false) {
used_parameters.mark_default_assignment(S.token);
@@ -1568,7 +1567,7 @@ function parse($TEXT, options) {
end: prev()
});
} else {
croak("SyntaxError: Invalid function parameter");
croak("Invalid function parameter");
}
}
@@ -1631,7 +1630,7 @@ function parse($TEXT, options) {
function _yield_expression() {
// Previous token must be keyword yield and not be interpret as an identifier
if (!is_in_generator()) {
croak("SyntaxError: Unexpected yield expression outside generator function",
croak("Unexpected yield expression outside generator function",
S.prev.line, S.prev.col, S.prev.pos);
}
var star = false;
@@ -1747,7 +1746,7 @@ function parse($TEXT, options) {
});
}
if (!bcatch && !bfinally)
croak("SyntaxError: Missing catch/finally blocks");
croak("Missing catch/finally blocks");
return new AST_Try({
body : body,
bcatch : bcatch,
@@ -1872,7 +1871,7 @@ function parse($TEXT, options) {
break;
case "operator":
if (!is_identifier_string(tok.value)) {
croak("SyntaxError: Invalid getter/setter name: " + tok.value,
croak("Invalid getter/setter name: " + tok.value,
tok.line, tok.col, tok.pos);
}
ret = _make_symbol(AST_SymbolRef);
@@ -1985,6 +1984,10 @@ function parse($TEXT, options) {
});
});
var create_accessor = embed_tokens(function() {
return function_(AST_Accessor);
});
var object_or_object_destructuring_ = embed_tokens(function() {
var start = S.token, first = true, a = [];
expect("{");
@@ -2142,7 +2145,7 @@ function parse($TEXT, options) {
key : name,
quote : name instanceof AST_SymbolMethod ?
property_token.quote : undefined,
value : function_(AST_Accessor),
value : create_accessor(),
end : prev()
});
}
@@ -2156,7 +2159,7 @@ function parse($TEXT, options) {
key : name,
quote : name instanceof AST_SymbolMethod ?
property_token.quote : undefined,
value : function_(AST_Accessor),
value : create_accessor(),
end : prev()
});
}
@@ -2286,7 +2289,7 @@ function parse($TEXT, options) {
}
case "name":
if (tmp.value === "yield" && S.input.has_directive("use strict") && !is_in_generator()) {
token_error(tmp, "SyntaxError: Unexpected yield identifier inside strict mode");
token_error(tmp, "Unexpected yield identifier inside strict mode");
}
case "string":
case "num":
@@ -2325,11 +2328,11 @@ function parse($TEXT, options) {
function as_symbol(type, noerror) {
if (!is("name")) {
if (!noerror) croak("SyntaxError: Name expected");
if (!noerror) croak("Name expected");
return null;
}
if (is("name", "yield") && S.input.has_directive("use strict")) {
token_error(S.prev, "SyntaxError: Unexpected yield identifier inside strict mode");
token_error(S.prev, "Unexpected yield identifier inside strict mode");
}
var sym = _make_symbol(type);
next();
@@ -2418,7 +2421,7 @@ function parse($TEXT, options) {
function make_unary(ctor, op, expr) {
if ((op == "++" || op == "--") && !is_assignable(expr))
croak("SyntaxError: Invalid use of " + op + " operator");
croak("Invalid use of " + op + " operator");
return new ctor({ operator: op, expression: expr });
};
@@ -2482,7 +2485,7 @@ function parse($TEXT, options) {
next();
return _yield_expression();
} else if (S.input.has_directive("use strict")) {
token_error(S.token, "SyntaxError: Unexpected yield identifier inside strict mode")
token_error(S.token, "Unexpected yield identifier inside strict mode")
}
}
@@ -2525,7 +2528,7 @@ function parse($TEXT, options) {
// Only allow expansion as last element
if (node.elements[i] instanceof AST_Expansion) {
if (i + 1 !== node.elements.length) {
token_error(node.elements[i].start, "SyntaxError: Spread must the be last element in destructuring array");
token_error(node.elements[i].start, "Spread must the be last element in destructuring array");
}
node.elements[i].expression = walk(node.elements[i].expression);
}
@@ -2565,7 +2568,7 @@ function parse($TEXT, options) {
end : prev()
});
}
croak("SyntaxError: Invalid assignment");
croak("Invalid assignment");
}
return left;
};

View File

@@ -174,6 +174,7 @@ function mangle_properties(ast, options) {
// only function declarations after this line
function can_mangle(name) {
if (!is_identifier(name)) return false;
if (unmangleable.indexOf(name) >= 0) return false;
if (reserved.indexOf(name) >= 0) return false;
if (options.only_cache) {

View File

@@ -53,7 +53,6 @@ function SymbolDef(scope, index, orig) {
this.mangled_name = null;
this.object_destructuring_arg = false;
this.undeclared = false;
this.constant = false;
this.index = index;
this.id = SymbolDef.next_id++;
};
@@ -105,15 +104,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var scope = self.parent_scope = null;
var labels = new Dictionary();
var defun = null;
var last_var_had_const_pragma = false;
var nesting = 0;
var in_destructuring = null;
var in_export;
var tw = new TreeWalker(function(node, descend){
if (node.is_block_scope()) {
var save_scope = scope;
scope = new AST_Scope(node);
scope.init_scope_vars(nesting);
scope.init_scope_vars();
scope.parent_scope = save_scope;
if (!(node instanceof AST_Scope)) {
scope.uses_with = save_scope.uses_with;
@@ -131,13 +128,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
return true;
}
if (node instanceof AST_Scope) {
node.init_scope_vars(nesting);
node.init_scope_vars();
var save_scope = node.parent_scope = scope;
var save_defun = defun;
var save_labels = labels;
defun = scope = node;
labels = new Dictionary();
++nesting; descend(); --nesting;
descend();
scope = save_scope;
defun = save_defun;
labels = save_labels;
@@ -200,14 +197,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// inside the class.
(node.scope = defun.parent_scope).def_function(node, in_export);
}
else if (node instanceof AST_Var) {
last_var_had_const_pragma = node.has_const_pragma();
}
else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst
|| node instanceof AST_SymbolLet) {
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node, in_export);
def.constant = node instanceof AST_SymbolConst || last_var_had_const_pragma;
def.destructuring = in_destructuring;
def.init = tw.parent().value;
}
@@ -232,17 +225,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var cls = null;
var globals = self.globals = new Dictionary();
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) {
var prev_func = func;
func = node;
@@ -273,21 +255,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
node.scope.uses_arguments = true;
}
if (!sym) {
var g;
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;
sym = self.def_global(node);
}
node.thedef = sym;
if (isModified(node, 0)) {
sym.modified = true;
}
node.reference(options);
return true;
}
@@ -299,7 +269,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.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
@@ -307,7 +290,6 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
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.cname = -1; // the current index for mangling functions/variables
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
});
AST_Node.DEFMETHOD("is_block_scope", function(){
@@ -338,15 +320,14 @@ AST_SymbolRef.DEFMETHOD("reference", function(options) {
var s = this.scope;
while (s) {
push_uniq(s.enclosed, def);
if (s === def.scope) break;
if (options.keep_fnames) {
s.variables.each(function(d) {
s.functions.each(function(d) {
push_uniq(def.scope.enclosed, d);
});
}
if (s === def.scope) break;
s = s.parent_scope;
}
this.frame = this.scope.nesting - def.scope.nesting;
});
AST_Scope.DEFMETHOD("find_variable", function(name){
@@ -455,12 +436,6 @@ AST_Symbol.DEFMETHOD("global", function(){
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){
return defaults(options, {
except : [],

View File

@@ -78,13 +78,28 @@ function repeat_string(str, i) {
return d;
};
function configure_error_stack(fn) {
Object.defineProperty(fn.prototype, "stack", {
get: function() {
var err = new Error(this.message);
err.name = this.name;
try {
throw err;
} catch(e) {
return e.stack;
}
}
});
}
function DefaultsError(msg, defs) {
Error.call(this, msg);
this.msg = msg;
this.message = msg;
this.defs = defs;
};
DefaultsError.prototype = Object.create(Error.prototype);
DefaultsError.prototype.constructor = DefaultsError;
DefaultsError.prototype.name = "DefaultsError";
configure_error_stack(DefaultsError);
DefaultsError.croak = function(msg, defs) {
throw new DefaultsError(msg, defs);
@@ -320,3 +335,26 @@ Dictionary.fromObject = function(obj) {
function HOP(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;
}
}
}

View File

@@ -4,7 +4,7 @@
"homepage": "http://lisperator.net/uglifyjs",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "2.7.5",
"version": "2.8.0",
"engines": {
"node": ">=0.8.0"
},

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

@@ -23,10 +23,19 @@ constant_join: {
input: {
var a = [ "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 c = [ boo(), "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 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 e = [].join(foo + bar);
var f = [].join("");
@@ -35,10 +44,19 @@ constant_join: {
expect: {
var a = "foobarbaz";
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 c = boo() + "foo123bar" + bar();
var c1 = "" + boo() + bar() + "foo123bar" + bar();
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 e = [].join(foo + bar);
var f = "";
@@ -148,6 +166,41 @@ spread_with_logical_expression_at_middle: {
}
}
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: {
options = {
unsafe : true,

View File

@@ -338,8 +338,9 @@ collapse_vars_while: {
collapse_vars_do_while: {
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
comparisons:true, evaluate:true, booleans:false, loops:false, unused:"keep_assign",
hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true,
side_effects:true
}
input: {
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: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
@@ -567,8 +641,9 @@ collapse_vars_assignment: {
collapse_vars_lvalues: {
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
comparisons:true, evaluate:true, booleans:true, loops:true, unused:"keep_assign",
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; }
@@ -593,7 +668,38 @@ collapse_vars_lvalues: {
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 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";
}
}
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

@@ -116,7 +116,8 @@ dead_code_const_declaration: {
loops : true,
booleans : true,
conditionals : true,
evaluate : true
evaluate : true,
reduce_vars : true,
};
input: {
var unused;
@@ -141,7 +142,8 @@ dead_code_const_annotation: {
loops : true,
booleans : true,
conditionals : true,
evaluate : true
evaluate : true,
reduce_vars : true,
};
input: {
var unused;
@@ -189,7 +191,8 @@ dead_code_const_annotation_complex_scope: {
loops : true,
booleans : true,
conditionals : true,
evaluate : true
evaluate : true,
reduce_vars : true,
};
input: {
var unused_var;
@@ -223,6 +226,5 @@ dead_code_const_annotation_complex_scope: {
var beef = 'good';
var meat = 'beef';
var pork = 'bad';
'good' === pork && console.log('reached, not const');
}
}

View File

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

View File

@@ -258,3 +258,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

@@ -692,3 +692,51 @@ unsafe_prototype_function: {
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 1;
}(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: {
// suboptimal
function f(x){return!!x||(foo(),void bar())}
function f(x){if(x)return!0;foo(),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: {
options = {
evaluate: true
evaluate: true,
reduce_vars: true,
};
input: {
@@ -27,7 +28,8 @@ const_pragma: {
// for completeness' sake
not_const: {
options = {
evaluate: true
evaluate: true,
reduce_vars: true,
};
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: {
options = {
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;
}
}
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();
}
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);
}
}
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: {
options = {
negate_iife: true
@@ -25,6 +35,7 @@ negate_iife_2: {
negate_iife_3: {
options = {
negate_iife: true,
conditionals: true
};
input: {
(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 = {
negate_iife: true,
conditionals: true,
sequences: true
};
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 = {
negate_iife: 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: {
options = {
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: {
options = {
negate_iife: true,
@@ -172,3 +287,36 @@ issue_1254_negate_iife_nested: {
}
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

@@ -540,3 +540,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(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 + b + c);
}
@@ -136,8 +134,8 @@ modified: {
}
function f2() {
var b = 2, c = 3;
b = c;
var b = 2;
b = 3;
console.log(1 + b);
console.log(b + 3);
console.log(4);
@@ -145,8 +143,8 @@ modified: {
}
function f3() {
var b = 2, c = 3;
b *= c;
var b = 2;
b *= 3;
console.log(1 + b);
console.log(b + 3);
console.log(4);
@@ -238,7 +236,7 @@ unsafe_evaluate_object: {
function f0(){
var a = 1;
var b = {};
b[a] = 2;
b[1] = 2;
console.log(4);
}
@@ -282,7 +280,7 @@ unsafe_evaluate_array: {
function f0(){
var a = 1;
var b = [];
b[a] = 2;
b[1] = 2;
console.log(4);
}
@@ -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;
b = 3;
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;);
}
}
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 @@
foo, bar(

View File

@@ -0,0 +1 @@
function f(a{}

View File

@@ -0,0 +1 @@
foo( xyz, 0abc);

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

View File

@@ -0,0 +1,3 @@
var Foo = function Foo(){console.log(1+2);}; new Foo();
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQU0sR0FBRyxHQUFDLEFBQUUsWUFBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBLEFBQUUsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDOyJ9

View File

@@ -0,0 +1,2 @@
new function(){console.log(3)};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxHQUFyQyxZQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19

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,5 +1,6 @@
var assert = require("assert");
var exec = require("child_process").exec;
var readFileSync = require("fs").readFileSync;
describe("bin/uglifyjs", function () {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
@@ -100,4 +101,141 @@ describe("bin/uglifyjs", function () {
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();
});
});
it("Should process inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js -cm toplevel --in-source-map inline --source-map-inline';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, readFileSync("test/input/issue-520/output.js", "utf8"));
done();
});
});
it("Should warn for missing inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-1323/sample.js --in-source-map inline';
exec(command, function (err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n");
assert.strictEqual(stderr, "WARN: inline source map not found\n");
done();
});
});
it("Should fail with multiple input and inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js test/input/issue-520/output.js --in-source-map inline --source-map-inline';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: Inline source map only works with singular input\n");
done();
});
});
it("Should fail with acorn and inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js --in-source-map inline --source-map-inline --acorn';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: Inline source map only works with built-in parser\n");
done();
});
});
it("Should fail with SpiderMonkey and inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js --in-source-map inline --source-map-inline --spidermonkey';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: Inline source map only works with built-in parser\n");
done();
});
});
it("Should fail with invalid syntax", function(done) {
var command = uglifyjscmd + ' test/input/invalid/simple.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/simple.js:1,12");
assert.strictEqual(lines[1], "function f(a{}");
assert.strictEqual(lines[2], " ^");
assert.strictEqual(lines[3], "SyntaxError: Unexpected token punc «{», expected punc «,»");
done();
});
});
it("Should fail with correct marking of tabs", function(done) {
var command = uglifyjscmd + ' test/input/invalid/tab.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/tab.js:1,12");
assert.strictEqual(lines[1], "\t\tfoo(\txyz, 0abc);");
assert.strictEqual(lines[2], "\t\t \t ^");
assert.strictEqual(lines[3], "SyntaxError: Invalid syntax: 0abc");
done();
});
});
it("Should fail with correct marking at start of line", function(done) {
var command = uglifyjscmd + ' test/input/invalid/eof.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/eof.js:2,0");
assert.strictEqual(lines[1], "foo, bar(");
assert.strictEqual(lines[2], " ^");
assert.strictEqual(lines[3], "SyntaxError: Unexpected token: eof (undefined)");
done();
});
});
});

View File

@@ -13,7 +13,7 @@ describe("Comment", function() {
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "SyntaxError: Unexpected token: operator (>)" &&
e.message === "Unexpected token: operator (>)" &&
e.line === 2 &&
e.col === 0;
}
@@ -37,7 +37,7 @@ describe("Comment", function() {
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "SyntaxError: Unexpected token: operator (>)" &&
e.message === "Unexpected token: operator (>)" &&
e.line === 5 &&
e.col === 0;
}

View File

@@ -7,7 +7,7 @@ describe("comment before constant", function() {
it("Should test comment before constant is retained and output after mangle.", function() {
var result = Uglify.minify(js, {
fromString: true,
compress: { collapse_vars: false },
compress: { collapse_vars: false, reduce_vars: false },
mangle: {},
output: { comments: true },
});
@@ -17,9 +17,9 @@ describe("comment before constant", function() {
it("Should test code works when comments disabled.", function() {
var result = Uglify.minify(js, {
fromString: true,
compress: { collapse_vars: false },
compress: { collapse_vars: false, reduce_vars: false },
mangle: {},
output: {},
output: { comments: false },
});
assert.strictEqual(result.code, 'function f(){var n=!1;return n}');
});

View File

@@ -178,7 +178,7 @@ describe("Directives", function() {
throw new Error("Expected parser to fail");
} catch (e) {
assert.strictEqual(e instanceof uglify.JS_Parse_Error, true);
assert.strictEqual(e.message, "SyntaxError: Unexpected token: punc (])");
assert.strictEqual(e.message, "Unexpected token: punc (])");
}
test_directive(tokenizer, tests[i]);

View File

@@ -0,0 +1,89 @@
var UglifyJS = require('../../');
var assert = require("assert");
describe("Getters and setters", function() {
it("Should not accept operator symbols as getter/setter name", function() {
var illegalOperators = [
"++",
"--",
"+",
"-",
"!",
"~",
"&",
"|",
"^",
"*",
"/",
"%",
">>",
"<<",
">>>",
"<",
">",
"<=",
">=",
"==",
"===",
"!=",
"!==",
"?",
"=",
"+=",
"-=",
"/=",
"*=",
"%=",
">>=",
"<<=",
">>>=",
"|=",
"^=",
"&=",
"&&",
"||"
];
var generator = function() {
var results = [];
for (var i in illegalOperators) {
results.push({
code: "var obj = { get " + illegalOperators[i] + "() { return test; }};",
operator: illegalOperators[i],
method: "get"
});
results.push({
code: "var obj = { set " + illegalOperators[i] + "(value) { test = value}};",
operator: illegalOperators[i],
method: "set"
});
}
return results;
};
var testCase = function(data) {
return function() {
UglifyJS.parse(data.code);
};
};
var fail = function(data) {
return function (e) {
return e instanceof UglifyJS.JS_Parse_Error &&
e.message === "Invalid getter/setter name: " + data.operator;
};
};
var errorMessage = function(data) {
return "Expected but didn't get a syntax error while parsing following line:\n" + data.code;
};
var tests = generator();
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
assert.throws(testCase(test), fail(test), errorMessage(test));
}
});
});

View File

@@ -50,7 +50,7 @@ describe("line-endings", function() {
}
var fail = function(e) {
return e instanceof Uglify.JS_Parse_Error &&
e.message === "SyntaxError: Unexpected line terminator";
e.message === "Unexpected line terminator";
}
for (var i = 0; i < inputs.length; i++) {
assert.throws(test(inputs[i]), fail);

View File

@@ -1,5 +1,6 @@
var Uglify = require('../../');
var assert = require("assert");
var readFileSync = require("fs").readFileSync;
describe("minify", function() {
it("Should test basic sanity of minify with default options", function() {
@@ -75,6 +76,51 @@ describe("minify", function() {
assert.equal(map.sourcesContent[0],
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
});
it("Should process inline source map", function() {
var code = Uglify.minify("./test/input/issue-520/input.js", {
inSourceMap: "inline",
sourceMapInline: true
}).code + "\n";
assert.strictEqual(code, readFileSync("test/input/issue-520/output.js", "utf8"));
});
it("Should warn for missing inline source map", function() {
var warn_function = Uglify.AST_Node.warn_function;
var warnings = [];
Uglify.AST_Node.warn_function = function(txt) {
warnings.push(txt);
};
try {
var result = Uglify.minify("./test/input/issue-1323/sample.js", {
inSourceMap: "inline",
mangle: false,
});
assert.strictEqual(result.code, "var bar=function(){function foo(bar){return bar}return foo}();");
assert.strictEqual(warnings.length, 1);
assert.strictEqual(warnings[0], "inline source map not found");
} finally {
Uglify.AST_Node.warn_function = warn_function;
}
});
it("Should fail with multiple input and inline source map", function() {
assert.throws(function() {
Uglify.minify([
"./test/input/issue-520/input.js",
"./test/input/issue-520/output.js"
], {
inSourceMap: "inline",
sourceMapInline: true
});
});
});
it("Should fail with SpiderMonkey and inline source map", function() {
assert.throws(function() {
Uglify.minify("./test/input/issue-520/input.js", {
inSourceMap: "inline",
sourceMapInline: true,
spidermonkey: true
});
});
});
});
describe("sourceMapInline", function() {
@@ -95,4 +141,34 @@ describe("minify", function() {
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();");
});
});
describe("JS_Parse_Error", function() {
it("should throw syntax error", function() {
assert.throws(function() {
Uglify.minify("function f(a{}", { fromString: true });
}, function(err) {
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token punc «{», expected punc «,»");
assert.strictEqual(err.filename, 0);
assert.strictEqual(err.line, 1);
assert.strictEqual(err.col, 12);
return true;
});
});
});
});

View File

@@ -15,7 +15,7 @@ describe("Number literals", function () {
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "SyntaxError: Legacy octal literals are not allowed in strict mode";
e.message === "Legacy octal literals are not allowed in strict mode";
}
for (var i = 0; i < inputs.length; i++) {
assert.throws(test(inputs[i]), error, inputs[i]);

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

@@ -19,7 +19,7 @@ describe("String literals", function() {
var error = function(e) {
return e instanceof UglifyJS.JS_Parse_Error &&
e.message === "SyntaxError: Unterminated string constant";
e.message === "Unterminated string constant";
};
for (var input in inputs) {
@@ -49,7 +49,7 @@ describe("String literals", function() {
var error = function(e) {
return e instanceof UglifyJS.JS_Parse_Error &&
e.message === "SyntaxError: Legacy octal escape sequences are not allowed in strict mode";
e.message === "Legacy octal escape sequences are not allowed in strict mode";
}
for (var input in inputs) {

View File

@@ -9,7 +9,7 @@ describe("With", function() {
}
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "SyntaxError: Strict mode may not include a with statement";
e.message === "Strict mode may not include a with statement";
}
assert.throws(test, error);
});

View File

@@ -194,6 +194,9 @@ function parse_test(file) {
if (node instanceof U.AST_LabeledStatement
&& tw.parent() instanceof U.AST_Toplevel) {
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);
return true;
}

View File

@@ -37,6 +37,15 @@ UglifyJS.AST_Node.warn_function = function(txt) {
console.error("WARN: %s", txt);
};
function read_source_map(code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
UglifyJS.AST_Node.warn("inline source map not found");
return null;
}
return JSON.parse(new Buffer(match[2], "base64"));
}
exports.minify = function(files, options) {
options = UglifyJS.defaults(options, {
spidermonkey : false,
@@ -57,17 +66,28 @@ exports.minify = function(files, options) {
});
UglifyJS.base54.reset();
var inMap = options.inSourceMap;
if (typeof inMap == "string" && inMap != "inline") {
inMap = JSON.parse(fs.readFileSync(inMap, "utf8"));
}
// 1. parse
var toplevel = null,
sourcesContent = {};
if (options.spidermonkey) {
if (inMap == "inline") {
throw new Error("inline source map only works with built-in parser");
}
toplevel = UglifyJS.AST_Node.from_mozilla_ast(files);
} else {
function addFile(file, fileUrl) {
var code = options.fromString
? file
: fs.readFileSync(file, "utf8");
if (inMap == "inline") {
inMap = read_source_map(code);
}
sourcesContent[fileUrl] = code;
toplevel = UglifyJS.parse(code, {
filename: fileUrl,
@@ -75,7 +95,12 @@ exports.minify = function(files, options) {
bare_returns: options.parse ? options.parse.bare_returns : undefined
});
}
if (!options.fromString) files = UglifyJS.simple_glob(files);
if (!options.fromString) {
files = UglifyJS.simple_glob(files);
if (inMap == "inline" && files.length > 1) {
throw new Error("inline source map only works with singular input");
}
}
[].concat(files).forEach(function (files, i) {
if (typeof files === 'string') {
addFile(files, options.fromString ? i : files);
@@ -114,11 +139,7 @@ exports.minify = function(files, options) {
}
// 5. output
var inMap = options.inSourceMap;
var output = {};
if (typeof options.inSourceMap == "string") {
inMap = JSON.parse(fs.readFileSync(options.inSourceMap, "utf8"));
}
var output = { max_line_len: 32000 };
if (options.outSourceMap || options.sourceMapInline) {
output.source_map = UglifyJS.SourceMap({
// prefer outFileName, otherwise use outSourceMap without .map suffix