Prompts
本指南介绍如何在自定义命令中使用提示。你将学习以下内容:
- 显示文本与密码输入提示
- 创建单选与多选列表
- 使用确认与切换提示
- 校验与转换用户输入
- 使用自动补全处理可搜索列表
- 对带有提示的命令进行测试
概述
提示通过直观的终端组件(而非命令行参数或标志)让用户输入信息,从而实现交互式命令行体验。对于需要引导用户完成多步骤流程、收集密码等敏感信息,或让用户从选项中进行选择的命令来说,这尤其有用。
Ace 提示由 @poppinss/prompts 包驱动,支持多种提示类型,包括文本输入、密码字段、确认、单选与多选列表,以及自动补全搜索。所有提示都支持校验、默认值,以及在将用户输入返回给你的命令之前对其进行转换。
Ace 提示的一个关键特性是它们的 测试支持 。在编写测试时,你可以拦截(trap)提示并以编程方式作出响应,从而无需手动输入即可轻松测试交互式命令。
显示文本输入
文本输入提示接受用户的自由格式文本。使用 this.prompt.ask 方法显示文本输入提示,第一个参数为提示信息。
import { BaseCommand } from '@adonisjs/core/ace'
export default class MakeModelCommand extends BaseCommand {
static commandName = 'make:model'
async run() {
/**
* 询问模型名称
*/
const modelName = await this.prompt.ask('Enter the model name')
this.logger.info(`Creating model: ${modelName}`)
}
}
添加校验
你可以在选项对象中提供 validate 函数来校验用户输入。该函数接收用户的输入,应返回 true 以接受该值,或返回错误消息字符串以拒绝该值。
const modelName = await this.prompt.ask('Enter the model name', {
validate(value) {
return value.length > 0
? true
: 'Model name is required'
}
})
如果校验失败,提示会显示错误消息并再次要求输入,直到用户提供有效的值为止。
提供默认值
默认值会作为建议显示,用户可以通过按 Enter 键接受。这对于提供常用值或合理的默认值很有帮助。
const modelName = await this.prompt.ask('Enter the model name', {
default: 'User'
})
收集密码
密码提示会屏蔽用户在终端中的输入,用星号或圆点替换每个字符。这对于收集密码、API 密钥或令牌等敏感信息至关重要。
使用 this.prompt.secure 方法显示密码提示。
import { BaseCommand } from '@adonisjs/core/ace'
export default class SetupCommand extends BaseCommand {
static commandName = 'setup'
async run() {
/**
* 安全地收集数据库密码
*/
const password = await this.prompt.secure('Enter database password')
this.logger.info('Password collected securely')
}
}
你可以像文本输入一样为密码提示添加校验。
const password = await this.prompt.secure('Enter account password', {
validate(value) {
return value.length >= 8
? true
: 'Password must be at least 8 characters long'
}
})
创建选择列表
选择提示会显示一组选项,用户可以使用方向键导航并使用 Enter 键选择。当你需要让用户从预定义选项中进行挑选时,这最为理想。
使用 this.prompt.choice 方法显示单选列表。该方法第一个参数为提示信息,第二个参数为选项数组。
import { BaseCommand } from '@adonisjs/core/ace'
export default class ConfigureCommand extends BaseCommand {
static commandName = 'configure'
async run() {
/**
* 让用户选择其包管理器
*/
const packageManager = await this.prompt.choice('Select package manager', [
'npm',
'yarn',
'pnpm'
])
this.logger.info(`Using ${packageManager}`)
}
}
自定义选择显示
当你希望显示的文本与返回的值不同时,可以将选项定义为带有 name 和 message 属性的对象。name 是你的命令接收到的值,而 message 是用户看到的内容。
const driver = await this.prompt.choice('Select database driver', [
{
name: 'sqlite',
message: 'SQLite'
},
{
name: 'mysql',
message: 'MySQL'
},
{
name: 'pg',
message: 'PostgreSQL'
}
])
this.logger.info(`Selected driver: ${driver}`)
// 如果用户选择了 "PostgreSQL",driver 的值将为 "pg"
允许多选
多选提示让用户使用空格键来切换选择,从而从列表中选择多个选项。当用户需要选择多个功能、包或配置时,这很有用。
使用 this.prompt.multiple 方法显示多选列表。其参数与选择提示相同。
import { BaseCommand } from '@adonisjs/core/ace'
export default class InstallCommand extends BaseCommand {
static commandName = 'install:packages'
async run() {
/**
* 让用户选择多个数据库驱动
*/
const drivers = await this.prompt.multiple('Select database drivers', [
{
name: 'sqlite',
message: 'SQLite'
},
{
name: 'mysql',
message: 'MySQL'
},
{
name: 'pg',
message: 'PostgreSQL'
}
])
this.logger.info(`Installing drivers: ${drivers.join(', ')}`)
}
}
该方法返回所选值的数组。用户可以选择全部、部分或不选任何选项。
确认操作
确认提示会让用户回答是或否的问题。它们对于破坏性操作或需要用户明确同意的操作来说至关重要。
使用 this.prompt.confirm 方法显示是/否确认。该方法返回一个布尔值。
import { BaseCommand } from '@adonisjs/core/ace'
export default class ResetCommand extends BaseCommand {
static commandName = 'db:reset'
async run() {
/**
* 在删除数据之前进行确认
*/
const shouldDelete = await this.prompt.confirm(
'Want to delete all files?'
)
if (shouldDelete) {
this.logger.warning('Deleting all files...')
// 执行删除操作
} else {
this.logger.info('Operation cancelled')
}
}
}
自定义是/否标签
如果你想把是/否标签自定义为更具语境化的内容,可以使用 this.prompt.toggle 方法。该方法接受一个包含「是」和「否」两个字符串的数组。
const shouldDelete = await this.prompt.toggle(
'Want to delete all files?',
['Yup', 'Nope']
)
if (shouldDelete) {
this.logger.warning('Deleting all files...')
}
使用自动补全
自动补全提示将选择与搜索功能结合起来,让用户可以模糊搜索大型选项列表。当你面对大量在标准选择列表中显得笨重的选项时,这尤其有用。
使用 this.prompt.autocomplete 方法显示可搜索列表。
import { BaseCommand } from '@adonisjs/core/ace'
export default class SelectCityCommand extends BaseCommand {
static commandName = 'select:city'
async run() {
/**
* 让用户搜索并从大型列表中选择
*/
const selectedCity = await this.prompt.autocomplete(
'Select your city',
await this.getCitiesList()
)
this.logger.info(`You selected: ${selectedCity}`)
}
private async getCitiesList() {
/**
* 返回包含大量城市名称的数组
*/
return [
'New York',
'Los Angeles',
'Chicago',
'Houston',
// ... 还有数百个城市
]
}
}
用户可以输入以筛选列表,提示会基于模糊搜索显示匹配的选项。
了解提示选项
所有提示类型都通过第二个参数接受一组通用选项。这些选项让你可以自定义提示行为、校验输入并转换返回值。
| 选项 | 适用提示 | 说明 |
|---|---|---|
default | 所有提示 | 未输入任何值时使用的默认值。对于选择、多选和自动补全提示,该值必须是选项数组的索引。 |
name | 所有提示 | 提示的唯一名称,用于在测试中识别提示。 |
hint | 所有提示 | 显示在提示旁边的提示文本,为用户提供额外的上下文。 |
result | 所有提示 | 转换提示的返回值。输入值取决于提示类型(例如,多选返回所选选项的数组)。 |
format | 所有提示 | 在用户键入时实时格式化输入值。该格式化仅应用于 CLI 输出,而不应用于返回值。 |
validate | 所有提示 | 校验用户输入。返回 true 以接受该值,或返回字符串错误消息以拒绝该值。 |
limit | autocomplete | 限制显示的选项数量。用户需要滚动才能看到更多选项。 |
转换返回值
result 函数转换提示返回的值。这对于将用户输入转换为不同的格式或类型很有用。
const modelName = await this.prompt.ask('Enter the model name', {
result(value) {
/**
* 转换为 PascalCase 以用作类名
*/
return value.charAt(0).toUpperCase() + value.slice(1)
}
})
格式化显示值
format 函数会改变输入在终端中随用户键入而显示的方式,但不影响实际的返回值。
const email = await this.prompt.ask('Enter your email', {
format(value) {
/**
* 在用户键入时将邮箱显示为小写
*/
return value.toLowerCase()
}
})
添加提示
提示(hint)提供额外的上下文或说明,显示在提示旁边。
const tableName = await this.prompt.ask('Enter table name', {
hint: 'Use plural form (e.g., users, posts)'
})