@johngw/stream
Version:
Reactive programming tools using the WHATWG Streams API.
94 lines • 3.18 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ForkableSink = void 0;
const ControllableSource_1 = require("@johngw/stream/sources/ControllableSource");
const SourceComposite_1 = require("@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
* ```
*/
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_1.ControllableSource();
const stream = new ReadableStream(new SourceComposite_1.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;
}
}
exports.ForkableSink = ForkableSink;
//# sourceMappingURL=ForkableSink.js.map