Merge remote-tracking branch 'upstream/master' into ternary-improvements
This commit is contained in:
commit
d522107537
|
|
@ -1,6 +1,6 @@
|
||||||
UglifyJS 2
|
UglifyJS 2
|
||||||
==========
|
==========
|
||||||
[](https://travis-ci.org/mishoo/UglifyJS2)
|
[](https://travis-ci.org/mishoo/UglifyJS2)
|
||||||
|
|
||||||
UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.
|
UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.
|
||||||
|
|
||||||
|
|
@ -44,6 +44,11 @@ variable/function declared in another file will be matched properly.
|
||||||
If you want to read from STDIN instead, pass a single dash instead of input
|
If you want to read from STDIN instead, pass a single dash instead of input
|
||||||
files.
|
files.
|
||||||
|
|
||||||
|
If you wish to pass your options before the input files, separate the two with
|
||||||
|
a double dash to prevent input files being used as option arguments:
|
||||||
|
|
||||||
|
uglifyjs --compress --mangle -- input.js
|
||||||
|
|
||||||
The available options are:
|
The available options are:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -612,7 +617,7 @@ or, for a shortcut you can do:
|
||||||
var code = compressed_ast.print_to_string(options);
|
var code = compressed_ast.print_to_string(options);
|
||||||
```
|
```
|
||||||
|
|
||||||
As usual, `options` is optional. The output stream accepts a lot of otions,
|
As usual, `options` is optional. The output stream accepts a lot of options,
|
||||||
most of them documented above in section “Beautifier options”. The two
|
most of them documented above in section “Beautifier options”. The two
|
||||||
which we care about here are `source_map` and `comments`.
|
which we care about here are `source_map` and `comments`.
|
||||||
|
|
||||||
|
|
|
||||||
18
bin/uglifyjs
18
bin/uglifyjs
|
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
var UglifyJS = require("../tools/node");
|
var UglifyJS = require("../tools/node");
|
||||||
var sys = require("util");
|
var sys = require("util");
|
||||||
var optimist = require("optimist");
|
var yargs = require("yargs");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var async = require("async");
|
var async = require("async");
|
||||||
var acorn;
|
var acorn;
|
||||||
var ARGS = optimist
|
var ARGS = yargs
|
||||||
.usage("$0 input1.js [input2.js ...] [options]\n\
|
.usage("$0 input1.js [input2.js ...] [options]\n\
|
||||||
Use a single dash to read input from the standard input.\
|
Use a single dash to read input from the standard input.\
|
||||||
\n\n\
|
\n\n\
|
||||||
|
|
@ -64,6 +64,8 @@ You need to pass an argument to this option to specify the name that your module
|
||||||
.describe("v", "Verbose")
|
.describe("v", "Verbose")
|
||||||
.describe("V", "Print version number and exit.")
|
.describe("V", "Print version number and exit.")
|
||||||
.describe("noerr", "Don't throw an error for unknown options in -c, -b or -m.")
|
.describe("noerr", "Don't throw an error for unknown options in -c, -b or -m.")
|
||||||
|
.describe("bare-returns", "Allow return outside of functions. Useful when minifying CommonJS modules.")
|
||||||
|
.describe("keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.")
|
||||||
|
|
||||||
.alias("p", "prefix")
|
.alias("p", "prefix")
|
||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
|
|
@ -100,6 +102,8 @@ You need to pass an argument to this option to specify the name that your module
|
||||||
.boolean("lint")
|
.boolean("lint")
|
||||||
.boolean("V")
|
.boolean("V")
|
||||||
.boolean("noerr")
|
.boolean("noerr")
|
||||||
|
.boolean("bare-returns")
|
||||||
|
.boolean("keep-fnames")
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
|
|
||||||
|
|
@ -127,7 +131,7 @@ if (ARGS.ast_help) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.h || ARGS.help) {
|
if (ARGS.h || ARGS.help) {
|
||||||
sys.puts(optimist.help());
|
sys.puts(yargs.help());
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,6 +162,11 @@ if (ARGS.screw_ie8) {
|
||||||
OUTPUT_OPTIONS.screw_ie8 = true;
|
OUTPUT_OPTIONS.screw_ie8 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ARGS.keep_fnames) {
|
||||||
|
if (COMPRESS) COMPRESS.keep_fnames = true;
|
||||||
|
if (MANGLE) MANGLE.keep_fnames = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (BEAUTIFY)
|
if (BEAUTIFY)
|
||||||
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
|
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
|
||||||
|
|
||||||
|
|
@ -250,7 +259,7 @@ async.eachLimit(files, 1, function (file, cb) {
|
||||||
}
|
}
|
||||||
if (ARGS.p != null) {
|
if (ARGS.p != null) {
|
||||||
if (P_RELATIVE) {
|
if (P_RELATIVE) {
|
||||||
file = path.relative(path.dirname(ARGS.source_map), file);
|
file = path.relative(path.dirname(ARGS.source_map), file).replace(/\\/g, '/');
|
||||||
} else {
|
} else {
|
||||||
var p = parseInt(ARGS.p, 10);
|
var p = parseInt(ARGS.p, 10);
|
||||||
if (!isNaN(p)) {
|
if (!isNaN(p)) {
|
||||||
|
|
@ -278,6 +287,7 @@ async.eachLimit(files, 1, function (file, cb) {
|
||||||
filename : file,
|
filename : file,
|
||||||
toplevel : TOPLEVEL,
|
toplevel : TOPLEVEL,
|
||||||
expression : ARGS.expr,
|
expression : ARGS.expr,
|
||||||
|
bare_returns : ARGS.bare_returns,
|
||||||
});
|
});
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
||||||
|
|
|
||||||
26
lib/ast.js
26
lib/ast.js
|
|
@ -84,7 +84,7 @@ function DEFNODE(type, props, methods, base) {
|
||||||
return ctor;
|
return ctor;
|
||||||
};
|
};
|
||||||
|
|
||||||
var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {
|
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file", {
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
var AST_Node = DEFNODE("Node", "start end", {
|
var AST_Node = DEFNODE("Node", "start end", {
|
||||||
|
|
@ -205,21 +205,27 @@ var AST_DWLoop = DEFNODE("DWLoop", "condition", {
|
||||||
$documentation: "Base class for do/while statements",
|
$documentation: "Base class for do/while statements",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
|
condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
|
||||||
},
|
}
|
||||||
|
}, AST_IterationStatement);
|
||||||
|
|
||||||
|
var AST_Do = DEFNODE("Do", null, {
|
||||||
|
$documentation: "A `do` statement",
|
||||||
|
_walk: function(visitor) {
|
||||||
|
return visitor._visit(this, function(){
|
||||||
|
this.body._walk(visitor);
|
||||||
|
this.condition._walk(visitor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, AST_DWLoop);
|
||||||
|
|
||||||
|
var AST_While = DEFNODE("While", null, {
|
||||||
|
$documentation: "A `while` statement",
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
this.condition._walk(visitor);
|
this.condition._walk(visitor);
|
||||||
this.body._walk(visitor);
|
this.body._walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, AST_IterationStatement);
|
|
||||||
|
|
||||||
var AST_Do = DEFNODE("Do", null, {
|
|
||||||
$documentation: "A `do` statement",
|
|
||||||
}, AST_DWLoop);
|
|
||||||
|
|
||||||
var AST_While = DEFNODE("While", null, {
|
|
||||||
$documentation: "A `while` statement",
|
|
||||||
}, AST_DWLoop);
|
}, AST_DWLoop);
|
||||||
|
|
||||||
var AST_For = DEFNODE("For", "init condition step", {
|
var AST_For = DEFNODE("For", "init condition step", {
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ function Compressor(options, false_by_default) {
|
||||||
unused : !false_by_default,
|
unused : !false_by_default,
|
||||||
hoist_funs : !false_by_default,
|
hoist_funs : !false_by_default,
|
||||||
keep_fargs : false,
|
keep_fargs : false,
|
||||||
|
keep_fnames : false,
|
||||||
hoist_vars : false,
|
hoist_vars : false,
|
||||||
if_return : !false_by_default,
|
if_return : !false_by_default,
|
||||||
join_vars : !false_by_default,
|
join_vars : !false_by_default,
|
||||||
|
|
@ -162,10 +163,10 @@ merge(Compressor.prototype, {
|
||||||
return make_node(AST_Undefined, orig).optimize(compressor);
|
return make_node(AST_Undefined, orig).optimize(compressor);
|
||||||
default:
|
default:
|
||||||
if (val === null) {
|
if (val === null) {
|
||||||
return make_node(AST_Null, orig).optimize(compressor);
|
return make_node(AST_Null, orig, { value: null }).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (val instanceof RegExp) {
|
if (val instanceof RegExp) {
|
||||||
return make_node(AST_RegExp, orig).optimize(compressor);
|
return make_node(AST_RegExp, orig, { value: val }).optimize(compressor);
|
||||||
}
|
}
|
||||||
throw new Error(string_template("Can't handle constant of type: {type}", {
|
throw new Error(string_template("Can't handle constant of type: {type}", {
|
||||||
type: typeof val
|
type: typeof val
|
||||||
|
|
@ -225,6 +226,17 @@ merge(Compressor.prototype, {
|
||||||
return statements;
|
return statements;
|
||||||
|
|
||||||
function process_for_angular(statements) {
|
function process_for_angular(statements) {
|
||||||
|
function has_inject(comment) {
|
||||||
|
return /@ngInject/.test(comment.value);
|
||||||
|
}
|
||||||
|
function make_arguments_names_list(func) {
|
||||||
|
return func.argnames.map(function(sym){
|
||||||
|
return make_node(AST_String, sym, { value: sym.name });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function make_array(orig, elements) {
|
||||||
|
return make_node(AST_Array, orig, { elements: elements });
|
||||||
|
}
|
||||||
function make_injector(func, name) {
|
function make_injector(func, name) {
|
||||||
return make_node(AST_SimpleStatement, func, {
|
return make_node(AST_SimpleStatement, func, {
|
||||||
body: make_node(AST_Assign, func, {
|
body: make_node(AST_Assign, func, {
|
||||||
|
|
@ -233,27 +245,44 @@ merge(Compressor.prototype, {
|
||||||
expression: make_node(AST_SymbolRef, name, name),
|
expression: make_node(AST_SymbolRef, name, name),
|
||||||
property: "$inject"
|
property: "$inject"
|
||||||
}),
|
}),
|
||||||
right: make_node(AST_Array, func, {
|
right: make_array(func, make_arguments_names_list(func))
|
||||||
elements: func.argnames.map(function(sym){
|
|
||||||
return make_node(AST_String, sym, { value: sym.name });
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function check_expression(body) {
|
||||||
|
if (body && body.args) {
|
||||||
|
// if this is a function call check all of arguments passed
|
||||||
|
body.args.forEach(function(argument, index, array) {
|
||||||
|
var comments = argument.start.comments_before;
|
||||||
|
// if the argument is function preceded by @ngInject
|
||||||
|
if (argument instanceof AST_Lambda && comments.length && has_inject(comments[0])) {
|
||||||
|
// replace the function with an array of names of its parameters and function at the end
|
||||||
|
array[index] = make_array(argument, make_arguments_names_list(argument).concat(argument));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// if this is chained call check previous one recursively
|
||||||
|
if (body.expression && body.expression.expression) {
|
||||||
|
check_expression(body.expression.expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return statements.reduce(function(a, stat){
|
return statements.reduce(function(a, stat){
|
||||||
a.push(stat);
|
a.push(stat);
|
||||||
|
|
||||||
|
if (stat.body && stat.body.args) {
|
||||||
|
check_expression(stat.body);
|
||||||
|
} else {
|
||||||
var token = stat.start;
|
var token = stat.start;
|
||||||
var comments = token.comments_before;
|
var comments = token.comments_before;
|
||||||
if (comments && comments.length > 0) {
|
if (comments && comments.length > 0) {
|
||||||
var last = comments.pop();
|
var last = comments.pop();
|
||||||
if (/@ngInject/.test(last.value)) {
|
if (has_inject(last)) {
|
||||||
// case 1: defun
|
// case 1: defun
|
||||||
if (stat instanceof AST_Defun) {
|
if (stat instanceof AST_Defun) {
|
||||||
a.push(make_injector(stat, stat.name));
|
a.push(make_injector(stat, stat.name));
|
||||||
}
|
}
|
||||||
else if (stat instanceof AST_Definitions) {
|
else if (stat instanceof AST_Definitions) {
|
||||||
stat.definitions.forEach(function(def){
|
stat.definitions.forEach(function(def) {
|
||||||
if (def.value && def.value instanceof AST_Lambda) {
|
if (def.value && def.value instanceof AST_Lambda) {
|
||||||
a.push(make_injector(def.value, def.name));
|
a.push(make_injector(def.value, def.name));
|
||||||
}
|
}
|
||||||
|
|
@ -264,6 +293,8 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
@ -949,7 +980,7 @@ merge(Compressor.prototype, {
|
||||||
def(AST_BlockStatement, block_aborts);
|
def(AST_BlockStatement, block_aborts);
|
||||||
def(AST_SwitchBranch, block_aborts);
|
def(AST_SwitchBranch, block_aborts);
|
||||||
def(AST_If, function(){
|
def(AST_If, function(){
|
||||||
return this.alternative && aborts(this.body) && aborts(this.alternative);
|
return this.alternative && aborts(this.body) && aborts(this.alternative) && this;
|
||||||
});
|
});
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
node.DEFMETHOD("aborts", func);
|
node.DEFMETHOD("aborts", func);
|
||||||
|
|
@ -1666,7 +1697,7 @@ merge(Compressor.prototype, {
|
||||||
|
|
||||||
OPT(AST_Function, function(self, compressor){
|
OPT(AST_Function, function(self, compressor){
|
||||||
self = AST_Lambda.prototype.optimize.call(self, compressor);
|
self = AST_Lambda.prototype.optimize.call(self, compressor);
|
||||||
if (compressor.option("unused")) {
|
if (compressor.option("unused") && !compressor.option("keep_fnames")) {
|
||||||
if (self.name && self.name.unreferenced()) {
|
if (self.name && self.name.unreferenced()) {
|
||||||
self.name = null;
|
self.name = null;
|
||||||
}
|
}
|
||||||
|
|
@ -1722,6 +1753,11 @@ merge(Compressor.prototype, {
|
||||||
}).transform(compressor);
|
}).transform(compressor);
|
||||||
break;
|
break;
|
||||||
case "Function":
|
case "Function":
|
||||||
|
// new Function() => function(){}
|
||||||
|
if (self.args.length == 0) return make_node(AST_Function, self, {
|
||||||
|
argnames: [],
|
||||||
|
body: []
|
||||||
|
});
|
||||||
if (all(self.args, function(x){ return x instanceof AST_String })) {
|
if (all(self.args, function(x){ return x instanceof AST_String })) {
|
||||||
// quite a corner-case, but we can handle it:
|
// quite a corner-case, but we can handle it:
|
||||||
// https://github.com/mishoo/UglifyJS2/issues/203
|
// https://github.com/mishoo/UglifyJS2/issues/203
|
||||||
|
|
@ -1901,7 +1937,7 @@ merge(Compressor.prototype, {
|
||||||
if (self.cdr instanceof AST_UnaryPrefix
|
if (self.cdr instanceof AST_UnaryPrefix
|
||||||
&& self.cdr.operator == "void"
|
&& self.cdr.operator == "void"
|
||||||
&& !self.cdr.expression.has_side_effects(compressor)) {
|
&& !self.cdr.expression.has_side_effects(compressor)) {
|
||||||
self.cdr.operator = self.car;
|
self.cdr.expression = self.car;
|
||||||
return self.cdr;
|
return self.cdr;
|
||||||
}
|
}
|
||||||
if (self.cdr instanceof AST_Undefined) {
|
if (self.cdr instanceof AST_Undefined) {
|
||||||
|
|
@ -2203,14 +2239,30 @@ merge(Compressor.prototype, {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
return make_node(AST_Undefined, self);
|
return make_node(AST_Undefined, self);
|
||||||
case "NaN":
|
case "NaN":
|
||||||
return make_node(AST_NaN, self);
|
return make_node(AST_NaN, self).transform(compressor);
|
||||||
case "Infinity":
|
case "Infinity":
|
||||||
return make_node(AST_Infinity, self);
|
return make_node(AST_Infinity, self).transform(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OPT(AST_Infinity, function (self, compressor) {
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator : '/',
|
||||||
|
left : make_node(AST_Number, null, {value: 1}),
|
||||||
|
right : make_node(AST_Number, null, {value: 0})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
OPT(AST_NaN, function (self, compressor) {
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator : '/',
|
||||||
|
left : make_node(AST_Number, null, {value: 0}),
|
||||||
|
right : make_node(AST_Number, null, {value: 0})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
OPT(AST_Undefined, function(self, compressor){
|
OPT(AST_Undefined, function(self, compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var scope = compressor.find_parent(AST_Scope);
|
var scope = compressor.find_parent(AST_Scope);
|
||||||
|
|
|
||||||
|
|
@ -370,25 +370,29 @@
|
||||||
/* -----[ tools ]----- */
|
/* -----[ tools ]----- */
|
||||||
|
|
||||||
function my_start_token(moznode) {
|
function my_start_token(moznode) {
|
||||||
var loc = moznode.loc;
|
var loc = moznode.loc, start = loc && loc.start;
|
||||||
var range = moznode.range;
|
var range = moznode.range;
|
||||||
return new AST_Token({
|
return new AST_Token({
|
||||||
file : loc && loc.source,
|
file : loc && loc.source,
|
||||||
line : loc && loc.start.line,
|
line : start && start.line,
|
||||||
col : loc && loc.start.column,
|
col : start && start.column,
|
||||||
pos : range ? range[0] : moznode.start,
|
pos : range ? range[0] : moznode.start,
|
||||||
|
endline : start && start.line,
|
||||||
|
endcol : start && start.column,
|
||||||
endpos : range ? range[0] : moznode.start
|
endpos : range ? range[0] : moznode.start
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function my_end_token(moznode) {
|
function my_end_token(moznode) {
|
||||||
var loc = moznode.loc;
|
var loc = moznode.loc, end = loc && loc.end;
|
||||||
var range = moznode.range;
|
var range = moznode.range;
|
||||||
return new AST_Token({
|
return new AST_Token({
|
||||||
file : loc && loc.source,
|
file : loc && loc.source,
|
||||||
line : loc && loc.end.line,
|
line : end && end.line,
|
||||||
col : loc && loc.end.column,
|
col : end && end.column,
|
||||||
pos : range ? range[1] : moznode.end,
|
pos : range ? range[1] : moznode.end,
|
||||||
|
endline : end && end.line,
|
||||||
|
endcol : end && end.column,
|
||||||
endpos : range ? range[1] : moznode.end
|
endpos : range ? range[1] : moznode.end
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -465,23 +469,16 @@
|
||||||
return ast;
|
return ast;
|
||||||
};
|
};
|
||||||
|
|
||||||
function moz_sub_loc(token) {
|
function set_moz_loc(mynode, moznode, myparent) {
|
||||||
return token.line ? {
|
|
||||||
line: token.line,
|
|
||||||
column: token.col
|
|
||||||
} : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
function set_moz_loc(mynode, moznode) {
|
|
||||||
var start = mynode.start;
|
var start = mynode.start;
|
||||||
var end = mynode.end;
|
var end = mynode.end;
|
||||||
if (start.pos != null && end.pos != null) {
|
if (start.pos != null && end.endpos != null) {
|
||||||
moznode.range = [start.pos, end.pos];
|
moznode.range = [start.pos, end.endpos];
|
||||||
}
|
}
|
||||||
if (start.line) {
|
if (start.line) {
|
||||||
moznode.loc = {
|
moznode.loc = {
|
||||||
start: moz_sub_loc(start),
|
start: {line: start.line, column: start.col},
|
||||||
end: moz_sub_loc(end)
|
end: end.endline ? {line: end.endline, column: end.endcol} : null
|
||||||
};
|
};
|
||||||
if (start.file) {
|
if (start.file) {
|
||||||
moznode.loc.source = start.file;
|
moznode.loc.source = start.file;
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ function OutputStream(options) {
|
||||||
|
|
||||||
function make_string(str) {
|
function make_string(str) {
|
||||||
var dq = 0, sq = 0;
|
var dq = 0, sq = 0;
|
||||||
str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
|
str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s){
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case "\\": return "\\\\";
|
case "\\": return "\\\\";
|
||||||
case "\b": return "\\b";
|
case "\b": return "\\b";
|
||||||
|
|
@ -98,6 +98,7 @@ function OutputStream(options) {
|
||||||
case '"': ++dq; return '"';
|
case '"': ++dq; return '"';
|
||||||
case "'": ++sq; return "'";
|
case "'": ++sq; return "'";
|
||||||
case "\0": return "\\x00";
|
case "\0": return "\\x00";
|
||||||
|
case "\ufeff": return "\\ufeff";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
|
@ -221,7 +222,7 @@ function OutputStream(options) {
|
||||||
|
|
||||||
var newline = options.beautify ? function() {
|
var newline = options.beautify ? function() {
|
||||||
print("\n");
|
print("\n");
|
||||||
} : noop;
|
} : maybe_newline;
|
||||||
|
|
||||||
var semicolon = options.beautify ? function() {
|
var semicolon = options.beautify ? function() {
|
||||||
print(";");
|
print(";");
|
||||||
|
|
@ -549,12 +550,6 @@ function OutputStream(options) {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_NaN, function(output){
|
|
||||||
var p = output.parent();
|
|
||||||
if (p instanceof AST_PropAccess && p.expression === this)
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
PARENS([ AST_Assign, AST_Conditional ], function (output){
|
PARENS([ AST_Assign, AST_Conditional ], function (output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// !(a = false) → true
|
// !(a = false) → true
|
||||||
|
|
@ -1109,10 +1104,10 @@ function OutputStream(options) {
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Hole, noop);
|
DEFPRINT(AST_Hole, noop);
|
||||||
DEFPRINT(AST_Infinity, function(self, output){
|
DEFPRINT(AST_Infinity, function(self, output){
|
||||||
output.print("1/0");
|
output.print("Infinity");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_NaN, function(self, output){
|
DEFPRINT(AST_NaN, function(self, output){
|
||||||
output.print("0/0");
|
output.print("NaN");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_This, function(self, output){
|
DEFPRINT(AST_This, function(self, output){
|
||||||
output.print("this");
|
output.print("this");
|
||||||
|
|
|
||||||
15
lib/parse.js
15
lib/parse.js
|
|
@ -206,7 +206,7 @@ var EX_EOF = {};
|
||||||
function tokenizer($TEXT, filename, html5_comments) {
|
function tokenizer($TEXT, filename, html5_comments) {
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ''),
|
text : $TEXT.replace(/\uFEFF/g, ''),
|
||||||
filename : filename,
|
filename : filename,
|
||||||
pos : 0,
|
pos : 0,
|
||||||
tokpos : 0,
|
tokpos : 0,
|
||||||
|
|
@ -225,10 +225,15 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
var ch = S.text.charAt(S.pos++);
|
var ch = S.text.charAt(S.pos++);
|
||||||
if (signal_eof && !ch)
|
if (signal_eof && !ch)
|
||||||
throw EX_EOF;
|
throw EX_EOF;
|
||||||
if (ch == "\n") {
|
if ("\r\n\u2028\u2029".indexOf(ch) >= 0) {
|
||||||
S.newline_before = S.newline_before || !in_string;
|
S.newline_before = S.newline_before || !in_string;
|
||||||
++S.line;
|
++S.line;
|
||||||
S.col = 0;
|
S.col = 0;
|
||||||
|
if (!in_string && ch == "\r" && peek() == "\n") {
|
||||||
|
// treat a \r\n sequence as a single \n
|
||||||
|
++S.pos;
|
||||||
|
ch = "\n";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
++S.col;
|
++S.col;
|
||||||
}
|
}
|
||||||
|
|
@ -267,6 +272,8 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
line : S.tokline,
|
line : S.tokline,
|
||||||
col : S.tokcol,
|
col : S.tokcol,
|
||||||
pos : S.tokpos,
|
pos : S.tokpos,
|
||||||
|
endline : S.line,
|
||||||
|
endcol : S.col,
|
||||||
endpos : S.pos,
|
endpos : S.pos,
|
||||||
nlb : S.newline_before,
|
nlb : S.newline_before,
|
||||||
file : filename
|
file : filename
|
||||||
|
|
@ -392,6 +399,7 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||||
ret = S.text.substring(S.pos, i);
|
ret = S.text.substring(S.pos, i);
|
||||||
S.pos = i;
|
S.pos = i;
|
||||||
}
|
}
|
||||||
|
S.col = S.tokcol + (S.pos - S.tokpos);
|
||||||
S.comments_before.push(token(type, ret, true));
|
S.comments_before.push(token(type, ret, true));
|
||||||
S.regex_allowed = regex_allowed;
|
S.regex_allowed = regex_allowed;
|
||||||
return next_token();
|
return next_token();
|
||||||
|
|
@ -609,6 +617,7 @@ function parse($TEXT, options) {
|
||||||
toplevel : null,
|
toplevel : null,
|
||||||
expression : false,
|
expression : false,
|
||||||
html5_comments : true,
|
html5_comments : true,
|
||||||
|
bare_returns : false,
|
||||||
});
|
});
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
|
|
@ -788,7 +797,7 @@ function parse($TEXT, options) {
|
||||||
return if_();
|
return if_();
|
||||||
|
|
||||||
case "return":
|
case "return":
|
||||||
if (S.in_function == 0)
|
if (S.in_function == 0 && !options.bare_returns)
|
||||||
croak("'return' outside of function");
|
croak("'return' outside of function");
|
||||||
return new AST_Return({
|
return new AST_Return({
|
||||||
value: ( is("punc", ";")
|
value: ( is("punc", ";")
|
||||||
|
|
|
||||||
14
lib/scope.js
14
lib/scope.js
|
|
@ -57,9 +57,14 @@ function SymbolDef(scope, index, orig) {
|
||||||
|
|
||||||
SymbolDef.prototype = {
|
SymbolDef.prototype = {
|
||||||
unmangleable: function(options) {
|
unmangleable: function(options) {
|
||||||
return (this.global && !(options && options.toplevel))
|
if (!options) options = {};
|
||||||
|
|
||||||
|
return (this.global && !options.toplevel)
|
||||||
|| this.undeclared
|
|| this.undeclared
|
||||||
|| (!(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with));
|
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|
||||||
|
|| (options.keep_fnames
|
||||||
|
&& (this.orig[0] instanceof AST_SymbolLambda
|
||||||
|
|| this.orig[0] instanceof AST_SymbolDefun));
|
||||||
},
|
},
|
||||||
mangle: function(options) {
|
mangle: function(options) {
|
||||||
if (!this.mangled_name && !this.unmangleable(options)) {
|
if (!this.mangled_name && !this.unmangleable(options)) {
|
||||||
|
|
@ -326,7 +331,8 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
|
||||||
eval : false,
|
eval : false,
|
||||||
sort : false,
|
sort : false,
|
||||||
toplevel : false,
|
toplevel : false,
|
||||||
screw_ie8 : false
|
screw_ie8 : false,
|
||||||
|
keep_fnames : false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -471,7 +477,9 @@ var base54 = (function() {
|
||||||
base54.freq = function(){ return frequency };
|
base54.freq = function(){ return frequency };
|
||||||
function base54(num) {
|
function base54(num) {
|
||||||
var ret = "", base = 54;
|
var ret = "", base = 54;
|
||||||
|
num++;
|
||||||
do {
|
do {
|
||||||
|
num--;
|
||||||
ret += String.fromCharCode(chars[num % base]);
|
ret += String.fromCharCode(chars[num % base]);
|
||||||
num = Math.floor(num / base);
|
num = Math.floor(num / base);
|
||||||
base = 64;
|
base = 64;
|
||||||
|
|
|
||||||
|
|
@ -53,11 +53,16 @@ function SourceMap(options) {
|
||||||
orig_line_diff : 0,
|
orig_line_diff : 0,
|
||||||
dest_line_diff : 0,
|
dest_line_diff : 0,
|
||||||
});
|
});
|
||||||
var generator = new MOZ_SourceMap.SourceMapGenerator({
|
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
|
||||||
|
var generator;
|
||||||
|
if (orig_map) {
|
||||||
|
generator = MOZ_SourceMap.SourceMapGenerator.fromSourceMap(orig_map);
|
||||||
|
} else {
|
||||||
|
generator = new MOZ_SourceMap.SourceMapGenerator({
|
||||||
file : options.file,
|
file : options.file,
|
||||||
sourceRoot : options.root
|
sourceRoot : options.root
|
||||||
});
|
});
|
||||||
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
|
}
|
||||||
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
|
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||||
if (orig_map) {
|
if (orig_map) {
|
||||||
var info = orig_map.originalPositionFor({
|
var info = orig_map.originalPositionFor({
|
||||||
|
|
@ -70,7 +75,7 @@ function SourceMap(options) {
|
||||||
source = info.source;
|
source = info.source;
|
||||||
orig_line = info.line;
|
orig_line = info.line;
|
||||||
orig_col = info.column;
|
orig_col = info.column;
|
||||||
name = info.name;
|
name = info.name || name;
|
||||||
}
|
}
|
||||||
generator.addMapping({
|
generator.addMapping({
|
||||||
generated : { line: gen_line + options.dest_line_diff, column: gen_col },
|
generated : { line: gen_line + options.dest_line_diff, column: gen_col },
|
||||||
|
|
@ -78,7 +83,7 @@ function SourceMap(options) {
|
||||||
source : source,
|
source : source,
|
||||||
name : name
|
name : name
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
return {
|
return {
|
||||||
add : add,
|
add : add,
|
||||||
get : function() { return generator },
|
get : function() { return generator },
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"main": "tools/node.js",
|
"main": "tools/node.js",
|
||||||
"version": "2.4.15",
|
"version": "2.4.16",
|
||||||
"engines": { "node" : ">=0.4.0" },
|
"engines": { "node" : ">=0.4.0" },
|
||||||
"maintainers": [{
|
"maintainers": [{
|
||||||
"name": "Mihai Bazon",
|
"name": "Mihai Bazon",
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async" : "~0.2.6",
|
"async" : "~0.2.6",
|
||||||
"source-map" : "0.1.34",
|
"source-map" : "0.1.34",
|
||||||
"optimist": "~0.3.5",
|
"yargs": "~1.3.3",
|
||||||
"uglify-to-browserify": "~1.0.0"
|
"uglify-to-browserify": "~1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
67
test/compress/angular-inject.js
vendored
Normal file
67
test/compress/angular-inject.js
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
ng_inject_defun: {
|
||||||
|
options = {
|
||||||
|
angular: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
/*@ngInject*/
|
||||||
|
function Controller(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function Controller(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
Controller.$inject=['dependency']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ng_inject_assignment: {
|
||||||
|
options = {
|
||||||
|
angular: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
/*@ngInject*/
|
||||||
|
var Controller = function(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var Controller = function(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
Controller.$inject=['dependency']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ng_inject_inline: {
|
||||||
|
options = {
|
||||||
|
angular: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
angular.module('a').
|
||||||
|
factory('b',
|
||||||
|
/*@ngInject*/
|
||||||
|
function(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}).
|
||||||
|
directive('c',
|
||||||
|
/*@ngInject*/
|
||||||
|
function(anotherDependency) {
|
||||||
|
return anotherDependency;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
angular.module('a').
|
||||||
|
factory('b',[
|
||||||
|
'dependency',
|
||||||
|
function(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}]).
|
||||||
|
directive('c',[
|
||||||
|
'anotherDependency',
|
||||||
|
function(anotherDependency) {
|
||||||
|
return anotherDependency;
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -163,3 +163,17 @@ used_var_in_catch: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keep_fnames: {
|
||||||
|
options = { unused: true, keep_fnames: true };
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
return function bar(baz) {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
return function bar() {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
test/compress/issue-597.js
Normal file
25
test/compress/issue-597.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
NaN_and_Infinity_must_have_parens: {
|
||||||
|
options = {};
|
||||||
|
input: {
|
||||||
|
Infinity.toString();
|
||||||
|
NaN.toString();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(1/0).toString();
|
||||||
|
(0/0).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
|
||||||
|
options = {};
|
||||||
|
input: {
|
||||||
|
var Infinity, NaN;
|
||||||
|
Infinity.toString();
|
||||||
|
NaN.toString();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var Infinity, NaN;
|
||||||
|
Infinity.toString();
|
||||||
|
NaN.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
test/compress/issue-611.js
Normal file
21
test/compress/issue-611.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
issue_611: {
|
||||||
|
options = {
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
define(function() {
|
||||||
|
function fn() {}
|
||||||
|
if (fn()) {
|
||||||
|
fn();
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
define(function() {
|
||||||
|
function fn(){}
|
||||||
|
if (fn()) return void fn();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,8 @@ var sys = require("util");
|
||||||
var UglifyJS = vm.createContext({
|
var UglifyJS = vm.createContext({
|
||||||
sys : sys,
|
sys : sys,
|
||||||
console : console,
|
console : console,
|
||||||
|
process : process,
|
||||||
|
Buffer : Buffer,
|
||||||
MOZ_SourceMap : require("source-map")
|
MOZ_SourceMap : require("source-map")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -33,7 +35,7 @@ var FILES = exports.FILES = [
|
||||||
"../lib/sourcemap.js",
|
"../lib/sourcemap.js",
|
||||||
"../lib/mozilla-ast.js"
|
"../lib/mozilla-ast.js"
|
||||||
].map(function(file){
|
].map(function(file){
|
||||||
return path.join(path.dirname(fs.realpathSync(__filename)), file);
|
return fs.realpathSync(path.join(path.dirname(__filename), file));
|
||||||
});
|
});
|
||||||
|
|
||||||
FILES.forEach(load_global);
|
FILES.forEach(load_global);
|
||||||
|
|
@ -95,8 +97,8 @@ exports.minify = function(files, options) {
|
||||||
|
|
||||||
// 3. mangle
|
// 3. mangle
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
toplevel.figure_out_scope();
|
toplevel.figure_out_scope(options.mangle);
|
||||||
toplevel.compute_char_frequency();
|
toplevel.compute_char_frequency(options.mangle);
|
||||||
toplevel.mangle_names(options.mangle);
|
toplevel.mangle_names(options.mangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user