命令标志

本指南介绍在自定义命令中定义命令标志。你将了解以下主题:

  • 定义布尔、字符串、数字和数组标志
  • 自定义标志名称和描述
  • 为简写用法创建标志别名
  • 为标志设置默认值
  • 转换和校验标志值
  • 访问所有提供的标志

概述

标志提供了一种接受可选或具名参数的方式,而无需特定顺序。它们使用两个连字符(--)表示全名,或使用单个连字符(-)表示别名。

在下面的命令中,--resource--singular 都是标志。

node ace make:controller users --resource --singular

与位置参数不同,标志可以出现在命令中的任何位置,如果它们是可选的,还可以完全省略。这使得标志非常适合用于自定义命令行为的选项,例如启用功能、指定输出格式或提供配置值。

Ace 支持多种标志类型,包括用于开/关选项的布尔标志、用于文本值的字符串标志、用于数字输入的数字标志,以及用于多个值的数组标志。

定义布尔标志

布尔标志表示开/关或是/否选项。它们是最简单的标志类型,不需要值——只需提及该标志就会将其设置为 true

使用 @flags.boolean 装饰器定义布尔标志。

commands/make_controller.ts
import { BaseCommand, flags } from '@adonisjs/core/ace'

export default class MakeControllerCommand extends BaseCommand {
  static commandName = 'make:controller'

  /**
   * 启用资源型控制器生成
   */
  @flags.boolean()
  declare resource: boolean

  /**
   * 创建一个单一的资源型控制器
   */
  @flags.boolean()
  declare singular: boolean

  async run() {
    if (this.resource) {
      this.logger.info('Creating a resource controller')
    }
  }
}

当用户提及该标志时,其值变为 true。如果他们省略该标志,则其值为 undefined

node ace make:controller users --resource
# this.resource === true

node ace make:controller users
# this.resource === undefined

否定布尔标志

布尔标志支持使用 --no- 前缀进行否定,允许用户显式地将标志设置为 false。当某个标志的默认值为 true 且用户需要禁用它时,这会很有用。

node ace make:controller users --no-resource
# this.resource === false

默认情况下,否定变体不会显示在帮助界面中,以保持输出简洁。你可以使用 showNegatedVariantInHelp 选项显示它。

commands/make_controller.ts
@flags.boolean({
  showNegatedVariantInHelp: true,
})
declare resource: boolean

定义字符串标志

字符串标志接受用户在标志名称之后提供的文本值。使用 @flags.string 装饰器定义字符串标志。

commands/make_controller.ts
import { BaseCommand, flags } from '@adonisjs/core/ace'

export default class MakeControllerCommand extends BaseCommand {
  static commandName = 'make:controller'

  /**
   * 要与控制器关联的模型名称
   */
  @flags.string()
  declare model: string

  async run() {
    if (this.model) {
      this.logger.info(`Creating controller for ${this.model} model`)
    }
  }
}

用户在标志名称之后提供值,用空格或等号分隔。

node ace make:controller users --model user
# this.model = 'user'

node ace make:controller users --model=user
# this.model = 'user'

如果标志值包含空格或特殊字符,用户必须用引号将其包裹。

node ace make:controller posts --model blog user
# this.model = 'blog'
# (只取第一个单词)

node ace make:controller posts --model "blog user"
# this.model = 'blog user'
# (捕获整个短语)

Ace 会显示错误,如果用户提及了标志但没有提供值,即使该标志是可选的。

node ace make:controller users
# 正常 - 可选的 flag 未被提及

node ace make:controller users --model
# 错误:Missing value for flag --model

定义数字标志

数字标志与字符串标志类似,但 Ace 会校验提供的值是否为有效的数字。这确保你的命令接收的是数值输入,而非任意文本。

使用 @flags.number 装饰器定义数字标志。

commands/create_user.ts
import { BaseCommand, flags } from '@adonisjs/core/ace'

export default class CreateUserCommand extends BaseCommand {
  static commandName = 'create:user'

  /**
   * 新用户的初始分数
   */
  @flags.number()
  declare score: number

  async run() {
    this.logger.info(`Creating user with score: ${this.score}`)
  }
}

用户必须提供有效的数值。

node ace create:user --score 100
# this.score = 100

node ace create:user --score abc
# 错误:Flag --score must be a valid number

定义数组标志

数组标志允许用户多次指定相同的标志,将所有值收集到一个数组中。当命令需要接受同一类型的多个项(如文件路径、标签或权限组)时,这会很有用。

使用 @flags.array 装饰器定义数组标志。

