Addition: opts.allowMultipleFlagValues & more accurate return flag types
opts.allowMultipleFlagValues -> returns flag values as array and add duplicate flags to the array instead of picking the last one (eg ["--foo", "hello", "--foo=world!"] -> { foo: ["hello", "world!"] }).
Flag return types are now typed as Partials if a default is not present and opts.allowMultipleFlagValues is not enabled.
This commit is contained in:
parent
c16dbc7d56
commit
86b8cfcfaa
21
index.js
21
index.js
@ -210,6 +210,7 @@ function validateAndFillDefaults(opts) {
|
||||
validateOrDefaultIfUnset(opts, 'allowSingularDashLongFlags', 'boolean', false);
|
||||
validateOrDefaultIfUnset(opts, 'lowerCaseFlagValues', 'boolean', false);
|
||||
validateOrDefaultIfUnset(opts, 'lowerCaseInputValues', 'boolean', false);
|
||||
validateOrDefaultIfUnset(opts, 'allowMultipleFlagValues', 'boolean', false);
|
||||
|
||||
if(opts.shouldStopParsingFunc !== null)
|
||||
validateOrDefaultIfUnset(opts, 'shouldStopParsingFunc', 'function', null);
|
||||
@ -825,9 +826,10 @@ function parseShorthandFlags(shorthandFlags, shorthandString) {
|
||||
// TODO: Fix typescript types of returned flags to include opts.resolveFlagValueTypes into it as well as checking if it has a default and if not make it an optional?, and type never if it's not in the flags object
|
||||
/**
|
||||
* @template {FlagsI} Flags
|
||||
* @template {{ [K in keyof Flags]: Flags[K]['type'] extends 'boolean' ? boolean : Flags[K]['type'] extends 'number' ? number : Flags[K]['type'] extends 'string' ? string : string | boolean | number }} FlagsReturn
|
||||
* @template {ParserOpts<Flags>} Opts
|
||||
* @template {import('./types.d.ts').FlagsReturn<Opts>} FlagsReturn
|
||||
* @param {string[]} argv
|
||||
* @param {ParserOpts<Flags>} opts
|
||||
* @param {Opts} opts
|
||||
* @returns {{ input: string[], flags: FlagsReturn, unparsed: string[] } }}
|
||||
*/
|
||||
function parser(argv, opts) {
|
||||
@ -1060,6 +1062,13 @@ function parser(argv, opts) {
|
||||
|
||||
const flagName = flag.config?.name || flag.key;
|
||||
|
||||
if(opts.allowMultipleFlagValues) {
|
||||
if(!Array.isArray(flagReturnObj[flagName]))
|
||||
flagReturnObj[flagName] = [flag.value];
|
||||
else
|
||||
flagReturnObj[flagName].push(flag.value);
|
||||
return
|
||||
}
|
||||
flagReturnObj[flagName] = flag.value;
|
||||
})
|
||||
|
||||
@ -1067,10 +1076,16 @@ function parser(argv, opts) {
|
||||
Object.entries(opts.flags).forEach(([flagName, flagConfig]) => {
|
||||
if(typeof flagReturnObj[flagName] !== 'undefined')
|
||||
return;
|
||||
|
||||
if(opts.allowMultipleFlagValues) {
|
||||
if(typeof flagConfig.default === 'undefined')
|
||||
return flagReturnObj[flagName] = [];
|
||||
return flagReturnObj[flagName] = [flagConfig.default];
|
||||
}
|
||||
/** Not a needed check as you can tell, but present to explicitly highlight that behavior in the code */
|
||||
if(typeof flagConfig.default === 'undefined')
|
||||
return flagReturnObj[flagName] = undefined;
|
||||
flagReturnObj[flagName] = flagConfig.default;
|
||||
return flagReturnObj[flagName] = flagConfig.default;
|
||||
});
|
||||
|
||||
/// @ts-ignore - falsly wrong flags type
|
||||
|
||||
46
types.d.ts
vendored
46
types.d.ts
vendored
@ -11,6 +11,8 @@ interface FlagT<T, Z> {
|
||||
acceptsNaturalValue?: boolean
|
||||
};
|
||||
|
||||
export type FlagTypes = "string" | "boolean" | "bigint" | "number" | "any";
|
||||
|
||||
export type FlagAny = FlagT<string, "string"> | FlagT<boolean, "boolean"> | FlagT<number, "number"> | FlagT<bigint, "bigint"> | FlagT<string | number | bigint | boolean, "any">
|
||||
|
||||
export interface FlagsI { [key: readonly string]: FlagAny }
|
||||
@ -49,7 +51,7 @@ export interface ParserOpts<Flags extends FlagsI> {
|
||||
/** Override to change how warnings are emitted @default console.warn */
|
||||
warningLogger?(log: string): void;
|
||||
/** Default type for either unknown flags or flags without an explicit type being set @default "any" */
|
||||
defaultFlagType?: "string" | "boolean" | "bigint" | "number" | "any";
|
||||
defaultFlagType?: FlagTypes;
|
||||
/**
|
||||
* Behavior when input does not follow the provided flags constraints (eg: flag assigned value (--flag=value) not being the correct type).
|
||||
*
|
||||
@ -125,6 +127,24 @@ export interface ParserOpts<Flags extends FlagsI> {
|
||||
* @default null
|
||||
*/
|
||||
parseFilterFunc?(arg: string, index: number, argv: string[], argMeta: argMeta, input: string[]): boolean
|
||||
/**
|
||||
* Allows multiple flag values & changes the returned flags to always be arrays, with the default being the first value if the flag was not set, or an
|
||||
* empty array if the flag does not have a default but was not present.
|
||||
* @example
|
||||
* ```js
|
||||
* const { flags } = parser(["--flag=hello", "--flag=world"], {
|
||||
* flags: {
|
||||
* defaultedFlag: { default: "missing", type: "string" },
|
||||
* missingFlag: { type: "string" },
|
||||
* },
|
||||
* allowMultipleFlagValues: true,
|
||||
* allowUnknownFlags: true,
|
||||
* });
|
||||
* flags === { flag: ["hello", "world"], defaultedFlag: ["missing"], missingFlag: [] }
|
||||
* ```
|
||||
* @default false
|
||||
*/
|
||||
allowMultipleFlagValues?: boolean
|
||||
}
|
||||
|
||||
export type argMeta = {
|
||||
@ -146,4 +166,26 @@ export type argMeta = {
|
||||
|
||||
function __type__getType(e: any) { return typeof e };
|
||||
|
||||
export type JSTypes = ReturnType<typeof __type__getType>
|
||||
export type JSTypes = ReturnType<typeof __type__getType>;
|
||||
|
||||
export type FlagReturnType<FlagType extends FlagTypes> =
|
||||
FlagType extends 'boolean' ? boolean
|
||||
: FlagType extends 'number' ? number
|
||||
: FlagType extends 'bigint' ? bigint
|
||||
: FlagType extends 'string' ? string
|
||||
: string | boolean | number | bigint;
|
||||
|
||||
type ValueOf<T> = T[keyof T];
|
||||
type OptionalKeys<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>;
|
||||
|
||||
type _OptionalIfFlagDefaultNotPresent<T> = OptionalKeys<T, ValueOf<{ [V in keyof T]: 'default' extends keyof T[V] ? never : V }>>;
|
||||
type _ResolveFlagTypes<Flags extends FlagsI, allowMultipleFlagValues extends boolean> = {
|
||||
[K in keyof Flags]: allowMultipleFlagValues extends true
|
||||
? FlagReturnType<Flags[K]['type']>[]
|
||||
: FlagReturnType<Flags[K]['type']>
|
||||
}
|
||||
|
||||
export type FlagsReturn<Opts extends ParserOpts> = _ResolveFlagTypes<
|
||||
Opts['allowMultipleFlagValues'] extends true ? Opts['flags'] : _OptionalIfFlagDefaultNotPresent<Opts['flags']>,
|
||||
Opts['allowMultipleFlagValues'] extends true ? true : false
|
||||
>;
|
||||
Loading…
x
Reference in New Issue
Block a user