UNPKG

@angular/cli

Version:
189 lines (188 loc) • 9.3 kB
"use strict"; /** * @license * Copyright Google LLC 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.dev/license */ Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@angular-devkit/core"); const command_module_1 = require("../../command-builder/command-module"); const schematics_command_module_1 = require("../../command-builder/schematics-command-module"); const command_1 = require("../../command-builder/utilities/command"); const command_config_1 = require("../command-config"); class GenerateCommandModule extends schematics_command_module_1.SchematicsCommandModule { command = 'generate'; aliases = command_config_1.RootCommands['generate'].aliases; describe = 'Generates and/or modifies files based on a schematic.'; longDescriptionPath; async builder(argv) { let localYargs = (await super.builder(argv)).command({ command: '$0 <schematic>', describe: 'Run the provided schematic.', builder: (localYargs) => localYargs .positional('schematic', { describe: 'The [collection:schematic] to run.', type: 'string', demandOption: true, }) .strict(), handler: (options) => this.handler(options), }); for (const [schematicName, collectionName] of await this.getSchematicsToRegister()) { const workflow = this.getOrCreateWorkflowForBuilder(collectionName); const collection = workflow.engine.createCollection(collectionName); const { description: { schemaJson, aliases: schematicAliases, hidden: schematicHidden, description: schematicDescription, }, } = collection.createSchematic(schematicName, true); if (!schemaJson) { continue; } const { 'x-deprecated': xDeprecated, description = schematicDescription, hidden = schematicHidden, } = schemaJson; const options = await this.getSchematicOptions(collection, schematicName, workflow); localYargs = localYargs.command({ command: await this.generateCommandString(collectionName, schematicName, options), // When 'describe' is set to false, it results in a hidden command. describe: hidden === true ? false : typeof description === 'string' ? description : '', deprecated: xDeprecated === true || typeof xDeprecated === 'string' ? xDeprecated : false, aliases: Array.isArray(schematicAliases) ? await this.generateCommandAliasesStrings(collectionName, schematicAliases) : undefined, builder: (localYargs) => this.addSchemaOptionsToCommand(localYargs, options).strict(), handler: (options) => this.handler({ ...options, schematic: `${collectionName}:${schematicName}`, }), }); } return localYargs.demandCommand(1, command_1.demandCommandFailureMessage); } async run(options) { const { dryRun, schematic, defaults, force, interactive, ...schematicOptions } = options; const [collectionName, schematicName] = this.parseSchematicInfo(schematic); if (!collectionName || !schematicName) { throw new command_module_1.CommandModuleError('A collection and schematic is required during execution.'); } return this.runSchematic({ collectionName, schematicName, schematicOptions, executionOptions: { dryRun, defaults, force, interactive, }, }); } async getCollectionNames() { const [collectionName] = this.parseSchematicInfo( // positional = [generate, component] or [generate] this.context.args.positional[1]); return collectionName ? [collectionName] : [...(await this.getSchematicCollections())]; } async shouldAddCollectionNameAsPartOfCommand() { const [collectionNameFromArgs] = this.parseSchematicInfo( // positional = [generate, component] or [generate] this.context.args.positional[1]); const schematicCollectionsFromConfig = await this.getSchematicCollections(); const collectionNames = await this.getCollectionNames(); // Only add the collection name as part of the command when it's not a known // schematics collection or when it has been provided via the CLI. // Ex:`ng generate @schematics/angular:c` return (!!collectionNameFromArgs || !collectionNames.some((c) => schematicCollectionsFromConfig.has(c))); } /** * Generate an aliases string array to be passed to the command builder. * * @example `[component]` or `[@schematics/angular:component]`. */ async generateCommandAliasesStrings(collectionName, schematicAliases) { // Only add the collection name as part of the command when it's not a known // schematics collection or when it has been provided via the CLI. // Ex:`ng generate @schematics/angular:c` return (await this.shouldAddCollectionNameAsPartOfCommand()) ? schematicAliases.map((alias) => `${collectionName}:${alias}`) : schematicAliases; } /** * Generate a command string to be passed to the command builder. * * @example `component [name]` or `@schematics/angular:component [name]`. */ async generateCommandString(collectionName, schematicName, options) { const dasherizedSchematicName = core_1.strings.dasherize(schematicName); // Only add the collection name as part of the command when it's not a known // schematics collection or when it has been provided via the CLI. // Ex:`ng generate @schematics/angular:component` const commandName = (await this.shouldAddCollectionNameAsPartOfCommand()) ? collectionName + ':' + dasherizedSchematicName : dasherizedSchematicName; const positionalArgs = options .filter((o) => o.positional !== undefined) .map((o) => { const label = `${core_1.strings.dasherize(o.name)}${o.type === 'array' ? ' ..' : ''}`; return o.required ? `<${label}>` : `[${label}]`; }) .join(' '); return `${commandName}${positionalArgs ? ' ' + positionalArgs : ''}`; } /** * Get schematics that can to be registered as subcommands. */ async *getSchematics() { const seenNames = new Set(); for (const collectionName of await this.getCollectionNames()) { const workflow = this.getOrCreateWorkflowForBuilder(collectionName); const collection = workflow.engine.createCollection(collectionName); for (const schematicName of collection.listSchematicNames(true /** includeHidden */)) { // If a schematic with this same name is already registered skip. if (!seenNames.has(schematicName)) { seenNames.add(schematicName); yield { schematicName, collectionName, schematicAliases: this.listSchematicAliases(collection, schematicName), }; } } } } listSchematicAliases(collection, schematicName) { const description = collection.description.schematics[schematicName]; if (description) { return description.aliases && new Set(description.aliases); } // Extended collections if (collection.baseDescriptions) { for (const base of collection.baseDescriptions) { const description = base.schematics[schematicName]; if (description) { return description.aliases && new Set(description.aliases); } } } return undefined; } /** * Get schematics that should to be registered as subcommands. * * @returns a sorted list of schematic that needs to be registered as subcommands. */ async getSchematicsToRegister() { const schematicsToRegister = []; const [, schematicNameFromArgs] = this.parseSchematicInfo( // positional = [generate, component] or [generate] this.context.args.positional[1]); for await (const { schematicName, collectionName, schematicAliases } of this.getSchematics()) { if (schematicNameFromArgs && (schematicName === schematicNameFromArgs || schematicAliases?.has(schematicNameFromArgs))) { return [[schematicName, collectionName]]; } schematicsToRegister.push([schematicName, collectionName]); } // Didn't find the schematic or no schematic name was provided Ex: `ng generate --help`. return schematicsToRegister.sort(([nameA], [nameB]) => nameA.localeCompare(nameB, undefined, { sensitivity: 'accent' })); } } exports.default = GenerateCommandModule;