commands/create_user.ts
import { BaseCommand, flags } from '@adonisjs/core/ace'

export default class CreateUserCommand extends BaseCommand {
  static commandName = 'create:user'

  /**
   * 要分配给用户的组
   */
  @flags.array()
  declare groups: string[]

  async run() {
    this.logger.info(`Assigning user to groups: ${this.groups.join(', ')}`)
  }
}

用户可以多次指定该标志以构建数组。

node ace create:user --groups=admin --groups=moderators --groups=creators
# this.groups = ['admin', 'moderators', 'creators']

自定义标志名称和描述

默认情况下,Ace 将你的属性名转换为短横线形式(dashed-case)作为标志名称。例如,名为 startServer 的属性会变成 --start-server。你可以使用 flagName 选项自定义它。

commands/serve.ts
@flags.boolean({
  flagName: 'server'
})
declare startServer: boolean

添加描述有助于用户理解标志的用途。描述会在用户使用 --help 标志运行命令时出现在帮助界面中。

commands/serve.ts
@flags.boolean({
  flagName: 'server',
  description: 'Start the application server after the build'
})
declare startServer: boolean

创建标志别名

标志别名提供了标志的简写名称,使常用选项的命令输入更快。别名使用单个连字符(-),且必须是单个字符。

commands/make_controller.ts
@flags.boolean({
  alias: 'r',
  description: 'Generate a resource controller'
})
declare resource: boolean

@flags.boolean({
  alias: 's',
  description: 'Create a singular resource controller'
})
declare singular: boolean

用户可以使用全名或别名。

node ace make:controller users --resource --singular
# 等同于
node ace make:controller users -r -s

多个单字符别名可以在单个连字符后组合。

node ace make:controller users -rs
# 等同于 --resource --singular

设置默认值

你可以使用 default 选项为标志指定默认值。当用户不提供标志时,Ace 会使用默认值代替 undefined

commands/build.ts
@flags.boolean({
  default: true,
  description: 'Start the application server after build'
})
declare startServer: boolean

@flags.string({
  default: 'sqlite',
  description: 'Database connection to use'
})
declare connection: string

默认值确保你的命令始终有一个值可用,即使用户没有指定标志。

node ace build
# this.startServer = true(默认)
# this.connection = 'sqlite'(默认)

node ace build --no-start-server --connection=mysql
# this.startServer = false(显式设置)
# this.connection = 'mysql'(显式设置)

转换标志值

parse 方法允许你在将标志值赋给你的类属性之前对其进行转换或校验。这对于规范化输入、查找配置值或执行校验很有用。

parse 方法接收原始字符串值,并且必须返回转换后的值。

commands/migrate.ts
@flags.string({
  description: 'Database connection to use',
  parse(value) {
    /**
     * 将短名称映射为完整的连接字符串
     */
    const connections = {
      pg: 'postgresql://localhost/myapp',
      mysql: 'mysql://localhost/myapp',
      sqlite: 'sqlite://./database.sqlite'
    }

    return value ? connections[value] || value : value
  }
})
declare connection: string

现在用户可以提供短连接名称,它们会被展开为完整的连接字符串。

node ace migrate --connection=pg
# this.connection = 'postgresql://localhost/myapp'

你也可以使用 parse 方法来校验输入,并为无效值抛出错误。

commands/deploy.ts
@flags.string({
  description: 'Deployment environment',
  parse(value) {
    const validEnvironments = ['development', 'staging', 'production']

    if (value && !validEnvironments.includes(value)) {
      throw new Error(`Environment must be one of: ${validEnvironments.join(', ')}`)
    }

    return value
  }
})
declare environment: string

访问所有标志

你可以使用 this.parsed.flags 属性访问用户提供的所有标志。这会返回一个包含所有标志值作为键值对的对象。

commands/make_controller.ts
import { BaseCommand, flags } from '@adonisjs/core/ace'

export default class MakeControllerCommand extends BaseCommand {
  static commandName = 'make:controller'

  @flags.boolean()
  declare resource: boolean

  @flags.boolean()
  declare singular: boolean

  async run() {
    /**
     * 访问所有已定义的标志
     */
    console.log(this.parsed.flags)
    // 输出:{ resource: true, singular: false }

    /**
     * 访问被提及但未定义的标志
     * (仅在 allowUnknownFlags 为 true 时可用)
     */
    console.log(this.parsed.unknownFlags)
    // 输出:['--some-unknown-flag']
  }
}

当你在命令选项中启用了 allowUnknownFlags,并且需要处理或透传命令未显式定义的标志时,unknownFlags 属性特别有用。