summaryrefslogtreecommitdiff
path: root/lib/trace/itrace.ts
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-07-27 17:03:10 -0700
committerElizabeth Hunt <me@liz.coffee>2025-07-27 18:30:30 -0700
commit9970036d203ba2d0a46b35ba6fad21d49441cdd4 (patch)
treea585d13933bf4149dcb07e28526063d071453105 /lib/trace/itrace.ts
downloadpengueno-9970036d203ba2d0a46b35ba6fad21d49441cdd4.tar.gz
pengueno-9970036d203ba2d0a46b35ba6fad21d49441cdd4.zip
hai
Diffstat (limited to 'lib/trace/itrace.ts')
-rw-r--r--lib/trace/itrace.ts91
1 files changed, 91 insertions, 0 deletions
diff --git a/lib/trace/itrace.ts b/lib/trace/itrace.ts
new file mode 100644
index 0000000..e2019fa
--- /dev/null
+++ b/lib/trace/itrace.ts
@@ -0,0 +1,91 @@
+import type { Mapper, SideEffect, Supplier } from '@emprespresso/pengueno';
+
+/**
+ * the "thing" every Trace writer must "trace()".
+ */
+type BaseTraceWith = string;
+export type ITraceWith<T> = BaseTraceWith | T;
+export interface ITrace<TraceWith> {
+ /**
+ * creates a new trace scope which inherits from this trace.
+ */
+ traceScope: Mapper<ITraceWith<TraceWith>, ITrace<TraceWith>>;
+
+ /**
+ * does the tracing.
+ */
+ trace: SideEffect<ITraceWith<TraceWith>>;
+}
+
+export type ITraceableTuple<T, TraceWith> = { item: T; trace: BaseTraceWith | TraceWith };
+export type ITraceableMapper<T, _T, TraceWith> = (w: ITraceable<T, TraceWith>) => _T;
+
+export interface ITraceable<T, Trace = BaseTraceWith> {
+ readonly trace: ITrace<Trace>;
+ readonly get: Supplier<T>;
+
+ readonly move: <_T>(t: _T) => ITraceable<_T, Trace>;
+ 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, 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>;
+
+ readonly flatMap: <_T>(mapper: ITraceableMapper<T, ITraceable<_T, Trace>, Trace>) => ITraceable<_T, Trace>;
+ readonly flatMapAsync: <_T>(
+ mapper: ITraceableMapper<T, Promise<ITraceable<_T, Trace>>, Trace>,
+ ) => ITraceable<Promise<_T>, Trace>;
+}
+
+export class TraceableImpl<T, Trace> implements ITraceable<T, Trace> {
+ protected constructor(
+ private readonly item: T,
+ public readonly trace: ITrace<Trace>,
+ ) {}
+
+ public map<_T>(mapper: ITraceableMapper<T, _T, Trace>) {
+ const result = mapper(this);
+ return new TraceableImpl(result, this.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));
+ }
+
+ public flatMap<_T>(mapper: ITraceableMapper<T, ITraceable<_T, Trace>, Trace>): ITraceable<_T, Trace> {
+ return mapper(this);
+ }
+
+ public flatMapAsync<_T>(
+ mapper: ITraceableMapper<T, Promise<ITraceable<_T, Trace>>, Trace>,
+ ): ITraceable<Promise<_T>, Trace> {
+ return new TraceableImpl(
+ mapper(this).then((t) => t.get()),
+ this.trace,
+ );
+ }
+
+ public traceScope(mapper: ITraceableMapper<T, Trace, Trace>): ITraceable<T, Trace> {
+ return new TraceableImpl(this.get(), this.trace.traceScope(mapper(this)));
+ }
+
+ public peek(peek: ITraceableMapper<T, void, Trace>) {
+ peek(this);
+ return this;
+ }
+
+ public move<_T>(t: _T): ITraceable<_T, Trace> {
+ return this.map(() => t);
+ }
+
+ public bimap<_T>(mapper: ITraceableMapper<T, ITraceableTuple<_T, Trace>, Trace>) {
+ const { item, trace: _trace } = mapper(this);
+ return this.move(item).traceScope(() => <Trace>_trace);
+ }
+
+ public get() {
+ return this.item;
+ }
+}