UNPKG

bluecodex

Version:

Turn repetitive dev tasks into CLI commands with Typescript

111 lines (96 loc) 3.54 kB
import { type CastData, castData } from "../data-type/cast-data"; import type { DataTypeToken } from "../data-type/data-type-token"; import { DataTypeCastBooleanError } from "../data-type/errors/data-type-cast-boolean-error"; import type { DataTypeCastError } from "../data-type/errors/data-type-cast-error"; import { DataTypeCastNumberError } from "../data-type/errors/data-type-cast-number-error"; import { type IsValidDataTypeToken, isValidDataType, } from "../data-type/is-valid-data-type"; import { type Arg } from "./arg"; import { ArgFallbackCastError } from "./errors/arg-fallback-cast-error"; import { InvalidArgTypeError } from "./errors/invalid-arg-type-error"; type ParseArg_Step1<Step1Token extends string> = // 1. fallback token Step1Token extends `${infer Step2Token}=${infer FallbackToken}` ? ParseArg_Step2<FallbackToken, Step2Token> : ParseArg_Step2<null, Step1Token>; type ParseArg_Step2< FallbackToken extends string | null, Step2Token extends string, > = // 2. type token Step2Token extends `${infer Step3Token}:${infer TypeToken}` ? ParseArg_Step3<FallbackToken, TypeToken, Step3Token> : ParseArg_Step3<FallbackToken, null, Step2Token>; type ParseArg_Step3< FallbackToken extends string | null, TypeToken extends string | null, Step3Token extends string, > = // 3. optional, name Step3Token extends `${infer Name}?` ? ParseArg_Step4<FallbackToken, TypeToken, true, Name> : ParseArg_Step4<FallbackToken, TypeToken, false, Step3Token>; type ParseArg_Step4< FallbackToken extends string | null, TypeToken extends string | null, Optional extends boolean, Name extends string, // -- computed ExplicitType extends boolean = TypeToken extends null ? false : true, Type extends | DataTypeToken | InvalidArgTypeError<Name, TypeToken & string> = TypeToken extends string ? IsValidDataTypeToken<TypeToken, InvalidArgTypeError<Name, TypeToken>> : "string", Fallback = Type extends DataTypeToken ? CastData<Type, FallbackToken> : null, > = // 4. Combine into Arg<...> Arg< Name, Optional, Type, ExplicitType, Fallback extends DataTypeCastError ? ArgFallbackCastError<Name, Fallback> : Fallback >; export type ParseArg<ArgToken extends string> = ParseArg_Step1<ArgToken>; export function parseArg(argToken: string): Arg { const tokenParts = argToken.split(/[:=]/); const explicitType = argToken.includes(":"); const nameOptionalToken = tokenParts.shift()!; const typeToken = explicitType ? tokenParts.shift() : undefined; const fallbackToken = argToken.includes("=") ? tokenParts.shift() : undefined; const optional = nameOptionalToken.endsWith("?"); const name = optional ? nameOptionalToken.slice(0, -1) : nameOptionalToken; const type: DataTypeToken | InvalidArgTypeError = (() => { if (!typeToken) return "string"; if (isValidDataType(typeToken)) return typeToken; return new InvalidArgTypeError(name, typeToken); })(); const fallback = (() => { if (typeof fallbackToken === "undefined" || type instanceof Error) return null; try { return castData({ type, input: fallbackToken }); } catch (error) { if ( error instanceof DataTypeCastBooleanError || error instanceof DataTypeCastNumberError ) { return new ArgFallbackCastError(name, error); } throw error; } })(); return { __objectType__: "arg", name, type, explicitType, optional, fallback, } satisfies Arg; }