import { Actual } from "base/Actual"; import { Message } from "base/Message"; import { MessageType, MessageTypeValue } from "types/MessageType"; // eslint-disable-next-line @typescript-eslint/no-unused-vars type Last = T extends readonly [...infer _, infer L] ? L : never; /** * Chains messages together and triggers * the last message only when all previous messages * have emitted their values. The value of Chain will be the value * of the last message. If any messages * emit a value again after the overall Chain response was already returned, * then Chain emits again with the value of the last message. */ export function Chain(...messages: T) { const $messages = messages.map(Actual); return Message>>( function ChainImpl(resolve, reject) { let $latest: MessageTypeValue> | undefined; const handleMessage = (index: number) => { const message = $messages[index] as Last; message.catch(reject); const next = $messages[index + 1] as Last | undefined; message.then(function chainMessageSub(v) { oneMessage(v as MessageTypeValue>, next, index); }); }; function oneMessage( v: MessageTypeValue>, next: Last | undefined, index: number, ) { if (!next) { $latest = v as MessageTypeValue>; } if ($latest) { resolve($latest); } if (next && !$latest) { handleMessage(index + 1); } } handleMessage(0); }, ); }