1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
import { Either, type Mapper, type IEither } from "@emprespresso/pengueno";
export const isArgKey = <K extends string>(k: string): k is K =>
k.startsWith("--");
interface ArgHandler<V> {
absent?: V;
unspecified?: V;
present: Mapper<string, V>;
}
export const getArg = <K extends string, V>(
arg: K,
argv: Array<string>,
whenValue: ArgHandler<V>,
): IEither<Error, V> => {
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<string>,
Handlers extends Partial<Record<Args[number], ArgHandler<unknown>>>
> = {
[K in Args[number]]: K extends keyof Handlers
? Handlers[K] extends ArgHandler<infer T>
? T
: string
: string;
};
export const argv = <
const Args extends ReadonlyArray<string>,
const Handlers extends Partial<Record<Args[number], ArgHandler<unknown>>>
>(
args: Args,
handlers?: Handlers,
argv = Deno.args,
): IEither<Error, MappedArgs<Args, Handlers>> => {
type Result = MappedArgs<Args, Handlers>;
const defaultHandler: ArgHandler<string> = { present: (value: string) => value };
const processArg = (arg: Args[number]): IEither<Error, [Args[number], unknown]> => {
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<Error, Partial<Result>>, current: IEither<Error, readonly [Args[number], unknown]>) => {
return acc.flatMap(accValue =>
current.mapRight(([key, value]) => ({
...accValue,
[key]: value
}))
);
},
Either.right({} as Partial<Result>)
).mapRight(result => result as Result);
};
|