diff options
Diffstat (limited to 'u/process/argv.ts')
-rw-r--r-- | u/process/argv.ts | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/u/process/argv.ts b/u/process/argv.ts new file mode 100644 index 0000000..657c9a7 --- /dev/null +++ b/u/process/argv.ts @@ -0,0 +1,65 @@ +import { Either, type IEither } from "@emprespresso/pengueno"; + +export const isArgKey = <K extends string>(k: string): k is K => + k.startsWith("--"); + +export const getArg = <K extends string, V extends string>( + arg: K, + args: Array<K>, +): IEither<Error, V> => { + const result = args.findIndex((_arg) => _arg.startsWith(arg)); + if (result < 0) return Either.left(new Error("no argument found for " + arg)); + const [resultArg, next]: Array<string | undefined> = [ + args[result], + args.at(result + 1), + ]; + if (resultArg && resultArg.includes("=")) { + return Either.right(resultArg.split("=")[1] as V); + } + if (typeof next === "undefined") + return Either.left(new Error("no value specified for " + arg)); + if (isArgKey(next)) + return Either.left( + new Error("next value for arg " + arg + " is another arg " + next), + ); + return Either.right(next as V); +}; + +type ObjectFromList<T extends ReadonlyArray<string>, V = string> = { + [K in T extends ReadonlyArray<infer U> ? U : never]: V; +}; +export const argv = <K extends string, V extends string>( + args: ReadonlyArray<K>, + defaultArgs?: Partial<Record<K, V>>, + argv = Deno.args, +) => { + return args + .map((arg) => [arg, getArg(arg, argv)] as [K, IEither<Error, V>]) + .map(([arg, specified]): [K, IEither<Error, V>] => [ + arg, + specified.fold((e, val) => { + const hasDefaultVal = e && defaultArgs && arg in defaultArgs; + if (hasDefaultVal) { + return Either.right<Error, V>(defaultArgs[arg]!); + } else if (!val || e) { + return Either.left<Error, V>(e ?? new Error("unknown")); + } + return Either.right<Error, V>(val); + }), + ]) + .reduce( + ( + acc: IEither<Error, ObjectFromList<typeof args, V>>, + x: [K, IEither<Error, V>], + ): IEither<Error, ObjectFromList<typeof args, V>> => { + const [arg, eitherVal] = x; + return acc.flatMap((args) => { + return eitherVal.mapRight((envValue) => ({ + ...args, + [arg]: envValue, + })); + }); + }, + Either.right({} as ObjectFromList<typeof args, V>), + ); +}; |