import { Kind, UnaryFunction } from '@jamashita/anden-type'; import { MapPlan } from '@jamashita/genitore-plan'; import { Chrono } from '../Chrono'; import { containsError, isSuperposition, ISuperposition, SReturnType } from '../ISuperposition'; export class AlivePlan implements MapPlan> { private readonly mapper: UnaryFunction, SReturnType>; private readonly chrono: Chrono; public static of( mapper: UnaryFunction, SReturnType>, chrono: Chrono ): AlivePlan { return new AlivePlan(mapper, chrono); } protected constructor( mapper: UnaryFunction, SReturnType>, chrono: Chrono ) { this.mapper = mapper; this.chrono = chrono; } private forError(e: unknown): unknown { if (containsError(e, this.chrono.getErrors())) { return this.chrono.decline(e); } return this.chrono.throw(e); } private forOther(v: Exclude): unknown { if (v instanceof Error) { return this.forError(v); } return this.chrono.accept(v); } private forSuperposition(superposition: ISuperposition): unknown { this.chrono.catch([...this.chrono.getErrors(), ...superposition.getErrors()]); return superposition.pass( (v: Exclude) => { return this.chrono.accept(v); }, (e: E) => { return this.chrono.decline(e); }, (c: unknown) => { return this.chrono.throw(c); } ); } public onMap(value: Exclude): unknown { try { const mapped: SReturnType = this.mapper(value); if (isSuperposition(mapped)) { return this.forSuperposition(mapped); } if (Kind.isPromiseLike | ISuperposition>(mapped)) { return mapped.then( (v: Exclude | ISuperposition) => { if (isSuperposition(v)) { return this.forSuperposition(v); } return this.forOther(v); }, (e: unknown) => { return this.forError(e); } ); } return this.forOther(mapped); } catch (err: unknown) { return this.forError(err); } } }