4 global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util");
5 var fs = require("fs");
6 var uglify = require("uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js
13 mangle_toplevel: false,
20 max_line_length: 32 * 1024,
35 output: true // stdout
38 var args = jsp.slice(process.argv, 2);
41 out: while (args.length > 0) {
46 options.codegen_options.beautify = true;
50 options.codegen_options.indent_level = args.shift();
54 options.codegen_options.quote_keys = true;
57 case "--mangle-toplevel":
58 options.mangle_toplevel = true;
62 options.mangle = false;
66 options.squeeze = false;
69 options.make_seqs = false;
71 case "--no-dead-code":
72 options.dead_code = false;
74 case "--no-copyright":
76 options.show_copyright = false;
80 options.output = args.shift();
83 options.out_same_file = true;
87 options.verbose = true;
93 options.unsafe = true;
95 case "--max-line-len":
96 options.max_line_length = parseInt(args.shift(), 10);
98 case "--reserved-names":
99 options.reserved_names = args.shift().split(",");
102 options.lift_vars = true;
106 var defarg = args.shift();
108 var defsym = function(sym) {
109 // KEYWORDS_ATOM doesn't include NaN or Infinity - should we check
110 // for them too ?? We don't check reserved words and the like as the
111 // define values are only substituted AFTER parsing
112 if (jsp.KEYWORDS_ATOM.hasOwnProperty(sym)) {
113 throw "Don't define values for inbuilt constant '"+sym+"'";
117 defval = function(v) {
118 if (v.match(/^"(.*)"$/) || v.match(/^'(.*)'$/)) {
119 return [ "string", RegExp.$1 ];
121 else if (!isNaN(parseFloat(v))) {
122 return [ "num", parseFloat(v) ];
124 else if (v.match(/^[a-z\$_][a-z\$_0-9]*$/i)) {
125 return [ "name", v ];
127 else if (!v.match(/"/)) {
128 return [ "string", v ];
130 else if (!v.match(/'/)) {
131 return [ "string", v ];
133 throw "Can't understand the specified value: "+v;
135 if (defarg.match(/^([a-z_\$][a-z_\$0-9]*)(=(.*))?$/i)) {
136 var sym = defsym(RegExp.$1),
137 val = RegExp.$2 ? defval(RegExp.$2.substr(1)) : [ 'name', 'true' ];
138 options.defines[sym] = val;
141 throw "The --define option expects SYMBOL[=value]";
144 sys.print("ERROR: In option --define "+defarg+"\n"+ex+"\n");
148 case "--define-from-module":
149 var defmodarg = args.shift(),
150 defmodule = require(defmodarg),
153 for (sym in defmodule) {
154 if (defmodule.hasOwnProperty(sym)) {
155 options.defines[sym] = function(val) {
156 if (typeof val == "string")
157 return [ "string", val ];
158 if (typeof val == "number")
159 return [ "num", val ];
161 return [ 'name', 'true' ];
163 return [ 'name', 'false' ];
165 return [ 'name', 'null' ];
166 if (val === undefined)
167 return [ 'name', 'undefined' ];
168 sys.print("ERROR: In option --define-from-module "+defmodarg+"\n");
169 sys.print("ERROR: Unknown object type for: "+sym+"="+val+"\n");
177 options.codegen_options.ascii_only = true;
182 case "--inline-script":
183 options.codegen_options.inline_script = true;
191 if (options.verbose) {
192 pro.set_logger(function(msg){
197 jsp.set_logger(function(msg){
202 options.out_same_file = false; // doesn't make sense in this case
203 var makefile = JSON.parse(fs.readFileSync(filename || "Makefile.uglify.js").toString());
204 output(makefile.files.map(function(file){
205 var code = fs.readFileSync(file.name);
207 code = "!function(exports, global){global = this;\n" + code + "\n;this." + file.module + " = exports;}({})";
209 else if (file.hide) {
210 code = "(function(){" + code + "}());";
212 return squeeze_it(code);
216 fs.readFile(filename, "utf8", function(err, text){
218 output(squeeze_it(text));
222 var stdin = process.openStdin();
223 stdin.setEncoding("utf8");
225 stdin.on("data", function(chunk){
228 stdin.on("end", function() {
229 output(squeeze_it(text));
233 function output(text) {
235 if (options.out_same_file && filename)
236 options.output = filename;
237 if (options.output === true) {
238 out = process.stdout;
240 out = fs.createWriteStream(options.output, {
246 out.write(text + ";");
247 if (options.output !== true) {
252 // --------- main ends here.
254 function show_copyright(comments) {
256 for (var i = 0; i < comments.length; ++i) {
258 if (c.type == "comment1") {
259 ret += "//" + c.value + "\n";
261 ret += "/*" + c.value + "*/";
267 function squeeze_it(code) {
269 if (options.show_copyright) {
270 var tok = jsp.tokenizer(code), c;
272 result += show_copyright(c.comments_before);
275 var ast = time_it("parse", function(){ return jsp.parse(code); });
276 if (options.lift_vars) {
277 ast = time_it("lift", function(){ return pro.ast_lift_variables(ast); });
279 if (options.mangle) ast = time_it("mangle", function(){
280 return pro.ast_mangle(ast, {
281 toplevel: options.mangle_toplevel,
282 defines: options.defines,
283 except: options.reserved_names
286 if (options.squeeze) ast = time_it("squeeze", function(){
287 ast = pro.ast_squeeze(ast, {
288 make_seqs : options.make_seqs,
289 dead_code : options.dead_code,
290 keep_comps : !options.unsafe
293 ast = pro.ast_squeeze_more(ast);
297 return sys.inspect(ast, null, null);
298 result += time_it("generate", function(){ return pro.gen_code(ast, options.codegen_options) });
299 if (!options.codegen_options.beautify && options.max_line_length) {
300 result = time_it("split", function(){ return pro.split_lines(result, options.max_line_length) });
305 sys.debug(sys.inspect(ex));
306 sys.debug(JSON.stringify(ex));
311 function time_it(name, cont) {
312 if (!options.verbose)
314 var t1 = new Date().getTime();
315 try { return cont(); }
316 finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); }