UNPKG

zlye

Version:

A type-safe CLI parser with a Zod-like schema validation.

128 lines (127 loc) 4.4 kB
type Prettify<T> = { [K in keyof T] : T[K] } & {}; type ExtractPositionalType<T> = T extends PositionalSchema<infer U> ? U : never; type ExtractPositionalTypes<T extends readonly PositionalSchema<any>[]> = { readonly [K in keyof T] : ExtractPositionalType<T[K]> }; type SchemaType = "string" | "number" | "boolean" | "array" | "object"; interface BaseSchema<T = any> { _type: SchemaType; _output: T; _input: unknown; parse(value: unknown, path?: string): T; optional(): Schema<T | undefined>; default(value: T): Schema<T>; transform<U>(fn: (value: T) => U): Schema<U>; describe(description: string): this; alias(alias: string): this; example(example: string): this; _description?: string; _alias?: string; _example?: string; _isOptional?: boolean; _defaultValue?: T; } type Schema<T = any> = BaseSchema<T>; interface StringSchemaBase<T extends string = string> extends BaseSchema<T> { min(length: number): this; max(length: number): this; regex(pattern: RegExp, message?: string): this; choices<const U extends readonly string[]>(choices: U): StringSchema<U[number]>; _minLength?: number; _maxLength?: number; _regex?: { pattern: RegExp message?: string }; _choices?: readonly string[]; } type StringSchema<T extends string = string> = StringSchemaBase<T>; interface NumberSchema extends BaseSchema<number> { min(value: number): this; max(value: number): this; int(): this; positive(): this; negative(): this; _min?: number; _max?: number; _isInt?: boolean; _isPositive?: boolean; _isNegative?: boolean; } interface BooleanSchema extends BaseSchema<boolean> {} interface ArraySchema<T> extends BaseSchema<T[]> { min(length: number): this; max(length: number): this; _itemSchema: Schema<T>; _minLength?: number; _maxLength?: number; } interface ObjectSchema<T extends Record<string, any>> extends BaseSchema<T> { _shape: { [K in keyof T] : Schema<T[K]> }; } interface PositionalSchema<T = string> extends BaseSchema<T> { _name: string; } interface Command< TOptions extends Record<string, Schema> = any, TPositionals extends readonly PositionalSchema<any>[] = readonly [] > { name: string; description?: string; usage?: string; example?: string | string[]; options: TOptions; positionals?: PositionalSchema<any>[]; action: (args: { options: Prettify<{ [K in keyof TOptions] : TOptions[K]["_output"] }> positionals: ExtractPositionalTypes<TPositionals> }) => void | Promise<void>; } interface CommandBuilder< TOptions extends Record<string, Schema>, TPositionals extends readonly PositionalSchema<any>[] = readonly [] > { description(desc: string): this; usage(usage: string): this; example(example: string | string[]): this; positional<T>(name: string, schema?: Schema<T>): CommandBuilder<TOptions, [...TPositionals, PositionalSchema<T>]>; action(fn: (args: { options: Prettify<{ [K in keyof TOptions] : TOptions[K]["_output"] }> positionals: ExtractPositionalTypes<TPositionals> }) => void | Promise<void>): Command<TOptions, TPositionals>; } interface CLI< TOptions extends Record<string, Schema> = Record<string, never>, TPositionals extends readonly PositionalSchema<any>[] = readonly [] > { name(name: string): this; version(version: string): this; description(description: string): this; usage(usage: string): this; example(example: string | string[]): this; option< K extends string, S extends Schema >(name: K, schema: S): CLI<TOptions & { [P in K] : S }, TPositionals>; positional<T>(name: string, schema?: Schema<T>): CLI<TOptions, [...TPositionals, PositionalSchema<T>]>; command<T extends Record<string, Schema> = Record<string, never>>(name: string, options?: T): CommandBuilder<T>; parse(argv?: string[]): { options: Prettify<{ [K in keyof TOptions] : TOptions[K]["_output"] }> positionals: ExtractPositionalTypes<TPositionals> } | undefined; _name?: string; _version?: string; _description?: string; _usage?: string; _examples?: string[]; _options: TOptions; _positionals?: PositionalSchema<any>[]; _commands: Command<any, any>[]; } declare const z: { string: () => StringSchema number: () => NumberSchema boolean: () => BooleanSchema array: <T>(schema: Schema<T>) => ArraySchema<T> object: <T extends Record<string, Schema>>(shape: T) => ObjectSchema<{ [K in keyof T] : T[K]["_output"] }> }; declare function cli(): CLI<Record<string, never>, readonly []>; export { z, cli };