a shy attempt to obey width in the beautifier; added bracketize option to always print brackets around if/do/while/for statements; export more options via the CLI
This commit is contained in:
@@ -7,35 +7,35 @@ var optimist = require("optimist");
|
|||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var ARGS = optimist
|
var ARGS = optimist
|
||||||
.usage("$0 [options] input1.js [input2.js ...]\n\
|
.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.\
|
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", "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("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("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("p", "Skip prefix for original filenames that appear in source maps. \
|
||||||
.describe("o", "Output file (default STDOUT)")
|
For example -p 3 will drop 3 directories from file names and ensure they are relative paths.")
|
||||||
.describe("b", "Beautify output")
|
.describe("o", "Output file (default STDOUT).")
|
||||||
.describe("m", "Don't mangle names")
|
.describe("b", "Beautify output/specify output options.")
|
||||||
.describe("c", "Disable compressor, or pass compressor 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. \
|
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")
|
.describe("v", "Verbose")
|
||||||
|
|
||||||
.alias("p", "prefix")
|
.alias("p", "prefix")
|
||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
.alias("v", "verbose")
|
.alias("v", "verbose")
|
||||||
.alias("b", "beautify")
|
.alias("b", "beautify")
|
||||||
.alias("c", "options")
|
.alias("m", "mangle")
|
||||||
.alias("m", "no-mangle")
|
.alias("c", "compress")
|
||||||
|
|
||||||
.boolean("b")
|
.string("b")
|
||||||
|
.string("m")
|
||||||
|
.string("c")
|
||||||
.boolean("v")
|
.boolean("v")
|
||||||
.boolean("stats")
|
.boolean("stats")
|
||||||
.boolean("m")
|
|
||||||
.string("c")
|
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
|
|
||||||
@@ -45,6 +45,7 @@ Use -c with no argument if you want to disable the squeezer entirely")
|
|||||||
function normalize(o) {
|
function normalize(o) {
|
||||||
for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
|
for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
|
||||||
o[i.replace(/-/g, "_")] = o[i];
|
o[i.replace(/-/g, "_")] = o[i];
|
||||||
|
delete o[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,15 +56,30 @@ if (ARGS.h || ARGS.help) {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
var COMPRESSOR_OPTIONS = {};
|
function getOptions(x) {
|
||||||
if (ARGS.c && ARGS.c !== true) {
|
x = ARGS[x];
|
||||||
ARGS.c.replace(/^\s+|\s+$/g).split(/\s*,+\s*/).forEach(function(opt){
|
if (!x) return null;
|
||||||
var a = opt.split(/\s*=\s*/);
|
var ret = {};
|
||||||
COMPRESSOR_OPTIONS[a[0]] = new Function("return(" + a[1] + ")")();
|
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(COMPRESSOR_OPTIONS);
|
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 files = ARGS._.slice();
|
||||||
|
|
||||||
var ORIG_MAP = ARGS.in_source_map;
|
var ORIG_MAP = ARGS.in_source_map;
|
||||||
@@ -103,10 +119,19 @@ var SOURCE_MAP = ARGS.source_map ? UglifyJS.SourceMap({
|
|||||||
orig: ORIG_MAP,
|
orig: ORIG_MAP,
|
||||||
}) : null;
|
}) : null;
|
||||||
|
|
||||||
var output = UglifyJS.OutputStream({
|
OUTPUT_OPTIONS.source_map = SOURCE_MAP;
|
||||||
beautify: ARGS.b,
|
|
||||||
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) {
|
files.forEach(function(file) {
|
||||||
var code = read_whole_file(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) {
|
if (SCOPE_IS_NEEDED) {
|
||||||
time_it("scope", function(){
|
time_it("scope", function(){
|
||||||
@@ -129,9 +154,8 @@ if (SCOPE_IS_NEEDED) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.c !== true) {
|
if (COMPRESS) {
|
||||||
time_it("squeeze", function(){
|
time_it("squeeze", function(){
|
||||||
var compressor = UglifyJS.Compressor(COMPRESSOR_OPTIONS);
|
|
||||||
TOPLEVEL = TOPLEVEL.transform(compressor);
|
TOPLEVEL = TOPLEVEL.transform(compressor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -139,15 +163,15 @@ if (ARGS.c !== true) {
|
|||||||
if (SCOPE_IS_NEEDED) {
|
if (SCOPE_IS_NEEDED) {
|
||||||
time_it("scope", function(){
|
time_it("scope", function(){
|
||||||
TOPLEVEL.figure_out_scope();
|
TOPLEVEL.figure_out_scope();
|
||||||
if (!ARGS.m) {
|
if (MANGLE) {
|
||||||
TOPLEVEL.compute_char_frequency();
|
TOPLEVEL.compute_char_frequency();
|
||||||
UglifyJS.base54.sort();
|
UglifyJS.base54.sort();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ARGS.m) time_it("mangle", function(){
|
if (MANGLE) time_it("mangle", function(){
|
||||||
TOPLEVEL.mangle_names();
|
TOPLEVEL.mangle_names(MANGLE);
|
||||||
});
|
});
|
||||||
time_it("generate", function(){
|
time_it("generate", function(){
|
||||||
TOPLEVEL.print(output);
|
TOPLEVEL.print(output);
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ function Compressor(options, false_by_default) {
|
|||||||
cascade : !false_by_default,
|
cascade : !false_by_default,
|
||||||
|
|
||||||
warnings : true
|
warnings : true
|
||||||
});
|
}, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
Compressor.prototype = new TreeTransformer;
|
Compressor.prototype = new TreeTransformer;
|
||||||
|
|||||||
@@ -53,9 +53,10 @@ function OutputStream(options) {
|
|||||||
width : 80,
|
width : 80,
|
||||||
max_line_len : 32000,
|
max_line_len : 32000,
|
||||||
ie_proof : true,
|
ie_proof : true,
|
||||||
beautify : true,
|
beautify : false,
|
||||||
source_map : null,
|
source_map : null,
|
||||||
});
|
bracketize : false,
|
||||||
|
}, true);
|
||||||
|
|
||||||
var indentation = 0;
|
var indentation = 0;
|
||||||
var current_col = 0;
|
var current_col = 0;
|
||||||
@@ -261,6 +262,9 @@ function OutputStream(options) {
|
|||||||
get : get,
|
get : get,
|
||||||
toString : get,
|
toString : get,
|
||||||
indent : indent,
|
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,
|
newline : newline,
|
||||||
print : print,
|
print : print,
|
||||||
space : space,
|
space : space,
|
||||||
@@ -271,6 +275,7 @@ function OutputStream(options) {
|
|||||||
force_semicolon : force_semicolon,
|
force_semicolon : force_semicolon,
|
||||||
print_name : function(name) { print(make_name(name)) },
|
print_name : function(name) { print(make_name(name)) },
|
||||||
print_string : function(str) { print(encode_string(str)) },
|
print_string : function(str) { print(encode_string(str)) },
|
||||||
|
next_indent : next_indent,
|
||||||
with_indent : with_indent,
|
with_indent : with_indent,
|
||||||
with_block : with_block,
|
with_block : with_block,
|
||||||
with_parens : with_parens,
|
with_parens : with_parens,
|
||||||
@@ -314,9 +319,6 @@ function OutputStream(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print_to_string", function(options){
|
AST_Node.DEFMETHOD("print_to_string", function(options){
|
||||||
options = defaults(options, {
|
|
||||||
beautify: false
|
|
||||||
});
|
|
||||||
var s = OutputStream(options);
|
var s = OutputStream(options);
|
||||||
this.print(s);
|
this.print(s);
|
||||||
return s.get();
|
return s.get();
|
||||||
@@ -610,6 +612,10 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
/* -----[ if ]----- */
|
/* -----[ if ]----- */
|
||||||
function make_then(self, output) {
|
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
|
// The squeezer replaces "block"-s that contain only a single
|
||||||
// statement with the statement itself; technically, the AST
|
// statement with the statement itself; technically, the AST
|
||||||
// is correct, but this can create problems when we output an
|
// is correct, but this can create problems when we output an
|
||||||
@@ -780,12 +786,28 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
AST_Call.prototype.print.call(self, output);
|
AST_Call.prototype.print.call(self, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Seq, function(self, output){
|
|
||||||
self.car.print(output);
|
AST_Seq.DEFMETHOD("_do_print", function(output){
|
||||||
if (self.cdr) {
|
this.car.print(output);
|
||||||
|
if (this.cdr) {
|
||||||
output.comma();
|
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){
|
DEFPRINT(AST_Dot, function(self, output){
|
||||||
var expr = self.expression;
|
var expr = self.expression;
|
||||||
@@ -919,10 +941,22 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function force_statement(stat, output) {
|
function force_statement(stat, output) {
|
||||||
if (stat instanceof AST_EmptyStatement)
|
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();
|
output.force_semicolon();
|
||||||
else
|
else
|
||||||
stat.print(output);
|
stat.print(output);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// return true if the node at the top of the stack (that means the
|
// return true if the node at the top of the stack (that means the
|
||||||
|
|||||||
@@ -339,7 +339,10 @@ AST_LoopControl.DEFMETHOD("target", function(){
|
|||||||
return this.loopcontrol_target;
|
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
|
// We only need to mangle declaration nodes. Special logic wired
|
||||||
// into the code generator will display the mangled name if it's
|
// 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
|
// 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);
|
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;
|
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(){
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(){
|
||||||
|
|||||||
@@ -96,10 +96,17 @@ function repeat_string(str, i) {
|
|||||||
return d;
|
return d;
|
||||||
};
|
};
|
||||||
|
|
||||||
function defaults(args, defs) {
|
function DefaultsError(msg, defs) {
|
||||||
|
this.msg = msg;
|
||||||
|
this.defs = defs;
|
||||||
|
};
|
||||||
|
|
||||||
|
function defaults(args, defs, croak) {
|
||||||
if (args === true)
|
if (args === true)
|
||||||
args = {};
|
args = {};
|
||||||
var ret = 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)) {
|
for (var i in defs) if (HOP(defs, i)) {
|
||||||
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
|
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user