diff options
Diffstat (limited to 'u')
-rw-r--r-- | u/process/argv.ts | 118 | ||||
-rw-r--r-- | u/process/run.ts | 2 | ||||
-rw-r--r-- | u/trace/logger.ts | 6 |
3 files changed, 66 insertions, 60 deletions
diff --git a/u/process/argv.ts b/u/process/argv.ts index 8e85477..45f8ff0 100644 --- a/u/process/argv.ts +++ b/u/process/argv.ts @@ -1,66 +1,72 @@ -import { Either, type IEither } from "@emprespresso/pengueno"; +import { Either, type Mapper, 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>( +interface ArgHandler<V> { + absent?: V; + unspecified?: V; + present: Mapper<string, V>; +} + +export const getArg = <K extends string, V>( arg: K, - args: Array<K>, + argv: Array<string>, + whenValue: ArgHandler<V>, ): 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); + 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 ObjectFromList<T extends ReadonlyArray<string>, V = string> = { - [K in T extends ReadonlyArray<infer U> ? U : never]: V; +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 = <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(({ isLeft, isRight, value }): IEither<Error, V> => { - if (isRight) { - return Either.right(value); - } - const hasDefaultVal = isLeft && defaultArgs && arg in defaultArgs; - if (hasDefaultVal) { - return Either.right(defaultArgs[arg]!); - } - return Either.left(value); - }), - ]) - .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>), - ); + +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); }; diff --git a/u/process/run.ts b/u/process/run.ts index b09e64e..abe143c 100644 --- a/u/process/run.ts +++ b/u/process/run.ts @@ -22,7 +22,7 @@ export const getStdout = ( .bimap(TraceUtil.withFunctionTrace(getStdout)) .map((tCmd) => { const cmd = tCmd.get(); - tCmd.trace.trace(`:> im gonna run this command! ${cmd}`); + tCmd.trace.trace(`Command = ${cmd} :> im gonna run this command! `); const [exec, ...args] = typeof cmd === "string" ? cmd.split(" ") : cmd; return new Deno.Command(exec, { args, diff --git a/u/trace/logger.ts b/u/trace/logger.ts index 29cabd4..d8392eb 100644 --- a/u/trace/logger.ts +++ b/u/trace/logger.ts @@ -93,11 +93,11 @@ export interface ILogger { class LoggerImpl implements ILogger { private readonly textEncoder = new TextEncoder(); - public log(level: LogLevel, ...msg: string[]) { + public log(level: LogLevel, ...trace: string[]) { const message = JSON.stringify({ level, - msg, - }, null, 2); + trace, + }, null, 4); const styled = `${this.getStyle(level)}${message}${ANSI.RESET}\n`; this.getStream(level).writeSync(this.textEncoder.encode(styled)); } |