node.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. var path = require("path");
  2. var fs = require("fs");
  3. var FILES = exports.FILES = [
  4. "../lib/utils.js",
  5. "../lib/ast.js",
  6. "../lib/parse.js",
  7. "../lib/transform.js",
  8. "../lib/scope.js",
  9. "../lib/output.js",
  10. "../lib/compress.js",
  11. "../lib/sourcemap.js",
  12. "../lib/mozilla-ast.js",
  13. "../lib/propmangle.js",
  14. "./exports.js",
  15. ].map(function(file){
  16. return fs.realpathSync(path.join(path.dirname(__filename), file));
  17. });
  18. var UglifyJS = exports;
  19. new Function("MOZ_SourceMap", "exports", FILES.map(function(file){
  20. return fs.readFileSync(file, "utf8");
  21. }).join("\n\n"))(
  22. require("source-map"),
  23. UglifyJS
  24. );
  25. UglifyJS.AST_Node.warn_function = function(txt) {
  26. console.error("WARN: %s", txt);
  27. };
  28. exports.minify = function(files, options) {
  29. options = UglifyJS.defaults(options, {
  30. spidermonkey : false,
  31. outSourceMap : null,
  32. sourceRoot : null,
  33. inSourceMap : null,
  34. fromString : false,
  35. warnings : false,
  36. mangle : {},
  37. output : null,
  38. compress : {}
  39. });
  40. UglifyJS.base54.reset();
  41. // 1. parse
  42. var toplevel = null,
  43. sourcesContent = {};
  44. if (options.spidermonkey) {
  45. toplevel = UglifyJS.AST_Node.from_mozilla_ast(files);
  46. } else {
  47. if (typeof files == "string")
  48. files = [ files ];
  49. files.forEach(function(file, i){
  50. var code = options.fromString
  51. ? file
  52. : fs.readFileSync(file, "utf8");
  53. sourcesContent[file] = code;
  54. toplevel = UglifyJS.parse(code, {
  55. filename: options.fromString ? i : file,
  56. toplevel: toplevel
  57. });
  58. });
  59. }
  60. if (options.wrap) {
  61. toplevel = toplevel.wrap_commonjs(options.wrap, options.exportAll);
  62. }
  63. // 2. compress
  64. if (options.compress) {
  65. var compress = { warnings: options.warnings };
  66. UglifyJS.merge(compress, options.compress);
  67. toplevel.figure_out_scope();
  68. var sq = UglifyJS.Compressor(compress);
  69. toplevel = toplevel.transform(sq);
  70. }
  71. // 3. mangle
  72. if (options.mangle) {
  73. toplevel.figure_out_scope(options.mangle);
  74. toplevel.compute_char_frequency(options.mangle);
  75. toplevel.mangle_names(options.mangle);
  76. }
  77. // 4. output
  78. var inMap = options.inSourceMap;
  79. var output = {};
  80. if (typeof options.inSourceMap == "string") {
  81. inMap = fs.readFileSync(options.inSourceMap, "utf8");
  82. }
  83. if (options.outSourceMap) {
  84. output.source_map = UglifyJS.SourceMap({
  85. file: options.outSourceMap,
  86. orig: inMap,
  87. root: options.sourceRoot
  88. });
  89. if (options.sourceMapIncludeSources) {
  90. for (var file in sourcesContent) {
  91. if (sourcesContent.hasOwnProperty(file)) {
  92. output.source_map.get().setSourceContent(file, sourcesContent[file]);
  93. }
  94. }
  95. }
  96. }
  97. if (options.output) {
  98. UglifyJS.merge(output, options.output);
  99. }
  100. var stream = UglifyJS.OutputStream(output);
  101. toplevel.print(stream);
  102. if (options.outSourceMap && "string" === typeof options.outSourceMap) {
  103. stream += "\n//# sourceMappingURL=" + options.outSourceMap;
  104. }
  105. var source_map = output.source_map;
  106. if (source_map) {
  107. source_map = source_map + "";
  108. }
  109. return {
  110. code : stream + "",
  111. map : source_map
  112. };
  113. };
  114. // exports.describe_ast = function() {
  115. // function doitem(ctor) {
  116. // var sub = {};
  117. // ctor.SUBCLASSES.forEach(function(ctor){
  118. // sub[ctor.TYPE] = doitem(ctor);
  119. // });
  120. // var ret = {};
  121. // if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS;
  122. // if (ctor.SUBCLASSES.length > 0) ret.sub = sub;
  123. // return ret;
  124. // }
  125. // return doitem(UglifyJS.AST_Node).sub;
  126. // }
  127. exports.describe_ast = function() {
  128. var out = UglifyJS.OutputStream({ beautify: true });
  129. function doitem(ctor) {
  130. out.print("AST_" + ctor.TYPE);
  131. var props = ctor.SELF_PROPS.filter(function(prop){
  132. return !/^\$/.test(prop);
  133. });
  134. if (props.length > 0) {
  135. out.space();
  136. out.with_parens(function(){
  137. props.forEach(function(prop, i){
  138. if (i) out.space();
  139. out.print(prop);
  140. });
  141. });
  142. }
  143. if (ctor.documentation) {
  144. out.space();
  145. out.print_string(ctor.documentation);
  146. }
  147. if (ctor.SUBCLASSES.length > 0) {
  148. out.space();
  149. out.with_block(function(){
  150. ctor.SUBCLASSES.forEach(function(ctor, i){
  151. out.indent();
  152. doitem(ctor);
  153. out.newline();
  154. });
  155. });
  156. }
  157. };
  158. doitem(UglifyJS.AST_Node);
  159. return out + "";
  160. };
  161. function readReservedFile(filename, reserved) {
  162. if (!reserved) {
  163. reserved = { vars: [], props: [] };
  164. }
  165. var data = fs.readFileSync(filename, "utf8");
  166. data = JSON.parse(data);
  167. if (data.vars) {
  168. data.vars.forEach(function(name){
  169. UglifyJS.push_uniq(reserved.vars, name);
  170. });
  171. }
  172. if (data.props) {
  173. data.props.forEach(function(name){
  174. UglifyJS.push_uniq(reserved.props, name);
  175. });
  176. }
  177. return reserved;
  178. }
  179. exports.readReservedFile = readReservedFile;
  180. exports.readDefaultReservedFile = function(reserved) {
  181. return readReservedFile(path.join(__dirname, "domprops.json"), reserved);
  182. };
  183. exports.readNameCache = function(filename, key) {
  184. var cache = null;
  185. if (filename) {
  186. try {
  187. var cache = fs.readFileSync(filename, "utf8");
  188. cache = JSON.parse(cache)[key];
  189. if (!cache) throw "init";
  190. cache.props = UglifyJS.Dictionary.fromObject(cache.props);
  191. } catch(ex) {
  192. cache = {
  193. cname: -1,
  194. props: new UglifyJS.Dictionary()
  195. };
  196. }
  197. }
  198. return cache;
  199. };
  200. exports.writeNameCache = function(filename, key, cache) {
  201. if (filename) {
  202. var data;
  203. try {
  204. data = fs.readFileSync(filename, "utf8");
  205. data = JSON.parse(data);
  206. } catch(ex) {
  207. data = {};
  208. }
  209. data[key] = {
  210. cname: cache.cname,
  211. props: cache.props.toObject()
  212. };
  213. fs.writeFileSync(filename, JSON.stringify(data, null, 2), "utf8");
  214. }
  215. };