Compare commits

...

33 Commits

Author SHA1 Message Date
Mihai Bazon
75cdbf19aa v2.4.10 2014-01-18 12:32:45 +02:00
Mihai Bazon
4339bd5cfa Don't unescape \x2f (slash) in regexps. #54 2014-01-18 12:31:50 +02:00
Mihai Bazon
1ab2fdaa10 Fix example 2014-01-17 15:48:47 +02:00
Mihai Bazon
eda540f6ec v2.4.9 2014-01-15 22:31:09 +02:00
Mihai Bazon
90a330da16 simplify 2014-01-10 10:36:15 +02:00
Mihai Bazon
cad1f9cbd1 Unescape Unicode sequences in regexps when ascii_only is false. #54 2014-01-10 10:33:58 +02:00
Mihai Bazon
c3087dd179 Better process_for_angular before other statement reductions. #395 2014-01-08 11:39:24 +02:00
Mihai Bazon
2c305af478 Support @ngInject with angular compressor option. Close #395. 2014-01-08 11:28:32 +02:00
Mihai Bazon
72e6f64ca8 Disable node 0.6 since the build fails consistently and it's not our fault. 2014-01-07 18:56:18 +02:00
Mihai Bazon
b9fac687ff Support SpiderMonkey AST in UglifyJS.minify. Fix #393. 2014-01-07 18:42:48 +02:00
Mihai Bazon
2c88eb6fbe doh. 2014-01-07 12:54:14 +02:00
Mihai Bazon
a67e3bfdd3 Fix #392 2014-01-07 12:48:54 +02:00
Mihai Bazon
27142df4f5 minor: exp["10"] => exp[10] 2014-01-07 12:48:21 +02:00
Mihai Bazon
5e4c7f4245 Fix parens for property access -- (foo, bar)["baz"] 2014-01-05 11:48:01 +02:00
Mihai Bazon
b521b4b926 Conditional/call optimization
foo ? bar(x) : bar(y)  ==>  bar(foo ? x : y)
2013-12-29 10:31:30 +02:00
Mihai Bazon
aa9de76370 Mark yield as reserved word. Close #375. 2013-12-22 20:52:19 +02:00
Mihai Bazon
5a083a938d Optimize seq,void 0. Close #377.
(x, void 0)    => void x
    (x, undefined) => void x
2013-12-22 11:36:45 +02:00
Mihai Bazon
7a30d826b8 Better fix for comments in AST_Exit
Close #374
2013-12-18 15:54:12 +02:00
Mihai Bazon
be55a09edf Take out all comments from an AST_Exit's value
Fix #372
2013-12-18 13:30:26 +02:00
Mihai Bazon
15a148ff6d v2.4.8 2013-12-18 12:10:43 +02:00
Mihai Bazon
428e19fed2 Add option to adjust the src/target line in the source map 2013-12-18 12:10:02 +02:00
Mihai Bazon
f65e55dff4 minor 2013-12-16 20:37:09 +02:00
Mihai Bazon
b634018618 Merge pull request #371 from colorhook/master
bugfix #242
2013-12-16 00:21:07 -08:00
colorhook
fa3300f314 bugfix #242 2013-12-16 15:53:43 +08:00
Mihai Bazon
bd0886a2c0 semicolons 2013-12-10 20:24:27 +02:00
Mihai Bazon
248f304f02 Merge pull request #245 from ForbesLindesay/patch-1
Make `DefaultsError` a real `Error` object
2013-12-10 10:23:29 -08:00
Mihai Bazon
dc5f70eab5 Add drop_console option to the compressor 2013-12-10 19:44:41 +02:00
Mihai Bazon
df8c5623af minor 2013-12-10 19:39:03 +02:00
Mihai Bazon
a790c09c91 v2.4.7 2013-12-09 12:09:31 +02:00
Mihai Bazon
8f35a363d9 AST_Catch shouldn't really inherit from AST_Scope. Fix #363
I hereby acknowledge that figure_out_scope has become a mess.
2013-12-05 13:30:29 +02:00
Mihai Bazon
d2190c2bf3 Properly scope catch identifier when --screw-ie8
Fix #344
2013-11-28 16:43:30 +02:00
Mihai Bazon
ea10642572 v2.4.6, because npm is foobar 2013-11-28 15:05:32 +02:00
Forbes Lindesay
dfa395f6ff Make DefaultsError a real Error object 2013-07-22 01:44:03 +01:00
15 changed files with 299 additions and 63 deletions

