Merge remote-tracking branch 'mishoo/master'

This commit is contained in:
Jo Simard 2012-10-29 14:33:38 -04:00
commit a049a7afe5
13 changed files with 423 additions and 48 deletions

View File

@ -3,8 +3,11 @@ UglifyJS 2
UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit. UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.
For now this page documents the command line utility. More advanced This page documents the command line utility. For
API documentation will be made available later. [API and internals documentation see my website](http://lisperator.net/uglifyjs/).
There's also an
[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox,
Chrome and probably Safari).
Install Install
------- -------
@ -319,6 +322,7 @@ There's a single toplevel function which combines all the steps. If you
don't need additional customization, you might want to go with `minify`. don't need additional customization, you might want to go with `minify`.
Example: Example:
// see "fromString" below if you need to pass code instead of file name
var result = UglifyJS.minify("/path/to/file.js"); var result = UglifyJS.minify("/path/to/file.js");
console.log(result.code); // minified output console.log(result.code); // minified output
@ -339,6 +343,14 @@ Note that the source map is not saved in a file, it's just returned in
`result.map`. The value passed for `outSourceMap` is only used to set the `result.map`. The value passed for `outSourceMap` is only used to set the
`file` attribute in the source map (see [the spec][sm-spec]). `file` attribute in the source map (see [the spec][sm-spec]).
You can also specify sourceRoot property to be included in source map:
var result = UglifyJS.minify([ "file1.js", "file2.js", "file3.js" ], {
outSourceMap: "out.js.map",
sourceRoot: "http://example.com/src"
});
If you're compressing compiled JavaScript and have a source map for it, you If you're compressing compiled JavaScript and have a source map for it, you
can use the `inSourceMap` argument: can use the `inSourceMap` argument:
@ -351,6 +363,12 @@ can use the `inSourceMap` argument:
The `inSourceMap` is only used if you also request `outSourceMap` (it makes The `inSourceMap` is only used if you also request `outSourceMap` (it makes
no sense otherwise). no sense otherwise).
Other options:
- `warnings` (default `false`) — pass `true` to display compressor warnings.
- `fromString` (default `false`) — if you pass `true` then you can pass
JavaScript source code, rather than file names.
We could add more options to `UglifyJS.minify` — if you need additional We could add more options to `UglifyJS.minify` — if you need additional
functionality please suggest! functionality please suggest!

View File

@ -127,7 +127,7 @@ if (ARGS.comments) {
var type = comment.type; var type = comment.type;
if (type == "comment2") { if (type == "comment2") {
// multiline comment // multiline comment
return /@preserve|@license|@cc_on/i.test(test); return /@preserve|@license|@cc_on/i.test(text);
} }
} }
} }

View File

@ -581,6 +581,18 @@ var AST_Seq = DEFNODE("Seq", "car cdr", {
} }
return list; return list;
}, },
to_array: function() {
var p = this, a = [];
while (p) {
a.push(p.car);
if (p.cdr && !(p.cdr instanceof AST_Seq)) {
a.push(p.cdr);
break;
}
p = p.cdr;
}
return a;
},
add: function(node) { add: function(node) {
var p = this; var p = this;
while (p) { while (p) {
@ -929,10 +941,10 @@ TreeWalker.prototype = {
} else { } else {
for (var i = stack.length; --i >= 0;) { for (var i = stack.length; --i >= 0;) {
var x = stack[i]; var x = stack[i];
if (x instanceof AST_Switch) return x; if (x instanceof AST_Switch
if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) { || x instanceof AST_For
return (x.body instanceof AST_BlockStatement ? x.body : x); || x instanceof AST_ForIn
} || x instanceof AST_DWLoop) return x;
} }
} }
} }

View File

