summaryrefslogtreecommitdiff
path: root/u
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-07-20 13:03:39 -0700
committerElizabeth Hunt <me@liz.coffee>2025-07-20 13:03:39 -0700
commitdc4ac7742690f8f2bd759d57108ac4455e717fe9 (patch)
treef138ba41dd44bf703087eaa8ec43a22fe842923d /u
parentdccb99505e92685ba8ade7c3be84555f2b539a47 (diff)
downloadci-dc4ac7742690f8f2bd759d57108ac4455e717fe9.tar.gz
ci-dc4ac7742690f8f2bd759d57108ac4455e717fe9.zip
Mount src directory from path on host running worker container
Diffstat (limited to 'u')
-rw-r--r--u/process/env.ts24
-rw-r--r--u/process/exec.ts (renamed from u/process/run.ts)25
-rw-r--r--u/process/index.ts2
-rw-r--r--u/trace/itrace.ts6
-rw-r--r--u/types/fn/callable.ts2
-rw-r--r--u/types/fn/either.ts56
-rw-r--r--u/types/fn/optional.ts8
-rw-r--r--u/types/index.ts2
-rw-r--r--u/types/misc.ts3
9 files changed, 85 insertions, 43 deletions
diff --git a/u/process/env.ts b/u/process/env.ts
index 88fb490..f59fadf 100644
--- a/u/process/env.ts
+++ b/u/process/env.ts
@@ -1,27 +1,25 @@
-import { IOptional, Either, Optional, type IEither } from '@emprespresso/pengueno';
+import { IOptional, Either, Optional, type IEither, type ObjectFromList } from '@emprespresso/pengueno';
-export const getEnv = <V extends string>(name: string): IOptional<V> => Optional.from(<V>process.env[name]);
+// type safe environment variables
-export const getRequiredEnv = <V extends string>(name: string): IEither<Error, V> =>
- Either.fromFailable(() => getEnv<V>(name).get()).mapLeft(
+export const getEnv = (name: string): IOptional<string> => Optional.from(process.env[name]);
+
+export const getRequiredEnv = <V extends string>(name: V): IEither<Error, string> =>
+ Either.fromFailable(() => getEnv(name).get()).mapLeft(
() => new Error(`environment variable "${name}" is required D:`),
);
-type ObjectFromList<T extends ReadonlyArray<string>, V = string> = {
- [K in T extends ReadonlyArray<infer U> ? U : never]: V;
-};
-
-export const getRequiredEnvVars = <V extends string>(vars: Array<V>) => {
+export const getRequiredEnvVars = <V extends string>(vars: Array<V>): IEither<Error, ObjectFromList<typeof vars>> => {
type Environment = ObjectFromList<typeof vars>;
const emptyEnvironment = Either.right<Error, Environment>(<Environment>{});
- const addTo = (env: Environment, key: V) => (val: string) =>
+ const addTo = (env: Environment, key: V, val: string) =>
<Environment>{
...env,
[key]: val,
};
- return Either.joinRight<V, Error, Environment>(
- vars,
- (envVar: V, environment: Environment) => getRequiredEnv(envVar).mapRight(addTo(environment, envVar)),
+ return vars.reduce(
+ (environment, key) =>
+ environment.joinRight(getRequiredEnv(key), (value, environment) => addTo(environment, key, value)),
emptyEnvironment,
);
};
diff --git a/u/process/run.ts b/u/process/exec.ts
index 1d19129..a2cdbca 100644
--- a/u/process/run.ts
+++ b/u/process/exec.ts
@@ -15,11 +15,13 @@ export type Command = string[] | string;
export type StdStreams = { stdout: string; stderr: string };
export const CmdMetric = Metric.fromName('Exec').asResult();
+type Environment = Record<string, string>;
+type Options = { env?: Environment; clearEnv?: boolean };
export const getStdout = (
- c: ITraceable<Command, LogMetricTraceSupplier>,
- options: { env?: Record<string, string>; clearEnv?: boolean } = {},
+ cmd: ITraceable<Command, LogMetricTraceSupplier>,
+ options: Options = {},
): Promise<IEither<Error, string>> =>
- c
+ cmd
.flatMap(TraceUtil.withFunctionTrace(getStdout))
.flatMap((tCmd) => tCmd.traceScope(() => `Command = ${tCmd.get()}`))
.map((tCmd) => {
@@ -38,3 +40,20 @@ export const getStdout = (
)
.peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(CmdMetric)))
.get();
+
+export const getStdoutMany = (
+ cmds: ITraceable<Array<Command>, LogMetricTraceSupplier>,
+ options: Options = {},
+): Promise<IEither<Error, Array<string>>> =>
+ cmds
+ .coExtend((t) => t.get())
+ .reduce(
+ async (_result, tCmd) => {
+ const result = await _result;
+ return result.joinRightAsync(
+ () => tCmd.map((cmd) => getStdout(cmd, options)).get(),
+ (stdout, pre) => pre.concat(stdout),
+ );
+ },
+ Promise.resolve(Either.right<Error, Array<string>>([])),
+ );
diff --git a/u/process/index.ts b/u/process/index.ts
index 6945a0f..2d74a5f 100644
--- a/u/process/index.ts
+++ b/u/process/index.ts
@@ -1,5 +1,5 @@
+export * from './exec.js';
export * from './env.js';
-export * from './run.js';
export * from './validate_identifier.js';
export * from './argv.js';
export * from './signals.js';
diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts
index 9c33ad2..57c4419 100644
--- a/u/trace/itrace.ts
+++ b/u/trace/itrace.ts
@@ -28,8 +28,8 @@ export interface ITraceable<T, Trace = BaseTraceWith> {
readonly map: <_T>(mapper: ITraceableMapper<T, _T, Trace>) => ITraceable<_T, Trace>;
readonly bimap: <_T>(mapper: ITraceableMapper<T, ITraceableTuple<_T, Trace>, Trace>) => ITraceable<_T, Trace>;
readonly coExtend: <_T>(
- mapper: ITraceableMapper<T, ReadonlyArray<_T>, Trace>,
- ) => ReadonlyArray<ITraceable<_T, Trace>>;
+ mapper: ITraceableMapper<T, Array<_T>, Trace>,
+ ) => Array<ITraceable<_T, Trace>>;
readonly peek: (peek: ITraceableMapper<T, void, Trace>) => ITraceable<T, Trace>;
readonly traceScope: (mapper: ITraceableMapper<T, Trace, Trace>) => ITraceable<T, Trace>;
@@ -51,7 +51,7 @@ export class TraceableImpl<T, Trace> implements ITraceable<T, Trace> {
return new TraceableImpl(result, this.trace);
}
- public coExtend<_T>(mapper: ITraceableMapper<T, ReadonlyArray<_T>, Trace>): ReadonlyArray<ITraceable<_T, Trace>> {
+ public coExtend<_T>(mapper: ITraceableMapper<T, Array<_T>, Trace>): Array<ITraceable<_T, Trace>> {
const results = mapper(this);
return Array.from(results).map((result) => this.move(result));
}
diff --git a/u/types/fn/callable.ts b/u/types/fn/callable.ts
index 51756d7..60d747b 100644
--- a/u/types/fn/callable.ts
+++ b/u/types/fn/callable.ts
@@ -10,6 +10,8 @@ export interface Mapper<T, U> extends Callable<U, T> {
(t: T): U;
}
+export interface Predicate<T> extends Mapper<T, boolean> {}
+
export interface BiMapper<T, U, R> extends Callable {
(t: T, u: U): R;
}
diff --git a/u/types/fn/either.ts b/u/types/fn/either.ts
index aa67d41..80f32b4 100644
--- a/u/types/fn/either.ts
+++ b/u/types/fn/either.ts
@@ -1,18 +1,36 @@
-import { BiMapper, IOptional, type Mapper, Optional, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno';
+import {
+ BiMapper,
+ IOptional,
+ type Mapper,
+ Optional,
+ Predicate,
+ type Supplier,
+ Tagged,
+ isTagged,
+} from '@emprespresso/pengueno';
export const IEitherTag = 'IEither' as const;
export type IEitherTag = typeof IEitherTag;
export const isEither = <E, T>(o: unknown): o is IEither<E, T> => isTagged(o, IEitherTag);
export interface IEither<E, T> extends Tagged<IEitherTag> {
- readonly mapBoth: <_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>) => IEither<_E, _T>;
- readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T;
readonly left: Supplier<IOptional<E>>;
readonly right: Supplier<IOptional<T>>;
- readonly moveRight: <_T>(t: _T) => IEither<E, _T>;
+
readonly mapRight: <_T>(mapper: Mapper<T, _T>) => IEither<E, _T>;
+ readonly filter: (mapper: Predicate<T>) => IEither<E, T>;
readonly mapLeft: <_E>(mapper: Mapper<E, _E>) => IEither<_E, T>;
+ readonly mapBoth: <_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>) => IEither<_E, _T>;
+
readonly flatMap: <_T>(mapper: Mapper<T, IEither<E, _T>>) => IEither<E, _T>;
readonly flatMapAsync: <_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>) => Promise<IEither<E, _T>>;
+
+ readonly moveRight: <_T>(t: _T) => IEither<E, _T>;
+ readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T;
+ readonly joinRight: <O, _T>(other: IEither<E, O>, mapper: BiMapper<O, T, _T>) => IEither<E, _T>;
+ readonly joinRightAsync: <O, _T>(
+ other: Supplier<Promise<IEither<E, O>>> | Promise<IEither<E, O>>,
+ mapper: BiMapper<O, T, _T>,
+ ) => Promise<IEither<E, _T>>;
}
const ELeftTag = 'E.Left' as const;
@@ -62,6 +80,11 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> {
return Either.left<E, _T>(this.self.err);
}
+ public filter(mapper: Predicate<T>): IEither<E, T> {
+ if (isLeft(this.self)) return Either.left<E, T>(this.self.err);
+ return Either.fromFailable<E, T>(() => this.right().filter(mapper).get());
+ }
+
public async flatMapAsync<_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>): Promise<IEither<E, _T>> {
if (isLeft(this.self)) return Promise.resolve(Either.left(this.self.err));
return await mapper(this.self.ok).catch((err) => Either.left(err));
@@ -82,23 +105,18 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> {
return Optional.none();
}
- static joinRight<K, E, T>(
- arr: Array<K>,
- mapper: BiMapper<K, T, IEither<E, T>>,
- init: IEither<E, T>,
- ): IEither<E, T> {
- return arr.reduce((acc: IEither<E, T>, x: K) => acc.flatMap((t) => mapper(x, t)), init);
+ public joinRight<O, _T>(other: IEither<E, O>, mapper: BiMapper<O, T, _T>) {
+ return this.flatMap((t) => other.mapRight((o) => mapper(o, t)));
}
- static joinRightAsync<K, E, T>(
- arr: Array<K>,
- mapper: BiMapper<K, T, Promise<IEither<E, T>>>,
- init: IEither<E, T>,
- ): Promise<IEither<E, T>> {
- return arr.reduce(
- (acc: Promise<IEither<E, T>>, x: K) => acc.then((res) => res.flatMapAsync((t) => mapper(x, t))),
- Promise.resolve(init),
- );
+ public joinRightAsync<O, _T>(
+ other: Supplier<Promise<IEither<E, O>>> | Promise<IEither<E, O>>,
+ mapper: BiMapper<O, T, _T>,
+ ) {
+ return this.flatMapAsync(async (t) => {
+ const o = typeof other === 'function' ? other() : other;
+ return o.then((other) => other.mapRight((o) => mapper(o, t)));
+ });
}
static left<E, T>(e: E): IEither<E, T> {
diff --git a/u/types/fn/optional.ts b/u/types/fn/optional.ts
index 3396a45..504e496 100644
--- a/u/types/fn/optional.ts
+++ b/u/types/fn/optional.ts
@@ -1,4 +1,4 @@
-import { type Mapper, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno';
+import { type Mapper, Predicate, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno';
export type MaybeGiven<T> = T | undefined | null;
@@ -9,7 +9,7 @@ export class IOptionalEmptyError extends Error {}
export interface IOptional<t, T extends NonNullable<t> = NonNullable<t>> extends Tagged<IOptionalTag>, Iterable<T> {
readonly move: <_T>(t: MaybeGiven<_T>) => IOptional<_T>;
readonly map: <_T>(mapper: Mapper<T, MaybeGiven<_T>>) => IOptional<_T>;
- readonly filter: (mapper: Mapper<T, boolean>) => IOptional<T>;
+ readonly filter: (mapper: Predicate<T>) => IOptional<T>;
readonly flatMap: <_T>(mapper: Mapper<T, MaybeGiven<IOptional<_T>>>) => IOptional<_T>;
readonly orSome: (supplier: Supplier<MaybeGiven<t>>) => IOptional<T>;
readonly get: Supplier<T>;
@@ -48,11 +48,11 @@ export class Optional<t, T extends NonNullable<t> = NonNullable<t>> extends _Tag
}
public get(): T {
- if (isNone(this.self)) throw new IOptionalEmptyError('empty value');
+ if (isNone(this.self)) throw new IOptionalEmptyError('called get() on None optional');
return this.self.value;
}
- public filter(mapper: Mapper<T, boolean>): IOptional<T> {
+ public filter(mapper: Predicate<T>): IOptional<T> {
if (isNone(this.self) || !mapper(this.self.value)) return Optional.none();
return Optional.some(this.self.value);
}
diff --git a/u/types/index.ts b/u/types/index.ts
index c68cedc..fc1b15a 100644
--- a/u/types/index.ts
+++ b/u/types/index.ts
@@ -1,3 +1,5 @@
+export * from './misc.js';
+
export * from './object.js';
export * from './tagged.js';
diff --git a/u/types/misc.ts b/u/types/misc.ts
new file mode 100644
index 0000000..77833c4
--- /dev/null
+++ b/u/types/misc.ts
@@ -0,0 +1,3 @@
+export type ObjectFromList<T extends ReadonlyArray<string | number | symbol>, V = string> = {
+ [K in T extends ReadonlyArray<infer U> ? U : never]: V;
+};