名称:inquirer-prompt-generator 描述:使用Inquirer.js生成交互式命令行提示,支持验证、条件逻辑和自定义渲染器。为CLI应用程序创建用户友好的输入收集流程。 允许使用的工具:读取、写入、编辑、Bash、Glob、Grep
Inquirer 提示生成器
使用Inquirer.js生成交互式CLI提示,具备全面的验证、条件流程和自定义格式化功能。
能力
- 生成Inquirer.js提示定义
- 创建多步骤向导流程
- 实现输入验证
- 支持条件提示
- 为答案生成TypeScript接口
- 创建自定义提示格式化器
使用场景
在以下情况时调用此技能:
- 创建交互式CLI输入收集
- 构建配置向导
- 实现用户确认流程
- 生成类似表单的CLI界面
输入参数
| 参数 | 类型 | 是否必需 | 描述 |
|---|---|---|---|
| flowName | 字符串 | 是 | 提示流程的名称 |
| prompts | 数组 | 是 | 提示定义列表 |
| typescript | 布尔值 | 否 | 生成TypeScript类型(默认:true) |
| validation | 布尔值 | 否 | 包含验证助手(默认:true) |
提示定义结构
{
"prompts": [
{
"type": "input",
"name": "projectName",
"message": "您的项目名称是什么?",
"default": "my-project",
"validate": {
"required": true,
"pattern": "^[a-z][a-z0-9-]*$",
"message": "项目名称必须为小写字母,可包含连字符"
}
},
{
"type": "list",
"name": "template",
"message": "选择模板:",
"choices": [
{ "name": "React + TypeScript", "value": "react-ts" },
{ "name": "Vue + TypeScript", "value": "vue-ts" },
{ "name": "Node.js + Express", "value": "node-express" }
]
},
{
"type": "checkbox",
"name": "features",
"message": "选择要包含的功能:",
"choices": ["ESLint", "Prettier", "Husky", "Jest", "Docker"],
"when": "answers.template !== 'node-express'"
},
{
"type": "confirm",
"name": "installDeps",
"message": "现在安装依赖项吗?",
"default": true
}
]
}
输出结构
prompts/
├── <flowName>/
│ ├── index.ts # 主提示流程
│ ├── types.ts # TypeScript接口
│ ├── validators.ts # 验证函数
│ ├── formatters.ts # 自定义格式化器
│ └── README.md # 使用文档
生成的代码模式
提示流程 (index.ts)
import { input, select, checkbox, confirm } from '@inquirer/prompts';
import { validateProjectName, validatePort } from './validators';
import type { ProjectConfig } from './types';
export async function createProjectPrompt(): Promise<ProjectConfig> {
// 项目名称
const projectName = await input({
message: '您的项目名称是什么?',
default: 'my-project',
validate: validateProjectName,
});
// 模板选择
const template = await select({
message: '选择模板:',
choices: [
{ name: 'React + TypeScript', value: 'react-ts' },
{ name: 'Vue + TypeScript', value: 'vue-ts' },
{ name: 'Node.js + Express', value: 'node-express' },
],
});
// 条件功能(node-express不显示)
let features: string[] = [];
if (template !== 'node-express') {
features = await checkbox({
message: '选择要包含的功能:',
choices: [
{ name: 'ESLint', value: 'eslint', checked: true },
{ name: 'Prettier', value: 'prettier', checked: true },
{ name: 'Husky', value: 'husky' },
{ name: 'Jest', value: 'jest' },
{ name: 'Docker', value: 'docker' },
],
});
}
// 确认
const installDeps = await confirm({
message: '现在安装依赖项吗?',
default: true,
});
return {
projectName,
template,
features,
installDeps,
};
}
TypeScript类型 (types.ts)
/**
* 从创建项目提示中收集的配置
*/
export interface ProjectConfig {
/** 项目名称(小写,允许连字符) */
projectName: string;
/** 选定的项目模板 */
template: 'react-ts' | 'vue-ts' | 'node-express';
/** 选定的可选功能 */
features: Array<'eslint' | 'prettier' | 'husky' | 'jest' | 'docker'>;
/** 是否安装依赖项 */
installDeps: boolean;
}
/**
* 用于显示的模板元数据
*/
export interface TemplateChoice {
name: string;
value: ProjectConfig['template'];
description?: string;
}
验证器 (validators.ts)
/**
* 验证项目名称格式
* - 必须以小写字母开头
* - 仅允许小写字母、数字和连字符
* - 最多50个字符
*/
export function validateProjectName(value: string): string | true {
if (!value.trim()) {
return '项目名称为必填项';
}
if (!/^[a-z][a-z0-9-]*$/.test(value)) {
return '项目名称必须以字母开头,且仅包含小写字母、数字和连字符';
}
if (value.length > 50) {
return '项目名称必须为50个字符或更少';
}
return true;
}
/**
* 验证端口号
*/
export function validatePort(value: string): string | true {
const port = parseInt(value, 10);
if (isNaN(port)) {
return '端口必须是数字';
}
if (port < 1024 || port > 65535) {
return '端口必须在1024到65535之间';
}
return true;
}
/**
* 验证URL格式
*/
export function validateUrl(value: string): string | true {
try {
new URL(value);
return true;
} catch {
return '请输入有效的URL';
}
}
/**
* 创建检查冲突的异步验证器
*/
export function createConflictValidator(
checkFn: (value: string) => Promise<boolean>
): (value: string) => Promise<string | true> {
return async (value: string) => {
const exists = await checkFn(value);
if (exists) {
return `"${value}" 已存在`;
}
return true;
};
}
自定义格式化器 (formatters.ts)
import chalk from 'chalk';
/**
* 格式化项目名称以进行显示
*/
export function formatProjectName(value: string): string {
return chalk.cyan(value);
}
/**
* 格式化功能列表以进行摘要显示
*/
export function formatFeatures(features: string[]): string {
if (features.length === 0) {
return chalk.dim('未选择任何功能');
}
return features.map(f => chalk.green(`+ ${f}`)).join('
');
}
/**
* 格式化配置摘要
*/
export function formatSummary(config: ProjectConfig): string {
return `
${chalk.bold('项目配置:')}
${chalk.dim('名称:')} ${formatProjectName(config.projectName)}
${chalk.dim('模板:')} ${config.template}
${chalk.dim('功能:')}
${formatFeatures(config.features).split('
').map(l => ' ' + l).join('
')}
${chalk.dim('安装:')} ${config.installDeps ? chalk.green('是') : chalk.yellow('否')}
`;
}
提示类型
| 类型 | 描述 | 使用场景 |
|---|---|---|
| input | 单行文本 | 名称、值 |
| password | 隐藏输入 | 密钥、令牌 |
| number | 数字输入 | 端口、计数 |
| confirm | 是/否 | 确认 |
| select | 单选列表 | 选项 |
| checkbox | 多选 | 功能 |
| expand | 缩写选项 | 快速操作 |
| editor | 多行编辑器 | 长文本 |
| search | 可搜索列表 | 大型列表 |
| rawlist | 编号列表 | 索引选项 |
验证模式
必填字段
validate: (value) => value.trim() ? true : '此字段为必填项'
模式匹配
validate: (value) => /^[a-z-]+$/.test(value) || '格式无效'
异步验证
validate: async (value) => {
const exists = await checkExists(value);
return exists ? '已存在' : true;
}
依赖验证
validate: (value, answers) => {
if (answers.type === 'advanced' && !value) {
return '高级模式下为必填项';
}
return true;
}
条件提示
When函数
{
type: 'input',
name: 'apiKey',
message: '输入API密钥:',
when: (answers) => answers.useExternalApi
}
跳过逻辑
const prompts = basePrompts.filter(p => {
if (p.name === 'advanced' && !options.showAdvanced) {
return false;
}
return true;
});
工作流程
- 解析提示定义 - 验证结构
- 生成提示流程 - 创建主提示文件
- 生成类型 - TypeScript接口
- 生成验证器 - 验证函数
- 生成格式化器 - 显示助手
- 创建文档 - 使用指南
应用的最佳实践
- 现代@inquirer/prompts API
- 可重用的验证函数
- 类型安全的答案接口
- 条件流程支持
- 自定义格式化器用于输出
- 清晰的错误消息
参考资料
- Inquirer.js: https://github.com/SBoudrias/Inquirer.js
- @inquirer/prompts: https://www.npmjs.com/package/@inquirer/prompts
- Chalk: https://github.com/chalk/chalk
目标流程
- 交互式提示系统
- 交互式表单实现
- CLI应用程序引导