UNPKG

@johngw/stream

Version:

Reactive programming tools using the WHATWG Streams API.

90 lines 3 kB
import { ControllableSource } from '@johngw/stream/sources/ControllableSource'; import { SourceComposite } from '@johngw/stream/sources/SourceComposite'; /** * A ForkableSink is the underlying logic for "1 Writable to many Readables". * * @group Sinks * @see {@link ForkableStream:class} * @example * ``` * const forkable = new ForkableStream<T>() * const writable = new WritableStream(forkable) * * fromCollection([1, 2, 3, 4, 5, 6, 7]).pipeTo(writable) * * forkable.fork().pipeTo(write(x => console.info('fork1', x))) * // fork1 1, fork1 2, fork1 3, fork1 4, fork1 5, fork1 6, fork1 7 * * forkable.fork().pipeTo(write(x => console.info('fork2', x))) * // fork2 1, fork2 2, fork2 3, fork2 4, fork2 5, fork2 6, fork2 7 * ``` */ export class ForkableSink { // eslint-disable-next-line @typescript-eslint/no-explicit-any #error; #finished = false; #controllers = new WeakMap(); #controllerSet = new Set(); abort(reason) { this.#forEachController((controller) => controller.error(reason)); this.#controllerSet.clear(); this.#controllers = new WeakMap(); this.#error = reason; this.#finished = true; } close() { this.#forEachController((controller) => { try { controller.close(); } catch (error) { // potentially already closed } }); this.#controllerSet.clear(); this.#controllers = new WeakMap(); this.#finished = true; } write(chunk) { this.#forEachController((controller) => controller.desiredSize && controller.enqueue(chunk)); } get finished() { return this.#finished; } fork(underlyingSource, queuingStrategy) { return this._pipeThroughController(this._addController(underlyingSource, queuingStrategy)); } #forEachController(fn) { for (const controller of this.#controllerSet) { const stream = this.#controllers.get(controller); if (stream) fn(controller, stream); } } _addController(underlyingSource, queuingStrategy) { const controller = new ControllableSource(); const stream = new ReadableStream(new SourceComposite([ controller, underlyingSource || {}, { cancel: () => { this.#controllers.delete(controller); this.#controllerSet.delete(controller); }, }, ]), queuingStrategy); if (!this.#finished) { this.#controllerSet.add(controller); this.#controllers.set(controller, stream); } return [controller, stream]; } _pipeThroughController([controller, stream]) { if (this.#error) controller.error(this.#error); else if (this.#finished) controller.close(); return stream; } } //# sourceMappingURL=ForkableSink.js.map