命令参数
本指南介绍在自定义命令中定义命令参数。你将了解以下主题:
- 定义位置参数
- 使参数变为可选
- 接受多个值
- 转换参数值
概述
参数是用户在执行命令时在命令名称之后提供的位置值。与可以按任意顺序指定的标志不同,参数必须严格按照它们在你的命令类中定义的顺序提供。
例如,在命令 node ace make:controller users --resource 中,单词 users 是一个参数,而 --resource 是一个标志。参数非常适合具有自然顺序的必需输入值,例如文件名、资源名称或实体标识符。
定义你的第一个参数
你将命令参数定义为带有 @args 装饰器的类属性。Ace 会按照与你的类中相同的顺序接受参数,因此属性的顺序很重要。
最常见的参数类型是字符串参数,它接受任何文本值。使用 @args.string 装饰器来定义字符串参数。
import { BaseCommand, args } from '@adonisjs/core/ace'
export default class GreetCommand extends BaseCommand {
static commandName = 'greet'
static description = 'Greet a user by name'
/**
* 定义一个必需的字符串参数
*/
@args.string()
declare name: string
async run() {
this.logger.info(`Hello, ${this.name}!`)
}
}
用户现在可以通过为 name 参数提供值来运行你的命令。
node ace greet John
# 输出:Hello, John!
如果用户忘记提供必需的参数,Ace 会显示一条错误消息,指出缺少哪个参数。
接受多个值
某些命令需要为单个参数接受多个值。例如,处理多个文件的命令可能接受任意数量的文件名。
使用 @args.spread 装饰器来接受多个值。spread 参数必须是你的命令中的最后一个参数,因为它会捕获所有剩余的值。
import { BaseCommand, args } from '@adonisjs/core/ace'
export default class GreetCommand extends BaseCommand {
static commandName = 'greet'
static description = 'Greet multiple users by name'
/**
* 将多个名称接受为数组
*/
@args.spread()
declare names: string[]
async run() {
this.names.forEach((name) => {
this.logger.info(`Hello, ${name}!`)
})
}
}
用户现在可以在运行命令时提供任意数量的值。
node ace greet John Jane Bob
# 输出:
# Hello, John!
# Hello, Jane!
# Hello, Bob!
自定义参数名称和描述
参数名称会出现在帮助界面和错误消息中。默认情况下,Ace 使用你的属性名的短横线形式(dashed-case)作为参数名称。例如,名为 userName 的属性在帮助输出中会变成 user-name。
你可以使用 argumentName 选项来自定义参数名称。
@args.string({
argumentName: 'user-name'
})
declare name: string
添加描述有助于用户理解他们应该提供什么值。描述会在用户运行 node ace greet --help 时出现在帮助界面中。
@args.string({
argumentName: 'user-name',
description: 'Name of the user to greet'
})
declare name: string
使参数变为可选
默认情况下,所有参数都是必需的,以确保用户在执行命令之前提供必要的输入。但是,你可以通过将 required 选项设为 false 来使参数变为可选。
可选参数必须位于所有必需参数之后。这个排序要求避免了参数解析中的歧义。
import { BaseCommand, args } from '@adonisjs/core/ace'
export default class GreetCommand extends BaseCommand {
static commandName = 'greet'
@args.string({
description: 'Name of the user to greet'
})
declare name: string
/**
* 带有自定义措辞的可选问候消息
*/
@args.string({
description: 'Custom greeting message',
required: false,
})
declare message?: string
async run() {
const greeting = this.message || 'Hello'
this.logger.info(`${greeting}, ${this.name}!`)
}
}
现在用户可以在有或没有第二个参数的情况下运行命令。
node ace greet John
# 输出:Hello, John!
node ace greet John "Good morning"
# 输出:Good morning, John!
提供默认值
你可以使用 default 属性为可选参数指定默认值。当用户不提供值时,Ace 会使用默认值代替。
@args.string({
description: 'Name of the user to greet',
required: false,
default: 'guest'
})
declare name: string
有了默认值,参数就变为可选的,但你的代码始终可以期望一个字符串值,而无需处理 undefined。
node ace greet
# 使用默认值 "guest"
# 输出:Hello, guest!
转换参数值
parse 方法允许你在将参数值赋给类属性之前对其进行转换或校验。这对于规范化输入、转换类型或执行校验很有用。
parse 方法接收来自命令行的原始字符串值,并且必须返回转换后的值。
@args.string({
argumentName: 'user-name',
description: 'Name of the user to greet',
parse(value) {
/**
* 将名称转换为大写
*/
return value ? value.toUpperCase() : value
}
})
declare name: string
现在,当用户提供名称时,它会在你的命令的 run 方法执行之前自动转换为大写。
node ace greet john
# 名称被转换为 "JOHN"
# 输出:Hello, JOHN!
你也可以使用 parse 方法进行校验,在值无效时抛出错误。
@args.string({
description: 'Email address of the user',
parse(value) {
if (!value.includes('@')) {
throw new Error('Please provide a valid email address')
}
return value.toLowerCase()
}
})
declare email: string
访问所有参数
你可以使用 this.parsed.args 属性访问用户提供的所有参数,包括它们的原始值。这对于调试,或当你需要检查完整的参数列表时很有用。
import { BaseCommand, args } from '@adonisjs/core/ace'
export default class GreetCommand extends BaseCommand {
static commandName = 'greet'
static description = 'Greet a user by name'
@args.string()
declare name: string
async run() {
/**
* 以键值对象形式访问所有参数
*/
console.log(this.parsed.args)
// 输出:{ name: 'John' }
this.logger.info(`Hello, ${this.name}!`)
}
}