| #! /usr/bin/env node |
| // -*- js2 -*- |
| |
| global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util"); |
| var fs = require("fs"), |
| jsp = require("./lib/parse-js"), |
| pro = require("./lib/process"); |
| |
| pro.set_logger(function(msg){ |
| sys.debug(msg); |
| }); |
| |
| var options = { |
| ast: false, |
| mangle: true, |
| mangle_toplevel: false, |
| squeeze: true, |
| make_seqs: true, |
| dead_code: true, |
| beautify: false, |
| verbose: false, |
| show_copyright: true, |
| out_same_file: false, |
| extra: false, |
| unsafe: false, // XXX: extra & unsafe? but maybe we don't want both, so.... |
| beautify_options: { |
| indent_level: 4, |
| indent_start: 0, |
| quote_keys: false, |
| space_colon: false |
| }, |
| output: true // stdout |
| }; |
| |
| var args = jsp.slice(process.argv, 2); |
| var filename; |
| |
| out: while (args.length > 0) { |
| var v = args.shift(); |
| switch (v) { |
| case "-b": |
| case "--beautify": |
| options.beautify = true; |
| break; |
| case "-i": |
| case "--indent": |
| options.beautify_options.indent_level = args.shift(); |
| break; |
| case "-q": |
| case "--quote-keys": |
| options.beautify_options.quote_keys = true; |
| break; |
| case "-mt": |
| case "--mangle-toplevel": |
| options.mangle_toplevel = true; |
| break; |
| case "--no-mangle": |
| case "-nm": |
| options.mangle = false; |
| break; |
| case "--no-squeeze": |
| case "-ns": |
| options.squeeze = false; |
| break; |
| case "--no-seqs": |
| options.make_seqs = false; |
| break; |
| case "--no-dead-code": |
| options.dead_code = false; |
| break; |
| case "--no-copyright": |
| case "-nc": |
| options.show_copyright = false; |
| break; |
| case "-o": |
| case "--output": |
| options.output = args.shift(); |
| break; |
| case "--overwrite": |
| options.out_same_file = true; |
| break; |
| case "-v": |
| case "--verbose": |
| options.verbose = true; |
| break; |
| case "--ast": |
| options.ast = true; |
| break; |
| case "--extra": |
| options.extra = true; |
| break; |
| case "--unsafe": |
| options.unsafe = true; |
| break; |
| default: |
| filename = v; |
| break out; |
| } |
| } |
| |
| if (filename) { |
| fs.readFile(filename, "utf8", function(err, text){ |
| if (err) { |
| throw err; |
| } |
| output(squeeze_it(text)); |
| }); |
| } else { |
| var stdin = process.openStdin(); |
| stdin.setEncoding("utf8"); |
| var text = ""; |
| stdin.on("data", function(chunk){ |
| text += chunk; |
| }); |
| stdin.on("end", function() { |
| output(squeeze_it(text)); |
| }); |
| } |
| |
| function output(text) { |
| var out; |
| if (options.out_same_file && filename) |
| options.output = filename; |
| if (options.output === true) { |
| out = process.stdout; |
| } else { |
| out = fs.createWriteStream(options.output, { |
| flags: "w", |
| encoding: "utf8", |
| mode: 0644 |
| }); |
| } |
| out.write(text); |
| out.end(); |
| }; |
| |
| // --------- main ends here. |
| |
| function show_copyright(comments) { |
| var ret = ""; |
| for (var i = 0; i < comments.length; ++i) { |
| var c = comments[i]; |
| if (c.type == "comment1") { |
| ret += "//" + c.value + "\n"; |
| } else { |
| ret += "/*" + c.value + "*/"; |
| } |
| } |
| return ret; |
| }; |
| |
| function squeeze_it(code) { |
| var result = ""; |
| if (options.show_copyright) { |
| var initial_comments = []; |
| // keep first comment |
| var tok = jsp.tokenizer(code, false), c; |
| c = tok(); |
| var prev = null; |
| while (/^comment/.test(c.type) && (!prev || prev == c.type)) { |
| initial_comments.push(c); |
| prev = c.type; |
| c = tok(); |
| } |
| result += show_copyright(initial_comments); |
| } |
| try { |
| var ast = time_it("parse", function(){ return jsp.parse(code); }); |
| if (options.mangle) |
| ast = time_it("mangle", function(){ return pro.ast_mangle(ast, options.mangle_toplevel); }); |
| if (options.squeeze) |
| ast = time_it("squeeze", function(){ |
| ast = pro.ast_squeeze(ast, { |
| make_seqs : options.make_seqs, |
| dead_code : options.dead_code, |
| extra : options.extra |
| }); |
| if (options.unsafe) |
| ast = pro.ast_squeeze_more(ast); |
| return ast; |
| }); |
| if (options.ast) |
| return sys.inspect(ast, null, null); |
| result += time_it("generate", function(){ return pro.gen_code(ast, options.beautify && options.beautify_options) }); |
| return result; |
| } catch(ex) { |
| sys.debug(ex.stack); |
| sys.debug(sys.inspect(ex)); |
| sys.debug(JSON.stringify(ex)); |
| } |
| }; |
| |
| function time_it(name, cont) { |
| if (!options.verbose) |
| return cont(); |
| var t1 = new Date().getTime(); |
| try { return cont(); } |
| finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); } |
| }; |