ng-annotate.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // ng-annotate.js
  2. // MIT licensed, see LICENSE file
  3. // Copyright (c) 2013-2015 Olov Lassus <olov.lassus@gmail.com>
  4. "use strict";
  5. const t0 = Date.now();
  6. const fs = require("fs");
  7. const fmt = require("simple-fmt");
  8. const tryor = require("tryor");
  9. const ngAnnotate = require("./ng-annotate-main");
  10. const version = require("./package.json").version;
  11. const optimist = require("optimist")
  12. .usage("ng-annotate v" + version + "\n\nUsage: ng-annotate OPTIONS <file>\n\n" +
  13. "provide - instead of <file> to read from stdin\n" +
  14. "use -a and -r together to remove and add (rebuild) annotations in one go")
  15. .options("a", {
  16. alias: "add",
  17. boolean: true,
  18. describe: "add dependency injection annotations where non-existing",
  19. })
  20. .options("r", {
  21. alias: "remove",
  22. boolean: true,
  23. describe: "remove all existing dependency injection annotations",
  24. })
  25. .options("o", {
  26. describe: "write output to <file>. output is written to stdout by default",
  27. })
  28. .options("sourcemap", {
  29. boolean: true,
  30. describe: "generate an inline sourcemap"
  31. })
  32. .options("sourceroot", {
  33. describe: "set the sourceRoot property of the generated sourcemap"
  34. })
  35. .options("single_quotes", {
  36. boolean: true,
  37. describe: "use single quotes (') instead of double quotes (\")",
  38. })
  39. .options("regexp", {
  40. describe: "detect short form myMod.controller(...) iff myMod matches regexp",
  41. })
  42. .options("rename", {
  43. describe: "rename declarations and annotated references\n" +
  44. "oldname1 newname1 oldname2 newname2 ...",
  45. default: ""
  46. })
  47. .options("plugin", {
  48. describe: "use plugin with path (experimental)",
  49. })
  50. .options("stats", {
  51. boolean: true,
  52. describe: "print statistics on stderr (experimental)",
  53. });
  54. const argv = optimist.argv;
  55. function exit(msg) {
  56. if (msg) {
  57. process.stderr.write(msg);
  58. process.stderr.write("\n");
  59. }
  60. process.exit(-1);
  61. }
  62. // validate options
  63. if (argv._.length !== 1) {
  64. optimist.showHelp();
  65. exit("error: no input file provided");
  66. }
  67. if (!argv.add && !argv.remove) {
  68. optimist.showHelp();
  69. exit("error: missing option --add and/or --remove");
  70. }
  71. const filename = argv._.shift();
  72. (filename === "-" ? slurpStdin : slurpFile)(runAnnotate);
  73. function slurpStdin(cb) {
  74. let buf = "";
  75. process.stdin.setEncoding("utf8");
  76. process.stdin.on("data", function(d) {
  77. buf += d;
  78. });
  79. process.stdin.on("end", function() {
  80. cb(null, buf);
  81. });
  82. process.stdin.resume();
  83. }
  84. function slurpFile(cb) {
  85. if (!fs.existsSync(filename)) {
  86. cb(new Error(fmt('error: file not found {0}', filename)));
  87. }
  88. fs.readFile(filename, cb);
  89. }
  90. function runAnnotate(err, src) {
  91. if (err) {
  92. exit(err.message);
  93. }
  94. src = String(src);
  95. const config = tryor(function() {
  96. return JSON.parse(String(fs.readFileSync("ng-annotate-config.json")));
  97. }, {});
  98. if (filename !== "-") {
  99. config.inFile = filename;
  100. }
  101. ["add", "remove", "o", "regexp", "rename", "single_quotes", "plugin", "stats"].forEach(function(opt) {
  102. if (opt in argv) {
  103. config[opt] = argv[opt];
  104. }
  105. });
  106. if (argv.sourcemap) {
  107. config.map = { inline: true, sourceRoot: argv.sourceroot };
  108. if (filename !== "-") {
  109. config.map.inFile = filename;
  110. }
  111. };
  112. if (config.plugin) {
  113. if (!Array.isArray(config.plugin)) {
  114. config.plugin = [config.plugin];
  115. }
  116. config.plugin = config.plugin.map(function(path) {
  117. const absPath = tryor(fs.realpathSync.bind(fs, path), null);
  118. if (!absPath) {
  119. exit(fmt('error: plugin file not found {0}', path));
  120. }
  121. // the require below may throw an exception on parse-error
  122. try {
  123. return require(absPath);
  124. } catch (e) {
  125. // node will already print file:line and offending line to stderr
  126. exit(fmt("error: couldn't require(\"{0}\")", absPath));
  127. }
  128. });
  129. }
  130. const trimmedRename = config.rename && config.rename.trim();
  131. if (trimmedRename) {
  132. const flattenRename = trimmedRename.split(" ");
  133. const renameArray = [];
  134. for (let i = 0; i < flattenRename.length; i = i + 2) {
  135. renameArray.push({
  136. "from": flattenRename[i],
  137. "to": flattenRename[i + 1],
  138. });
  139. }
  140. config.rename = renameArray;
  141. } else {
  142. config.rename = null;
  143. }
  144. const run_t0 = Date.now();
  145. const ret = ngAnnotate(src, config);
  146. const run_t1 = Date.now();
  147. if (ret.errors) {
  148. exit(ret.errors.join("\n"));
  149. }
  150. const stats = ret._stats;
  151. if (config.stats && stats) {
  152. const t1 = Date.now();
  153. const all = t1 - t0;
  154. const run_parser = stats.parser_parse_t1 - stats.parser_parse_t0;
  155. const all_parser = run_parser + (stats.parser_require_t1 - stats.parser_require_t0);
  156. const nga_run = (run_t1 - run_t0) - run_parser;
  157. const nga_init = all - all_parser - nga_run;
  158. const pct = function(n) {
  159. return Math.round(100 * n / all);
  160. }
  161. process.stderr.write(fmt("[{0} ms] parser: {1}, nga init: {2}, nga run: {3}\n", all, all_parser, nga_init, nga_run));
  162. process.stderr.write(fmt("[%] parser: {0}, nga init: {1}, nga run: {2}\n", pct(all_parser), pct(nga_init), pct(nga_run)));
  163. }
  164. if (ret.src && config.o) {
  165. try {
  166. fs.writeFileSync(config.o, ret.src);
  167. } catch (e) {
  168. exit(e.message);
  169. }
  170. } else if (ret.src) {
  171. process.stdout.write(ret.src);
  172. }
  173. }