diff options
author | Elizabeth Hunt <me@liz.coffee> | 2025-07-27 17:03:10 -0700 |
---|---|---|
committer | Elizabeth Hunt <me@liz.coffee> | 2025-07-27 18:30:30 -0700 |
commit | 9970036d203ba2d0a46b35ba6fad21d49441cdd4 (patch) | |
tree | a585d13933bf4149dcb07e28526063d071453105 /lib/trace/itrace.ts | |
download | pengueno-9970036d203ba2d0a46b35ba6fad21d49441cdd4.tar.gz pengueno-9970036d203ba2d0a46b35ba6fad21d49441cdd4.zip |
hai
Diffstat (limited to 'lib/trace/itrace.ts')
-rw-r--r-- | lib/trace/itrace.ts | 91 |
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; + } +} |