| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- /**
- * @license
- * Copyright Google Inc. All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.io/license
- */
- const core_1 = require("@angular-devkit/core");
- const debug = require("debug");
- const fs_1 = require("fs");
- const path_1 = require("path");
- const json_schema_1 = require("../utilities/json-schema");
- const analytics_1 = require("./analytics");
- const command_1 = require("./command");
- const parser = require("./parser");
- const analyticsDebug = debug('ng:analytics:commands');
- // NOTE: Update commands.json if changing this. It's still deep imported in one CI validation
- const standardCommands = {
- 'add': '../commands/add.json',
- 'analytics': '../commands/analytics.json',
- 'build': '../commands/build.json',
- 'deploy': '../commands/deploy.json',
- 'config': '../commands/config.json',
- 'doc': '../commands/doc.json',
- 'e2e': '../commands/e2e.json',
- 'make-this-awesome': '../commands/easter-egg.json',
- 'generate': '../commands/generate.json',
- 'get': '../commands/deprecated.json',
- 'set': '../commands/deprecated.json',
- 'help': '../commands/help.json',
- 'lint': '../commands/lint.json',
- 'new': '../commands/new.json',
- 'run': '../commands/run.json',
- 'serve': '../commands/serve.json',
- 'test': '../commands/test.json',
- 'update': '../commands/update.json',
- 'version': '../commands/version.json',
- 'xi18n': '../commands/xi18n.json',
- };
- /**
- * Create the analytics instance.
- * @private
- */
- async function _createAnalytics() {
- const config = analytics_1.getGlobalAnalytics();
- const maybeSharedAnalytics = analytics_1.getSharedAnalytics();
- if (config && maybeSharedAnalytics) {
- return new core_1.analytics.MultiAnalytics([config, maybeSharedAnalytics]);
- }
- else if (config) {
- return config;
- }
- else if (maybeSharedAnalytics) {
- return maybeSharedAnalytics;
- }
- else {
- return new core_1.analytics.NoopAnalytics();
- }
- }
- async function loadCommandDescription(name, path, registry) {
- const schemaPath = path_1.resolve(__dirname, path);
- const schemaContent = fs_1.readFileSync(schemaPath, 'utf-8');
- const schema = core_1.json.parseJson(schemaContent, core_1.JsonParseMode.Loose, { path: schemaPath });
- if (!core_1.isJsonObject(schema)) {
- throw new Error('Invalid command JSON loaded from ' + JSON.stringify(schemaPath));
- }
- return json_schema_1.parseJsonSchemaToCommandDescription(name, schemaPath, registry, schema);
- }
- /**
- * Run a command.
- * @param args Raw unparsed arguments.
- * @param logger The logger to use.
- * @param workspace Workspace information.
- * @param commands The map of supported commands.
- * @param options Additional options.
- */
- async function runCommand(args, logger, workspace, commands = standardCommands, options = {}) {
- // This registry is exclusively used for flattening schemas, and not for validating.
- const registry = new core_1.schema.CoreSchemaRegistry([]);
- registry.registerUriHandler((uri) => {
- if (uri.startsWith('ng-cli://')) {
- const content = fs_1.readFileSync(path_1.join(__dirname, '..', uri.substr('ng-cli://'.length)), 'utf-8');
- return Promise.resolve(JSON.parse(content));
- }
- else {
- return null;
- }
- });
- let commandName = undefined;
- for (let i = 0; i < args.length; i++) {
- const arg = args[i];
- if (!arg.startsWith('-')) {
- commandName = arg;
- args.splice(i, 1);
- break;
- }
- }
- let description = null;
- // if no commands were found, use `help`.
- if (!commandName) {
- if (args.length === 1 && args[0] === '--version') {
- commandName = 'version';
- }
- else {
- commandName = 'help';
- }
- if (!(commandName in commands)) {
- logger.error(core_1.tags.stripIndent `
- The "${commandName}" command seems to be disabled.
- This is an issue with the CLI itself. If you see this comment, please report it and
- provide your repository.
- `);
- return 1;
- }
- }
- if (commandName in commands) {
- description = await loadCommandDescription(commandName, commands[commandName], registry);
- }
- else {
- const commandNames = Object.keys(commands);
- // Optimize loading for common aliases
- if (commandName.length === 1) {
- commandNames.sort((a, b) => {
- const aMatch = a[0] === commandName;
- const bMatch = b[0] === commandName;
- if (aMatch && !bMatch) {
- return -1;
- }
- else if (!aMatch && bMatch) {
- return 1;
- }
- else {
- return 0;
- }
- });
- }
- for (const name of commandNames) {
- const aliasDesc = await loadCommandDescription(name, commands[name], registry);
- const aliases = aliasDesc.aliases;
- if (aliases && aliases.some(alias => alias === commandName)) {
- commandName = name;
- description = aliasDesc;
- break;
- }
- }
- }
- if (!description) {
- const commandsDistance = {};
- const name = commandName;
- const allCommands = Object.keys(commands).sort((a, b) => {
- if (!(a in commandsDistance)) {
- commandsDistance[a] = core_1.strings.levenshtein(a, name);
- }
- if (!(b in commandsDistance)) {
- commandsDistance[b] = core_1.strings.levenshtein(b, name);
- }
- return commandsDistance[a] - commandsDistance[b];
- });
- logger.error(core_1.tags.stripIndent `
- The specified command ("${commandName}") is invalid. For a list of available options,
- run "ng help".
- Did you mean "${allCommands[0]}"?
- `);
- return 1;
- }
- try {
- const parsedOptions = parser.parseArguments(args, description.options, logger);
- command_1.Command.setCommandMap(async () => {
- const map = {};
- for (const [name, path] of Object.entries(commands)) {
- map[name] = await loadCommandDescription(name, path, registry);
- }
- return map;
- });
- const analytics = options.analytics || await _createAnalytics();
- const context = { workspace, analytics };
- const command = new description.impl(context, description, logger);
- // Flush on an interval (if the event loop is waiting).
- let analyticsFlushPromise = Promise.resolve();
- setInterval(() => {
- analyticsFlushPromise = analyticsFlushPromise.then(() => analytics.flush());
- }, 1000);
- const result = await command.validateAndRun(parsedOptions);
- // Flush one last time.
- await analyticsFlushPromise.then(() => analytics.flush());
- return result;
- }
- catch (e) {
- if (e instanceof parser.ParseArgumentException) {
- logger.fatal('Cannot parse arguments. See below for the reasons.');
- logger.fatal(' ' + e.comments.join('\n '));
- return 1;
- }
- else {
- throw e;
- }
- }
- }
- exports.runCommand = runCommand;
|