export enum NodeType { HELP = 'help', PROGRAM = 'program', COMMAND = 'command', ARG = 'arg', KW_ARG = 'kwarg', FLAG = 'flag', REQUIRED = 'required', REQUIRE_ALL = 'require-all', REQUIRE_ANY = 'require-any', } export type AnyKWArgs = Partial>; export type AnyFlags = Partial>; export type AnyArgs = Partial>; export interface AnyTree { name: string; command?: AnyTree; kwargs: AnyKWArgs; flags: AnyFlags; args: AnyArgs; rest?: readonly string[]; } export interface HelpOptions { description?: string; alias?: string; } export interface ProgramOptions { description?: string; usage?: string; examples?: ReadonlyArray; callback?: ( tree: AnyTree, // eslint-disable-next-line @typescript-eslint/no-explicit-any parentTree?: any, // eslint-disable-next-line @typescript-eslint/no-explicit-any parentReturned?: any ) => void; } export interface ProgramOptionsWithCallback< N extends string, C extends ProgramOrCommandChildren, > extends Omit { callback: ( tree: InferTree, // eslint-disable-next-line @typescript-eslint/no-explicit-any parentTree?: any, // eslint-disable-next-line @typescript-eslint/no-explicit-any parentReturned?: any ) => void; } export interface CommandOptions { description?: string; alias?: string; usage?: string; examples?: ReadonlyArray; callback?: ( tree: AnyTree, // eslint-disable-next-line @typescript-eslint/no-explicit-any parentTree?: any, // eslint-disable-next-line @typescript-eslint/no-explicit-any parentReturned?: any ) => void; } export interface CommandOptionsWithCallback< N extends string, C extends ProgramOrCommandChildren, > extends Omit { callback: ( tree: InferTree, // eslint-disable-next-line @typescript-eslint/no-explicit-any parentTree?: any, // eslint-disable-next-line @typescript-eslint/no-explicit-any parentReturned?: any ) => void; } export interface KWArgOptions { description?: string; alias?: string; options?: ReadonlyArray; type?: string; multi?: boolean; } export interface FlagOptions { description?: string; alias?: string; } export interface ArgOptions { description?: string; options?: ReadonlyArray; type?: string; multi?: boolean; } export interface HelpNode { _type: NodeType.HELP; name: string; options: HelpOptions; } export interface GlobalsInjected { help?: Omit & { _type: NodeType.FLAG; }; } export type AnyRequiredChild = | ArgNode | FlagNode | KWArgNode // eslint-disable-next-line @typescript-eslint/no-explicit-any | CommandNode; export type RequiredChildren = readonly [AnyRequiredChild]; export type RequireAllChildren = readonly [ AnyRequiredChild, ...(readonly AnyRequiredChild[]), ]; export type RequireAnyChildren = readonly [ AnyRequiredChild, ...(readonly AnyRequiredChild[]), ]; export type AnyRequiredChildren = | RequiredChildren | RequireAllChildren | RequireAnyChildren; export type ProgramOrCommandChildren = readonly ( | ArgNode | FlagNode | KWArgNode // eslint-disable-next-line @typescript-eslint/no-explicit-any | CommandNode | RequireAllNode | RequireAnyNode | RequiredNode )[]; export interface ProgramNode< N extends string, C extends ProgramOrCommandChildren, > { _type: NodeType.PROGRAM; _globals: GlobalsInjected; _requireAll: InferRequiredChildren; _requireAny: InferMaybeRequiredChildren; name: N; options: ProgramOptions; children: UnwrapRequiredChildren; } export type InferRequiredChildren = readonly (C extends readonly (infer V)[] ? V extends RequiredNode ? R extends readonly (infer I)[] ? I : never : V extends RequireAllNode ? R extends readonly (infer I)[] ? I : never : never : never)[]; export type InferMaybeRequiredChildren = readonly (readonly (C extends readonly (infer V)[] ? V extends RequireAnyNode ? R extends readonly (infer I)[] ? I : never : never : never)[])[]; export type UnwrapRequiredChildren = readonly (C extends readonly (infer V)[] ? V extends RequiredNode ? R extends readonly (infer I)[] ? I : never : V extends RequireAllNode ? R extends readonly (infer I)[] ? I : never : V extends RequireAnyNode ? R extends readonly (infer I)[] ? I : never : V : never)[]; export interface CommandNode< N extends string, C extends ProgramOrCommandChildren, > { _type: NodeType.COMMAND; _requireAll: InferRequiredChildren; _requireAny: InferMaybeRequiredChildren; name: N; options: CommandOptions; children: UnwrapRequiredChildren; } export interface ArgNode { _type: NodeType.ARG; name: N; options: ArgOptions; } export interface KWArgNode { _type: NodeType.KW_ARG; name: N; options: KWArgOptions; } export interface FlagNode { _type: NodeType.FLAG; name: N; options: FlagOptions; } export interface RequiredNode< C extends readonly [ | ArgNode | FlagNode | KWArgNode // eslint-disable-next-line @typescript-eslint/no-explicit-any | CommandNode, ], > { _type: NodeType.REQUIRED; children: C; } export interface RequireAllNode< C extends readonly ( | ArgNode | FlagNode | KWArgNode // eslint-disable-next-line @typescript-eslint/no-explicit-any | CommandNode )[], > { _type: NodeType.REQUIRE_ALL; children: C; } export interface RequireAnyNode< C extends readonly ( | ArgNode | FlagNode | KWArgNode // eslint-disable-next-line @typescript-eslint/no-explicit-any | CommandNode )[], > { _type: NodeType.REQUIRE_ANY; children: C; } export type AnyNode = | HelpNode | ProgramNode | CommandNode | KWArgNode | FlagNode | ArgNode | RequiredNode | RequireAllNode | RequireAnyNode; export type InferKWArgNames = UnwrapRequiredChildren extends readonly (infer V)[] ? V extends KWArgNode ? N : never : never; export type InferFlagNames = UnwrapRequiredChildren extends readonly (infer V)[] ? V extends FlagNode ? N : never : never; export type InferArgNames = UnwrapRequiredChildren extends readonly (infer V)[] ? V extends ArgNode ? N : never : never; export type InferCommands = UnwrapRequiredChildren extends readonly (infer V)[] ? V extends CommandNode ? CommandNode : never : never; export type InferTree = { name: N; kwargs: Partial, string | readonly string[]>>; flags: Partial, true>>; args: Partial, string | readonly string[]>>; rest?: readonly string[]; command?: InferCommands extends CommandNode ? { [P in CN]: InferTree; }[CN] : never; };