From 2938ba4082d1b0c603a55678fe47f5beed9acbb5 Mon Sep 17 00:00:00 2001 From: Mike Donnalley Date: Fri, 5 Aug 2022 08:35:02 -0700 Subject: [PATCH] fix: flag types (#454) * fix: flag types * fix: support global flag types * chore: remove comment * fix: flag types when no global flags defined * chore: rename computed prop --- src/command.ts | 16 ++++++++-------- src/interfaces/parser.ts | 13 +++++++------ src/parser/index.ts | 12 +++++------- src/parser/validate.ts | 2 +- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/command.ts b/src/command.ts index 45ec4fd3..f938cf12 100644 --- a/src/command.ts +++ b/src/command.ts @@ -128,25 +128,25 @@ export default abstract class Command { return cmd._run(argv) } - protected static _globalFlags: Interfaces.FlagInput + protected static _globalFlags: Interfaces.FlagInput - static get globalFlags(): Interfaces.FlagInput { + static get globalFlags(): Interfaces.FlagInput { return this._globalFlags } - static set globalFlags(flags: Interfaces.FlagInput) { + static set globalFlags(flags: Interfaces.FlagInput) { this._globalFlags = Object.assign({}, this.globalFlags, flags) this.flags = {} // force the flags setter to run } /** A hash of flags for the command */ - protected static _flags: Interfaces.FlagInput + protected static _flags: Interfaces.FlagInput - static get flags(): Interfaces.FlagInput { + static get flags(): Interfaces.FlagInput { return this._flags } - static set flags(flags: Interfaces.FlagInput) { + static set flags(flags: Interfaces.FlagInput) { this._flags = Object.assign({}, this._flags ?? {}, this.globalFlags, flags) } @@ -242,11 +242,11 @@ export default abstract class Command { g['http-call']!.userAgent = this.config.userAgent } - protected async parse(options?: Interfaces.Input, argv = this.argv): Promise> { + protected async parse(options?: Interfaces.Input, argv = this.argv): Promise> { if (!options) options = this.constructor as any const opts = {context: this, ...options} // the spread operator doesn't work with getters so we have to manually add it here - opts.flags = Object.assign({}, options?.flags, options?.globalFlags) + opts.flags = options?.flags return Parser.parse(argv, opts) } diff --git a/src/interfaces/parser.ts b/src/interfaces/parser.ts index c410e55b..10317e06 100644 --- a/src/interfaces/parser.ts +++ b/src/interfaces/parser.ts @@ -43,17 +43,18 @@ export type ArgInput = Arg[] export interface CLIParseErrorOptions { parse: { input?: ParserInput; - output?: ParserOutput; + output?: ParserOutput; }; } export type OutputArgs = { [name: string]: any } export type OutputFlags = { [P in keyof T]: any } -export type ParserOutput, TArgs extends OutputArgs> = { + +export type ParserOutput = any, GFlags extends OutputFlags = any, TArgs extends OutputArgs = any> = { // Add in global flags so that they show up in the types // This is necessary because there's no easy way to optionally return // the individual flags based on wether they're enabled or not - flags: TFlags & { json: boolean | undefined }; + flags: TFlags & GFlags & { json: boolean | undefined }; args: TArgs; argv: string[]; raw: ParsingToken[]; @@ -162,9 +163,9 @@ export type EnumFlagOptions = Partial> & { export type Flag = BooleanFlag | OptionFlag -export type Input = { +export type Input = { flags?: FlagInput; - globalFlags?: FlagInput; + globalFlags?: FlagInput; args?: ArgInput; strict?: boolean; context?: any; @@ -200,4 +201,4 @@ export type CompletableOptionFlag = OptionFlag & { export type CompletableFlag = BooleanFlag | CompletableOptionFlag -export type FlagInput = { [P in keyof T]: CompletableFlag } +export type FlagInput = { [P in keyof T]: CompletableFlag } diff --git a/src/parser/index.ts b/src/parser/index.ts index a75b4bc1..dfbf21ed 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -1,10 +1,8 @@ -// tslint:disable interface-over-type-literal - import * as args from './args' import Deps from './deps' import * as flags from './flags' import {Parser} from './parse' -import {Input, ParserOutput} from '../interfaces' +import {FlagInput, Input, ParserOutput} from '../interfaces' import * as Validate from './validate' export {args} export {flags} @@ -15,7 +13,7 @@ const m = Deps() // eslint-disable-next-line node/no-missing-require .add('validate', () => require('./validate').validate as typeof Validate.validate) -export async function parse(argv: string[], options: Input): Promise> { +export async function parse(argv: string[], options: Input): Promise> { const input = { argv, context: options.context, @@ -23,14 +21,14 @@ export async function parse(ar '--': options['--'], flags: { color: flags.defaultFlags.color, - ...((options.flags || {})) as any, - }, + ...options.flags, + } as FlagInput, strict: options.strict !== false, } const parser = new Parser(input) const output = await parser.parse() m.validate({input, output}) - return output as ParserOutput + return output as ParserOutput } const {boolean, integer, url, directory, file} = flags diff --git a/src/parser/validate.ts b/src/parser/validate.ts index e0fccb6b..fb5f01c3 100644 --- a/src/parser/validate.ts +++ b/src/parser/validate.ts @@ -10,7 +10,7 @@ import {ParserArg, ParserInput, ParserOutput, Flag} from '../interfaces' export function validate(parse: { input: ParserInput; - output: ParserOutput; + output: ParserOutput; }) { function validateArgs() { const maxArgs = parse.input.args.length