import { Rejections } from "base/Rejections"; import { Silence, SilenceUse } from "base/Silence"; import { Shared } from "components/Shared"; import { isFilled } from "helpers/guards"; import { ConstructorType } from "types/ConstructorType"; import { MessageType } from "types/MessageType"; import { MessageSourceType } from "types/SourceType"; /** * A component that allows creating linked objects of information and its owner * in such a way that if a new value is assigned to the owner, this value * will become the value of the linked information source * * @url https://silentium.pw/article/late/view */ export function Late(v?: T) { return Shared(new LateImpl(v)); } export class LateImpl implements MessageSourceType { private rejections = Rejections(); private lateR: ConstructorType<[T]> | null = null; private notify() { if (isFilled(this.v) && this.lateR) { try { this.lateR(this.v); } catch (e: any) { this.rejections.reject(e); } } } private silenceUse: ReturnType; public constructor(private v?: T) { this.silenceUse = SilenceUse(); } public then(r: ConstructorType<[T]>): this { if (this.lateR) { throw new Error( "Late component gets new resolver, when another was already connected!", ); } this.lateR = Silence(r); this.notify(); return this; } public use(value: T): this { const silenceUseLateExecutor = (v: unknown) => { this.v = v as T; this.notify(); }; this.silenceUse.use(value, silenceUseLateExecutor); return this; } public catch(rejected: ConstructorType<[unknown]>) { this.rejections.catch(rejected); return this; } public chain(m: MessageType) { return m.then(this.use.bind(this)); } public destroy() { this.lateR = null; return this; } }