programs.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const options_1 = require("./options");
  4. /**
  5. * A program has a command, a description, options, and a run method
  6. */
  7. class Program {
  8. constructor() {
  9. this.options = {};
  10. }
  11. /**
  12. * Register a command and the description.
  13. * @param cmd The command.
  14. * @param cmdDescription The description of the command.
  15. * @returns The program for method chaining.
  16. */
  17. command(cmd, cmdDescription) {
  18. this.cmd = cmd;
  19. this.cmdDescription = cmdDescription;
  20. return this;
  21. }
  22. /**
  23. * Register a new option.
  24. * @param opt The option.
  25. * @param description The description of the option.
  26. * @param type The type of value expected: boolean, number, or string
  27. * @param defaultValue The option's default value.
  28. * @returns The program for method chaining.
  29. */
  30. option(opt, description, type, opt_defaultValue) {
  31. this.options[opt] = new options_1.Option(opt, description, type, opt_defaultValue);
  32. return this;
  33. }
  34. /**
  35. * Adds an option to the program.
  36. * @param option The option.
  37. * @returns The program for method chaining.
  38. */
  39. addOption(option) {
  40. this.options[option.opt] = option;
  41. return this;
  42. }
  43. /**
  44. * Registers a method that will be used to run the program.
  45. * @param runMethod The method that will be used to run the program.
  46. * @returns The program for method chaining.
  47. */
  48. action(runMethod) {
  49. this.runMethod = runMethod;
  50. return this;
  51. }
  52. /**
  53. * Adds the value to the options and passes the updated options to the run
  54. * method.
  55. * @param args The arguments that will be parsed to run the method.
  56. */
  57. run(json) {
  58. for (let opt in this.options) {
  59. this.options[opt].value = this.getValue_(opt, json);
  60. }
  61. return Promise.resolve(this.runMethod(this.options));
  62. }
  63. getValue_(key, json) {
  64. let keyList = key.split('.');
  65. let tempJson = json;
  66. while (keyList.length > 0) {
  67. let keyItem = keyList[0];
  68. if (tempJson[keyItem] != null) {
  69. tempJson = tempJson[keyItem];
  70. keyList = keyList.slice(1);
  71. }
  72. else {
  73. return undefined;
  74. }
  75. }
  76. return tempJson;
  77. }
  78. /**
  79. * Prints the command with the description. The description will have spaces
  80. * between the cmd so that the starting position is "posDescription". If the
  81. * gap between the cmd and the description is less than MIN_SPACING or
  82. * posDescription is undefined, the spacing will be MIN_SPACING.
  83. *
  84. * @param opt_postDescription Starting position of the description.
  85. */
  86. printCmd(opt_posDescription) {
  87. let log = ' ' + this.cmd;
  88. let spacing = Program.MIN_SPACING;
  89. if (opt_posDescription) {
  90. let diff = opt_posDescription - log.length;
  91. if (diff < Program.MIN_SPACING) {
  92. spacing = Program.MIN_SPACING;
  93. }
  94. else {
  95. spacing = diff;
  96. }
  97. }
  98. log += Array(spacing).join(' ') + this.cmdDescription;
  99. console.log(log);
  100. }
  101. /**
  102. * Prints the options with the option descriptions and default values.
  103. * The posDescription and posDefault is the starting position for the option
  104. * description. If extOptions are provided, check to see if we have already
  105. * printed those options. Also, once we print the option, add them to the extOptions.
  106. *
  107. * @param posDescription Position to start logging the description.
  108. * @param posDefault Position to start logging the default value.
  109. * @param opt_extOptions A collection of options that will be updated.
  110. */
  111. printOptions(posDescription, posDefault, opt_extOptions) {
  112. for (let opt in this.options) {
  113. // we have already logged it
  114. if (opt_extOptions && opt_extOptions[opt]) {
  115. continue;
  116. }
  117. let option = this.options[opt];
  118. let log = ' --' + option.opt;
  119. let spacing = Program.MIN_SPACING;
  120. // description
  121. let diff = posDescription - log.length;
  122. if (diff < Program.MIN_SPACING) {
  123. spacing = Program.MIN_SPACING;
  124. }
  125. else {
  126. spacing = diff;
  127. }
  128. log += Array(spacing).join(' ') + option.description;
  129. // default value
  130. if (option.defaultValue) {
  131. spacing = Program.MIN_SPACING;
  132. let diff = posDefault - log.length - 1;
  133. if (diff <= Program.MIN_SPACING) {
  134. spacing = Program.MIN_SPACING;
  135. }
  136. else {
  137. spacing = diff;
  138. }
  139. log += Array(spacing).join(' ');
  140. log += '[default: ' + option.defaultValue + ']';
  141. }
  142. console.log(log);
  143. if (opt_extOptions) {
  144. opt_extOptions[option.opt] = option;
  145. }
  146. }
  147. }
  148. /**
  149. * Assuming that the this program can run by itself, to print out the program's
  150. * help. Also assuming that the commands are called cmd-run and cmd-help.
  151. */
  152. printHelp() {
  153. console.log('\n' +
  154. 'Usage: ' + this.cmd + ' [options]\n' +
  155. ' ' + this.cmd + ' help\n' +
  156. 'Description: ' + this.cmdDescription + '\n');
  157. console.log('Options:');
  158. this.printOptions(this.posDescription(), this.posDefault());
  159. }
  160. posDescription() {
  161. return this.lengthOf_('opt') + 2 * Program.MIN_SPACING;
  162. }
  163. posDefault() {
  164. return this.posDescription() + this.lengthOf_('description') + Program.MIN_SPACING;
  165. }
  166. lengthOf_(param) {
  167. let maxLength = -1;
  168. for (let opt in this.options) {
  169. let option = this.options[opt];
  170. if (param === 'description') {
  171. maxLength = Math.max(maxLength, option.description.length);
  172. }
  173. else if (param === 'opt') {
  174. maxLength = Math.max(maxLength, option.opt.length);
  175. }
  176. }
  177. return maxLength;
  178. }
  179. /**
  180. * Create a collection of options used by this program.
  181. * @returns The options used in the programs.
  182. */
  183. getOptions_(allOptions) {
  184. for (let opt in this.options) {
  185. allOptions[opt] = this.options[opt];
  186. }
  187. return allOptions;
  188. }
  189. /**
  190. * Get the options used by the program and create the minimist options
  191. * to ensure that minimist parses the values properly.
  192. * @returns The options for minimist.
  193. */
  194. getMinimistOptions() {
  195. let allOptions = {};
  196. allOptions = this.getOptions_(allOptions);
  197. let minimistOptions = {};
  198. let minimistBoolean = [];
  199. let minimistString = [];
  200. let minimistNumber = [];
  201. let minimistDefault = {};
  202. for (let opt in allOptions) {
  203. let option = allOptions[opt];
  204. if (option.type === 'boolean') {
  205. minimistBoolean.push(option.opt);
  206. }
  207. else if (option.type === 'string') {
  208. minimistString.push(option.opt);
  209. }
  210. else if (option.type === 'number') {
  211. minimistNumber.push(option.opt);
  212. }
  213. if (typeof option.defaultValue !== 'undefined') {
  214. minimistDefault[option.opt] = option.defaultValue;
  215. }
  216. }
  217. minimistOptions['boolean'] = minimistBoolean;
  218. minimistOptions['string'] = minimistString;
  219. minimistOptions['number'] = minimistNumber;
  220. minimistOptions['default'] = minimistDefault;
  221. return minimistOptions;
  222. }
  223. }
  224. Program.MIN_SPACING = 4;
  225. exports.Program = Program;
  226. //# sourceMappingURL=programs.js.map