@ -162,6 +162,9 @@ merge(Compressor.prototype, {
if (val === null) { if (val === null) {
return make_node(AST_Null, orig).optimize(compressor); return make_node(AST_Null, orig).optimize(compressor);
} }
if (val instanceof RegExp) {
return make_node(AST_RegExp, orig).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
})); }));
@ -183,6 +186,14 @@ merge(Compressor.prototype, {
return false; return false;
}; };
function loop_body(x) {
if (x instanceof AST_Switch) return x;
if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
return (x.body instanceof AST_BlockStatement ? x.body : x);
}
return x;
};
function tighten_body(statements, compressor) { function tighten_body(statements, compressor) {
var CHANGED; var CHANGED;
do { do {
@ -300,8 +311,13 @@ merge(Compressor.prototype, {
} }
var ab = aborts(stat.body); var ab = aborts(stat.body);
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda) if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
|| (ab instanceof AST_Continue && self === compressor.loopcontrol_target(ab.label)))) { || (ab instanceof AST_Continue && self === loop_body(lct))
|| (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
if (ab.label) {
remove(ab.label.thedef.references, ab.label);
}
CHANGED = true; CHANGED = true;
var body = as_statement_array(stat.body).slice(0, -1); var body = as_statement_array(stat.body).slice(0, -1);
stat = stat.clone(); stat = stat.clone();
@ -317,8 +333,13 @@ merge(Compressor.prototype, {
} }
var ab = aborts(stat.alternative); var ab = aborts(stat.alternative);
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda) if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
|| (ab instanceof AST_Continue && self === compressor.loopcontrol_target(ab.label)))) { || (ab instanceof AST_Continue && self === loop_body(lct))
|| (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
if (ab.label) {
remove(ab.label.thedef.references, ab.label);
}
CHANGED = true; CHANGED = true;
stat = stat.clone(); stat = stat.clone();
stat.body = make_node(AST_BlockStatement, stat.body, { stat.body = make_node(AST_BlockStatement, stat.body, {
@ -344,14 +365,27 @@ merge(Compressor.prototype, {
function eliminate_dead_code(statements, compressor) { function eliminate_dead_code(statements, compressor) {
var has_quit = false; var has_quit = false;
var orig = statements.length; var orig = statements.length;
var self = compressor.self();
statements = statements.reduce(function(a, stat){ statements = statements.reduce(function(a, stat){
if (has_quit) { if (has_quit) {
extract_declarations_from_unreachable_code(compressor, stat, a); extract_declarations_from_unreachable_code(compressor, stat, a);
} else { } else {
a.push(stat); if (stat instanceof AST_LoopControl) {
if (stat instanceof AST_Jump) { var lct = compressor.loopcontrol_target(stat.label);
has_quit = true; if ((stat instanceof AST_Break
&& lct instanceof AST_BlockStatement
&& loop_body(lct) === self) || (stat instanceof AST_Continue
&& loop_body(lct) === self)) {
if (stat.label) {
remove(stat.label.thedef.references, stat.label);
} }
} else {
a.push(stat);
}
} else {
a.push(stat);
}
if (aborts(stat)) has_quit = true;
} }
return a; return a;
}, []); }, []);
@ -707,9 +741,10 @@ merge(Compressor.prototype, {
}); });
def(AST_SimpleStatement, function(){ def(AST_SimpleStatement, function(){
if (this.body instanceof AST_Function) return false;
return this.body.has_side_effects(); return this.body.has_side_effects();
}); });
def(AST_Defun, function(){ return true });
def(AST_Function, function(){ return false });
def(AST_Binary, function(){ def(AST_Binary, function(){
return this.left.has_side_effects() return this.left.has_side_effects()
|| this.right.has_side_effects(); || this.right.has_side_effects();
@ -771,6 +806,9 @@ merge(Compressor.prototype, {
var n = this.body.length; var n = this.body.length;
return n > 0 && aborts(this.body[n - 1]); return n > 0 && aborts(this.body[n - 1]);
}); });
def(AST_If, function(){
return this.alternative && aborts(this.body) && aborts(this.alternative);
});
})(function(node, func){ })(function(node, func){
node.DEFMETHOD("aborts", func); node.DEFMETHOD("aborts", func);
}); });
@ -791,6 +829,10 @@ merge(Compressor.prototype, {
}); });
OPT(AST_LabeledStatement, function(self, compressor){ OPT(AST_LabeledStatement, function(self, compressor){
if (self.body instanceof AST_Break
&& compressor.loopcontrol_target(self.body.label) === self.body) {
return make_node(AST_EmptyStatement, self);
}
return self.label.references.length == 0 ? self.body : self; return self.label.references.length == 0 ? self.body : self;
}); });
@ -1108,7 +1150,7 @@ merge(Compressor.prototype, {
extract_declarations_from_unreachable_code(compressor, self.alternative, a); extract_declarations_from_unreachable_code(compressor, self.alternative, a);
} }
a.push(self.body); a.push(self.body);
return make_node(AST_BlockStatement, self, { body: a }); return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
} }
} else { } else {
compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start); compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
@ -1116,7 +1158,7 @@ merge(Compressor.prototype, {
var a = []; var a = [];
extract_declarations_from_unreachable_code(compressor, self.body, a); extract_declarations_from_unreachable_code(compressor, self.body, a);
if (self.alternative) a.push(self.alternative); if (self.alternative) a.push(self.alternative);
return make_node(AST_BlockStatement, self, { body: a }); return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
} }
} }
} }
@ -1133,7 +1175,7 @@ merge(Compressor.prototype, {
if (is_empty(self.body) && is_empty(self.alternative)) { if (is_empty(self.body) && is_empty(self.alternative)) {
return make_node(AST_SimpleStatement, self.condition, { return make_node(AST_SimpleStatement, self.condition, {
body: self.condition body: self.condition
}); }).transform(compressor);
} }
if (self.body instanceof AST_SimpleStatement if (self.body instanceof AST_SimpleStatement
&& self.alternative instanceof AST_SimpleStatement) { && self.alternative instanceof AST_SimpleStatement) {
@ -1143,7 +1185,7 @@ merge(Compressor.prototype, {
consequent : self.body.body, consequent : self.body.body,
alternative : self.alternative.body alternative : self.alternative.body
}) })
}); }).transform(compressor);
} }
if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
if (negated_is_best) return make_node(AST_SimpleStatement, self, { if (negated_is_best) return make_node(AST_SimpleStatement, self, {
@ -1152,14 +1194,14 @@ merge(Compressor.prototype, {
left : negated, left : negated,
right : self.body.body right : self.body.body
}) })
}); }).transform(compressor);
return make_node(AST_SimpleStatement, self, { return make_node(AST_SimpleStatement, self, {
body: make_node(AST_Binary, self, { body: make_node(AST_Binary, self, {
operator : "&&", operator : "&&",
left : self.condition, left : self.condition,
right : self.body.body right : self.body.body
}) })
}); }).transform(compressor);
} }
if (self.body instanceof AST_EmptyStatement if (self.body instanceof AST_EmptyStatement
&& self.alternative && self.alternative
@ -1170,7 +1212,7 @@ merge(Compressor.prototype, {
left : self.condition, left : self.condition,
right : self.alternative.body right : self.alternative.body
}) })
}); }).transform(compressor);
} }
if (self.body instanceof AST_Exit if (self.body instanceof AST_Exit
&& self.alternative instanceof AST_Exit && self.alternative instanceof AST_Exit
@ -1178,10 +1220,10 @@ merge(Compressor.prototype, {
return make_node(self.body.CTOR, self, { return make_node(self.body.CTOR, self, {
value: make_node(AST_Conditional, self, { value: make_node(AST_Conditional, self, {
condition : self.condition, condition : self.condition,
consequent : self.body.value, consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
alternative : self.alternative.value || make_node(AST_Undefined, self).optimize(compressor) alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
}) })
}); }).transform(compressor);
} }
if (self.body instanceof AST_If if (self.body instanceof AST_If
&& !self.body.alternative && !self.body.alternative
@ -1199,7 +1241,7 @@ merge(Compressor.prototype, {
self.alternative = null; self.alternative = null;
return make_node(AST_BlockStatement, self, { return make_node(AST_BlockStatement, self, {
body: [ self, alt ] body: [ self, alt ]
}); }).transform(compressor);
} }
} }
if (aborts(self.alternative)) { if (aborts(self.alternative)) {
@ -1209,16 +1251,21 @@ merge(Compressor.prototype, {
self.alternative = null; self.alternative = null;
return make_node(AST_BlockStatement, self, { return make_node(AST_BlockStatement, self, {
body: [ self, body ] body: [ self, body ]
}); }).transform(compressor);
} }
return self; return self;
}); });
OPT(AST_Switch, function(self, compressor){ OPT(AST_Switch, function(self, compressor){
if (self.body.length == 0 && compressor.option("conditionals")) {
return make_node(AST_SimpleStatement, self, {
body: self.expression
}).transform(compressor);
}
var last_branch = self.body[self.body.length - 1]; var last_branch = self.body[self.body.length - 1];
if (last_branch) { if (last_branch) {
var stat = last_branch.body[last_branch.body.length - 1]; // last statement var stat = last_branch.body[last_branch.body.length - 1]; // last statement
if (stat instanceof AST_Break && compressor.loopcontrol_target(stat.label) === self) if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)
last_branch.body.pop(); last_branch.body.pop();
} }
return self; return self;
@ -1302,14 +1349,14 @@ merge(Compressor.prototype, {
left: exp.expression, left: exp.expression,
operator: "+", operator: "+",
right: make_node(AST_String, self, { value: "" }) right: make_node(AST_String, self, { value: "" })
}); }).transform(compressor);
} }
} }
if (compressor.option("side_effects")) { if (compressor.option("side_effects")) {
if (self.expression instanceof AST_Function if (self.expression instanceof AST_Function
&& self.args.length == 0 && self.args.length == 0
&& !self.expression.has_side_effects()) { && !AST_Block.prototype.has_side_effects.call(self.expression)) {
return make_node(AST_Undefined, self); return make_node(AST_Undefined, self).transform(compressor);
} }
} }
return self; return self;
@ -1333,6 +1380,10 @@ merge(Compressor.prototype, {
}); });
OPT(AST_Seq, function(self, compressor){ OPT(AST_Seq, function(self, compressor){
if (!compressor.option("side_effects"))
return self;
if (!self.car.has_side_effects())
return self.cdr;
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() && !self.car.left.has_side_effects()
@ -1348,7 +1399,26 @@ merge(Compressor.prototype, {
return self; return self;
}); });
AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
if (compressor.option("sequences")) {
if (this.expression instanceof AST_Seq) {
var seq = this.expression;
var x = seq.to_array();
this.expression = x.pop();
x.push(this);
seq = AST_Seq.from_array(x).transform(compressor);
return seq;
}
}
return this;
});
OPT(AST_UnaryPostfix, function(self, compressor){
return self.lift_sequences(compressor);
});
OPT(AST_UnaryPrefix, function(self, compressor){ OPT(AST_UnaryPrefix, function(self, compressor){
self = self.lift_sequences(compressor);
var e = self.expression; var e = self.expression;
if (compressor.option("booleans") && compressor.in_boolean_context()) { if (compressor.option("booleans") && compressor.in_boolean_context()) {
switch (self.operator) { switch (self.operator) {
@ -1371,7 +1441,32 @@ merge(Compressor.prototype, {
return self.evaluate(compressor)[0]; return self.evaluate(compressor)[0];
}); });
AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
if (compressor.option("sequences")) {
if (this.left instanceof AST_Seq) {
var seq = this.left;
var x = seq.to_array();
this.left = x.pop();
x.push(this);
seq = AST_Seq.from_array(x).transform(compressor);
return seq;
}
if (this.right instanceof AST_Seq
&& !(this.operator == "||" || this.operator == "&&")
&& !this.left.has_side_effects()) {
var seq = this.right;
var x = seq.to_array();
this.right = x.pop();
x.push(this);
seq = AST_Seq.from_array(x).transform(compressor);
return seq;
}
}
return this;
});
OPT(AST_Binary, function(self, compressor){ OPT(AST_Binary, function(self, compressor){
self = self.lift_sequences(compressor);
if (compressor.option("comparisons")) switch (self.operator) { if (compressor.option("comparisons")) switch (self.operator) {
case "===": case "===":
case "!==": case "!==":
@ -1510,6 +1605,7 @@ merge(Compressor.prototype, {
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ]; var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
OPT(AST_Assign, function(self, compressor){ OPT(AST_Assign, function(self, compressor){
self = self.lift_sequences(compressor);
if (self.operator == "=" if (self.operator == "="
&& self.left instanceof AST_SymbolRef && self.left instanceof AST_SymbolRef
&& self.right instanceof AST_Binary && self.right instanceof AST_Binary
@ -1613,4 +1709,14 @@ merge(Compressor.prototype, {
return self; return self;
}); });
function literals_in_boolean_context(self, compressor) {
if (compressor.option("booleans") && compressor.in_boolean_context()) {
return make_node(AST_True, self);
}
return self;
};
OPT(AST_Array, literals_in_boolean_context);
OPT(AST_Object, literals_in_boolean_context);
OPT(AST_RegExp, literals_in_boolean_context);
})(); })();

View File

@ -414,7 +414,7 @@ function OutputStream(options) {
var p = output.parent(); var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz) || p instanceof AST_Unary // !(foo, bar, baz)
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 7 || 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_Dot // (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 ]

View File

@ -115,7 +115,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
node.init_scope_vars(); node.init_scope_vars();
} }
if (node instanceof AST_SymbolLambda) { if (node instanceof AST_SymbolLambda) {
scope.def_function(node); //scope.def_function(node);
//
// https://github.com/mishoo/UglifyJS2/issues/24 — MSIE
// leaks function expression names into the containing
// scope. Don't like this fix but seems we can't do any
// better. IE: please die. Please!
(node.scope = scope.parent_scope).def_function(node);
node.init.push(tw.parent()); node.init.push(tw.parent());
} }
else if (node instanceof AST_SymbolDefun) { else if (node instanceof AST_SymbolDefun) {

View File

@ -166,6 +166,12 @@ function string_template(text, props) {
}); });
}; };
function remove(array, el) {
for (var i = array.length; --i >= 0;) {
if (array[i] === el) array.splice(i, 1);
}
};
function mergeSort(array, cmp) { function mergeSort(array, cmp) {
if (array.length < 2) return array.slice(); if (array.length < 2) return array.slice();
function merge(a, b) { function merge(a, b) {

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

17
test/compress/issue-22.js Normal file
View File

@ -0,0 +1,17 @@
return_with_no_value_in_if_body: {
options = { conditionals: true };
input: {
function foo(bar) {
if (bar) {
return;
} else {
return 1;
}
}
}
expect: {
function foo (bar) {
return bar ? void 0 : 1;
}
}
}

163
test/compress/labels.js Normal file
View File

@ -0,0 +1,163 @@
labels_1: {
options = { if_return: true, conditionals: true, dead_code: true };
input: {
out: {
if (foo) break out;
console.log("bar");
}
};
expect: {
foo || console.log("bar");
}
}
labels_2: {
options = { if_return: true, conditionals: true, dead_code: true };
input: {
out: {
if (foo) print("stuff");
else break out;
console.log("here");
}
};
expect: {
if (foo) {
print("stuff");
console.log("here");
}
}
}
labels_3: {
options = { if_return: true, conditionals: true, dead_code: true };
input: {
for (var i = 0; i < 5; ++i) {
if (i < 3) continue;
console.log(i);
}
};
expect: {
for (var i = 0; i < 5; ++i)
i < 3 || console.log(i);
}
}
labels_4: {
options = { if_return: true, conditionals: true, dead_code: true };
input: {
out: for (var i = 0; i < 5; ++i) {
if (i < 3) continue out;
console.log(i);
}
};
expect: {
for (var i = 0; i < 5; ++i)
i < 3 || console.log(i);
}
}
labels_5: {
options = { if_return: true, conditionals: true, dead_code: true };
// should keep the break-s in the following
input: {
while (foo) {
if (bar) break;
console.log("foo");
}
out: while (foo) {
if (bar) break out;
console.log("foo");
}
};
expect: {
while (foo) {
if (bar) break;
console.log("foo");
}
out: while (foo) {
if (bar) break out;
console.log("foo");
}
}
}
labels_6: {
input: {
out: break out;
};
expect: {}
}
labels_7: {
options = { if_return: true, conditionals: true, dead_code: true };
input: {
while (foo) {
x();
y();
continue;
}
};
expect: {
while (foo) {
x();
y();
}
}
}
labels_8: {
options = { if_return: true, conditionals: true, dead_code: true };
input: {
while (foo) {
x();
y();
break;
}
};
expect: {
while (foo) {
x();
y();
break;
}
}
}
labels_9: {
options = { if_return: true, conditionals: true, dead_code: true };
input: {
out: while (foo) {
x();
y();
continue out;
z();
k();
}
};
expect: {
while (foo) {
x();
y();
}
}
}
labels_10: {
options = { if_return: true, conditionals: true, dead_code: true };
input: {
out: while (foo) {
x();
y();
break out;
z();
k();
}
};
expect: {
out: while (foo) {
x();
y();
break out;
}
}
}

View File

@ -87,3 +87,43 @@ make_sequences_4: {
with (x = 5, obj); with (x = 5, obj);
} }
} }
lift_sequences_1: {
options = { sequences: true };
input: {
foo = !(x(), y(), bar());
}
expect: {
x(), y(), foo = !bar();
}
}
lift_sequences_2: {
options = { sequences: true, evaluate: true };
input: {
q = 1 + (foo(), bar(), 5) + 7 * (5 / (3 - (a(), (QW=ER), c(), 2))) - (x(), y(), 5);
}
expect: {
foo(), bar(), a(), QW = ER, c(), x(), y(), q = 36
}
}
lift_sequences_3: {
options = { sequences: true, conditionals: true };
input: {
x = (foo(), bar(), baz()) ? 10 : 20;
}
expect: {
foo(), bar(), x = baz() ? 10 : 20;
}
}
lift_sequences_4: {
options = { side_effects: true };
input: {
x = (foo, bar, baz);
}
expect: {
x = baz;
}
}

View File

@ -73,12 +73,13 @@ function run_compress_tests() {
var cmp = new U.Compressor(options, true); var cmp = new U.Compressor(options, true);
var expect = make_code(as_toplevel(test.expect), false); var expect = make_code(as_toplevel(test.expect), false);
var input = as_toplevel(test.input); var input = as_toplevel(test.input);
var input_code = make_code(test.input);
var output = input.transform(cmp); var output = input.transform(cmp);
output.figure_out_scope(); output.figure_out_scope();
output = make_code(output, false); output = make_code(output, false);
if (expect != output) { if (expect != output) {
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", { log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
input: make_code(test.input), input: input_code,
output: output, output: output,
expected: expect expected: expect
}); });

View File

@ -1,27 +1,27 @@
var save_stderr = process.stderr; var path = require("path");
var fs = require("fs"); var fs = require("fs");
// discard annoying NodeJS warning ("path.existsSync is now called `fs.existsSync`.") // Avoid NodeJS warning.
var devnull = fs.createWriteStream("/dev/null"); //
process.__defineGetter__("stderr", function(){ // There's a --no-deprecation command line argument supported by
return devnull; // NodeJS, but that's tricky to use, so I'd like to set it from the
}); // program itself. Turns out you need to set `process.noDeprecation`,
// but by the time you can set that the `path` module is already
// loaded and `path.existsSync` is already changed to display that
// warning, therefore here's the poor solution:
if (fs.existsSync) {
path.existsSync = fs.existsSync;
}
var vm = require("vm"); var vm = require("vm");
var sys = require("util"); var sys = require("util");
var path = require("path");
var UglifyJS = vm.createContext({ var UglifyJS = vm.createContext({
sys : sys, sys : sys,
console : console, console : console,
MOZ_SourceMap : require("source-map") MOZ_SourceMap : require("source-map")
}); });
process.__defineGetter__("stderr", function(){
return save_stderr;
});
function load_global(file) { function load_global(file) {
file = path.resolve(path.dirname(module.filename), file); file = path.resolve(path.dirname(module.filename), file);
try { try {
@ -66,7 +66,9 @@ exports.minify = function(files, options)
{ {
options = UglifyJS.defaults(options, { options = UglifyJS.defaults(options, {
outSourceMap : null, outSourceMap : null,
sourceRoot : null,
inSourceMap : null, inSourceMap : null,
fromString : false,
warnings : false, warnings : false,
compressor : null, compressor : null,
output : null, output : null,
@ -104,9 +106,11 @@ exports.minify = function(files, options)
// 1. parse // 1. parse
var toplevel = null; var toplevel = null;
files.forEach(function(file){ files.forEach(function(file){
var code = fs.readFileSync(file, "utf8"); var code = options.fromString
? file
: fs.readFileSync(file, "utf8");
toplevel = UglifyJS.parse(code, { toplevel = UglifyJS.parse(code, {
filename: file, filename: options.fromString ? "?" : file,
toplevel: toplevel toplevel: toplevel
}); });
}); });
@ -133,7 +137,8 @@ exports.minify = function(files, options)
} }
if (options.outSourceMap) map = UglifyJS.SourceMap({ if (options.outSourceMap) map = UglifyJS.SourceMap({
file: options.outSourceMap, file: options.outSourceMap,
orig: inMap orig: inMap,
root: options.sourceRoot
}); });
// Add sourcemap to output options // Add sourcemap to output options