View File

@@ -1,7 +1,6 @@
language: node_js language: node_js
node_js: node_js:
- "0.4" - "0.4"
- "0.6"
- "0.8" - "0.8"
- "0.10" - "0.10"
- "0.11" - "0.11"

View File

@@ -249,6 +249,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
statement would get discarded. The current implementation adds some statement would get discarded. The current implementation adds some
overhead (compression will be slower). overhead (compression will be slower).
- `drop_console` -- default `false`. Pass `true` to discard calls to
`console.*` functions.
### The `unsafe` option ### The `unsafe` option
It enables some transformations that *might* break code logic in certain It enables some transformations that *might* break code logic in certain
@@ -502,7 +505,7 @@ something like this:
```javascript ```javascript
var toplevel = null; var toplevel = null;
files.forEach(function(file){ files.forEach(function(file){
var code = fs.readFileSync(file); var code = fs.readFileSync(file, "utf8");
toplevel = UglifyJS.parse(code, { toplevel = UglifyJS.parse(code, {
filename: file, filename: file,
toplevel: toplevel toplevel: toplevel

View File

@@ -357,7 +357,6 @@ async.eachLimit(files, 1, function (file, cb) {
fs.writeFileSync(OUTPUT_FILE, output, "utf8"); fs.writeFileSync(OUTPUT_FILE, output, "utf8");
} else { } else {
sys.print(output); sys.print(output);
sys.error("\n");
} }
if (ARGS.stats) { if (ARGS.stats) {

View File

@@ -498,12 +498,6 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
} }
}, AST_Block); }, AST_Block);
// XXX: this is wrong according to ECMA-262 (12.4). the catch block
// should introduce another scope, as the argname should be visible
// only inside the catch block. However, doing it this way because of
// IE which simply introduces the name in the surrounding scope. If
// we ever want to fix this then AST_Catch should inherit from
// AST_Scope.
var AST_Catch = DEFNODE("Catch", "argname", { var AST_Catch = DEFNODE("Catch", "argname", {
$documentation: "A `catch` node; only makes sense as part of a `try` statement", $documentation: "A `catch` node; only makes sense as part of a `try` statement",
$propdoc: { $propdoc: {

View File

@@ -70,6 +70,8 @@ function Compressor(options, false_by_default) {
pure_funcs : null, pure_funcs : null,
negate_iife : !false_by_default, negate_iife : !false_by_default,
screw_ie8 : false, screw_ie8 : false,
drop_console : false,
angular : false,
warnings : true, warnings : true,
global_defs : {} global_defs : {}
@@ -197,6 +199,9 @@ merge(Compressor.prototype, {
var CHANGED; var CHANGED;
do { do {
CHANGED = false; CHANGED = false;
if (compressor.option("angular")) {
statements = process_for_angular(statements);
}
statements = eliminate_spurious_blocks(statements); statements = eliminate_spurious_blocks(statements);
if (compressor.option("dead_code")) { if (compressor.option("dead_code")) {
statements = eliminate_dead_code(statements, compressor); statements = eliminate_dead_code(statements, compressor);
@@ -218,6 +223,50 @@ merge(Compressor.prototype, {
return statements; return statements;
function process_for_angular(statements) {
function make_injector(func, name) {
return make_node(AST_SimpleStatement, func, {
body: make_node(AST_Assign, func, {
operator: "=",
left: make_node(AST_Dot, name, {
expression: make_node(AST_SymbolRef, name, name),
property: "$inject"
}),
right: make_node(AST_Array, func, {
elements: func.argnames.map(function(sym){
return make_node(AST_String, sym, { value: sym.name });
})
})
})
});
}
return statements.reduce(function(a, stat){
a.push(stat);
var token = stat.start;
var comments = token.comments_before;
if (comments && comments.length > 0) {
var last = comments.pop();
if (/@ngInject/.test(last.value)) {
// case 1: defun
if (stat instanceof AST_Defun) {
a.push(make_injector(stat, stat.name));
}
else if (stat instanceof AST_Definitions) {
stat.definitions.forEach(function(def){
if (def.value && def.value instanceof AST_Lambda) {
a.push(make_injector(def.value, def.name));
}
});
}
else {
compressor.warn("Unknown statement marked with @ngInject [{file}:{line},{col}]", token);
}
}
}
return a;
}, []);
}
function eliminate_spurious_blocks(statements) { function eliminate_spurious_blocks(statements) {
var seen_dirs = []; var seen_dirs = [];
return statements.reduce(function(a, stat){ return statements.reduce(function(a, stat){
@@ -1669,10 +1718,10 @@ merge(Compressor.prototype, {
return arg.value; return arg.value;
}).join(",") + "){" + self.args[self.args.length - 1].value + "})()"; }).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
var ast = parse(code); var ast = parse(code);
ast.figure_out_scope(); ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });
var comp = new Compressor(compressor.options); var comp = new Compressor(compressor.options);
ast = ast.transform(comp); ast = ast.transform(comp);
ast.figure_out_scope(); ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });
ast.mangle_names(); ast.mangle_names();
var fun; var fun;
try { try {
@@ -1773,6 +1822,14 @@ merge(Compressor.prototype, {
return make_node(AST_Undefined, self).transform(compressor); return make_node(AST_Undefined, self).transform(compressor);
} }
} }
if (compressor.option("drop_console")) {
if (self.expression instanceof AST_PropAccess &&
self.expression.expression instanceof AST_SymbolRef &&
self.expression.expression.name == "console" &&
self.expression.expression.undeclared()) {
return make_node(AST_Undefined, self).transform(compressor);
}
}
return self.evaluate(compressor)[0]; return self.evaluate(compressor)[0];
}); });
@@ -1811,9 +1868,15 @@ merge(Compressor.prototype, {
} }
if (compressor.option("cascade")) { if (compressor.option("cascade")) {
if (self.car instanceof AST_Assign if (self.car instanceof AST_Assign
&& !self.car.left.has_side_effects(compressor) && !self.car.left.has_side_effects(compressor)) {
&& self.car.left.equivalent_to(self.cdr)) { if (self.car.left.equivalent_to(self.cdr)) {
return self.car; return self.car;
}
if (self.cdr instanceof AST_Call
&& self.cdr.expression.equivalent_to(self.car.left)) {
self.cdr.expression = self.car;
return self.cdr;
}
} }
if (!self.car.has_side_effects(compressor) if (!self.car.has_side_effects(compressor)
&& !self.cdr.has_side_effects(compressor) && !self.cdr.has_side_effects(compressor)
@@ -1821,6 +1884,18 @@ merge(Compressor.prototype, {
return self.car; return self.car;
} }
} }
if (self.cdr instanceof AST_UnaryPrefix
&& self.cdr.operator == "void"
&& !self.cdr.expression.has_side_effects(compressor)) {
self.cdr.operator = self.car;
return self.cdr;
}
if (self.cdr instanceof AST_Undefined) {
return make_node(AST_UnaryPrefix, self, {
operator : "void",
expression : self.car
});
}
return self; return self;
}); });
@@ -2192,7 +2267,7 @@ merge(Compressor.prototype, {
* ==> * ==>
* exp = foo ? something : something_else; * exp = foo ? something : something_else;
*/ */
self = make_node(AST_Assign, self, { return make_node(AST_Assign, self, {
operator: consequent.operator, operator: consequent.operator,
left: consequent.left, left: consequent.left,
right: make_node(AST_Conditional, self, { right: make_node(AST_Conditional, self, {
@@ -2202,6 +2277,25 @@ merge(Compressor.prototype, {
}) })
}); });
} }
if (consequent instanceof AST_Call
&& alternative.TYPE === consequent.TYPE
&& consequent.args.length == alternative.args.length
&& consequent.expression.equivalent_to(alternative.expression)) {
if (consequent.args.length == 0) {
return make_node(AST_Seq, self, {
car: self.condition,
cdr: consequent
});
}
if (consequent.args.length == 1) {
consequent.args[0] = make_node(AST_Conditional, self, {
condition: self.condition,
consequent: consequent.args[0],
alternative: alternative.args[0]
});
return consequent;
}
}
return self; return self;
}); });
@@ -2241,6 +2335,12 @@ merge(Compressor.prototype, {
property : prop property : prop
}); });
} }
var v = parseFloat(prop);
if (!isNaN(v) && v.toString() == prop) {
self.property = make_node(AST_Number, self.property, {
value: v
});
}
} }
return self; return self;
}); });

View File

@@ -386,13 +386,20 @@ function OutputStream(options) {
var comments = start.comments_before || []; var comments = start.comments_before || [];
// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
// if this node is `return` or `throw`, we cannot allow comments before // and https://github.com/mishoo/UglifyJS2/issues/372
// the returned or thrown value. if (self instanceof AST_Exit && self.value) {
if (self instanceof AST_Exit && self.value self.value.walk(new TreeWalker(function(node){
&& self.value.start.comments_before if (node.start && node.start.comments_before) {
&& self.value.start.comments_before.length > 0) { comments = comments.concat(node.start.comments_before);
comments = comments.concat(self.value.start.comments_before); node.start.comments_before = [];
self.value.start.comments_before = []; }
if (node instanceof AST_Function ||
node instanceof AST_Array ||
node instanceof AST_Object)
{
return true; // don't go inside.
}
}));
} }
if (c.test) { if (c.test) {
@@ -456,7 +463,7 @@ function OutputStream(options) {
|| p instanceof AST_Unary // !(foo, bar, baz) || p instanceof AST_Unary // !(foo, bar, baz)
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8 || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4 || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|| p instanceof AST_Dot // (1, {foo:2}).foo ==> 2 || p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ] || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2 || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30) || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
@@ -1113,8 +1120,16 @@ function OutputStream(options) {
}); });
DEFPRINT(AST_RegExp, function(self, output){ DEFPRINT(AST_RegExp, function(self, output){
var str = self.getValue().toString(); var str = self.getValue().toString();
if (output.option("ascii_only")) if (output.option("ascii_only")) {
str = output.to_ascii(str); str = output.to_ascii(str);
} else {
str = str.split("\\\\").map(function(str){
return str.replace(/\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g, function(s){
var code = parseInt(s.substr(2), 16);
return code == 0x2f || code == 10 || code == 13 || code == 0x2028 || code == 0x2029 ? s : String.fromCharCode(code);
});
}).join("\\\\");
}
output.print(str); output.print(str);
var p = output.parent(); var p = output.parent();
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)

View File

@@ -46,7 +46,7 @@
var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with'; var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
var KEYWORDS_ATOM = 'false null true'; var KEYWORDS_ATOM = 'false null true';
var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile' var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield'
+ " " + KEYWORDS_ATOM + " " + KEYWORDS; + " " + KEYWORDS_ATOM + " " + KEYWORDS;
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case'; var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';

View File

@@ -71,27 +71,34 @@ SymbolDef.prototype = {
} }
}; };
AST_Toplevel.DEFMETHOD("figure_out_scope", function(){ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// This does what ast_add_scope did in UglifyJS v1. options = defaults(options, {
// screw_ie8: false
// Part of it could be done at parse time, but it would complicate });
// the parser (and it's already kinda complex). It's also worth
// having it separated because we might need to call it multiple
// times on the same tree.
// pass 1: setup scope chaining and handle definitions // pass 1: setup scope chaining and handle definitions
var self = this; var self = this;
var scope = self.parent_scope = null; var scope = self.parent_scope = null;
var defun = null;
var nesting = 0; var nesting = 0;
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (options.screw_ie8 && node instanceof AST_Catch) {
var save_scope = scope;
scope = new AST_Scope(node);
scope.init_scope_vars(nesting);
scope.parent_scope = save_scope;
descend();
scope = save_scope;
return true;
}
if (node instanceof AST_Scope) { if (node instanceof AST_Scope) {
node.init_scope_vars(nesting); node.init_scope_vars(nesting);
var save_scope = node.parent_scope = scope; var save_scope = node.parent_scope = scope;
++nesting; var save_defun = defun;
scope = node; defun = scope = node;
descend(); ++nesting; descend(); --nesting;
scope = save_scope; scope = save_scope;
--nesting; defun = save_defun;
return true; // don't descend again in TreeWalker return true; // don't descend again in TreeWalker
} }
if (node instanceof AST_Directive) { if (node instanceof AST_Directive) {
@@ -108,7 +115,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
node.scope = scope; node.scope = scope;
} }
if (node instanceof AST_SymbolLambda) { if (node instanceof AST_SymbolLambda) {
scope.def_function(node); defun.def_function(node);
} }
else if (node instanceof AST_SymbolDefun) { else if (node instanceof AST_SymbolDefun) {
// Careful here, the scope where this should be defined is // Careful here, the scope where this should be defined is
@@ -116,22 +123,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
// scope when we encounter the AST_Defun node (which is // scope when we encounter the AST_Defun node (which is
// instanceof AST_Scope) but we get to the symbol a bit // instanceof AST_Scope) but we get to the symbol a bit
// later. // later.
(node.scope = scope.parent_scope).def_function(node); (node.scope = defun.parent_scope).def_function(node);
} }
else if (node instanceof AST_SymbolVar else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst) { || node instanceof AST_SymbolConst) {
var def = scope.def_variable(node); var def = defun.def_variable(node);
def.constant = node instanceof AST_SymbolConst; def.constant = node instanceof AST_SymbolConst;
def.init = tw.parent().value; def.init = tw.parent().value;
} }
else if (node instanceof AST_SymbolCatch) { else if (node instanceof AST_SymbolCatch) {
// XXX: this is wrong according to ECMA-262 (12.4). the (options.screw_ie8 ? scope : defun)
// `catch` argument name should be visible only inside the .def_variable(node);
// catch block. For a quick fix AST_Catch should inherit
// from AST_Scope. Keeping it this way because of IE,
// which doesn't obey the standard. (it introduces the
// identifier in the enclosing scope)
scope.def_variable(node);
} }
}); });
self.walk(tw); self.walk(tw);
@@ -244,6 +246,11 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
out: while (true) { out: while (true) {
var m = base54(++this.cname); var m = base54(++this.cname);
if (!is_identifier(m)) continue; // skip over "do" if (!is_identifier(m)) continue; // skip over "do"
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
// shadow a name excepted from mangling.
if (options.except.indexOf(m) >= 0) continue;
// we must ensure that the mangled name does not shadow a name // we must ensure that the mangled name does not shadow a name
// from some parent scope that is referenced in this or in // from some parent scope that is referenced in this or in
// inner scopes. // inner scopes.

View File

@@ -49,6 +49,9 @@ function SourceMap(options) {
file : null, file : null,
root : null, root : null,
orig : null, orig : null,
orig_line_diff : 0,
dest_line_diff : 0,
}); });
var generator = new MOZ_SourceMap.SourceMapGenerator({ var generator = new MOZ_SourceMap.SourceMapGenerator({
file : options.file, file : options.file,
@@ -67,8 +70,8 @@ function SourceMap(options) {
name = info.name; name = info.name;
} }
generator.addMapping({ generator.addMapping({
generated : { line: gen_line, column: gen_col }, generated : { line: gen_line + options.dest_line_diff, column: gen_col },
original : { line: orig_line, column: orig_col }, original : { line: orig_line + options.orig_line_diff, column: orig_col },
source : source, source : source,
name : name name : name
}); });

View File

@@ -82,9 +82,12 @@ function repeat_string(str, i) {
}; };
function DefaultsError(msg, defs) { function DefaultsError(msg, defs) {
Error.call(this, msg);
this.msg = msg; this.msg = msg;
this.defs = defs; this.defs = defs;
}; };
DefaultsError.prototype = Object.create(Error.prototype);
DefaultsError.prototype.constructor = DefaultsError;
DefaultsError.croak = function(msg, defs) { DefaultsError.croak = function(msg, defs) {
throw new DefaultsError(msg, defs); throw new DefaultsError(msg, defs);

View File

@@ -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.5", "version": "2.4.10",
"engines": { "node" : ">=0.4.0" }, "engines": { "node" : ">=0.4.0" },
"maintainers": [{ "maintainers": [{
"name": "Mihai Bazon", "name": "Mihai Bazon",

View File

@@ -141,3 +141,67 @@ ifs_6: {
x = foo || bar || baz || boo ? 20 : 10; x = foo || bar || baz || boo ? 20 : 10;
} }
} }
cond_1: {
options = {
conditionals: true
};
input: {
if (some_condition()) {
do_something(x);
} else {
do_something(y);
}
}
expect: {
do_something(some_condition() ? x : y);
}
}
cond_2: {
options = {
conditionals: true
};
input: {
if (some_condition()) {
x = new FooBar(1);
} else {
x = new FooBar(2);
}
}
expect: {
x = new FooBar(some_condition() ? 1 : 2);
}
}
cond_3: {
options = {
conditionals: true
};
input: {
if (some_condition()) {
new FooBar(1);
} else {
FooBar(2);
}
}
expect: {
some_condition() ? new FooBar(1) : FooBar(2);
}
}
cond_4: {
options = {
conditionals: true
};
input: {
if (some_condition()) {
do_something();
} else {
do_something();
}
}
expect: {
some_condition(), do_something();
}
}

View File

@@ -119,3 +119,47 @@ unused_keep_setter_arg: {
} }
} }
} }
unused_var_in_catch: {
options = { unused: true };
input: {
function foo() {
try {
foo();
} catch(ex) {
var x = 10;
}
}
}
expect: {
function foo() {
try {
foo();
} catch(ex) {}
}
}
}
used_var_in_catch: {
options = { unused: true };
input: {
function foo() {
try {
foo();
} catch(ex) {
var x = 10;
}
return x;
}
}
expect: {
function foo() {
try {
foo();
} catch(ex) {
var x = 10;
}
return x;
}
}
}

