diff --git a/packages/nx/src/command-line/init/implementation/add-nx-to-monorepo.ts b/packages/nx/src/command-line/init/implementation/add-nx-to-monorepo.ts index 40d22d184fa3e..2ec476dac5af5 100644 --- a/packages/nx/src/command-line/init/implementation/add-nx-to-monorepo.ts +++ b/packages/nx/src/command-line/init/implementation/add-nx-to-monorepo.ts @@ -38,27 +38,35 @@ export async function addNxToMonorepo(options: Options) { }); targetDefaults = ( - (await prompt([ + await prompt<{ targetDefaults: string[] }>([ { type: 'multiselect', name: 'targetDefaults', message: 'Which scripts need to be run in order? (e.g. before building a project, dependent projects must be built)', choices: scripts, - }, - ])) as any + /** + * limit is missing from the interface but it limits the amount of options shown + */ + limit: process.stdout.rows - 4, // 4 leaves room for the header above, the prompt and some whitespace + } as any, + ]) ).targetDefaults; cacheableOperations = ( - (await prompt([ + await prompt<{ cacheableOperations: string[] }>([ { type: 'multiselect', name: 'cacheableOperations', message: 'Which scripts are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not)', choices: scripts, - }, - ])) as any + /** + * limit is missing from the interface but it limits the amount of options shown + */ + limit: process.stdout.rows - 4, // 4 leaves room for the header above, the prompt and some whitespace + } as any, + ]) ).cacheableOperations; for (const scriptName of cacheableOperations) { diff --git a/packages/nx/src/command-line/init/implementation/add-nx-to-nest.ts b/packages/nx/src/command-line/init/implementation/add-nx-to-nest.ts index 5ebfcf374e7bf..d94ec2c978e28 100644 --- a/packages/nx/src/command-line/init/implementation/add-nx-to-nest.ts +++ b/packages/nx/src/command-line/init/implementation/add-nx-to-nest.ts @@ -74,15 +74,19 @@ export async function addNxToNest(options: Options, packageJson: PackageJson) { '🧑‍🔧 Please answer the following questions about the scripts found in your package.json in order to generate task runner configuration', }); cacheableOperations = ( - (await enquirer.prompt([ + await enquirer.prompt<{ cacheableOperations: string[] }>([ { type: 'multiselect', name: 'cacheableOperations', message: 'Which of the following scripts are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not)', choices: scripts, - }, - ])) as any + /** + * limit is missing from the interface but it limits the amount of options shown + */ + limit: process.stdout.rows - 4, // 4 leaves room for the header above, the prompt and some whitespace + } as any, + ]) ).cacheableOperations; for (const scriptName of cacheableOperations) { diff --git a/packages/nx/src/command-line/init/implementation/add-nx-to-npm-repo.ts b/packages/nx/src/command-line/init/implementation/add-nx-to-npm-repo.ts index 6ca9fa8af16b4..ebfa87521a906 100644 --- a/packages/nx/src/command-line/init/implementation/add-nx-to-npm-repo.ts +++ b/packages/nx/src/command-line/init/implementation/add-nx-to-npm-repo.ts @@ -40,15 +40,19 @@ export async function addNxToNpmRepo(options: Options) { }); cacheableOperations = ( - (await enquirer.prompt([ + await enquirer.prompt<{ cacheableOperations: string[] }>([ { type: 'multiselect', name: 'cacheableOperations', message: 'Which of the following scripts are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not). You can use spacebar to select one or more scripts.', choices: scripts, - }, - ])) as any + /** + * limit is missing from the interface but it limits the amount of options shown + */ + limit: process.stdout.rows - 4, // 4 leaves room for the header above, the prompt and some whitespace + } as any, + ]) ).cacheableOperations; for (const scriptName of cacheableOperations) { diff --git a/packages/nx/src/command-line/init/implementation/angular/index.ts b/packages/nx/src/command-line/init/implementation/angular/index.ts index b65a469b92bd9..2ac238d5ecc54 100644 --- a/packages/nx/src/command-line/init/implementation/angular/index.ts +++ b/packages/nx/src/command-line/init/implementation/angular/index.ts @@ -90,7 +90,11 @@ async function collectCacheableOperations(options: Options): Promise { 'Which of the following targets are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not)', // enquirer mutates the array below, create a new one to avoid it choices: [...workspaceTargets], - }, + /** + * limit is missing from the interface but it limits the amount of options shown + */ + limit: process.stdout.rows - 4, // 4 leaves room for the header above, the prompt and some whitespace + } as any, ])) as any ).cacheableOperations; } else { diff --git a/packages/nx/src/command-line/init/init-v2.ts b/packages/nx/src/command-line/init/init-v2.ts index e2d0e31900cf5..f7cf3ec2a36d4 100644 --- a/packages/nx/src/command-line/init/init-v2.ts +++ b/packages/nx/src/command-line/init/init-v2.ts @@ -220,7 +220,11 @@ async function detectPlugins(): Promise<{ type: 'multiselect', message: `Which plugins would you like to add? Press to select and to submit.`, choices: plugins.map((p) => ({ name: p, value: p })), - }, + /** + * limit is missing from the interface but it limits the amount of options shown + */ + limit: process.stdout.rows - 4, // 4 leaves room for the header above, the prompt and some whitespace + } as any, ]).then((r) => r.plugins); if (pluginsToInstall?.length === 0) diff --git a/packages/nx/src/utils/params.spec.ts b/packages/nx/src/utils/params.spec.ts index b76e38862f32e..3187073ade5c3 100644 --- a/packages/nx/src/utils/params.spec.ts +++ b/packages/nx/src/utils/params.spec.ts @@ -1870,22 +1870,16 @@ describe('params', () => { } ); - expect(prompts).toMatchInlineSnapshot(` - [ - { - "choices": [ - "cat", - "dog", - "fish", - ], - "limit": 10, - "message": "What kind of pets do you have?", - "name": "pets", - "type": "multiselect", - "validate": [Function], - }, - ] - `); + expect(prompts).toEqual([ + { + message: 'What kind of pets do you have?', + name: 'pets', + type: 'multiselect', + choices: ['cat', 'dog', 'fish'], + limit: expect.any(Number), + validate: expect.any(Function), + }, + ]); }); describe('Project prompts', () => { diff --git a/packages/nx/src/utils/params.ts b/packages/nx/src/utils/params.ts index 91317b300755d..daa0237c9b0ac 100644 --- a/packages/nx/src/utils/params.ts +++ b/packages/nx/src/utils/params.ts @@ -1,15 +1,13 @@ import { logger } from './logger'; import type { NxJsonConfiguration } from '../config/nx-json'; import type { - TargetConfiguration, ProjectsConfigurations, + TargetConfiguration, } from '../config/workspace-json-project-json'; import { output } from './output'; import type { ProjectGraphError } from '../project-graph/error-types'; import { daemonClient } from '../daemon/client/client'; -const LIST_CHOICE_DISPLAY_LIMIT = 10; - type PropertyDescription = { type?: string | string[]; required?: string[]; @@ -892,10 +890,14 @@ export function getPromptsForSchema( } }; + // Limit the number of choices displayed so that the prompt fits on the screen + const limitForChoicesDisplayed = + process.stdout.rows - question.message.split('\n').length; + if (v.type === 'string' && v.enum && Array.isArray(v.enum)) { question.type = 'autocomplete'; question.choices = [...v.enum]; - question.limit = LIST_CHOICE_DISPLAY_LIMIT; + question.limit = limitForChoicesDisplayed; } else if ( v.type === 'string' && (v.$default?.$source === 'projectName' || @@ -906,7 +908,7 @@ export function getPromptsForSchema( ) { question.type = 'autocomplete'; question.choices = Object.keys(projectsConfigurations.projects); - question.limit = LIST_CHOICE_DISPLAY_LIMIT; + question.limit = limitForChoicesDisplayed; } else if (v.type === 'number' || v['x-prompt'].type == 'number') { question.type = 'numeral'; } else if ( @@ -931,7 +933,7 @@ export function getPromptsForSchema( }; } }); - question.limit = LIST_CHOICE_DISPLAY_LIMIT; + question.limit = limitForChoicesDisplayed; } else if (v.type === 'boolean') { question.type = 'confirm'; } else {