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");
12 require.paths.unshift(path.join(__dirname, '..', 'lib'));
16 var uglify = require("uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js
23 mangle_toplevel: false,
24 no_mangle_functions: false,
31 max_line_length: 32 * 1024,
46 output: true // stdout
49 var args = jsp.slice(process.argv, 2);
52 out: while (args.length > 0) {
57 options.codegen_options.beautify = true;
61 options.codegen_options.indent_level = args.shift();
65 options.codegen_options.quote_keys = true;
68 case "--mangle-toplevel":
69 options.mangle_toplevel = true;
72 case "--no-mangle-functions":
73 options.no_mangle_functions = true;
77 options.mangle = false;
81 options.squeeze = false;
84 options.make_seqs = false;
86 case "--no-dead-code":
87 options.dead_code = false;
89 case "--no-copyright":
91 options.show_copyright = false;
95 options.output = args.shift();
98 options.out_same_file = true;
102 options.verbose = true;
108 options.unsafe = true;
110 case "--max-line-len":
111 options.max_line_length = parseInt(args.shift(), 10);
113 case "--reserved-names":
114 options.reserved_names = args.shift().split(",");
117 options.lift_vars = true;
121 var defarg = args.shift();
123 var defsym = function(sym) {
124 // KEYWORDS_ATOM doesn't include NaN or Infinity - should we check
125 // for them too ?? We don't check reserved words and the like as the
126 // define values are only substituted AFTER parsing
127 if (jsp.KEYWORDS_ATOM.hasOwnProperty(sym)) {
128 throw "Don't define values for inbuilt constant '"+sym+"'";
132 defval = function(v) {
133 if (v.match(/^"(.*)"$/) || v.match(/^'(.*)'$/)) {
134 return [ "string", RegExp.$1 ];
136 else if (!isNaN(parseFloat(v))) {
137 return [ "num", parseFloat(v) ];
139 else if (v.match(/^[a-z\$_][a-z\$_0-9]*$/i)) {
140 return [ "name", v ];
142 else if (!v.match(/"/)) {
143 return [ "string", v ];
145 else if (!v.match(/'/)) {
146 return [ "string", v ];
148 throw "Can't understand the specified value: "+v;
150 if (defarg.match(/^([a-z_\$][a-z_\$0-9]*)(=(.*))?$/i)) {
151 var sym = defsym(RegExp.$1),
152 val = RegExp.$2 ? defval(RegExp.$2.substr(1)) : [ 'name', 'true' ];
153 options.defines[sym] = val;
156 throw "The --define option expects SYMBOL[=value]";
159 sys.print("ERROR: In option --define "+defarg+"\n"+ex+"\n");
163 case "--define-from-module":
164 var defmodarg = args.shift(),
165 defmodule = require(defmodarg),
168 for (sym in defmodule) {
169 if (defmodule.hasOwnProperty(sym)) {
170 options.defines[sym] = function(val) {
171 if (typeof val == "string")
172 return [ "string", val ];
173 if (typeof val == "number")
174 return [ "num", val ];
176 return [ 'name', 'true' ];
178 return [ 'name', 'false' ];
180 return [ 'name', 'null' ];
181 if (val === undefined)
182 return [ 'name', 'undefined' ];
183 sys.print("ERROR: In option --define-from-module "+defmodarg+"\n");
184 sys.print("ERROR: Unknown object type for: "+sym+"="+val+"\n");
192 options.codegen_options.ascii_only = true;
197 case "--inline-script":
198 options.codegen_options.inline_script = true;
206 if (options.verbose) {
207 pro.set_logger(function(msg){
212 jsp.set_logger(function(msg){
217 options.out_same_file = false; // doesn't make sense in this case
218 var makefile = JSON.parse(fs.readFileSync(filename || "Makefile.uglify.js").toString());
219 output(makefile.files.map(function(file){
220 var code = fs.readFileSync(file.name);
222 code = "!function(exports, global){global = this;\n" + code + "\n;this." + file.module + " = exports;}({})";
224 else if (file.hide) {
225 code = "(function(){" + code + "}());";
227 return squeeze_it(code);
231 fs.readFile(filename, "utf8", function(err, text){
233 output(squeeze_it(text));
237 var stdin = process.openStdin();
238 stdin.setEncoding("utf8");
240 stdin.on("data", function(chunk){
243 stdin.on("end", function() {
244 output(squeeze_it(text));
248 function output(text) {
250 if (options.out_same_file && filename)
251 options.output = filename;
252 if (options.output === true) {
253 out = process.stdout;
255 out = fs.createWriteStream(options.output, {
261 out.write(text.replace(/;*$/, ";"));
262 if (options.output !== true) {
267 // --------- main ends here.
269 function show_copyright(comments) {
271 for (var i = 0; i < comments.length; ++i) {
273 if (c.type == "comment1") {
274 ret += "//" + c.value + "\n";
276 ret += "/*" + c.value + "*/";
282 function squeeze_it(code) {
284 if (options.show_copyright) {
285 var tok = jsp.tokenizer(code), c;
287 result += show_copyright(c.comments_before);
290 var ast = time_it("parse", function(){ return jsp.parse(code); });
291 if (options.lift_vars) {
292 ast = time_it("lift", function(){ return pro.ast_lift_variables(ast); });
294 if (options.mangle) ast = time_it("mangle", function(){
295 return pro.ast_mangle(ast, {
296 toplevel : options.mangle_toplevel,
297 defines : options.defines,
298 except : options.reserved_names,
299 no_functions : options.no_mangle_functions
302 if (options.squeeze) ast = time_it("squeeze", function(){
303 ast = pro.ast_squeeze(ast, {
304 make_seqs : options.make_seqs,
305 dead_code : options.dead_code,
306 keep_comps : !options.unsafe
309 ast = pro.ast_squeeze_more(ast);
313 return sys.inspect(ast, null, null);
314 result += time_it("generate", function(){ return pro.gen_code(ast, options.codegen_options) });
315 if (!options.codegen_options.beautify && options.max_line_length) {
316 result = time_it("split", function(){ return pro.split_lines(result, options.max_line_length) });
321 sys.debug(sys.inspect(ex));
322 sys.debug(JSON.stringify(ex));
327 function time_it(name, cont) {
328 if (!options.verbose)
330 var t1 = new Date().getTime();
331 try { return cont(); }
332 finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); }