UNPKG

ts-stream

Version:

Type-safe object streams with seamless support for backpressure, ending, and error handling

986 lines (985 loc) 45.8 kB
/** * Promise-based object stream with seamless support for back-pressure and error * handling, written in Typescript. * * Copyright (C) 2015 Martin Poelstra * License: MIT */ import BaseError from "./BaseError"; import { Transform } from "./Transform"; /** * Required methods for both readable and writable parts of a stream. */ export interface Common<T> { /** * Obtain a promise that resolves when all parts of a stream chain have * completely ended. * * Specifically: * - `end()` has been called (possibly with an Error), * - `ender` callback has run and its returned promise resolved, * - `end()`'s result parameter (if any) has been resolved. * * @return Promise resolved when stream chain has completely ended */ result(): Promise<void>; /** * Signal that the stream is aborted: it will no longer read incoming * elements and will no longer write elements except in the course of * processing any pending asynchronous reader callbacks (i.e. unresolved * Promises returned by `forEach()` or other stream iterators). Does not * end the stream. * * An upstream source can handle this `abort()` by catching the exception * from its own `aborted()` method--for example, to cancel pending fetch * operations, or close a continuous data stream. * * If the stream's `forEach()` function provided an `aborter` callback and * the stream is not yet ended, `aborter` will be called with the abort reason. * This can be used to cancel any remaining operations inside the asynchronous * reader callback. * * Once the last pending callback is resolved, any pending and future `write()`s * to this stream will be rejected with the error provided to `abort()`. * * It is still necessary to explicitly `end()` the stream, to ensure that any * resources can be cleaned up correctly both on the reader and writer side. * The stream's `ender` callback will be called with the abort error (i.e. any * error passed to `end()` is ignored.) * * The abort is ignored if the stream is already aborted. * * It's possible to abort an ended stream. This can be used to 'bubble' an * abort signal to other parts in a chain of streams which may not have ended * yet. It will not change the end-state of this part of the stream though. * * @param reason Optional Error value to signal a reason for the abort */ abort(reason?: Error): void; /** * Obtain promise that resolves to a rejection when `abort()` is called. * * Useful to pass abort to upstream sources. * * Note: this promise either stays pending, or is rejected. It is never * fulfilled. * * @return Promise that is rejected with abort error when stream is aborted */ aborted(): Promise<never>; /** * Obtain promise that resolves to a rejection when `abort()` is called. * * Useful to pass abort to upstream sources. * * Note: this promise either stays pending, or is rejected. It is never * fulfilled. * * @return Promise that is rejected with abort error when stream is aborted */ aborted(aborter: (reason: Error) => void): void; } /** * Required methods for the readable part of a stream. */ export interface Readable<T> extends Common<T> { /** * Read all values from stream, optionally waiting for explicit stream end. * * `reader` is called for every written value. * * `ender` is called once, when the writer `end()`s the stream, either with * or without an error. * * `reader` and `ender` callbacks can return a promise to indicate when the * value or end-of-stream condition has been completely processed. This * ensures that a fast writer can never overload a slow reader, and is * called 'backpressure'. * * The `reader` callback is never called while its previously returned * promise is still pending, and the `ender` callback is likewise only * called after all reads have completed. * * The corresponding `write()` or `end()` operation is blocked until the * value returned from the reader or ender callback is resolved. If the * callback throws an error or the returned promise resolves to a rejection, * the `write()` or `end()` will be rejected with it. * * All callbacks are always called asynchronously (i.e. some time after * `forEach()`, `write()`, `end()` or `abort()` returns), and their `this` * argument will be undefined. * * `aborter` is called once if the stream is aborted and has not ended yet. * (I.e. it will be called if e.g. `ender`'s returned promise is still * pending, to allow early termination, but it will no longer be called * if its promise has resolved). * * The `aborter` callback can be called while a reader callback's promise is * still pending, and should try to let `reader` or `ender` finish as fast * as possible. * * Note that even when a stream is aborted, it still needs to be `end()`'ed * correctly. * * If no `ender` is given, a default end handler is installed that directly * acknowledges the end-of-stream, also in case of an error. Note that that * error will still be returned from `forEach()`. * * If no `aborter` is given, an abort is ignored (but will still cause * further writes to fail, and it will be reflected in the returned promise). * * It is an error to call `forEach()` multiple times, and it is not possible * to 'detach' already attached callbacks. Reason is that the exact behaviour * of such actions (e.g. block or simply ignore further writes) is application * dependent, and should be implemented as a transform instead. * * The return value of `forEach()` is `result()`, a promise that resolves * when all parts in the stream(-chain) have completely finished. * * @param reader Callback called with every written value * @param ender Optional callback called when stream is ended * @param aborter Optional callback called when stream is aborted * @return Promise for completely finished stream, i.e. same promise as `result()` */ forEach(reader: (value: T) => void | PromiseLike<void>, ender?: (error?: Error) => void | PromiseLike<void>, aborter?: (error: Error) => void): Promise<void>; } /** * Required methods for the writable part of a stream. */ export interface Writable<T> extends Common<T> { /** * Write value (or promise for value) to stream. * * Writer is blocked until the value is read by the read handler passed to * `forEach()`, and the value returned by that read handler is resolved. * * It is an error to write an `undefined` value (as this is a common * programming error). Writing a promise for a void is currently allowed, * but discouraged. * * The promise returned by `write()` will be rejected with the same reason if: * - the written value is a PromiseLike that resolves to a rejection * - the read handler throws an error or returns a rejected promise * It is still possible to write another value after that, or e.g. `end()` * the stream with or without an error. * * @param value Value to write, or promise for it * @return Void-promise that resolves when value was processed by reader */ write(value: T | PromiseLike<T>): Promise<void>; /** * End the stream, optionally passing an error. * * Already pending writes will be processed by the reader passed to * `forEach()` before passing the end-of-stream to its end handler. * * The returned promise will resolve after the end handler has finished * processing. It is rejected if the end handler throws an error or returns * a rejected promise. * * All calls to `write()` or `end()` after the first `end()` will be * rejected with a `WriteAfterEndError`. * * By default, this stream's `result()` will be resolved when `end()` * resolves, or rejected with the error if `end()` is called with an error. * It is possible to let this stream's `result()` 'wait' until any upstream * streams have completed by e.g. passing that upstream's `result()` as the * second argument to `end()`. * * Note: even if a stream is aborted, it is still necessary to call `end()` * to allow any resources to correctly be cleaned up. * * @param error Optional Error to pass to `forEach()` end handler * @param result Optional promise that determines final value of `result()` * @return Void-promise that resolves when `ended`-handler has processed the * end-of-stream */ end(error?: Error, result?: PromiseLike<void>): Promise<void>; } export interface CommonStream<T> { /** * Determine whether `end()` has been called on the stream, but the stream * is still processing it. * * @return true when `end()` was called but not acknowledged yet, false * otherwise */ isEnding(): boolean; /** * Determine whether stream has completely ended (i.e. end handler has been * called and its return PromiseLike, if any, is resolved). * * @return true when stream has ended, false otherwise */ isEnded(): boolean; /** * Determine whether `end()` has been called on the stream. * * @return true when `end()` was called */ isEndingOrEnded(): boolean; /** * Determine whether `forEach()` callback(s) are currently attached to the * stream. * * @return true when `forEach()` has been called on this stream */ hasReader(): boolean; } /** * Readable part of a generic Stream, which contains handy helpers such as * .map() in addition to the basic requirements of a Readable interface. */ export interface ReadableStream<T> extends Readable<T>, CommonStream<T> { /** * Run all input values through a mapping callback, which must produce a new * value (or promise for a value), similar to e.g. `Array`'s `map()`. * * Stream end in the input stream (normal or with error) will be passed to * the output stream, after awaiting the result of the optional ender. * * Any error (thrown or rejection) in mapper or ender is returned to the * input stream. * * @param mapper Callback which receives each value from this stream, and * must produce a new value (or promise for a value) * @param ender Called when stream is ending, result is waited for before * passing on `end()` * @param aborter Called when stream is aborted * @return New stream with mapped values */ map<R>(mapper: (value: T) => R | PromiseLike<R>, ender?: (error?: Error) => void | PromiseLike<void>, aborter?: (error: Error) => void): ReadableStream<R>; /** * Run all input values through a filtering callback. If the filter callback * returns a truthy value (or a promise for a truthy value), the input value * is written to the output stream, otherwise it is ignored. * Similar to e.g. `Array`'s `filter()`. * * Stream end in the input stream (normal or with error) will be passed to * the output stream, after awaiting the result of the optional ender. * * Any error (thrown or rejection) in mapper or ender is returned to the * input stream. * * @param filterer Callback which receives each value from this stream, * input value is written to output if callback returns a * (promise for) a truthy value. * @param ender Called when stream is ending, result is waited for before * passing on `end()` * @param aborter Called when stream is aborted * @return New stream with filtered values. */ filter(filterer: (value: T) => boolean | PromiseLike<boolean>, ender?: (error?: Error) => void | PromiseLike<void>, aborter?: (error: Error) => void): ReadableStream<T>; /** * Reduce the stream into a single value by calling a reducer callback for * each value in the stream. Similar to `Array#reduce()`. * * The output of the previous call to `reducer` (aka `accumulator`) is given * as the first argument of the next call. For the first call, either the * `initial` value to `reduce()` is passed, or the first value of the stream * is used (and `current` will be the second value). * * The result of `reduce()` is a promise for the last value returned by * `reducer` (or the initial value, if there were no calls to `reducer`). * If no initial value could be determined, the result is rejected with a * TypeError. * If the stream is ended with an error, the result is rejected with that * error. * * It is possible for `reducer` to return a promise for its result. * * If the `reducer` throws an error or returns a rejected promise, the * originating `write()` will fail with that error. * * Examples: * s.reduce((acc, val) => acc + val); // sums all values * s.reduce((acc, val) => { acc.push(val); return acc; }, []); // toArray() * * @param reducer Callback called for each value in the stream, with * accumulator, current value, index of current value, and * this stream. * @param initial Optional initial value for accumulator. If no initial * value is given, first value of stream is used. * @return Promise for final accumulator. */ reduce(reducer: (accumulator: T, current: T, index: number, stream: ReadableStream<T>) => T | PromiseLike<T>, initial?: T): Promise<T>; /** * Reduce the stream into a single value by calling a reducer callback for * each value in the stream. Similar to `Array#reduce()`. * * The output of the previous call to `reducer` (aka `accumulator`) is given * as the first argument of the next call. For the first call, either the * `initial` value to `reduce()` is passed, or the first value of the stream * is used (and `current` will be the second value). * * The result of `reduce()` is a promise for the last value returned by * `reducer` (or the initial value, if there were no calls to `reducer`). * If no initial value could be determined, the result is rejected with a * TypeError. * If the stream is ended with an error, the result is rejected with that * error. * * It is possible for `reducer` to return a promise for its result. * * If the `reducer` throws an error or returns a rejected promise, the * originating `write()` will fail with that error. * * Examples: * s.reduce((acc, val) => acc + val); // sums all values * s.reduce((acc, val) => { acc.push(val); return acc; }, []); // toArray() * * @param reducer Callback called for each value in the stream, with * accumulator, current value, index of current value, and * this stream. * @param initial Optional initial value for accumulator. If no initial * value is given, first value of stream is used. * @return Promise for final accumulator. */ reduce<R>(reducer: (accumulator: R, current: T, index: number, stream: ReadableStream<T>) => PromiseLike<R>, initial: R): Promise<R>; /** * Reduce the stream into a single value by calling a reducer callback for * each value in the stream. Similar to `Array#reduce()`. * * The output of the previous call to `reducer` (aka `accumulator`) is given * as the first argument of the next call. For the first call, either the * `initial` value to `reduce()` is passed, or the first value of the stream * is used (and `current` will be the second value). * * The result of `reduce()` is a promise for the last value returned by * `reducer` (or the initial value, if there were no calls to `reducer`). * If no initial value could be determined, the result is rejected with a * TypeError. * If the stream is ended with an error, the result is rejected with that * error. * * It is possible for `reducer` to return a promise for its result. * * If the `reducer` throws an error or returns a rejected promise, the * originating `write()` will fail with that error. * * Examples: * s.reduce((acc, val) => acc + val); // sums all values * s.reduce((acc, val) => { acc.push(val); return acc; }, []); // toArray() * * @param reducer Callback called for each value in the stream, with * accumulator, current value, index of current value, and * this stream. * @param initial Optional initial value for accumulator. If no initial * value is given, first value of stream is used. * @return Promise for final accumulator. */ reduce<R>(reducer: (accumulator: R, current: T, index: number, stream: ReadableStream<T>) => R, initial: R): Promise<R>; /** * Read all stream values into an array. * * Returns a promise that resolves to that array if the stream ends * normally, or to the error if the stream is ended with an error. * * @return Promise for an array of all stream values */ toArray(): Promise<T[]>; /** * Read all values and end-of-stream from this stream, writing them to * `writable`. * * @param writable Destination stream * @return The stream passed in, for easy chaining */ pipe<R extends Writable<T>>(writable: R): R; /** * Return a new stream with the results of running the given * transform. * * @param transformer Function that receives this stream and result stream * as inputs. * @return Readable stream with the transformed results */ transform<R>(transformer: Transform<T, R>): ReadableStream<R>; } /** * Writable part of a generic Stream, which contains handy helpers such as * .mappedBy() in addition to the basic requirements of a Writable interface. */ export interface WritableStream<T> extends Writable<T>, CommonStream<T> { /** * Repeatedly call `writer` and write its returned value (or promise for it) * to the stream. * The stream is ended when `writer` returns `undefined` (or a promise that * resolves to `undefined`). * * `writer` is only called again when its previously returned value has been * processed by the stream. * * If writing of a value fails (either by the `writer` throwing an error, * returning a rejection, or the write call failing), the stream is aborted * and ended with that error. * * `ender` is always called once, just before the stream is ended. I.e. * after `writer` returned (a promise for) `undefined` or the stream is * aborted. * It can be used to e.g. close a resource such as a database. * Note: `ender` will only be called when `writer`'s promise (if any) has * resolved. * * `aborter` is called once iff the stream is aborted. It can be called * while e.g. a promise returned from the writer or ender is still pending, * and can be used to make sure that that promise is resolved/rejected * sooner. * Note: the aborter should be considered a 'signal to abort', but cleanup * of resources should be done in the `ender` (i.e. it cannot return a * promise). * It can be called (long) after `ender` has been called, because a stream * can be aborted even after it is already ended, which is useful if this * stream element is part of a larger chain of streams. * An aborter must never throw an error. * * @param writer Called when the next value can be written to the stream, * should return (a promise for) a value to be written, * or `undefined` (or void promise) to end the stream. * Will always be called asynchronously. * @param ender Optional callback called once after `writer` indicated * end-of-stream, or when the stream is aborted (and * previously written value resolved/rejected). It's called * without an argument if stream was not aborted (yet), and * the abort reason if it was aborted (`aborter` will have * been called, too). Will always be called asynchronously. * @param aborter Optional callback called once when stream is aborted. * Receives abort reason as its argument. Should be used * to prematurely terminate any pending promises of * `writer` or `ender`. Will always be called * asynchronously. Can be called before and after * `writer` or `ender` have been called, even when `ender` * is completely finished (useful to e.g. abort other streams, which may * not be aborted yet). * Must not throw any errors, will lead to unhandled * rejected promise if it does. * @return Promise for completely finished stream, i.e. same promise as `result()` */ writeEach(writer: () => T | undefined | void | PromiseLike<T | undefined | void>, ender?: (abortReason?: Error) => void | PromiseLike<void>, aborter?: (abortReason: Error) => void): Promise<void>; mappedBy<X>(mapper: (value: X) => T | PromiseLike<T>): WritableStream<X>; filterBy(filterer: (value: T) => boolean | PromiseLike<boolean>): WritableStream<T>; } /** * Used when writing to an already-ended stream. */ export declare class WriteAfterEndError extends BaseError { constructor(); } /** * Used when read callback(s) have already been attached. */ export declare class AlreadyHaveReaderError extends BaseError { constructor(); } /** * Object stream with seamless support for backpressure, ending and error * handling. */ export declare class Stream<T> implements ReadableStream<T>, WritableStream<T> { /** * Writers waiting for `_reader` to retrieve and process their value. */ private _writers; /** * Read handler that is called for every written value, as set by * `forEach()`. */ private _reader?; /** * End handler that is called when the stream is ended, as set by * `forEach()`. Note that `forEach()` installs a default handler if the user * did not supply one. * Set to 'undefined' when it has been called. */ private _ender?; /** * Abort handler that is called when the stream is aborted, as set by * `forEach()` (can be undefined). * Set to 'undefined' when it has been called. */ private _aborter?; /** * When a written value is being processed by the `_reader`, this property * is set to a promise that resolves when the reader's returned PromiseLike is * resolved (or rejected). */ private _readBusy?; /** * Set to an instance of an Eof object, containing optional error and final * result of this stream. Set when `end()` is called. */ private _ending?; /** * Set to an instance of an Eof object, containing optional error and final * result of this stream. Set when `_ender` is being called but not finished * yet, unset when `_ended` is set. */ private _endPending?; /** * Set to the error passed to `end()` (or the special value `eof`) when the * stream has ended, and the operation was confirmed by the `_ender`. */ private _ended?; /** * Set to a rejected promise when the stream is explicitly `abort()`'ed. */ private _abortPromise?; /** * Error given in abort() method */ private _abortReason?; /** * Resolved to a rejection when `abort()` is called. */ private _abortDeferred; /** * Resolved to the result of calling `_ender`, then the `result` property of * the end-of-stream value. */ private _resultDeferred; /** * Write value (or promise for value) to stream. * * Writer is blocked until the value is read by the read handler passed to * `forEach()`, and the value returned by that read handler is resolved. * * It is an error to write an `undefined` value (as this is a common * programming error). Writing a promise for a void is currently allowed, * but discouraged. * * The promise returned by `write()` will be rejected with the same reason if: * - the written value is a PromiseLike that resolves to a rejection * - the read handler throws an error or returns a rejected promise * It is still possible to write another value after that, or e.g. `end()` * the stream with or without an error. * * @param value Value to write, or promise for it * @return Void-promise that resolves when value was processed by reader */ write(value: T | PromiseLike<T>): Promise<void>; /** * End the stream, optionally passing an error. * * Already pending writes will be processed by the reader passed to * `forEach()` before passing the end-of-stream to its end handler. * * The returned promise will resolve after the end handler has finished * processing. It is rejected if the end handler throws an error or returns * a rejected promise. * * All calls to `write()` or `end()` after the first `end()` will be * rejected with a `WriteAfterEndError`. * * By default, this stream's `result()` will be resolved when `end()` * resolves, or rejected with the error if `end()` is called with an error. * It is possible to let this stream's `result()` 'wait' until any upstream * streams have completed by e.g. passing that upstream's `result()` as the * second argument to `end()`. * * Note: even if a stream is aborted, it is still necessary to call `end()` * to allow any resources to correctly be cleaned up. * * @param error Optional Error to pass to `forEach()` end handler * @param result Optional promise that determines final value of `result()` * @return Void-promise that resolves when `ended`-handler has processed the * end-of-stream */ end(error?: Error, endedResult?: PromiseLike<void>): Promise<void>; /** * Read all values from stream, optionally waiting for explicit stream end. * * `reader` is called for every written value. * * `ender` is called once, when the writer `end()`s the stream, either with * or without an error. * * `reader` and `ender` callbacks can return a promise to indicate when the * value or end-of-stream condition has been completely processed. This * ensures that a fast writer can never overload a slow reader, and is * called 'backpressure'. * * The `reader` callback is never called while its previously returned * promise is still pending, and the `ender` callback is likewise only * called after all reads have completed. * * The corresponding `write()` or `end()` operation is blocked until the * value returned from the reader or ender callback is resolved. If the * callback throws an error or the returned promise resolves to a rejection, * the `write()` or `end()` will be rejected with it. * * All callbacks are always called asynchronously (i.e. some time after * `forEach()`, `write()`, `end()` or `abort()` returns), and their `this` * argument will be undefined. * * `aborter` is called once if the stream is aborted and has not ended yet. * (I.e. it will be called if e.g. `ender`'s returned promise is still * pending, to allow early termination, but it will no longer be called * if its promise has resolved). * * The `aborter` callback can be called while a reader callback's promise is * still pending, and should try to let `reader` or `ender` finish as fast * as possible. * * Note that even when a stream is aborted, it still needs to be `end()`'ed * correctly. * * If no `ender` is given, a default end handler is installed that directly * acknowledges the end-of-stream, also in case of an error. Note that that * error will still be returned from `forEach()`. * * If no `aborter` is given, an abort is ignored (but will still cause * further writes to fail, and it will be reflected in the returned promise). * * It is an error to call `forEach()` multiple times, and it is not possible * to 'detach' already attached callbacks. Reason is that the exact behaviour * of such actions (e.g. block or simply ignore further writes) is application * dependent, and should be implemented as a transform instead. * * The return value of `forEach()` is `result()`, a promise that resolves * when all parts in the stream(-chain) have completely finished. * * @param reader Callback called with every written value * @param ender Optional callback called when stream is ended * @param aborter Optional callback called when stream is aborted * @return Promise for completely finished stream, i.e. same promise as `result()` */ forEach(reader: (value: T) => void | PromiseLike<void>, ender?: (error?: Error) => void | PromiseLike<void>, aborter?: (error: Error) => void): Promise<void>; /** * Signal that the stream is aborted: it will no longer read incoming * elements and will no longer write elements except in the course of * processing any pending asynchronous reader callbacks (i.e. unresolved * Promises returned by `forEach()` or other stream iterators). Does not * end the stream. * * An upstream source can handle this `abort()` by catching the exception * from its own `aborted()` method--for example, to cancel pending fetch * operations, or close a continuous data stream. * * If the stream's `forEach()` function provided an `aborter` callback and * the stream is not yet ended, `aborter` will be called with the abort reason. * This can be used to cancel any remaining operations inside the asynchronous * reader callback. * * Once the last pending callback is resolved, any pending and future `write()`s * to this stream will be rejected with the error provided to `abort()`. * * It is still necessary to explicitly `end()` the stream, to ensure that any * resources can be cleaned up correctly both on the reader and writer side. * The stream's `ender` callback will be called with the abort error (i.e. any * error passed to `end()` is ignored.) * * The abort is ignored if the stream is already aborted. * * It's possible to abort an ended stream. This can be used to 'bubble' an * abort signal to other parts in a chain of streams which may not have ended * yet. It will not change the end-state of this part of the stream though. * * @param reason Optional Error value to signal a reason for the abort */ abort(reason?: Error): void; /** * Obtain promise that resolves to a rejection when `abort()` is called. * * Useful to pass abort to up- and down-stream sources. * * Note: this promise either stays pending, or is rejected. It is never * fulfilled. * * @return Promise that is rejected with abort error when stream is aborted */ aborted(): Promise<never>; /** * Obtain a promise that resolves when the stream has completely ended: * - `end()` has been called (possibly with an Error), * - `ender` callback has run and its returned promise resolved, * - `end()`'s result parameter (if any) has been resolved. * * @return Promise resolved when stream has completely ended */ result(): Promise<void>; /** * Determine whether `end()` has been called on the stream, but the stream * is still processing it. * * @return true when `end()` was called but not acknowledged yet, false * otherwise */ isEnding(): boolean; /** * Determine whether stream has completely ended (i.e. end handler has been * called and its return PromiseLike, if any, is resolved). * @return true when stream has ended, false otherwise */ isEnded(): boolean; /** * Determine whether `end()` has been called on the stream. * * @return true when `end()` was called */ isEndingOrEnded(): boolean; /** * Determine whether `forEach()` callback(s) are currently attached to the * stream. * * @return true when `forEach()` has been called on this stream */ hasReader(): boolean; /** * Run all input values through a mapping callback, which must produce a new * value (or promise for a value), similar to e.g. `Array`'s `map()`. * * Stream end in the input stream (normal or with error) will be passed to * the output stream, after awaiting the result of the optional ender. * * Any error (thrown or rejection) in mapper or ender is returned to the * input stream. * * @param mapper Callback which receives each value from this stream, and * must produce a new value (or promise for a value) * @param ender Called when stream is ending, result is waited for before * passing on `end()` * @param aborter Called when stream is aborted * @return New stream with mapped values */ map<R>(mapper: (value: T) => R | PromiseLike<R>, ender?: (error?: Error) => void | PromiseLike<void>, aborter?: (error: Error) => void): ReadableStream<R>; /** * Run all input values through a filtering callback. If the filter callback * returns a truthy value (or a promise for a truthy value), the input value * is written to the output stream, otherwise it is ignored. * Similar to e.g. `Array`'s `filter()`. * * Stream end in the input stream (normal or with error) will be passed to * the output stream, after awaiting the result of the optional ender. * * Any error (thrown or rejection) in mapper or ender is returned to the * input stream. * * @param filterer Callback which receives each value from this stream, * input value is written to output if callback returns a * (promise for) a truthy value. * @param ender Called when stream is ending, result is waited for before * passing on `end()` * @param aborter Called when stream is aborted * @return New stream with filtered values. */ filter(filterer: (value: T) => boolean | PromiseLike<boolean>, ender?: (error?: Error) => void | PromiseLike<void>, aborter?: (error: Error) => void): ReadableStream<T>; /** * Reduce the stream into a single value by calling a reducer callback for * each value in the stream. Similar to `Array#reduce()`. * * The output of the previous call to `reducer` (aka `accumulator`) is given * as the first argument of the next call. For the first call, either the * `initial` value to `reduce()` is passed, or the first value of the stream * is used (and `current` will be the second value). * * The result of `reduce()` is a promise for the last value returned by * `reducer` (or the initial value, if there were no calls to `reducer`). * If no initial value could be determined, the result is rejected with a * TypeError. * If the stream is ended with an error, the result is rejected with that * error. * * It is possible for `reducer` to return a promise for its result. * * If the `reducer` throws an error or returns a rejected promise, the * originating `write()` will fail with that error. * * Examples: * s.reduce((acc, val) => acc + val); // sums all values * s.reduce((acc, val) => { acc.push(val); return acc; }, []); // toArray() * * @param reducer Callback called for each value in the stream, with * accumulator, current value, index of current value, and * this stream. * @param initial Optional initial value for accumulator. If no initial * value is given, first value of stream is used. * @return Promise for final accumulator. */ reduce(reducer: (accumulator: T, current: T, index: number, stream: ReadableStream<T>) => T | PromiseLike<T>, initial?: T): Promise<T>; /** * Reduce the stream into a single value by calling a reducer callback for * each value in the stream. Similar to `Array#reduce()`. * * The output of the previous call to `reducer` (aka `accumulator`) is given * as the first argument of the next call. For the first call, either the * `initial` value to `reduce()` is passed, or the first value of the stream * is used (and `current` will be the second value). * * The result of `reduce()` is a promise for the last value returned by * `reducer` (or the initial value, if there were no calls to `reducer`). * If no initial value could be determined, the result is rejected with a * TypeError. * If the stream is ended with an error, the result is rejected with that * error. * * It is possible for `reducer` to return a promise for its result. * * If the `reducer` throws an error or returns a rejected promise, the * originating `write()` will fail with that error. * * Examples: * s.reduce((acc, val) => acc + val); // sums all values * s.reduce((acc, val) => { acc.push(val); return acc; }, []); // toArray() * * @param reducer Callback called for each value in the stream, with * accumulator, current value, index of current value, and * this stream. * @param initial Optional initial value for accumulator. If no initial * value is given, first value of stream is used. * @return Promise for final accumulator. */ reduce<R>(reducer: (accumulator: R, current: T, index: number, stream: ReadableStream<T>) => PromiseLike<R>, initial: R): Promise<R>; /** * Read all stream values into an array. * * Returns a promise that resolves to that array if the stream ends * normally, or to the error if the stream is ended with an error. * * @return Promise for an array of all stream values */ toArray(): Promise<T[]>; /** * Read all values and end-of-stream from this stream, writing them to * `writable`. * * @param writable Destination stream * @return The stream passed in, for easy chaining */ pipe<R extends Writable<T>>(writable: R): R; /** * Return a new stream with the results of running the given * transform. * * @param transformer Function that receives this stream and result stream * as inputs. * @return Readable stream with the transformed results */ transform<R>(transformer: Transform<T, R>): ReadableStream<R>; /** * Repeatedly call `writer` and write its returned value (or promise for it) * to the stream. * The stream is ended when `writer` returns `undefined` (or a promise that * resolves to `undefined`). * * `writer` is only called again when its previously returned value has been * processed by the stream. * * If writing of a value fails (either by the `writer` throwing an error, * returning a rejection, or the write call failing), the stream is aborted * and ended with that error. * * `ender` is always called once, just before the stream is ended. I.e. * after `writer` returned (a promise for) `undefined` or the stream is * aborted. * It can be used to e.g. close a resource such as a database. * Note: `ender` will only be called when `writer`'s promise (if any) has * resolved. * * `aborter` is called once iff the stream is aborted. It can be called * while e.g. a promise returned from the writer or ender is still pending, * and can be used to make sure that that promise is resolved/rejected * sooner. * Note: the aborter should be considered a 'signal to abort', but cleanup * of resources should be done in the `ender` (i.e. it cannot return a * promise). * It can be called (long) after `ender` has been called, because a stream * can be aborted even after it is already ended, which is useful if this * stream element is part of a larger chain of streams. * An aborter must never throw an error. * * @param writer Called when the next value can be written to the stream, * should return (a promise for) a value to be written, * or `undefined` (or void promise) to end the stream. * Will always be called asynchronously. * @param ender Optional callback called once after `writer` indicated * end-of-stream, or when the stream is aborted (and * previously written value resolved/rejected). It's called * without an argument if stream was not aborted (yet), and * the abort reason if it was aborted (`aborter` will have * been called, too). Will always be called asynchronously. * @param aborter Optional callback called once when stream is aborted. * Receives abort reason as its argument. Should be used * to prematurely terminate any pending promises of * `writer` or `ender`. Will always be called * asynchronously. Can be called before and after * `writer` or `ender` have been called, even when `ender` * is completely finished (useful to e.g. abort other streams, which may * not be aborted yet). * Must not throw any errors, will lead to unhandled * rejected promise if it does. * @return Promise for completely finished stream, i.e. same promise as `result()` */ writeEach(writer: () => T | undefined | void | PromiseLike<T | undefined | void>, ender?: (abortReason?: Error) => void | PromiseLike<void>, aborter?: (abortReason: Error) => void): Promise<void>; mappedBy<X>(mapper: (value: X) => T | PromiseLike<T>): WritableStream<X>; filterBy(filterer: (value: T) => boolean | PromiseLike<boolean>): WritableStream<T>; /** * Return a Stream for all values in the input array. * * The stream is ended as soon as the first `undefined` value is * encountered. * * The array itself, and/or the values in the array may also be promises. * * @see result() to wait for completion * @see writeEach() for error handling behavior * * @param data (Promise for) input array of (promises for) values * @return Stream of all values in the input array */ static from<T>(data: PromiseLike<PromiseLike<T>[]>): ReadableStream<T>; /** * Return a Stream for all values in the input array. * * The stream is ended as soon as the first `undefined` value is * encountered. * * The array itself, and/or the values in the array may also be promises. * * @see result() to wait for completion * @see writeEach() for error handling behavior * * @param data (Promise for) input array of (promises for) values * @return Stream of all values in the input array */ static from<T>(data: PromiseLike<T>[]): ReadableStream<T>; /** * Return a Stream for all values in the input array. * * The stream is ended as soon as the first `undefined` value is * encountered. * * The array itself, and/or the values in the array may also be promises. * * @see result() to wait for completion * @see writeEach() for error handling behavior * * @param data (Promise for) input array of (promises for) values * @return Stream of all values in the input array */ static from<T>(data: PromiseLike<T[]>): ReadableStream<T>; /** * Return a Stream for all values in the input array. * * The stream is ended as soon as the first `undefined` value is * encountered. * * The array itself, and/or the values in the array may also be promises. * * @see result() to wait for completion * @see writeEach() for error handling behavior * * @param data (Promise for) input array of (promises for) values * @return Stream of all values in the input array */ static from<T>(data: T[]): ReadableStream<T>; /** * Bound callback to be passed as handlers to Promise.then() */ private _pumper; /** * Pump written values to `_reader` and `_ender`, resolve results of * `write()` and `end()`. */ private _pump; } export default Stream;