View File

@@ -60,16 +60,16 @@ negate_iife_4: {
}; };
input: { input: {
if ((function(){ return true })()) { if ((function(){ return true })()) {
console.log(true); foo(true);
} else { } else {
console.log(false); bar(false);
} }
(function(){ (function(){
console.log("something"); console.log("something");
})(); })();
} }
expect: { expect: {
!function(){ return true }() ? console.log(false) : console.log(true), function(){ !function(){ return true }() ? bar(false) : foo(true), function(){
console.log("something"); console.log("something");
}(); }();
} }

View File

@@ -51,6 +51,7 @@ for (var i in UglifyJS) {
exports.minify = function(files, options) { exports.minify = function(files, options) {
options = UglifyJS.defaults(options, { options = UglifyJS.defaults(options, {
spidermonkey : false,
outSourceMap : null, outSourceMap : null,
sourceRoot : null, sourceRoot : null,
inSourceMap : null, inSourceMap : null,
@@ -60,22 +61,26 @@ exports.minify = function(files, options) {
output : null, output : null,
compress : {} compress : {}
}); });
if (typeof files == "string")
files = [ files ];
UglifyJS.base54.reset(); UglifyJS.base54.reset();
// 1. parse // 1. parse
var toplevel = null; var toplevel = null;
files.forEach(function(file){
var code = options.fromString if (options.spidermonkey) {
? file toplevel = UglifyJS.AST_Node.from_mozilla_ast(files);
: fs.readFileSync(file, "utf8"); } else {
toplevel = UglifyJS.parse(code, { if (typeof files == "string")
filename: options.fromString ? "?" : file, files = [ files ];
toplevel: toplevel files.forEach(function(file){
var code = options.fromString
? file
: fs.readFileSync(file, "utf8");
toplevel = UglifyJS.parse(code, {
filename: options.fromString ? "?" : file,
toplevel: toplevel
});
}); });
}); }
// 2. compress // 2. compress
if (options.compress) { if (options.compress) {