tizen beta release
[platform/framework/web/web-ui-fw.git] / build-tools / bin / uglifyjs
1 #!/usr/bin/env node
2 // -*- js -*-
3
4 global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util");
5 var fs = require("fs");
6
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'));       
11
12 var uglify = require("uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js
13     jsp = uglify.parser,
14     pro = uglify.uglify;
15
16 var options = {
17         ast: false,
18         mangle: true,
19         mangle_toplevel: false,
20         no_mangle_functions: false,
21         squeeze: true,
22         make_seqs: true,
23         dead_code: true,
24         verbose: false,
25         show_copyright: true,
26         out_same_file: false,
27         max_line_length: 32 * 1024,
28         unsafe: false,
29         reserved_names: null,
30         defines: { },
31         lift_vars: false,
32         codegen_options: {
33                 ascii_only: false,
34                 beautify: false,
35                 indent_level: 4,
36                 indent_start: 0,
37                 quote_keys: false,
38                 space_colon: false,
39                 inline_script: false
40         },
41         make: false,
42         output: true            // stdout
43 };
44
45 var args = jsp.slice(process.argv, 2);
46 var filename;
47
48 out: while (args.length > 0) {
49         var v = args.shift();
50         switch (v) {
51             case "-b":
52             case "--beautify":
53                 options.codegen_options.beautify = true;
54                 break;
55             case "-i":
56             case "--indent":
57                 options.codegen_options.indent_level = args.shift();
58                 break;
59             case "-q":
60             case "--quote-keys":
61                 options.codegen_options.quote_keys = true;
62                 break;
63             case "-mt":
64             case "--mangle-toplevel":
65                 options.mangle_toplevel = true;
66                 break;
67             case "-nmf":
68             case "--no-mangle-functions":
69                 options.no_mangle_functions = true;
70                 break;
71             case "--no-mangle":
72             case "-nm":
73                 options.mangle = false;
74                 break;
75             case "--no-squeeze":
76             case "-ns":
77                 options.squeeze = false;
78                 break;
79             case "--no-seqs":
80                 options.make_seqs = false;
81                 break;
82             case "--no-dead-code":
83                 options.dead_code = false;
84                 break;
85             case "--no-copyright":
86             case "-nc":
87                 options.show_copyright = false;
88                 break;
89             case "-o":
90             case "--output":
91                 options.output = args.shift();
92                 break;
93             case "--overwrite":
94                 options.out_same_file = true;
95                 break;
96             case "-v":
97             case "--verbose":
98                 options.verbose = true;
99                 break;
100             case "--ast":
101                 options.ast = true;
102                 break;
103             case "--unsafe":
104                 options.unsafe = true;
105                 break;
106             case "--max-line-len":
107                 options.max_line_length = parseInt(args.shift(), 10);
108                 break;
109             case "--reserved-names":
110                 options.reserved_names = args.shift().split(",");
111                 break;
112             case "--lift-vars":
113                 options.lift_vars = true;
114                 break;
115             case "-d":
116             case "--define":
117                  var defarg = args.shift();
118                  try {
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+"'";
125                              }
126                              return sym;
127                          },
128                          defval = function(v) {
129                              if (v.match(/^"(.*)"$/) || v.match(/^'(.*)'$/)) {
130                                  return [ "string", RegExp.$1 ];
131                              }
132                              else if (!isNaN(parseFloat(v))) {
133                                  return [ "num", parseFloat(v) ];
134                              }
135                              else if (v.match(/^[a-z\$_][a-z\$_0-9]*$/i)) {
136                                  return [ "name", v ];
137                              }
138                              else if (!v.match(/"/)) {
139                                  return [ "string", v ];
140                              }
141                              else if (!v.match(/'/)) {
142                                  return [ "string", v ];
143                              }
144                              throw "Can't understand the specified value: "+v;
145                          };
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;
150                      }
151                      else {
152                          throw "The --define option expects SYMBOL[=value]";
153                      }
154                  } catch(ex) {
155                      sys.print("ERROR: In option --define "+defarg+"\n"+ex+"\n");
156                      process.exit(1);
157                  }
158                  break;
159             case "--define-from-module":
160                 var defmodarg = args.shift(),
161                     defmodule = require(defmodarg),
162                     sym,
163                     val;
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 ];
171                             if (val === true)
172                                 return [ 'name', 'true' ];
173                             if (val === false)
174                                 return [ 'name', 'false' ];
175                             if (val === null)
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");
181                             process.exit(1);
182                             return null;
183                         }(defmodule[sym]);
184                     }
185                 }
186                 break;
187             case "--ascii":
188                 options.codegen_options.ascii_only = true;
189                 break;
190             case "--make":
191                 options.make = true;
192                 break;
193             case "--inline-script":
194                 options.codegen_options.inline_script = true;
195                 break;
196             default:
197                 filename = v;
198                 break out;
199         }
200 }
201
202 if (options.verbose) {
203         pro.set_logger(function(msg){
204                 sys.debug(msg);
205         });
206 }
207
208 jsp.set_logger(function(msg){
209         sys.debug(msg);
210 });
211
212 if (options.make) {
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);
217                 if (file.module) {
218                         code = "!function(exports, global){global = this;\n" + code + "\n;this." + file.module + " = exports;}({})";
219                 }
220                 else if (file.hide) {
221                         code = "(function(){" + code + "}());";
222                 }
223                 return squeeze_it(code);
224         }).join("\n"));
225 }
226 else if (filename) {
227         fs.readFile(filename, "utf8", function(err, text){
228                 if (err) throw err;
229                 output(squeeze_it(text));
230         });
231 }
232 else {
233         var stdin = process.openStdin();
234         stdin.setEncoding("utf8");
235         var text = "";
236         stdin.on("data", function(chunk){
237                 text += chunk;
238         });
239         stdin.on("end", function() {
240                 output(squeeze_it(text));
241         });
242 }
243
244 function output(text) {
245         var out;
246         if (options.out_same_file && filename)
247                 options.output = filename;
248         if (options.output === true) {
249                 out = process.stdout;
250         } else {
251                 out = fs.createWriteStream(options.output, {
252                         flags: "w",
253                         encoding: "utf8",
254                         mode: 0644
255                 });
256         }
257         out.write(text.replace(/;*$/, ";"));
258         if (options.output !== true) {
259                 out.end();
260         }
261 };
262
263 // --------- main ends here.
264
265 function show_copyright(comments) {
266         var ret = "";
267         for (var i = 0; i < comments.length; ++i) {
268                 var c = comments[i];
269                 if (c.type == "comment1") {
270                         ret += "//" + c.value + "\n";
271                 } else {
272                         ret += "/*" + c.value + "*/";
273                 }
274         }
275         return ret;
276 };
277
278 function squeeze_it(code) {
279         var result = "";
280         if (options.show_copyright) {
281                 var tok = jsp.tokenizer(code), c;
282                 c = tok();
283                 result += show_copyright(c.comments_before);
284         }
285         try {
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); });
289                 }
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
296                         });
297                 });
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
303                         });
304                         if (options.unsafe)
305                                 ast = pro.ast_squeeze_more(ast);
306                         return ast;
307                 });
308                 if (options.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) });
313                 }
314                 return result;
315         } catch(ex) {
316                 sys.debug(ex.stack);
317                 sys.debug(sys.inspect(ex));
318                 sys.debug(JSON.stringify(ex));
319                 process.exit(1);
320         }
321 };
322
323 function time_it(name, cont) {
324         if (!options.verbose)
325                 return cont();
326         var t1 = new Date().getTime();
327         try { return cont(); }
328         finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); }
329 };