UNPKG

nx

Version:

The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.

265 lines (264 loc) • 12.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.printChanges = printChanges; exports.parseGeneratorString = parseGeneratorString; exports.printGenHelp = printGenHelp; exports.generate = generate; const chalk = require("chalk"); const enquirer_1 = require("enquirer"); const path_1 = require("path"); const configuration_1 = require("../../config/configuration"); const tree_1 = require("../../generators/tree"); const project_graph_1 = require("../../project-graph/project-graph"); const logger_1 = require("../../utils/logger"); const params_1 = require("../../utils/params"); const handle_errors_1 = require("../../utils/handle-errors"); const local_plugins_1 = require("../../utils/plugins/local-plugins"); const print_help_1 = require("../../utils/print-help"); const workspace_root_1 = require("../../utils/workspace-root"); const calculate_default_project_name_1 = require("../../config/calculate-default-project-name"); const installed_plugins_1 = require("../../utils/plugins/installed-plugins"); const generator_utils_1 = require("./generator-utils"); const path_2 = require("../../utils/path"); function printChanges(fileChanges) { fileChanges.forEach((f) => { if (f.type === 'CREATE') { console.log(`${chalk.green('CREATE')} ${f.path}`); } else if (f.type === 'UPDATE') { console.log(`${chalk.white('UPDATE')} ${f.path}`); } else if (f.type === 'DELETE') { console.log(`${chalk.yellow('DELETE')} ${f.path}`); } }); } async function promptForCollection(generatorName, interactive, projectsConfiguration) { const localPlugins = await (0, local_plugins_1.getLocalWorkspacePlugins)(projectsConfiguration, (0, configuration_1.readNxJson)()); const installedCollections = Array.from(new Set((0, installed_plugins_1.findInstalledPlugins)().map((x) => x.name))); const choicesMap = new Set(); const deprecatedChoices = new Set(); for (const collectionName of installedCollections) { try { const { resolvedCollectionName, normalizedGeneratorName, generatorConfiguration: { ['x-deprecated']: deprecated, hidden }, } = (0, generator_utils_1.getGeneratorInformation)(collectionName, generatorName, workspace_root_1.workspaceRoot, projectsConfiguration.projects); if (hidden) { continue; } if (deprecated) { deprecatedChoices.add(`${resolvedCollectionName}:${normalizedGeneratorName}`); } else { choicesMap.add(`${resolvedCollectionName}:${normalizedGeneratorName}`); } } catch { } } const choicesFromLocalPlugins = []; for (const [name] of localPlugins) { try { const { resolvedCollectionName, normalizedGeneratorName, generatorConfiguration: { ['x-deprecated']: deprecated, hidden }, } = (0, generator_utils_1.getGeneratorInformation)(name, generatorName, workspace_root_1.workspaceRoot, projectsConfiguration.projects); if (hidden) { continue; } const value = `${resolvedCollectionName}:${normalizedGeneratorName}`; if (!choicesMap.has(value)) { if (deprecated) { deprecatedChoices.add(value); } else { choicesFromLocalPlugins.push({ name: value, message: chalk.bold(value), value, }); } } } catch { } } if (choicesFromLocalPlugins.length) { choicesFromLocalPlugins[choicesFromLocalPlugins.length - 1].message += '\n'; } const choices = choicesFromLocalPlugins.concat(...choicesMap); if (choices.length === 1) { return typeof choices[0] === 'string' ? choices[0] : choices[0].value; } else if (!interactive && choices.length > 1) { throwInvalidInvocation(Array.from(choicesMap)); } else if (interactive && choices.length > 1) { const noneOfTheAbove = `\nNone of the above`; choices.push(noneOfTheAbove); let { generator, customCollection } = await (0, enquirer_1.prompt)([ { name: 'generator', message: `Which generator would you like to use?`, type: 'autocomplete', // enquirer's typings are incorrect here... It supports (string | Choice)[], but is typed as (string[] | Choice[]) choices: choices, }, { name: 'customCollection', type: 'input', message: `Which collection would you like to use?`, skip: function () { // Skip this question if the user did not answer None of the above return this.state.answers.generator !== noneOfTheAbove; }, validate: function (value) { if (this.skipped) { return true; } try { (0, generator_utils_1.getGeneratorInformation)(value, generatorName, workspace_root_1.workspaceRoot, projectsConfiguration.projects); return true; } catch { logger_1.logger.error(`\nCould not find ${value}:${generatorName}`); return false; } }, }, ]); return customCollection ? `${customCollection}:${generatorName}` : generator; } else if (deprecatedChoices.size > 0) { throw new Error([ `All installed generators named "${generatorName}" are deprecated. To run one, provide its full \`collection:generator\` id.`, [...deprecatedChoices].map((x) => ` - ${x}`), ].join('\n')); } else { throw new Error(`Could not find any generators named "${generatorName}"`); } } function parseGeneratorString(value) { const separatorIndex = value.lastIndexOf(':'); if (separatorIndex > 0) { return { collection: value.slice(0, separatorIndex), generator: value.slice(separatorIndex + 1), }; } else { return { generator: value, }; } } async function convertToGenerateOptions(generatorOptions, mode, projectsConfiguration) { let collectionName = null; let generatorName = null; const interactive = generatorOptions.interactive; if (mode === 'generate') { const generatorDescriptor = generatorOptions['generator']; const { collection, generator } = parseGeneratorString(generatorDescriptor); if (collection) { collectionName = collection; generatorName = generator; } else { const generatorString = await promptForCollection(generatorDescriptor, interactive, projectsConfiguration); const parsedGeneratorString = parseGeneratorString(generatorString); collectionName = parsedGeneratorString.collection; generatorName = parsedGeneratorString.generator; } } else { collectionName = generatorOptions.collection; generatorName = 'new'; } const res = { collectionName, generatorName, generatorOptions, help: generatorOptions.help, dryRun: generatorOptions.dryRun, interactive, defaults: generatorOptions.defaults, quiet: generatorOptions.quiet, }; delete generatorOptions.d; delete generatorOptions.dryRun; delete generatorOptions['dry-run']; delete generatorOptions.interactive; delete generatorOptions.help; delete generatorOptions.collection; delete generatorOptions.verbose; delete generatorOptions.generator; delete generatorOptions['--']; delete generatorOptions['$0']; delete generatorOptions.quiet; return res; } function throwInvalidInvocation(availableGenerators) { throw new Error(`Specify the generator name (e.g., nx generate ${availableGenerators.join(', ')})`); } function printGenHelp(opts, schema, normalizedGeneratorName, aliases) { (0, print_help_1.printHelp)(`generate ${opts.collectionName}:${normalizedGeneratorName}`, { ...schema, properties: schema.properties, }, { mode: 'generate', plugin: opts.collectionName, entity: normalizedGeneratorName, aliases, }); } async function generate(args) { return (0, handle_errors_1.handleErrors)(args.verbose, async () => { const nxJsonConfiguration = (0, configuration_1.readNxJson)(); const projectGraph = await (0, project_graph_1.createProjectGraphAsync)(); const projectsConfigurations = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph); const opts = await convertToGenerateOptions(args, 'generate', projectsConfigurations); const { normalizedGeneratorName, schema, implementationFactory, generatorConfiguration: { aliases, hidden, ['x-deprecated']: deprecated, ['x-use-standalone-layout']: isStandalonePreset, }, } = (0, generator_utils_1.getGeneratorInformation)(opts.collectionName, opts.generatorName, workspace_root_1.workspaceRoot, projectsConfigurations.projects); if (deprecated) { logger_1.logger.warn([ `${logger_1.NX_PREFIX}: ${opts.collectionName}:${normalizedGeneratorName} is deprecated`, `${deprecated}`, ].join('\n')); } if (!opts.quiet && !opts.help) { logger_1.logger.info(`NX Generating ${opts.collectionName}:${normalizedGeneratorName}`); } if (opts.help) { printGenHelp(opts, schema, normalizedGeneratorName, aliases); return 0; } const cwd = (0, path_2.getCwd)(); const combinedOpts = await (0, params_1.combineOptionsForGenerator)(opts.generatorOptions, opts.collectionName, normalizedGeneratorName, projectsConfigurations, nxJsonConfiguration, schema, opts.interactive, (0, calculate_default_project_name_1.calculateDefaultProjectName)(cwd, workspace_root_1.workspaceRoot, projectsConfigurations, nxJsonConfiguration), (0, path_1.relative)(workspace_root_1.workspaceRoot, cwd), args.verbose); if ((0, generator_utils_1.getGeneratorInformation)(opts.collectionName, normalizedGeneratorName, workspace_root_1.workspaceRoot, projectsConfigurations.projects).isNxGenerator) { const host = new tree_1.FsTree(workspace_root_1.workspaceRoot, args.verbose, `generating (${opts.collectionName}:${normalizedGeneratorName})`); const implementation = implementationFactory(); // @todo(v17): Remove this, isStandalonePreset property is defunct. if (normalizedGeneratorName === 'preset' && !isStandalonePreset) { host.write('apps/.gitkeep', ''); host.write('libs/.gitkeep', ''); } const task = await implementation(host, combinedOpts); host.lock(); const changes = host.listChanges(); if (!opts.quiet) { printChanges(changes); } if (!opts.dryRun) { (0, tree_1.flushChanges)(workspace_root_1.workspaceRoot, changes); if (task) { await task(); } } else { logger_1.logger.warn(`\nNOTE: The "dryRun" flag means no changes were made.`); } } else { require('../../adapter/compat'); return (await Promise.resolve().then(() => require('../../adapter/ngcli-adapter'))).generate(workspace_root_1.workspaceRoot, { ...opts, generatorOptions: combinedOpts, }, projectsConfigurations.projects, args.verbose); } }); }