Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: flag types #454

Merged
merged 7 commits into from Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 8 additions & 8 deletions src/command.ts
Expand Up @@ -128,25 +128,25 @@ export default abstract class Command {
return cmd._run(argv)
}

protected static _globalFlags: Interfaces.FlagInput<any>
protected static _globalFlags: Interfaces.FlagInput

static get globalFlags(): Interfaces.FlagInput<any> {
static get globalFlags(): Interfaces.FlagInput {
return this._globalFlags
}

static set globalFlags(flags: Interfaces.FlagInput<any>) {
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<any>
protected static _flags: Interfaces.FlagInput

static get flags(): Interfaces.FlagInput<any> {
static get flags(): Interfaces.FlagInput {
return this._flags
}

static set flags(flags: Interfaces.FlagInput<any>) {
static set flags(flags: Interfaces.FlagInput) {
this._flags = Object.assign({}, this._flags ?? {}, this.globalFlags, flags)
}

Expand Down Expand Up @@ -242,11 +242,11 @@ export default abstract class Command {
g['http-call']!.userAgent = this.config.userAgent
}

protected async parse<F, A extends { [name: string]: any }>(options?: Interfaces.Input<F>, argv = this.argv): Promise<Interfaces.ParserOutput<F, A>> {
protected async parse<F, G, A extends { [name: string]: any }>(options?: Interfaces.Input<F, G>, argv = this.argv): Promise<Interfaces.ParserOutput<F, G, A>> {
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
RodEsp marked this conversation as resolved.
Show resolved Hide resolved
opts.flags = Object.assign({}, options?.flags, options?.globalFlags)
opts.flags = options?.flags
return Parser.parse(argv, opts)
}

Expand Down
13 changes: 7 additions & 6 deletions src/interfaces/parser.ts
Expand Up @@ -43,17 +43,18 @@ export type ArgInput = Arg<any>[]
export interface CLIParseErrorOptions {
parse: {
input?: ParserInput;
output?: ParserOutput<any, any>;
output?: ParserOutput;
};
}

export type OutputArgs = { [name: string]: any }
export type OutputFlags<T extends ParserInput['flags']> = { [P in keyof T]: any }
export type ParserOutput<TFlags extends OutputFlags<any>, TArgs extends OutputArgs> = {

export type ParserOutput<TFlags extends OutputFlags<any> = any, GFlags extends OutputFlags<any> = 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[];
Expand Down Expand Up @@ -162,9 +163,9 @@ export type EnumFlagOptions<T> = Partial<OptionFlag<T>> & {

export type Flag<T> = BooleanFlag<T> | OptionFlag<T>

export type Input<TFlags extends FlagOutput> = {
export type Input<TFlags extends FlagOutput, GFlags extends FlagOutput> = {
flags?: FlagInput<TFlags>;
globalFlags?: FlagInput<TFlags>;
globalFlags?: FlagInput<GFlags>;
args?: ArgInput;
strict?: boolean;
context?: any;
Expand Down Expand Up @@ -200,4 +201,4 @@ export type CompletableOptionFlag<T> = OptionFlag<T> & {

export type CompletableFlag<T> = BooleanFlag<T> | CompletableOptionFlag<T>

export type FlagInput<T extends FlagOutput> = { [P in keyof T]: CompletableFlag<T[P]> }
export type FlagInput<T extends FlagOutput = {[flag: string]: unknown}> = { [P in keyof T]: CompletableFlag<T[P]> }
12 changes: 5 additions & 7 deletions 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}
Expand All @@ -15,22 +13,22 @@ const m = Deps()
// eslint-disable-next-line node/no-missing-require
.add('validate', () => require('./validate').validate as typeof Validate.validate)

export async function parse<TFlags, TArgs extends { [name: string]: string }>(argv: string[], options: Input<TFlags>): Promise<ParserOutput<TFlags, TArgs>> {
export async function parse<TFlags, GFlags, TArgs extends { [name: string]: string }>(argv: string[], options: Input<TFlags, GFlags>): Promise<ParserOutput<TFlags, GFlags, TArgs>> {
const input = {
argv,
context: options.context,
args: (options.args || []).map((a: any) => args.newArg(a as any)),
'--': options['--'],
flags: {
color: flags.defaultFlags.color,
...((options.flags || {})) as any,
},
...options.flags,
} as FlagInput<any>,
strict: options.strict !== false,
}
const parser = new Parser(input)
const output = await parser.parse()
m.validate({input, output})
return output as ParserOutput<TFlags, TArgs>
return output as ParserOutput<TFlags, GFlags, TArgs>
}

const {boolean, integer, url, directory, file} = flags
Expand Down
2 changes: 1 addition & 1 deletion src/parser/validate.ts
Expand Up @@ -10,7 +10,7 @@ import {ParserArg, ParserInput, ParserOutput, Flag} from '../interfaces'

export function validate(parse: {
input: ParserInput;
output: ParserOutput<any, any>;
output: ParserOutput;
}) {
function validateArgs() {
const maxArgs = parse.input.args.length
Expand Down