Skip to content

Commit

Permalink
feat(core): support strictOptions for command, fix #1288
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Dec 16, 2023
1 parent 81a32d9 commit d899330
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 14 deletions.
13 changes: 8 additions & 5 deletions packages/core/src/command/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,12 @@ export namespace Command {
= string | ((session: Session<U, G>) => Awaitable<string>)
}

export class Command<U extends User.Field = never, G extends Channel.Field = never, A extends any[] = any[], O extends {} = {}> extends Argv.CommandBase {
config: Command.Config
export class Command<
U extends User.Field = never,
G extends Channel.Field = never,
A extends any[] = any[],
O extends {} = {},
> extends Argv.CommandBase<Command.Config> {
children: Command[] = []

_parent: Command = null
Expand Down Expand Up @@ -77,8 +81,7 @@ export class Command<U extends User.Field = never, G extends Channel.Field = nev
}

constructor(name: string, decl: string, ctx: Context) {
super(name, decl, ctx)
this.config = { ...Command.defaultConfig }
super(name, decl, ctx, { ...Command.defaultConfig })
this._registerAlias(name)
ctx.$commander._commandList.push(this)
}
Expand Down Expand Up @@ -380,7 +383,7 @@ function toStringType(type: Argv.Type) {
}

export namespace Command {
export interface Config extends PermissionConfig {
export interface Config extends Argv.CommandBase.Config, PermissionConfig {
/** disallow unknown options */
checkUnknown?: boolean
/** check argument count */
Expand Down
26 changes: 17 additions & 9 deletions packages/core/src/command/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,13 @@ export namespace Argv {

type OptionDeclarationMap = Dict<OptionDeclaration>

export class CommandBase {
export namespace CommandBase {
export interface Config {
strictOptions?: boolean
}
}

export class CommandBase<T extends CommandBase.Config = CommandBase.Config> {
public declaration: string

public _arguments: Declaration[]
Expand All @@ -405,7 +411,7 @@ export namespace Argv {
private _namedOptions: OptionDeclarationMap = {}
private _symbolicOptions: OptionDeclarationMap = {}

constructor(public readonly name: string, declaration: string, public ctx: Context) {
constructor(public readonly name: string, declaration: string, public ctx: Context, public config: T) {
if (!name) throw new Error('expect a command name')
const declList = this._arguments = parseDecl(declaration)
this.declaration = declList.stripped
Expand Down Expand Up @@ -539,22 +545,24 @@ export namespace Argv {

// find -
let i = 0
let name: string
for (; i < content.length; ++i) {
if (content.charCodeAt(i) !== 45) break
}
if (content.slice(i, i + 3) === 'no-' && !this._namedOptions[content.slice(i)]) {
name = content.slice(i + 3)
options[camelCase(name)] = false
continue
}

// find =
let j = i + 1
for (; j < content.length; j++) {
if (content.charCodeAt(j) === 61) break
}
name = content.slice(i, j)
const name = content.slice(i, j)
if (this.config.strictOptions && !this._namedOptions[name]) {
args.push(Argv.parseValue(content, 'argument', argv, argDecl))
continue
}
if (i > 1 && name.startsWith('no-') && !this._namedOptions[name]) {
options[camelCase(name.slice(3))] = false
continue
}
names = i > 1 ? [name] : name
param = content.slice(++j)
option = this._namedOptions[names[names.length - 1]]
Expand Down
9 changes: 9 additions & 0 deletions packages/core/tests/parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ describe('Parser API', () => {
expect(cmd.parse('a b -c')).to.have.shape({ args: ['a', 'b -c'] })
})

it('strict options', () => {
cmd = app.command('test-strict', { strictOptions: true })
cmd.option('gamma', '-c', { value: 1 })
expect(cmd.parse('-a')).to.have.shape({ options: {}, args: ['-a'] })
expect(cmd.parse('--alpha')).to.have.shape({ options: {}, args: ['--alpha'] })
expect(cmd.parse('--no-alpha')).to.have.shape({ options: {}, args: ['--no-alpha'] })
expect(cmd.parse('-c')).to.have.shape({ options: { gamma: 1 } })
})

it('valued options', () => {
cmd = app.command('cmd2 <foo> [bar:text]')
cmd.option('alpha', '-A, --no-alpha', { value: false })
Expand Down

0 comments on commit d899330

Please sign in to comment.