cli-vir
Version:
Parse CLI args with type safety.
71 lines (70 loc) • 3.32 kB
TypeScript
import { type AnyObject, type InverseBoolean, type Values } from '@augment-vir/common';
import { type IsEqual, type IsNever } from 'type-fest';
import { type ArgDefinition, type ArgDefinitions, type ArgValueType, type FlagArgOptions, type FlagRequirement, type MapArgValueType, type PositionArgOptions } from './arg-definition.js';
/**
* Optionally adds a union.
*
* @category Internal
*/
export type WithUnion<ShouldAdd extends boolean | undefined, ExtraType, Original> = IsNever<Exclude<ShouldAdd, true>> extends true ? Original | ExtraType : Original;
/**
* Sets `Fallback` if `Original` is `undefined`.
*
* @category Internal
*/
export type WithFallback<Original, Fallback> = undefined extends Original ? Fallback : Original;
/**
* Optionally wraps `T` in an array.
*
* @category Internal
*/
export type WithArray<T, ShouldUseArray extends boolean | undefined> = ShouldUseArray extends true ? T[] : T;
/**
* Extracts arg types for a potential flag arg.
*
* @category Internal
*/
export type ExtractArgTypeWithFlag<Arg extends ArgDefinition> = Arg extends {
flag: FlagArgOptions;
} ? Arg['flag']['valueRequirement'] extends `${FlagRequirement.Blocked}` ? boolean : Arg['flag']['valueRequirement'] extends `${FlagRequirement.Required}` ? ExtractArgType<Arg> : ExtractIfMultiple<Arg> extends true ? ExtractArgType<Arg> | true : IsEqual<Arg['required'], true> extends true ? ExtractArgType<Arg> | true : ExtractArgType<Arg> | boolean : Arg extends {
flag: true;
} ? IsEqual<Arg['required'], true> extends true ? ExtractArgType<Arg> | true : ExtractArgType<Arg> | boolean : ExtractArgType<Arg>;
/**
* Extracts an arg's raw value type.
*
* @category Internal
*/
export type ExtractArgType<Arg extends ArgDefinition> = Arg['type'] extends ArgValueType | `${ArgValueType}` ? MapArgValueType[Arg['type']] : undefined extends Arg['type'] ? MapArgValueType[ArgValueType.String] : Arg['type'] extends ReadonlyArray<infer InnerValue> ? InnerValue : Values<Arg['type']>;
/**
* Determines if the arg definition supports multiple values.
*
* @category Internal
*/
export type ExtractIfMultiple<Arg extends ArgDefinition> = Arg extends {
flag: FlagArgOptions;
} ? Arg['flag']['allowMultiple'] : false;
/**
* Determines if a positional arg is a rest arg.
*
* @category Internal
*/
export type ExtractIfRest<Arg extends ArgDefinition> = Arg extends {
position: infer Options extends PositionArgOptions;
} ? Options['rest'] extends true ? true : false : false;
/**
* Removes the dashes from an argument name. See {@link sanitizeFlagName} for the run-time
* equivalent.
*
* @category Internal
*/
export type RemoveArgDashes<Key extends PropertyKey> = Key extends `-${infer Rest}` ? RemoveArgDashes<Rest> : Key;
/**
* Converts all arg definitions into their parsed types.
*
* @category Internal
*/
export type ParsedArgs<Args extends ArgDefinitions> = {
[Key in RemoveArgDashes<keyof Args>]: WithUnion<InverseBoolean<IsEqual<Args[Key]['required'], true>> | InverseBoolean<ExtractIfMultiple<Args[Key]>> | InverseBoolean<ExtractIfRest<Args[Key]>>, Args[Key] extends {
flag: true | AnyObject;
} ? false : undefined, WithArray<ExtractArgTypeWithFlag<Args[Key]>, ExtractIfMultiple<Args[Key]> extends true ? true : ExtractIfRest<Args[Key]> extends true ? true : false>>;
};