4 global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util");
5 var fs = require("fs");
7 // Add ../lib to require path
8 // by Youmin Ha <youmin.ha@samsung.com>
9 var path = require("path");
10 require.paths.unshift(path.join(__dirname, '..', 'lib'));
12 var uglify = require("uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js
19 mangle_toplevel: false,
20 no_mangle_functions: false,
27 max_line_length: 32 * 1024,
42 output: true // stdout
45 var args = jsp.slice(process.argv, 2);
48 out: while (args.length > 0) {
53 options.codegen_options.beautify = true;
57 options.codegen_options.indent_level = args.shift();
61 options.codegen_options.quote_keys = true;
64 case "--mangle-toplevel":
65 options.mangle_toplevel = true;
68 case "--no-mangle-functions":
69 options.no_mangle_functions = true;
73 options.mangle = false;
77 options.squeeze = false;
80 options.make_seqs = false;
82 case "--no-dead-code":
83 options.dead_code = false;
85 case "--no-copyright":
87 options.show_copyright = false;
91 options.output = args.shift();
94 options.out_same_file = true;
98 options.verbose = true;
104 options.unsafe = true;
106 case "--max-line-len":
107 options.max_line_length = parseInt(args.shift(), 10);
109 case "--reserved-names":
110 options.reserved_names = args.shift().split(",");
113 options.lift_vars = true;
117 var defarg = args.shift();
119 var defsym = function(sym) {
120 // KEYWORDS_ATOM doesn't include NaN or Infinity - should we check
121 // for them too ?? We don't check reserved words and the like as the
122 // define values are only substituted AFTER parsing
123 if (jsp.KEYWORDS_ATOM.hasOwnProperty(sym)) {
124 throw "Don't define values for inbuilt constant '"+sym+"'";
128 defval = function(v) {
129 if (v.match(/^"(.*)"$/) || v.match(/^'(.*)'$/)) {
130 return [ "string", RegExp.$1 ];
132 else if (!isNaN(parseFloat(v))) {
133 return [ "num", parseFloat(v) ];
135 else if (v.match(/^[a-z\$_][a-z\$_0-9]*$/i)) {
136 return [ "name", v ];
138 else if (!v.match(/"/)) {
139 return [ "string", v ];
141 else if (!v.match(/'/)) {
142 return [ "string", v ];
144 throw "Can't understand the specified value: "+v;
146 if (defarg.match(/^([a-z_\$][a-z_\$0-9]*)(=(.*))?$/i)) {
147 var sym = defsym(RegExp.$1),
148 val = RegExp.$2 ? defval(RegExp.$2.substr(1)) : [ 'name', 'true' ];
149 options.defines[sym] = val;
152 throw "The --define option expects SYMBOL[=value]";
155 sys.print("ERROR: In option --define "+defarg+"\n"+ex+"\n");
159 case "--define-from-module":
160 var defmodarg = args.shift(),
161 defmodule = require(defmodarg),
164 for (sym in defmodule) {
165 if (defmodule.hasOwnProperty(sym)) {
166 options.defines[sym] = function(val) {
167 if (typeof val == "string")
168 return [ "string", val ];
169 if (typeof val == "number")
170 return [ "num", val ];
172 return [ 'name', 'true' ];
174 return [ 'name', 'false' ];
176 return [ 'name', 'null' ];
177 if (val === undefined)
178 return [ 'name', 'undefined' ];
179 sys.print("ERROR: In option --define-from-module "+defmodarg+"\n");
180 sys.print("ERROR: Unknown object type for: "+sym+"="+val+"\n");
188 options.codegen_options.ascii_only = true;
193 case "--inline-script":
194 options.codegen_options.inline_script = true;
202 if (options.verbose) {
203 pro.set_logger(function(msg){
208 jsp.set_logger(function(msg){
213 options.out_same_file = false; // doesn't make sense in this case
214 var makefile = JSON.parse(fs.readFileSync(filename || "Makefile.uglify.js").toString());
215 output(makefile.files.map(function(file){
216 var code = fs.readFileSync(file.name);
218 code = "!function(exports, global){global = this;\n" + code + "\n;this." + file.module + " = exports;}({})";
220 else if (file.hide) {
221 code = "(function(){" + code + "}());";
223 return squeeze_it(code);
227 fs.readFile(filename, "utf8", function(err, text){
229 output(squeeze_it(text));
233 var stdin = process.openStdin();
234 stdin.setEncoding("utf8");
236 stdin.on("data", function(chunk){
239 stdin.on("end", function() {
240 output(squeeze_it(text));
244 function output(text) {
246 if (options.out_same_file && filename)
247 options.output = filename;
248 if (options.output === true) {
249 out = process.stdout;
251 out = fs.createWriteStream(options.output, {
257 out.write(text.replace(/;*$/, ";"));
258 if (options.output !== true) {
263 // --------- main ends here.
265 function show_copyright(comments) {
267 for (var i = 0; i < comments.length; ++i) {
269 if (c.type == "comment1") {
270 ret += "//" + c.value + "\n";
272 ret += "/*" + c.value + "*/";
278 function squeeze_it(code) {
280 if (options.show_copyright) {
281 var tok = jsp.tokenizer(code), c;
283 result += show_copyright(c.comments_before);
286 var ast = time_it("parse", function(){ return jsp.parse(code); });
287 if (options.lift_vars) {
288 ast = time_it("lift", function(){ return pro.ast_lift_variables(ast); });
290 if (options.mangle) ast = time_it("mangle", function(){
291 return pro.ast_mangle(ast, {
292 toplevel : options.mangle_toplevel,
293 defines : options.defines,
294 except : options.reserved_names,
295 no_functions : options.no_mangle_functions
298 if (options.squeeze) ast = time_it("squeeze", function(){
299 ast = pro.ast_squeeze(ast, {
300 make_seqs : options.make_seqs,
301 dead_code : options.dead_code,
302 keep_comps : !options.unsafe
305 ast = pro.ast_squeeze_more(ast);
309 return sys.inspect(ast, null, null);
310 result += time_it("generate", function(){ return pro.gen_code(ast, options.codegen_options) });
311 if (!options.codegen_options.beautify && options.max_line_length) {
312 result = time_it("split", function(){ return pro.split_lines(result, options.max_line_length) });
317 sys.debug(sys.inspect(ex));
318 sys.debug(JSON.stringify(ex));
323 function time_it(name, cont) {
324 if (!options.verbose)
326 var t1 = new Date().getTime();
327 try { return cont(); }
328 finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); }