From 2543ac8b11af11f034836591046cdb52911f9403 Mon Sep 17 00:00:00 2001 From: Elizabeth Alexander Hunt Date: Tue, 13 May 2025 09:50:15 -0700 Subject: snapshot --- utils/either.ts | 29 ++++++++++++++++++++++++++--- utils/isObject.ts | 2 ++ utils/mod.ts | 1 + utils/run.ts | 11 +++++++++-- utils/trace.ts | 5 +++++ utils/validate_identifier.ts | 12 +++++++++--- 6 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 utils/isObject.ts (limited to 'utils') diff --git a/utils/either.ts b/utils/either.ts index d21c796..10e4f43 100644 --- a/utils/either.ts +++ b/utils/either.ts @@ -5,14 +5,37 @@ export interface IEither { errBranch: (e: E) => Ee, okBranch: (o: T) => Tt, ) => IEither; + mapRight: (mapper: (t: T) => Tt) => Either; + mapLeft: (mapper: (e: E) => Ee) => Either; + flatMap: ( + mapper: (e: T) => Either, + ) => Either; } export class Either implements IEither { private constructor(readonly err?: E, readonly ok?: T) {} - public mapBoth(errBranch: (e: E) => Ee, okBranch: (t: T) => Tt) { - if (this.err) return new Either(errBranch(this.err)); - return new Either(undefined, okBranch(this.ok!)); + public mapBoth( + errBranch: (e: E) => Ee, + okBranch: (t: T) => Tt, + ): Either { + if (this.err) return Either.left(errBranch(this.err)); + return Either.right(okBranch(this.ok!)); + } + + public flatMap(mapper: (t: T) => Either) { + if (this.ok) return mapper(this.ok); + return this; + } + + public mapRight(mapper: (t: T) => Tt): Either { + if (this.ok) return Either.right(mapper(this.ok)); + return Either.left(this.err!); + } + + public mapLeft(mapper: (e: E) => Ee): Either { + if (this.err) return Either.left(mapper(this.err)); + return Either.right(this.ok!); } static left(e: E) { diff --git a/utils/isObject.ts b/utils/isObject.ts new file mode 100644 index 0000000..73f7f80 --- /dev/null +++ b/utils/isObject.ts @@ -0,0 +1,2 @@ +export const isObject = (o: unknown): o is object => + typeof o === "object" && !Array.isArray(o) && !!o; diff --git a/utils/mod.ts b/utils/mod.ts index 53ea173..d8cb526 100644 --- a/utils/mod.ts +++ b/utils/mod.ts @@ -1,3 +1,4 @@ +export * from "./isObject.ts"; export * from "./trace.ts"; export * from "./either.ts"; export * from "./env.ts"; diff --git a/utils/run.ts b/utils/run.ts index 06e7d9f..9093863 100644 --- a/utils/run.ts +++ b/utils/run.ts @@ -1,10 +1,13 @@ -import { Either } from "./mod.ts"; +import { Either, type Traceable } from "./mod.ts"; export class ProcessError extends Error {} export const getStdout = async ( - cmd: string[] | string, + { item: cmd, logger: _logger }: Traceable, options: Deno.CommandOptions = {}, ): Promise> => { + const logger = _logger.addTracer(() => "[getStdout]"); + + logger.log(`:> im gonna run this command!`, cmd); const [exec, ...args] = (typeof cmd === "string") ? cmd.split(" ") : cmd; const command = new Deno.Command(exec, { args, @@ -19,12 +22,16 @@ export const getStdout = async ( const stderrText = new TextDecoder().decode(stderr); if (code !== 0) { + logger.error(`i weceived an exit code of ${code} i wanna zeroooo :<`); return Either.left( new ProcessError(`command failed\n${stderrText}`), ); } + + logger.log("yay! i got code 0 :3", cmd); return Either.right(stdoutText); } catch (e) { + logger.error(`o.o wat`, e); if (e instanceof Error) { return Either.left(e); } diff --git a/utils/trace.ts b/utils/trace.ts index 373f37e..1a5e51d 100644 --- a/utils/trace.ts +++ b/utils/trace.ts @@ -31,6 +31,7 @@ export interface ITraceable> { flatMapAsync( mapper: ITraceableMapper>>, ): ITraceable, L>; + move(t: Tt): ITraceable; } export class TraceableLogger implements ITraceableLogger { @@ -96,6 +97,10 @@ class TraceableImpl< return this; } + public move(t: Tt) { + return this.map(() => t); + } + public bimap(mapper: ITraceableMapper>) { const [item, trace] = mapper(this); return new TraceableImpl(item, this.logger.addTracer(trace)); diff --git a/utils/validate_identifier.ts b/utils/validate_identifier.ts index e2a1dc5..ec8b77b 100644 --- a/utils/validate_identifier.ts +++ b/utils/validate_identifier.ts @@ -1,11 +1,17 @@ +import { Either } from "./mod.ts"; + export const validateIdentifier = (token: string) => { return (/^[a-zA-Z0-9_\-:. \/]+$/).test(token) && !token.includes(".."); }; -export const invalidExecutionEntriesOf = ( +// ensure {@param obj} is a Record with stuff that won't +// have the potential for shell injection, just to be super safe. +export const validateExecutionEntries = ( obj: Record, -): Array<[string, unknown]> => { - return Object.entries(obj).filter((e) => +): Either, Record> => { + const invalidEntries = Object.entries(obj).filter((e) => !e.every((x) => typeof x === "string" && validateIdentifier(x)) ); + if (invalidEntries.length > 0) return Either.left(invalidEntries); + return Either.right(> obj); }; -- cgit v1.2.3-70-g09d2