node.js 6.9 KB

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