@clerc/core
Version:
499 lines (487 loc) • 17.5 kB
TypeScript
import { Equals, Dict, CamelCase, MaybeArray as MaybeArray$1 } from '@clerc/utils';
import { OmitIndexSignature, LiteralUnion, Simplify } from 'type-fest';
declare const DOUBLE_DASH = "--";
type TypeFunction<ReturnType = any> = (value: any) => ReturnType;
type TypeFunctionArray<ReturnType> = readonly [TypeFunction<ReturnType>];
type FlagType<ReturnType = any> = TypeFunction<ReturnType> | TypeFunctionArray<ReturnType>;
type FlagSchemaBase<TF> = {
/**
* Type of the flag as a function that parses the argv string and returns the
* parsed value.
*
* @example
*
* ```
* type: String;
* ```
*
* @example Wrap in an array to accept multiple values. `type: [Boolean]`
*
* @example Custom function type that uses moment.js to parse string as date.
* `type: function CustomDate(value: string) { return moment(value).toDate();
* }`
*/
type: TF;
/**
* A single-character alias for the flag.
*
* @example
*
* ```
* alias: "s";
* ```
*/
alias?: string;
} & Record<PropertyKey, unknown>;
type FlagSchemaDefault<TF, DefaultType = any> = FlagSchemaBase<TF> & {
/**
* Default value of the flag. Also accepts a function that returns the default
* value. [Default: undefined]
*
* @example
*
* ```
* default: 'hello'
* ```
*
* @example
*
* ```
* default: () => [1, 2, 3]
* ```
*/
default: DefaultType | (() => DefaultType);
};
type FlagSchema<TF = FlagType> = FlagSchemaBase<TF> | FlagSchemaDefault<TF>;
type FlagTypeOrSchema<ExtraOptions = Record<string, unknown>> = FlagType | (FlagSchema & ExtraOptions);
type Flags$1<ExtraOptions = Record<string, unknown>> = Record<string, FlagTypeOrSchema<ExtraOptions>>;
type InferFlagType<Flag extends FlagTypeOrSchema> = Flag extends TypeFunctionArray<infer T> | FlagSchema<TypeFunctionArray<infer T>> ? Flag extends FlagSchemaDefault<TypeFunctionArray<T>, infer D> ? T[] | D : T[] : Flag extends TypeFunction<infer T> | FlagSchema<TypeFunction<infer T>> ? Flag extends FlagSchemaDefault<TypeFunction<T>, infer D> ? T | D : T | undefined : never;
interface ParsedFlags<Schemas = Record<string, unknown>> {
flags: Schemas;
unknownFlags: Record<string, (string | boolean)[]>;
_: string[] & {
[DOUBLE_DASH]: string[];
};
}
type TypeFlag<Schemas extends Flags$1> = ParsedFlags<{
[flag in keyof Schemas]: InferFlagType<Schemas[flag]>;
}>;
type StripBrackets<Parameter extends string> = Parameter extends `<${infer ParameterName}>` | `[${infer ParameterName}]` ? ParameterName extends `${infer SpreadName}...` ? SpreadName : ParameterName : never;
type ParameterType<Parameter extends string> = Parameter extends `<${infer _ParameterName}...>` | `[${infer _ParameterName}...]` ? string[] : Parameter extends `<${infer _ParameterName}>` ? string : Parameter extends `[${infer _ParameterName}]` ? string | undefined : never;
type NonNullableParameters<T extends string[] | undefined> = T extends undefined ? [] : NonNullable<T>;
type TransformParameters<C extends Command> = {
[Parameter in NonNullableParameters<C["parameters"]>[number] as CamelCase<StripBrackets<Parameter>>]: ParameterType<Parameter>;
};
type MakeEventMap<T extends Commands> = {
[K in keyof T]: [InterceptorContext];
};
type FallbackFlags<F extends Flags | undefined> = Equals<NonNullableFlag<F>["flags"], {}> extends true ? Dict<any> : NonNullableFlag<F>["flags"];
type NonNullableFlag<F extends Flags | undefined> = TypeFlag<NonNullable<F>>;
type ParseFlag<C extends Commands, N extends keyof C, GF extends GlobalFlagOptions = {}> = N extends keyof C ? OmitIndexSignature<NonNullableFlag<C[N]["flags"] & GF>["flags"]> : FallbackFlags<C[N]["flags"] & GF>["flags"];
type ParseRaw<C extends Command, GF extends GlobalFlagOptions = {}> = NonNullableFlag<C["flags"] & GF> & {
flags: FallbackFlags<C["flags"] & GF>;
parameters: string[];
mergedFlags: FallbackFlags<C["flags"] & GF> & NonNullableFlag<C["flags"] & GF>["unknownFlags"];
};
type ParseParameters<C extends Commands = Commands, N extends keyof C = keyof C> = Equals<TransformParameters<C[N]>, {}> extends true ? N extends keyof C ? TransformParameters<C[N]> : Dict<string | string[] | undefined> : TransformParameters<C[N]>;
type Locales = Dict<Dict<string>>;
type TranslateFn = (name: string, ...args: string[]) => string | undefined;
interface I18N {
add: (locales: Locales) => void;
t: TranslateFn;
}
interface Plugin<T extends Clerc = Clerc, U extends Clerc = Clerc> {
setup: (cli: T) => U;
}
type CommandType = RootType | string;
type FlagOptions = FlagSchema & {
description: string;
};
type Flag = FlagOptions & {
name: string;
};
type GlobalFlagOption = FlagSchema;
type Flags = Dict<FlagOptions>;
type GlobalFlagOptions = Dict<GlobalFlagOption>;
declare interface CommandCustomProperties {
}
interface CommandOptions<P extends string[] = string[], A extends MaybeArray$1<string | RootType> = MaybeArray$1<string | RootType>, F extends Flags = Flags> extends CommandCustomProperties {
alias?: A;
parameters?: P;
flags?: F;
}
type Command<N extends string | RootType = string, O extends CommandOptions = CommandOptions> = O & {
name: N;
description: string;
};
type CommandAlias<N extends string | RootType = string, O extends CommandOptions = CommandOptions> = Command<N, O> & {
__isAlias?: true;
};
type CommandWithHandler<N extends string | RootType = string, O extends CommandOptions = CommandOptions> = Command<N, O> & {
handler?: HandlerInCommand<HandlerContext<Record<N, Command<N, O>> & Record<never, never>, N>>;
};
type Commands = Dict<Command> & {
[Root]?: Command;
};
interface ParseOptions {
argv?: string[];
run?: boolean;
}
interface HandlerContext<C extends Commands = Commands, N extends keyof C = keyof C, GF extends GlobalFlagOptions = {}> {
name?: LiteralUnion<N, string>;
called?: string | RootType;
resolved: boolean;
hasRootOrAlias: boolean;
hasRoot: boolean;
raw: Simplify<ParseRaw<C[N], GF>>;
parameters: Simplify<ParseParameters<C, N>>;
unknownFlags: ParsedFlags["unknownFlags"];
flags: Simplify<ParseFlag<C, N, GF> & Record<string, any>>;
cli: Clerc<C, GF>;
}
type Handler<C extends Commands = Commands, K extends keyof C = keyof C, GF extends GlobalFlagOptions = {}> = (ctx: HandlerContext<C, K, GF>) => void;
type HandlerInCommand<C extends HandlerContext> = (ctx: {
[K in keyof C]: C[K];
}) => void;
type FallbackType<T, U> = {} extends T ? U : T;
/**
* @deprecated This is a typo. Use `InterceptorContext` instead.
*/
type InspectorContext<C extends Commands = Commands> = InterceptorContext<C>;
/**
* @deprecated This is a typo. Use `Interceptor` instead.
*/
type Inspector<C extends Commands = Commands> = Interceptor<C>;
/**
* @deprecated This is a typo. Use `InspectorFn` instead.
*/
type InspectorFn<C extends Commands = Commands> = InterceptorFn<C>;
/**
* @deprecated This is a typo. Use `InspectorObject` instead.
*/
type InspectorObject<C extends Commands = Commands> = InterceptorObject<C>;
type InterceptorContext<C extends Commands = Commands> = HandlerContext<C> & {
flags: FallbackType<TypeFlag<NonNullable<C[keyof C]["flags"]>>["flags"], Dict<any>>;
};
type Interceptor<C extends Commands = Commands> = InterceptorFn<C> | InterceptorObject<C>;
type InterceptorFn<C extends Commands = Commands> = (ctx: InterceptorContext<C>, next: () => void) => void;
interface InterceptorObject<C extends Commands = Commands> {
enforce?: "pre" | "post";
fn: InterceptorFn<C>;
}
declare const Root: unique symbol;
type RootType = typeof Root;
declare class Clerc<C extends Commands = {}, GF extends GlobalFlagOptions = {}> {
#private;
get i18n(): I18N;
private constructor();
get _name(): string;
get _scriptName(): string;
get _description(): string;
get _version(): string;
/**
* @deprecated This is a typo. Use `_interceptor` instead.
*/
get _inspectors(): Interceptor[];
get _interceptors(): Interceptor[];
get _commands(): C;
get _flags(): GF;
/**
* Create a new cli
*
* @example
*
* ```ts
* const cli = Clerc.create();
* ```
*
* @param name
* @param description
* @param version
* @returns
*/
static create(name?: string, description?: string, version?: string): Clerc<{}, {}>;
/**
* Set the name of the cli
*
* @example
*
* ```ts
* Clerc.create().name("test");
* ```
*
* @param name
* @returns
*/
name(name: string): this;
/**
* Set the script name of the cli
*
* @example
*
* ```ts
* Clerc.create().scriptName("test");
* ```
*
* @param scriptName
* @returns
*/
scriptName(scriptName: string): this;
/**
* Set the description of the cli
*
* @example
*
* ```ts
* Clerc.create().description("test cli");
* ```
*
* @param description
* @returns
*/
description(description: string): this;
/**
* Set the version of the cli
*
* @example
*
* ```ts
* Clerc.create().version("1.0.0");
* ```
*
* @param version
* @returns
*/
version(version: string): this;
/**
* Set the Locale You must call this method once after you created the Clerc
* instance.
*
* @example
*
* ```ts
* Clerc.create()
* .locale("en")
* .command(...)
* ```
*
* @param locale
* @returns
*/
locale(locale: string): this;
/**
* Set the fallback Locale You must call this method once after you created
* the Clerc instance.
*
* @example
*
* ```ts
* Clerc.create()
* .fallbackLocale("en")
* .command(...)
* ```
*
* @param fallbackLocale
* @returns
*/
fallbackLocale(fallbackLocale: string): this;
/**
* Register a error handler
*
* @example
*
* ```ts
* Clerc.create().errorHandler((err) => {
* console.log(err);
* });
* ```
*
* @param handler
* @returns
*/
errorHandler(handler: (err: any) => void): this;
/**
* Register a command
*
* @example
*
* ```ts
* Clerc.create().command("test", "test command", {
* alias: "t",
* flags: {
* foo: {
* alias: "f",
* description: "foo flag",
* },
* },
* });
* ```
*
* @example
*
* ```ts
* Clerc.create().command("", "root", {
* flags: {
* foo: {
* alias: "f",
* description: "foo flag",
* },
* },
* });
* ```
*
* @param name
* @param description
* @param options
* @returns
*/
command<C extends CommandWithHandler<any, any>[]>(c: [...C]): this;
command<N extends string | RootType, O extends CommandOptions<[...P], A, F>, P extends string[] = string[], A extends MaybeArray$1<string | RootType> = MaybeArray$1<string | RootType>, F extends Flags = Flags>(c: CommandWithHandler<N, O & CommandOptions<[...P], A, F>>): this & Clerc<C & Record<N, Command<N, O>>, GF>;
command<N extends string | RootType, O extends CommandOptions<[...P], A, F>, P extends string[] = string[], A extends MaybeArray$1<string | RootType> = MaybeArray$1<string | RootType>, F extends Flags = Flags>(name: N, description: string, options?: O & CommandOptions<[...P], A, F>): this & Clerc<C & Record<N, Command<N, O>>, GF>;
/**
* Register a global flag
*
* @example
*
* ```ts
* Clerc.create().flag("help", "help", {
* alias: "h",
* type: Boolean,
* });
* ```
*
* @param name
* @param description
* @param options
* @returns
*/
flag<N extends string, O extends GlobalFlagOption>(name: N, description: string, options: O): this & Clerc<C, GF & Record<N, O>>;
/**
* Register a handler
*
* @example
*
* ```ts
* Clerc.create()
* .command("test", "test command")
* .on("test", (ctx) => {
* console.log(ctx);
* });
* ```
*
* @param name
* @param handler
* @returns
*/
on<K extends LiteralUnion<keyof CM, string | RootType>, CM extends this["_commands"] = this["_commands"]>(name: K, handler: Handler<CM, K, this["_flags"]>): this;
/**
* Use a plugin
*
* @example
*
* ```ts
* Clerc.create().use(plugin);
* ```
*
* @param plugin
* @returns
*/
use<T extends Clerc, U extends Clerc>(plugin: Plugin<T, U>): this & Clerc<C & U["_commands"]> & U;
/**
* @deprecated This is a typo. Use `intercetor()` instead.
*/
inspector(interceptor: Interceptor): this;
/**
* Register a interceptor
*
* @example
*
* ```ts
* Clerc.create().interceptor((ctx, next) => {
* console.log(ctx);
* next();
* });
* ```
*
* @param interceptor
* @returns
*/
interceptor(interceptor: Interceptor): this;
/**
* Parse the command line arguments
*
* @example
*
* ```ts
* Clerc.create().parse(process.argv.slice(2)); // Optional
* ```
*
* @param args
* @param optionsOrArgv
* @returns
*/
parse(optionsOrArgv?: string[] | ParseOptions): this;
/**
* Run matched command
*
* @example
*
* ```ts
* Clerc.create().parse({ run: false }).runMatchedCommand();
* ```
*
* @returns
*/
runMatchedCommand(): this;
}
declare class CommandExistsError extends Error {
commandName: string;
constructor(commandName: string, t: TranslateFn);
}
declare class NoSuchCommandError extends Error {
commandName: string;
constructor(commandName: string, t: TranslateFn);
}
declare class NoCommandGivenError extends Error {
constructor(t: TranslateFn);
}
declare class CommandNameConflictError extends Error {
n1: string;
n2: string;
constructor(n1: string, n2: string, t: TranslateFn);
}
declare class ScriptNameNotSetError extends Error {
constructor(t: TranslateFn);
}
declare class DescriptionNotSetError extends Error {
constructor(t: TranslateFn);
}
declare class VersionNotSetError extends Error {
constructor(t: TranslateFn);
}
declare class InvalidCommandNameError extends Error {
commandName: string;
constructor(commandName: string, t: TranslateFn);
}
declare class LocaleNotCalledFirstError extends Error {
constructor(t: TranslateFn);
}
type MaybeArray<T> = T | T[];
declare const definePlugin: <T extends Clerc<{}, {}>, U extends Clerc<{}, {}>>(p: Plugin<T, U>) => Plugin<T, U>;
declare const defineHandler: <C extends Clerc<{}, {}>, K extends keyof C["_commands"]>(_cli: C, _key: K, handler: Handler<C["_commands"], K>) => Handler<C["_commands"], K>;
declare const defineInterceptor: <C extends Clerc<{}, {}>>(_cli: C, interceptor: Interceptor<C["_commands"]>) => Interceptor<C["_commands"]>;
/**
* @deprecated This is a typo. Use `defineInterceptor` instead.
*/
declare const defineInspector: <C extends Clerc<{}, {}>>(_cli: C, interceptor: Interceptor<C["_commands"]>) => Interceptor<C["_commands"]>;
declare const defineCommand: <N extends string | typeof Root, O extends CommandOptions<[...P], MaybeArray<string | typeof Root>, Flags>, P extends string[]>(command: Command<N, O & CommandOptions<[...P], MaybeArray<string | typeof Root>, Flags>>, handler?: HandlerInCommand<HandlerContext<Record<N, Command<N, O>> & Record<never, never>, N, {}>> | undefined) => CommandWithHandler<N, O & CommandOptions<[...P], MaybeArray<string | typeof Root>, Flags>>;
declare function resolveFlattenCommands(commands: Commands, t: TranslateFn): Map<string[] | typeof Root, CommandAlias>;
declare function resolveCommand(commands: Commands, argv: string[], t: TranslateFn): [Command<string | RootType> | undefined, string[] | RootType | undefined];
declare const resolveArgv: () => string[];
declare function compose(interceptors: Interceptor[]): (ctx: InterceptorContext) => void;
declare const isValidName: (name: CommandType) => boolean;
declare const withBrackets: (s: string, isOptional?: boolean) => string;
declare const formatCommandName: (name: string | string[] | RootType) => string;
declare const detectLocale: () => string;
declare const stripFlags: (argv: string[]) => string[];
export { Clerc, Command, CommandAlias, CommandCustomProperties, CommandExistsError, CommandNameConflictError, CommandOptions, CommandType, CommandWithHandler, Commands, DescriptionNotSetError, FallbackType, Flag, FlagOptions, Flags, GlobalFlagOption, GlobalFlagOptions, Handler, HandlerContext, HandlerInCommand, I18N, Inspector, InspectorContext, InspectorFn, InspectorObject, Interceptor, InterceptorContext, InterceptorFn, InterceptorObject, InvalidCommandNameError, LocaleNotCalledFirstError, Locales, MakeEventMap, NoCommandGivenError, NoSuchCommandError, ParseOptions, Plugin, Root, RootType, ScriptNameNotSetError, TranslateFn, VersionNotSetError, compose, defineCommand, defineHandler, defineInspector, defineInterceptor, definePlugin, detectLocale, formatCommandName, isValidName, resolveArgv, resolveCommand, resolveFlattenCommands, stripFlags, withBrackets };