aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/uglifyjs284
-rw-r--r--lib/compress.js2
-rw-r--r--lib/output.js62
-rw-r--r--lib/scope.js9
-rw-r--r--lib/utils.js9
5 files changed, 117 insertions, 49 deletions
diff --git a/bin/uglifyjs2 b/bin/uglifyjs2
index daf17573..dd8a758a 100755
--- a/bin/uglifyjs2
+++ b/bin/uglifyjs2
@@ -7,35 +7,35 @@ var optimist = require("optimist");
var fs = require("fs");
var ARGS = optimist
.usage("$0 [options] input1.js [input2.js ...]\n\
-Maximum compression settings are on by default.\n\
Use a single dash to read input from the standard input.\
")
.describe("source-map", "Specify an output file where to generate source map.")
.describe("source-map-root", "The path to the original source to be included in the source map.")
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
- .describe("p", "Skip prefix for original filenames that appear in source maps. For example -p 3 will drop 3 directories from file names and ensure they are relative paths.")
- .describe("o", "Output file (default STDOUT)")
- .describe("b", "Beautify output")
- .describe("m", "Don't mangle names")
- .describe("c", "Disable compressor, or pass compressor options. \
+ .describe("p", "Skip prefix for original filenames that appear in source maps. \
+For example -p 3 will drop 3 directories from file names and ensure they are relative paths.")
+ .describe("o", "Output file (default STDOUT).")
+ .describe("b", "Beautify output/specify output options.")
+ .describe("m", "Mangle names/pass mangler options.")
+ .describe("c", "Enable compressor/pass compressor options. \
Pass options like -c hoist_vars=false,if_return=false. \
-Use -c with no argument if you want to disable the squeezer entirely")
+Use -c with no argument if you want to disable the squeezer entirely.")
- .describe("stats", "Display operations run time on STDERR")
+ .describe("stats", "Display operations run time on STDERR.")
.describe("v", "Verbose")
.alias("p", "prefix")
.alias("o", "output")
.alias("v", "verbose")
.alias("b", "beautify")
- .alias("c", "options")
- .alias("m", "no-mangle")
+ .alias("m", "mangle")
+ .alias("c", "compress")
- .boolean("b")
+ .string("b")
+ .string("m")
+ .string("c")
.boolean("v")
.boolean("stats")
- .boolean("m")
- .string("c")
.wrap(80)
@@ -45,6 +45,7 @@ Use -c with no argument if you want to disable the squeezer entirely")
function normalize(o) {
for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
o[i.replace(/-/g, "_")] = o[i];
+ delete o[i];
}
}
@@ -55,15 +56,30 @@ if (ARGS.h || ARGS.help) {
process.exit(0);
}
-var COMPRESSOR_OPTIONS = {};
-if (ARGS.c && ARGS.c !== true) {
- ARGS.c.replace(/^\s+|\s+$/g).split(/\s*,+\s*/).forEach(function(opt){
- var a = opt.split(/\s*=\s*/);
- COMPRESSOR_OPTIONS[a[0]] = new Function("return(" + a[1] + ")")();
- });
- normalize(COMPRESSOR_OPTIONS);
+function getOptions(x) {
+ x = ARGS[x];
+ if (!x) return null;
+ var ret = {};
+ if (x !== true) {
+ x.replace(/^\s+|\s+$/g).split(/\s*,+\s*/).forEach(function(opt){
+ var a = opt.split(/\s*[=:]\s*/);
+ ret[a[0]] = a.length > 1 ? new Function("return(" + a[1] + ")")() : true;
+ });
+ normalize(ret)
+ }
+ return ret;
}
+var COMPRESS = getOptions("c");
+var MANGLE = getOptions("m");
+var BEAUTIFY = getOptions("b");
+
+var OUTPUT_OPTIONS = {
+ beautify: BEAUTIFY ? true : false
+};
+if (BEAUTIFY)
+ UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
+
var files = ARGS._.slice();
var ORIG_MAP = ARGS.in_source_map;
@@ -103,10 +119,19 @@ var SOURCE_MAP = ARGS.source_map ? UglifyJS.SourceMap({
orig: ORIG_MAP,
}) : null;
-var output = UglifyJS.OutputStream({
- beautify: ARGS.b,
- source_map: SOURCE_MAP
-});
+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) {
+ sys.error(ex.msg);
+ sys.error("Supported options:");
+ sys.error(sys.inspect(ex.defs));
+ process.exit(1);
+ }
+}
files.forEach(function(file) {
var code = read_whole_file(file);
@@ -121,7 +146,7 @@ files.forEach(function(file) {
});
});
-var SCOPE_IS_NEEDED = ARGS.c !== true || !ARGS.m;
+var SCOPE_IS_NEEDED = COMPRESS || MANGLE;
if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
@@ -129,9 +154,8 @@ if (SCOPE_IS_NEEDED) {
});
}
-if (ARGS.c !== true) {
+if (COMPRESS) {
time_it("squeeze", function(){
- var compressor = UglifyJS.Compressor(COMPRESSOR_OPTIONS);
TOPLEVEL = TOPLEVEL.transform(compressor);
});
}
@@ -139,15 +163,15 @@ if (ARGS.c !== true) {
if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
TOPLEVEL.figure_out_scope();
- if (!ARGS.m) {
+ if (MANGLE) {
TOPLEVEL.compute_char_frequency();
UglifyJS.base54.sort();
}
});
}
-if (!ARGS.m) time_it("mangle", function(){
- TOPLEVEL.mangle_names();
+if (MANGLE) time_it("mangle", function(){
+ TOPLEVEL.mangle_names(MANGLE);
});
time_it("generate", function(){
TOPLEVEL.print(output);
diff --git a/lib/compress.js b/lib/compress.js
index 3054e1fe..14e722d3 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -64,7 +64,7 @@ function Compressor(options, false_by_default) {
cascade : !false_by_default,
warnings : true
- });
+ }, true);
};
Compressor.prototype = new TreeTransformer;
diff --git a/lib/output.js b/lib/output.js
index 69401d0d..615f7110 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -53,9 +53,10 @@ function OutputStream(options) {
width : 80,
max_line_len : 32000,
ie_proof : true,
- beautify : true,
+ beautify : false,
source_map : null,
- });
+ bracketize : false,
+ }, true);
var indentation = 0;
var current_col = 0;
@@ -261,6 +262,9 @@ function OutputStream(options) {
get : get,
toString : get,
indent : indent,
+ indentation : function() { return indentation },
+ current_width : function() { return current_col - indentation },
+ should_break : function() { return options.width && this.current_width() >= options.width },
newline : newline,
print : print,
space : space,
@@ -271,6 +275,7 @@ function OutputStream(options) {
force_semicolon : force_semicolon,
print_name : function(name) { print(make_name(name)) },
print_string : function(str) { print(encode_string(str)) },
+ next_indent : next_indent,
with_indent : with_indent,
with_block : with_block,
with_parens : with_parens,
@@ -314,9 +319,6 @@ function OutputStream(options) {
};
AST_Node.DEFMETHOD("print_to_string", function(options){
- options = defaults(options, {
- beautify: false
- });
var s = OutputStream(options);
this.print(s);
return s.get();
@@ -610,6 +612,10 @@ function OutputStream(options) {
/* -----[ if ]----- */
function make_then(self, output) {
+ if (output.option("bracketize")) {
+ make_block(self.body, output);
+ return;
+ }
// The squeezer replaces "block"-s that contain only a single
// statement with the statement itself; technically, the AST
// is correct, but this can create problems when we output an
@@ -780,13 +786,29 @@ function OutputStream(options) {
output.space();
AST_Call.prototype.print.call(self, output);
});
- DEFPRINT(AST_Seq, function(self, output){
- self.car.print(output);
- if (self.cdr) {
+
+ AST_Seq.DEFMETHOD("_do_print", function(output){
+ this.car.print(output);
+ if (this.cdr) {
output.comma();
- self.cdr.print(output);
+ if (output.should_break()) {
+ output.newline();
+ output.indent();
+ }
+ this.cdr.print(output);
}
});
+ DEFPRINT(AST_Seq, function(self, output){
+ self._do_print(output);
+ // var p = output.parent();
+ // if (p instanceof AST_Statement) {
+ // output.with_indent(output.next_indent(), function(){
+ // self._do_print(output);
+ // });
+ // } else {
+ // self._do_print(output);
+ // }
+ });
DEFPRINT(AST_Dot, function(self, output){
var expr = self.expression;
expr.print(output);
@@ -919,10 +941,22 @@ function OutputStream(options) {
});
function force_statement(stat, output) {
- if (stat instanceof AST_EmptyStatement)
- output.force_semicolon();
- else
- stat.print(output);
+ if (output.option("bracketize")) {
+ if (!stat || stat instanceof AST_EmptyStatement)
+ output.print("{}");
+ else if (stat instanceof AST_BlockStatement)
+ stat.print(output);
+ else output.with_block(function(){
+ output.indent();
+ stat.print(output);
+ output.newline();
+ });
+ } else {
+ if (!stat || stat instanceof AST_EmptyStatement)
+ output.force_semicolon();
+ else
+ stat.print(output);
+ }
};
// return true if the node at the top of the stack (that means the
@@ -938,7 +972,7 @@ function OutputStream(options) {
(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_Binary && p.left === node ) ||
(p instanceof AST_UnaryPostfix && p.expression === node ))
{
node = p;
diff --git a/lib/scope.js b/lib/scope.js
index 1f564431..9f8981f9 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -339,7 +339,10 @@ AST_LoopControl.DEFMETHOD("target", function(){
return this.loopcontrol_target;
});
-AST_Toplevel.DEFMETHOD("mangle_names", function(sort){
+AST_Toplevel.DEFMETHOD("mangle_names", function(options){
+ options = defaults(options, {
+ sort: false
+ });
// We only need to mangle declaration nodes. Special logic wired
// into the code generator will display the mangled name if it's
// present (and for AST_SymbolRef-s it'll use the mangled name of
@@ -374,11 +377,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(sort){
});
this.walk(tw);
- if (sort) to_mangle = mergeSort(to_mangle, function(a, b){
+ if (options.sort) to_mangle = mergeSort(to_mangle, function(a, b){
return b.references.length - a.references.length;
});
- to_mangle.forEach(function(def){ def.mangle() });
+ to_mangle.forEach(function(def){ def.mangle(options) });
});
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(){
diff --git a/lib/utils.js b/lib/utils.js
index 5de83fbd..3b8aa00c 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -96,10 +96,17 @@ function repeat_string(str, i) {
return d;
};
-function defaults(args, defs) {
+function DefaultsError(msg, defs) {
+ this.msg = msg;
+ this.defs = defs;
+};
+
+function defaults(args, defs, croak) {
if (args === true)
args = {};
var ret = args || {};
+ if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i))
+ throw new DefaultsError("`" + i + "` is not a supported option", defs);
for (var i in defs) if (HOP(defs, i)) {
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
}