command.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright Google Inc. All Rights Reserved.
  5. *
  6. * Use of this source code is governed by an MIT-style license that can be
  7. * found in the LICENSE file at https://angular.io/license
  8. */
  9. Object.defineProperty(exports, "__esModule", { value: true });
  10. // tslint:disable:no-global-tslint-disable no-any
  11. const core_1 = require("@angular-devkit/core");
  12. const path = require("path");
  13. const color_1 = require("../utilities/color");
  14. const config_1 = require("../utilities/config");
  15. const interface_1 = require("./interface");
  16. class Command {
  17. constructor(context, description, logger) {
  18. this.description = description;
  19. this.logger = logger;
  20. this.allowMissingWorkspace = false;
  21. this.workspace = context.workspace;
  22. this.analytics = context.analytics || new core_1.analytics.NoopAnalytics();
  23. }
  24. static setCommandMap(map) {
  25. this.commandMap = map;
  26. }
  27. async initialize(options) {
  28. return;
  29. }
  30. async printHelp(options) {
  31. await this.printHelpUsage();
  32. await this.printHelpOptions();
  33. return 0;
  34. }
  35. async printJsonHelp(_options) {
  36. this.logger.info(JSON.stringify(this.description));
  37. return 0;
  38. }
  39. async printHelpUsage() {
  40. this.logger.info(this.description.description);
  41. const name = this.description.name;
  42. const args = this.description.options.filter(x => x.positional !== undefined);
  43. const opts = this.description.options.filter(x => x.positional === undefined);
  44. const argDisplay = args && args.length > 0 ? ' ' + args.map(a => `<${a.name}>`).join(' ') : '';
  45. const optionsDisplay = opts && opts.length > 0 ? ` [options]` : ``;
  46. this.logger.info(`usage: ng ${name}${argDisplay}${optionsDisplay}`);
  47. this.logger.info('');
  48. }
  49. async printHelpSubcommand(subcommand) {
  50. this.logger.info(subcommand.description);
  51. await this.printHelpOptions(subcommand.options);
  52. }
  53. async printHelpOptions(options = this.description.options) {
  54. const args = options.filter(opt => opt.positional !== undefined);
  55. const opts = options.filter(opt => opt.positional === undefined);
  56. const formatDescription = (description) => ` ${description.replace(/\n/g, '\n ')}`;
  57. if (args.length > 0) {
  58. this.logger.info(`arguments:`);
  59. args.forEach(o => {
  60. this.logger.info(` ${color_1.colors.cyan(o.name)}`);
  61. if (o.description) {
  62. this.logger.info(formatDescription(o.description));
  63. }
  64. });
  65. }
  66. if (options.length > 0) {
  67. if (args.length > 0) {
  68. this.logger.info('');
  69. }
  70. this.logger.info(`options:`);
  71. opts
  72. .filter(o => !o.hidden)
  73. .sort((a, b) => a.name.localeCompare(b.name))
  74. .forEach(o => {
  75. const aliases = o.aliases && o.aliases.length > 0
  76. ? '(' + o.aliases.map(a => `-${a}`).join(' ') + ')'
  77. : '';
  78. this.logger.info(` ${color_1.colors.cyan('--' + core_1.strings.dasherize(o.name))} ${aliases}`);
  79. if (o.description) {
  80. this.logger.info(formatDescription(o.description));
  81. }
  82. });
  83. }
  84. }
  85. async validateScope(scope) {
  86. switch (scope === undefined ? this.description.scope : scope) {
  87. case interface_1.CommandScope.OutProject:
  88. if (this.workspace.configFile) {
  89. this.logger.fatal(core_1.tags.oneLine `
  90. The ${this.description.name} command requires to be run outside of a project, but a
  91. project definition was found at "${path.join(this.workspace.root, this.workspace.configFile)}".
  92. `);
  93. throw 1;
  94. }
  95. break;
  96. case interface_1.CommandScope.InProject:
  97. if (!this.workspace.configFile || config_1.getWorkspace('local') === null) {
  98. this.logger.fatal(core_1.tags.oneLine `
  99. The ${this.description.name} command requires to be run in an Angular project, but a
  100. project definition could not be found.
  101. `);
  102. throw 1;
  103. }
  104. break;
  105. case interface_1.CommandScope.Everywhere:
  106. // Can't miss this.
  107. break;
  108. }
  109. }
  110. async reportAnalytics(paths, options, dimensions = [], metrics = []) {
  111. for (const option of this.description.options) {
  112. const ua = option.userAnalytics;
  113. const v = options[option.name];
  114. if (v !== undefined && !Array.isArray(v) && ua) {
  115. dimensions[ua] = v;
  116. }
  117. }
  118. this.analytics.pageview('/command/' + paths.join('/'), { dimensions, metrics });
  119. }
  120. async validateAndRun(options) {
  121. if (!(options.help === true || options.help === 'json' || options.help === 'JSON')) {
  122. await this.validateScope();
  123. }
  124. await this.initialize(options);
  125. if (options.help === true) {
  126. return this.printHelp(options);
  127. }
  128. else if (options.help === 'json' || options.help === 'JSON') {
  129. return this.printJsonHelp(options);
  130. }
  131. else {
  132. const startTime = +new Date();
  133. await this.reportAnalytics([this.description.name], options);
  134. const result = await this.run(options);
  135. const endTime = +new Date();
  136. this.analytics.timing(this.description.name, 'duration', endTime - startTime);
  137. return result;
  138. }
  139. }
  140. }
  141. exports.Command = Command;