import { Either, type Mapper, type IEither } from "@emprespresso/pengueno"; export const isArgKey = (k: string): k is K => k.startsWith("--"); interface ArgHandler { absent?: V; unspecified?: V; present: Mapper; } export const getArg = ( arg: K, argv: Array, whenValue: ArgHandler, ): IEither => { const value = argv.filter((_argv) => isArgKey(_argv) && _argv.split("=")[0] === arg).map((_argv, i) => { const next = _argv.includes("=") ? _argv.split("=")[1] : argv.at(i + 1); if (next) { if (isArgKey(next)) return whenValue.unspecified; return whenValue.present(next); } return whenValue.unspecified; }).find(x => x) ?? whenValue.absent; if (value === undefined) { return Either.left(new Error("no value specified for " + arg)); } return Either.right(value); }; type MappedArgs< Args extends ReadonlyArray, Handlers extends Partial>> > = { [K in Args[number]]: K extends keyof Handlers ? Handlers[K] extends ArgHandler ? T : string : string; }; export const argv = < const Args extends ReadonlyArray, const Handlers extends Partial>> >( args: Args, handlers?: Handlers, argv = Deno.args, ): IEither> => { type Result = MappedArgs; const defaultHandler: ArgHandler = { present: (value: string) => value }; const processArg = (arg: Args[number]): IEither => { const handler = handlers?.[arg] ?? defaultHandler; return getArg(arg, argv, handler).mapRight(value => [arg, value] as const); }; const argResults = args.map(processArg); return argResults.reduce( (acc: IEither>, current: IEither) => { return acc.flatMap(accValue => current.mapRight(([key, value]) => ({ ...accValue, [key]: value })) ); }, Either.right({} as Partial) ).mapRight(result => result as Result); };