UglifyJS/bin/uglifyjs2

208 lines
5.4 KiB
Plaintext
Raw Normal View History

#! /usr/bin/env node
// -*- js -*-
var UglifyJS = require("../tools/node");
var sys = require("util");
var optimist = require("optimist");
var fs = require("fs");
var ARGS = optimist
2012-09-26 08:24:04 +00:00
.usage("$0 [options] input1.js [input2.js ...]\n\
2012-09-03 16:43:46 +00:00
Maximum compression settings are on by default.\n\
Use a single dash to read input from the standard input.\
2012-09-03 07:14:15 +00:00
")
.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)")
2012-09-03 07:14:15 +00:00
.describe("b", "Beautify output")
2012-09-13 16:45:16 +00:00
.describe("m", "Don't mangle names")
.describe("c", "Disable compressor, or 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")
.describe("stats", "Display operations run time on STDERR")
.describe("v", "Verbose")
2012-09-03 07:14:15 +00:00
.alias("p", "prefix")
.alias("o", "output")
.alias("v", "verbose")
.alias("b", "beautify")
2012-09-13 16:45:16 +00:00
.alias("c", "options")
.alias("m", "no-mangle")
2012-09-03 07:14:15 +00:00
2012-09-03 09:03:45 +00:00
.boolean("b")
.boolean("v")
2012-09-05 15:19:24 +00:00
.boolean("stats")
2012-09-13 16:45:16 +00:00
.boolean("m")
.string("c")
2012-09-03 09:03:45 +00:00
.wrap(80)
.argv
;
2012-09-13 16:45:16 +00:00
function normalize(o) {
for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
o[i.replace(/-/g, "_")] = o[i];
}
}
2012-09-13 16:45:16 +00:00
normalize(ARGS);
if (ARGS.h || ARGS.help) {
sys.puts(optimist.help());
process.exit(0);
}
2012-09-13 16:45:16 +00:00
var COMPRESSOR_OPTIONS = {};
if (ARGS.c && ARGS.c !== true) {
2012-09-13 16:45:16 +00:00
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);
2012-09-13 16:45:16 +00:00
}
var files = ARGS._.slice();
var ORIG_MAP = ARGS.in_source_map;
if (ORIG_MAP) {
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
if (files.length == 0) {
sys.error("INFO: Using file from the input source map: " + ORIG_MAP.file);
files = [ ORIG_MAP.file ];
}
if (ARGS.source_map_root == null) {
ARGS.source_map_root = ORIG_MAP.sourceRoot;
}
}
if (files.length == 0) {
files = [ "-" ];
}
if (files.indexOf("-") >= 0 && ARGS.source_map) {
sys.error("ERROR: Source map doesn't work with input from STDIN");
process.exit(1);
}
if (files.filter(function(el){ return el == "-" }).length > 1) {
sys.error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
process.exit(1);
}
var STATS = {};
var OUTPUT_FILE = ARGS.o;
var TOPLEVEL = null;
var SOURCE_MAP = ARGS.source_map ? UglifyJS.SourceMap({
2012-09-10 12:52:53 +00:00
file: OUTPUT_FILE,
root: ARGS.source_map_root,
orig: ORIG_MAP,
}) : null;
var output = UglifyJS.OutputStream({
2012-09-03 07:14:15 +00:00
beautify: ARGS.b,
source_map: SOURCE_MAP
});
files.forEach(function(file) {
var code = read_whole_file(file);
if (ARGS.p != null) {
file = file.replace(/^\/+/, "").split(/\/+/).slice(ARGS.p).join("/");
}
time_it("parse", function(){
TOPLEVEL = UglifyJS.parse(code, {
filename: file,
toplevel: TOPLEVEL
});
});
});
2012-09-26 08:24:04 +00:00
var SCOPE_IS_NEEDED = ARGS.c !== true || !ARGS.m;
if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
TOPLEVEL.figure_out_scope();
});
}
if (ARGS.c !== true) {
time_it("squeeze", function(){
var compressor = UglifyJS.Compressor(COMPRESSOR_OPTIONS);
TOPLEVEL = TOPLEVEL.transform(compressor);
});
}
2012-09-26 08:24:04 +00:00
if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
TOPLEVEL.figure_out_scope();
if (!ARGS.m) {
TOPLEVEL.compute_char_frequency();
UglifyJS.base54.sort();
}
});
}
if (!ARGS.m) time_it("mangle", function(){
TOPLEVEL.mangle_names();
});
time_it("generate", function(){
TOPLEVEL.print(output);
});
2012-09-03 07:14:15 +00:00
output = output.get();
if (SOURCE_MAP) {
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
2012-09-03 07:14:15 +00:00
output += "\n//@ sourceMappingURL=" + ARGS.source_map;
}
if (OUTPUT_FILE) {
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
} else {
sys.print(output);
sys.error("\n");
}
if (ARGS.stats) {
sys.error(UglifyJS.string_template("Timing information (compressed {count} files):", {
count: files.length
}));
for (var i in STATS) if (STATS.hasOwnProperty(i)) {
sys.error(UglifyJS.string_template("- {name}: {time}s", {
name: i,
time: (STATS[i] / 1000).toFixed(3)
}));
}
}
/* -----[ functions ]----- */
function read_whole_file(filename) {
if (filename == "-") {
// XXX: this sucks. How does one read the whole STDIN
// synchronously?
filename = "/dev/stdin";
}
try {
return fs.readFileSync(filename, "utf8");
} catch(ex) {
sys.error("ERROR: can't read file: " + filename);
process.exit(1);
}
}
function time_it(name, cont) {
var t1 = new Date().getTime();
var ret = cont();
if (ARGS.stats) {
var spent = new Date().getTime() - t1;
if (STATS[name]) STATS[name] += spent;
else STATS[name] = spent;
}
return ret;
};