From 3a3fb9c8ab0c798a278f76d40de216fa96f6e2c4 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Wed, 14 May 2025 18:02:34 -0700 Subject: moar --- u/trace/itrace.ts | 68 +++++++++++++++++++++++++++++++++++++------------------ u/trace/logger.ts | 67 ++++++++++++++++++++++++++++++++---------------------- u/trace/trace.ts | 40 ++++++++++++++++++++------------ 3 files changed, 112 insertions(+), 63 deletions(-) (limited to 'u/trace') diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts index b483067..b9b750d 100644 --- a/u/trace/itrace.ts +++ b/u/trace/itrace.ts @@ -1,71 +1,95 @@ -import { Mapper, SideEffect } from "../fn/mod.ts"; +import type { Mapper, SideEffect } from "@emprespresso/pengueno"; -export interface ITrace { - addTrace: Mapper>; - trace: SideEffect; +// the "thing" every Trace writer must "trace()" +type BaseTraceWith = string; +export type ITraceWith = BaseTraceWith | T; +export interface ITrace { + addTrace: Mapper, ITrace>; + trace: SideEffect>; } -export type ITraceableTuple = [T, Trace]; -export type ITraceableMapper> = ( +export type ITraceableTuple = [T, BaseTraceWith | TraceWith]; +export type ITraceableMapper< + T, + U, + TraceWith, + W = ITraceable, +> = ( w: W, ) => U; -export interface ITraceable { +export interface ITraceable { readonly item: T; readonly trace: ITrace; move(u: U): ITraceable; map: ( - mapper: ITraceableMapper, + mapper: ITraceableMapper, ) => ITraceable; bimap: ( - mapper: ITraceableMapper>, + mapper: ITraceableMapper, Trace>, ) => ITraceable; - peek: (peek: ITraceableMapper) => ITraceable; + peek: (peek: ITraceableMapper) => ITraceable; flatMap: ( - mapper: ITraceableMapper>, + mapper: ITraceableMapper, Trace>, ) => ITraceable; flatMapAsync( - mapper: ITraceableMapper>>, + mapper: ITraceableMapper>, Trace>, ): ITraceable, Trace>; } -export class TraceableImpl implements ITraceable { +export class TraceableImpl implements ITraceable { protected constructor( readonly item: T, - readonly trace: ITrace, + readonly trace: ITrace, ) {} - public map(mapper: ITraceableMapper) { + public map( + mapper: ITraceableMapper, + ) { const result = mapper(this); return new TraceableImpl(result, this.trace); } public flatMap( - mapper: ITraceableMapper>, - ): ITraceable { + mapper: ITraceableMapper< + T, + ITraceable, + TraceWith + >, + ): ITraceable { return mapper(this); } public flatMapAsync( - mapper: ITraceableMapper>>, - ): ITraceable, L> { + mapper: ITraceableMapper< + T, + Promise>, + TraceWith + >, + ): ITraceable, TraceWith> { return new TraceableImpl( mapper(this).then(({ item }) => item), this.trace, ); } - public peek(peek: ITraceableMapper) { + public peek(peek: ITraceableMapper) { peek(this); return this; } - public move(t: Tt): ITraceable { + public move(t: Tt): ITraceable { return this.map(() => t); } - public bimap(mapper: ITraceableMapper>) { + public bimap( + mapper: ITraceableMapper< + T, + ITraceableTuple, + TraceWith + >, + ) { const [item, trace] = mapper(this); return new TraceableImpl(item, this.trace.addTrace(trace)); } diff --git a/u/trace/logger.ts b/u/trace/logger.ts index 79da367..4f3c856 100644 --- a/u/trace/logger.ts +++ b/u/trace/logger.ts @@ -1,10 +1,9 @@ import { isDebug, - isObject, type ITrace, type SideEffect, type Supplier, -} from "@emprespresso/utils"; +} from "@emprespresso/pengueno"; export interface ILogger { log: (...args: unknown[]) => void; @@ -12,74 +11,88 @@ export interface ILogger { warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void; } -export type ILoggerLevel = "UNKNOWN" | "INFO" | "WARN" | "DEBUG" | "ERROR"; -const logLevelOrder: Array = ["DEBUG", "INFO", "WARN", "ERROR"]; +export enum LogLevel { + UNKNOWN = "UNKNOWN", + INFO = "INFO", + WARN = "WARN", + DEBUG = "DEBUG", + ERROR = "ERROR", +} +const logLevelOrder: Array = [ + LogLevel.DEBUG, + LogLevel.INFO, + LogLevel.WARN, + LogLevel.ERROR, +]; +export const isLogLevel = (l: string): l is LogLevel => + logLevelOrder.some((level) => level === l); + const defaultAllowedLevels = () => [ - "UNKNOWN", - ...(isDebug() ? ["DEBUG"] : []), - "INFO", - "WARN", - "ERROR", - ] as Array; + LogLevel.UNKNOWN, + ...(isDebug() ? [LogLevel.DEBUG] : []), + LogLevel.INFO, + LogLevel.WARN, + LogLevel.ERROR, + ] as Array; export const logWithLevel = ( logger: ILogger, - level: ILoggerLevel, + level: LogLevel, ): SideEffect => { switch (level) { - case "UNKNOWN": - case "INFO": + case LogLevel.UNKNOWN: + case LogLevel.INFO: return logger.log; - case "DEBUG": + case LogLevel.DEBUG: return logger.debug; - case "WARN": + case LogLevel.WARN: return logger.warn; - case "ERROR": + case LogLevel.ERROR: return logger.error; } }; export const LoggerImpl = console; -export type LogTraceSupplier = string | Supplier | { - level: ILoggerLevel; -}; +export type LogTraceSupplier = string | Supplier; const foldTraces = (traces: Array) => { const { line, level } = traces.reduce( (acc: { line: string; level: number }, t) => { - if (isObject(t) && "level" in t) { + const val = typeof t === "function" ? t() : t; + if (isLogLevel(val)) { return { ...acc, - level: Math.max(logLevelOrder.indexOf(t.level), acc.level), + level: Math.max(logLevelOrder.indexOf(val), acc.level), }; } const prefix = [ acc.line, - typeof t === "function" ? t() : t, + val, ].join(" "); return { ...acc, prefix }; }, { line: "", level: -1 }, ); - return { line, level: logLevelOrder[level] ?? "UNKNOWN" }; + return { line, level: logLevelOrder[level] ?? LogLevel.UNKNOWN }; }; const defaultTrace = () => `[${new Date().toISOString()}]`; export const LogTrace = ( logger: ILogger, traces: Array = [defaultTrace], - allowedLevels: Supplier> = defaultAllowedLevels, - defaultLevel: ILoggerLevel = "INFO", + allowedLevels: Supplier> = defaultAllowedLevels, + defaultLevel: LogLevel = LogLevel.INFO, ): ITrace => { return { addTrace: (trace: LogTraceSupplier) => - LogTrace(logger, traces.concat(trace)), + LogTrace(logger, traces.concat(trace), allowedLevels, defaultLevel), trace: (trace: LogTraceSupplier) => { const { line, level: _level } = foldTraces(traces.concat(trace)); if (!allowedLevels().includes(_level)) return; - const level = _level === "UNKNOWN" ? defaultLevel : _level; + + const level = _level === LogLevel.UNKNOWN ? defaultLevel : _level; logWithLevel(logger, level)(`[${level}]${line}`); }, }; diff --git a/u/trace/trace.ts b/u/trace/trace.ts index 5d5c59b..1d3d2d8 100644 --- a/u/trace/trace.ts +++ b/u/trace/trace.ts @@ -1,31 +1,43 @@ -import type { Callable } from "@emprespresso/utils"; import { + type Callable, type ITraceableMapper, type ITraceableTuple, + LoggerImpl, + LogTrace, + type LogTraceSupplier, TraceableImpl, - TraceableLogger, -} from "./mod.ts"; +} from "@emprespresso/pengueno"; -export class Traceable extends TraceableImpl { +export class LogTraceable extends TraceableImpl { static from(t: T) { - return new Traceable(t, new TraceableLogger()); + return new LogTraceable(t, LogTrace(LoggerImpl)); } +} - static withFunctionTrace( +export class TraceUtil { + static withFunctionTrace( f: F, - ): ITraceableMapper> { - return (t) => [t.item, f.name]; + ): ITraceableMapper< + T, + ITraceableTuple, + Trace + > { + return (t) => [t.item, `[${f.name}]`]; } - static withClassTrace( + static withClassTrace( c: C, - ): ITraceableMapper> { - return (t) => [t.item, c.constructor.name]; + ): ITraceableMapper< + T, + ITraceableTuple, + Trace + > { + return (t) => [t.item, `[${c.constructor.name}]`]; } - static promiseify( - mapper: ITraceableMapper, - ): ITraceableMapper, TraceableLogger, Promise> { + static promiseify( + mapper: ITraceableMapper, + ): ITraceableMapper, Promise, Trace> { return (traceablePromise) => traceablePromise.flatMapAsync(async (t) => t.move(await t.item).map(mapper) -- cgit v1.2.3-70-g09d2