@johngw/stream
Version:
Reactive programming tools using the WHATWG Streams API.
81 lines • 2.88 kB
JavaScript
import { ForkableStream } from '../sinks/ForkableStream.js';
import { ControllableStream } from '../sources/ControllableStream.js';
/**
* The base class for all subjects.
*
* @group Subjects
* @see {@link Subject:class}
* @see {@link StatefulSubject:class}
*/
export class Subject {
#controllable;
#controllers = new Set();
#forkable;
constructor(options = {}) {
const { pre = [], post = [], transform, pipeThroughOptions, pipeToOptions, } = options;
const controllable = 'controllable' in options && options.controllable
? options.controllable
: new ControllableStream(options.controllableStrategy);
const forkable = 'forkable' in options && options.forkable
? options.forkable
: new ForkableStream(options.forkableStrategy);
this.#controllable = controllable;
this.#forkable = forkable;
const inReadable = pre.reduce((readable, transform) => readable.pipeThrough(transform, pipeThroughOptions), controllable);
(transform
? post.reduce((readable, transform) => readable.pipeThrough(transform, pipeThroughOptions), inReadable.pipeThrough(transform, pipeThroughOptions))
: inReadable)
.pipeTo(this.forkable, pipeToOptions)
.catch(() => {
// errors can be handled in downstream forks
});
}
get controllable() {
return this.#controllable;
}
get finished() {
return this.#forkable.finished;
}
get forkable() {
return this.#forkable;
}
fork(underlyingSource, queuingStrategy) {
return this.#forkable.fork(underlyingSource, queuingStrategy);
}
write(queuingStrategy) {
const controller = this.control();
return new WritableStream({
abort(reason) {
controller.error(reason);
},
close() {
controller.close();
},
write(chunk) {
controller.enqueue(chunk);
},
}, queuingStrategy);
}
/**
* Returns a proxy to the ControllableStream. Once all proxies
* have been closed, then the source is also closed.
*/
control() {
const controller = new Proxy(this.#controllable, {
get: (target, prop) => {
if (prop === 'close')
return this.#closeController.bind(this, controller);
const value = target[prop];
return typeof value === 'function' ? value.bind(target) : value;
},
});
this.#controllers.add(controller);
return controller;
}
#closeController(controller) {
this.#controllers.delete(controller);
if (!this.#controllers.size)
this.#controllable.close();
}
}
//# sourceMappingURL=Subject.js.map