@rimbu/stream
Version:
Efficient structure representing a sequence of elements, with powerful operations for TypeScript
471 lines • 24.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncTransformer = void 0;
var tslib_1 = require("tslib");
var common_1 = require("@rimbu/common");
var stream_1 = require("@rimbu/stream");
var async_1 = require("@rimbu/stream/async");
var AsyncTransformer;
(function (AsyncTransformer) {
var _this = this;
/**
* Returns an AsyncTransformer based on a given synchronous or asynchronous transformer.
* @param transformer - the transformer to convert
* @typeparam T - the input element type
* @typeparam R - the result stream element type
*/
function from(transformer) {
return async_1.AsyncReducer.from(transformer);
}
AsyncTransformer.from = from;
/**
* Returns an async transformer that produces windows/collections of `windowSize` size, each
* window starting `skipAmount` of elements after the previous, and optionally collected
* by a custom reducer.
* @typeparam T - the input element type
* @typeparam R - the window type
* @param windowSize - the amount of elements for each window
* @param options - (optional) object specifying the following properties<br/>
* - skipAmount: (default: `windowSize`) the amount of elements between the start of each window<br/>
* - collector: (default: Reducer.toArray()) the reducer to use to convert elements to windows
* @example
* ```ts
* await AsyncStream.of(1, 2, 3, 4, 5, 6)
* .transform(AsyncTransformer.window(3))
* .toArray()
* // => [[1, 2, 3], [4, 5, 6]]
* ```
*/
AsyncTransformer.window = function (windowSize, options) {
if (options === void 0) { options = {}; }
var _a = options.skipAmount, skipAmount = _a === void 0 ? windowSize : _a, _b = options.collector, collector = _b === void 0 ? stream_1.Reducer.toArray() : _b;
return async_1.AsyncReducer.create(function () { return new Set(); }, function (state, elem, index) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var state_1, state_1_1, instance, e_1_1, newInstance;
var e_1, _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_b.trys.push([0, 6, 7, 8]);
state_1 = tslib_1.__values(state), state_1_1 = state_1.next();
_b.label = 1;
case 1:
if (!!state_1_1.done) return [3 /*break*/, 5];
instance = state_1_1.value;
if (!(instance.index >= windowSize || instance.halted)) return [3 /*break*/, 2];
state.delete(instance);
return [3 /*break*/, 4];
case 2: return [4 /*yield*/, instance.next(elem)];
case 3:
_b.sent();
_b.label = 4;
case 4:
state_1_1 = state_1.next();
return [3 /*break*/, 1];
case 5: return [3 /*break*/, 8];
case 6:
e_1_1 = _b.sent();
e_1 = { error: e_1_1 };
return [3 /*break*/, 8];
case 7:
try {
if (state_1_1 && !state_1_1.done && (_a = state_1.return)) _a.call(state_1);
}
finally { if (e_1) throw e_1.error; }
return [7 /*endfinally*/];
case 8:
if (!(index % skipAmount === 0)) return [3 /*break*/, 11];
return [4 /*yield*/, async_1.AsyncReducer.from(collector).compile()];
case 9:
newInstance = _b.sent();
return [4 /*yield*/, newInstance.next(elem)];
case 10:
_b.sent();
state.add(newInstance);
_b.label = 11;
case 11: return [2 /*return*/, state];
}
});
}); }, function (state, _, halted) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
if (halted) {
return [2 /*return*/, async_1.AsyncStream.empty()];
}
return [2 /*return*/, async_1.AsyncStream.from(state).collect(function (instance, _, skip) {
return instance.index === windowSize ? instance.getOutput() : skip;
})];
});
}); });
};
/**
* Returns an async transformer that applies the given flatMap function to each element of the input stream,
* and concatenates all the resulting resulting streams into one stream.
* @typeparam T - the input element type
* @typeparam T2 - the output element type
* @param flatMapFun - a potentially async function that maps each input element to an `AsyncStreamSource`.
* The function receives three parameters:<br/>
* - `value`: the current element being processed<br/>
* - `index`: the index of the current element in the input stream<br/>
* - `halt`: a function that can be called to halt further processing of the input stream<br/>
*/
function flatMap(flatMapFun) {
return async_1.AsyncReducer.createOutput(function () { return async_1.AsyncStream.empty(); }, function (state, next, index, halt) { return flatMapFun(next, index, halt); }, function (state, _, halted) { return (halted ? async_1.AsyncStream.empty() : state); });
}
AsyncTransformer.flatMap = flatMap;
/**
* Returns an async transformer that applies the given flatMap function to each element of the input stream,
* and concatenates all the resulting resulting streams into one stream, where each resulting element is tupled
* with the originating input element.
* @typeparam T - the input element type
* @typeparam T2 - the output element type
* @param flatMapFun - a potentially async function that maps each input element to an `AsyncStreamSource`.
* The function receives three parameters:<br/>
* - `value`: the current element being processed<br/>
* - `index`: the index of the current element in the input stream<br/>
* - `halt`: a function that can be called to halt further processing of the input stream<br/>
*/
function flatZip(flatMapFun) {
var _this = this;
return flatMap(function (value, index, halt) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var _a, _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
_b = (_a = async_1.AsyncStream).from;
return [4 /*yield*/, flatMapFun(value, index, halt)];
case 1: return [2 /*return*/, _b.apply(_a, [_c.sent()]).mapPure(function (stream) { return [value, stream]; })];
}
});
}); });
}
AsyncTransformer.flatZip = flatZip;
/**
* Returns an async transformer that filters elements from the input stream based on the provided predicate function.
* @typeparam T - the type of elements in the input stream
* @param pred - a potentially async predicate function that determines whether an element should be included in the output stream, receiving:<br/>
* - `value`: the current element being processed<br/>
* - `index`: the index of the current element in the input stream<br/>
* - `halt`: a function that can be called to halt further processing of the input stream
* @param options - (optional) object specifying the following properties:<br/>
* - negate: (default: false) if true, the predicate will be negated
* @note if the predicate is a type guard, the return type is automatically inferred
*/
AsyncTransformer.filter = function (pred, options) {
if (options === void 0) { options = {}; }
var _a = options.negate, negate = _a === void 0 ? false : _a;
return flatMap(function (value, index, halt) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, pred(value, index, halt)];
case 1: return [2 /*return*/, (_a.sent()) !== negate
? async_1.AsyncStream.of(value)
: async_1.AsyncStream.empty()];
}
});
}); });
};
/**
* Returns an `AsyncTransformer` instance that converts or filters its input values using given `collectFun` before passing them to the reducer.
* @param collectFun - a potentially async function receiving the following arguments, and returns a new value or `skip` if the value should be skipped:<br/>
* - `value`: the next value<br/>
* - `index`: the value index<br/>
* - `skip`: a token that, when returned, will not add a value to the resulting collection<br/>
* - `halt`: a function that, when called, ensures no next elements are passed
* @typeparam T - the input element type
* @typeparam R - the result element type
*/
function collect(collectFun) {
var _this = this;
return flatMap(function (value, index, halt) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var result;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, collectFun(value, index, common_1.CollectFun.Skip, halt)];
case 1:
result = _a.sent();
return [2 /*return*/, common_1.CollectFun.Skip === result
? async_1.AsyncStream.empty()
: async_1.AsyncStream.of(result)];
}
});
}); });
}
AsyncTransformer.collect = collect;
/**
* Returns an `AsyncTransformer` that inserts the given `sep` stream source elements between each received input element.
* @param sep - the async StreamSource to insert between each received element
* @typeparam T - the input and output element type
*/
function intersperse(sep) {
return flatMap(function (value, index) {
return index === 0 ? async_1.AsyncStream.of(value) : async_1.AsyncStream.from(sep).append(value);
});
}
AsyncTransformer.intersperse = intersperse;
/**
* Returns an `AsyncTransformer` that outputs the index of each received element that satisfies the given predicate.
* @param pred - a potentially async predicate function taking an element
* @param options - (optional) object specifying the following properties<br/>
* - negate: (default: false) when true will negate the given predicate
* @typeparam T - the input element type
*/
function indicesWhere(pred, options) {
if (options === void 0) { options = {}; }
var _a = options.negate, negate = _a === void 0 ? false : _a;
return flatMap(function (value, index) {
return pred(value) !== negate ? async_1.AsyncStream.of(index) : async_1.AsyncStream.empty();
});
}
AsyncTransformer.indicesWhere = indicesWhere;
/**
* Returns an `AsyncTransformer` that applies the given `pred` function to each received element, and collects the received elements
* into a `collector` that will be returned as output every time the predicate returns true.
* @typeparam T - the input element type
* @typeparam R - the collector result type
* @param pred - a potentially async predicate function taking an element
* @param options - (optional) object specifying the following properties<br/>
* - negate: (default: false) when true will negate the given predicate<br/>
* - collector: (default: Reducer.toArray()) an AsyncReducer that can accept multiple values and reduce them into a single value of type `R`.
*/
function splitWhere(pred, options) {
var _this = this;
if (options === void 0) { options = {}; }
var _a = options.negate, negate = _a === void 0 ? false : _a, _b = options.collector, collector = _b === void 0 ? stream_1.Reducer.toArray() : _b;
return async_1.AsyncReducer.create(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = {};
return [4 /*yield*/, async_1.AsyncReducer.from(collector).compile()];
case 1: return [2 /*return*/, (_a.collection = _b.sent(),
_a.done = false,
_a)];
}
});
}); }, function (state, nextValue, index) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!state.done) return [3 /*break*/, 2];
state.done = false;
_a = state;
return [4 /*yield*/, async_1.AsyncReducer.from(collector).compile()];
case 1:
_a.collection = _b.sent();
_b.label = 2;
case 2: return [4 /*yield*/, pred(nextValue, index)];
case 3:
if (!((_b.sent()) === negate)) return [3 /*break*/, 5];
return [4 /*yield*/, state.collection.next(nextValue)];
case 4:
_b.sent();
return [3 /*break*/, 6];
case 5:
state.done = true;
_b.label = 6;
case 6: return [2 /*return*/, state];
}
});
}); }, function (state, _, halted) {
return state.done !== halted
? async_1.AsyncStream.of(state.collection.getOutput())
: async_1.AsyncStream.empty();
});
}
AsyncTransformer.splitWhere = splitWhere;
/**
* Returns an `AsyncTransformer` that collects the received elements
* into a `collector` that will be returned as output every time the input matches the given `sepElem` value.
* @typeparam T - the input element type
* @typeparam R - the collector result type
* @param pred - a potentially async predicate function taking an element
* @param options - (optional) object specifying the following properties<br/>
* - eq - (default: `Eq.objectIs`) the equality testing function
* - negate: (default: false) when true will negate the given predicate<br/>
* - collector: (default: Reducer.toArray()) an AsyncReducer that can accept multiple values and reduce them into a single value of type `R`.
*/
function splitOn(sepElem, options) {
var _this = this;
if (options === void 0) { options = {}; }
var _a = options.eq, eq = _a === void 0 ? common_1.Eq.objectIs : _a, _b = options.negate, negate = _b === void 0 ? false : _b, _c = options.collector, collector = _c === void 0 ? stream_1.Reducer.toArray() : _c;
return async_1.AsyncReducer.create(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = {};
return [4 /*yield*/, async_1.AsyncReducer.from(collector).compile()];
case 1: return [2 /*return*/, (_a.collection = _b.sent(),
_a.done = false,
_a)];
}
});
}); }, function (state, nextValue) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!state.done) return [3 /*break*/, 2];
state.done = false;
_a = state;
return [4 /*yield*/, async_1.AsyncReducer.from(collector).compile()];
case 1:
_a.collection = _b.sent();
_b.label = 2;
case 2:
if (!(eq(nextValue, sepElem) === negate)) return [3 /*break*/, 4];
return [4 /*yield*/, state.collection.next(nextValue)];
case 3:
_b.sent();
return [3 /*break*/, 5];
case 4:
state.done = true;
_b.label = 5;
case 5: return [2 /*return*/, state];
}
});
}); }, function (state, _, halted) {
return state.done !== halted
? async_1.AsyncStream.of(state.collection.getOutput())
: async_1.AsyncStream.empty();
});
}
AsyncTransformer.splitOn = splitOn;
/**
* Returns an `AsyncTransformer` that collects the received elements
* into a `collector` that will be returned as output every time the input matches the given `sepSlice` sequence of elements.
* @typeparam T - the input element type
* @typeparam R - the collector result type
* @param pred - a potentially async predicate function taking an element
* @param options - (optional) object specifying the following properties<br/>
* - eq - (default: `Eq.objectIs`) the equality testing function
* - collector: (default: Reducer.toArray()) an AsyncReducer that can accept multiple values and reduce them into a single value of type `R`.
*/
function splitOnSlice(sepSlice, options) {
var _this = this;
if (options === void 0) { options = {}; }
var _a = options.eq, eq = _a === void 0 ? common_1.Eq.objectIs : _a, _b = options.collector, collector = _b === void 0 ? stream_1.Reducer.toArray() : _b;
return async_1.AsyncReducer.create(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = {
done: false,
instances: new Map(),
buffer: []
};
return [4 /*yield*/, async_1.AsyncReducer.from(collector).compile()];
case 1: return [2 /*return*/, (_a.result = _b.sent(),
_a)];
}
});
}); }, function (state, nextValue) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var _a, _b, _c, _d, instance, startIndex, e_2_1, nextStartsWith;
var e_2, _e;
return tslib_1.__generator(this, function (_f) {
switch (_f.label) {
case 0:
if (!state.done) return [3 /*break*/, 2];
_a = state;
return [4 /*yield*/, async_1.AsyncReducer.from(collector).compile()];
case 1:
_a.result = _f.sent();
state.done = false;
_f.label = 2;
case 2:
_f.trys.push([2, 9, 10, 11]);
_b = tslib_1.__values(state.instances), _c = _b.next();
_f.label = 3;
case 3:
if (!!_c.done) return [3 /*break*/, 8];
_d = tslib_1.__read(_c.value, 2), instance = _d[0], startIndex = _d[1];
return [4 /*yield*/, instance.next(nextValue)];
case 4:
_f.sent();
if (instance.halted) {
state.instances.delete(instance);
}
return [4 /*yield*/, instance.getOutput()];
case 5:
if (!_f.sent()) return [3 /*break*/, 7];
state.done = true;
return [4 /*yield*/, async_1.AsyncStream.from(stream_1.Stream.fromArray(state.buffer, {
range: { end: [startIndex, false] },
})).forEachPure(state.result.next)];
case 6:
_f.sent();
state.buffer = [];
state.instances.clear();
return [2 /*return*/, state];
case 7:
_c = _b.next();
return [3 /*break*/, 3];
case 8: return [3 /*break*/, 11];
case 9:
e_2_1 = _f.sent();
e_2 = { error: e_2_1 };
return [3 /*break*/, 11];
case 10:
try {
if (_c && !_c.done && (_e = _b.return)) _e.call(_b);
}
finally { if (e_2) throw e_2.error; }
return [7 /*endfinally*/];
case 11: return [4 /*yield*/, async_1.AsyncReducer.startsWithSlice(sepSlice, {
eq: eq,
}).compile()];
case 12:
nextStartsWith = _f.sent();
return [4 /*yield*/, nextStartsWith.next(nextValue)];
case 13:
_f.sent();
return [4 /*yield*/, nextStartsWith.getOutput()];
case 14:
if (!_f.sent()) return [3 /*break*/, 16];
state.done = true;
return [4 /*yield*/, async_1.AsyncStream.from(state.buffer).forEachPure(state.result.next)];
case 15:
_f.sent();
state.buffer = [];
state.instances.clear();
return [2 /*return*/, state];
case 16:
if (!nextStartsWith.halted) {
state.instances.set(nextStartsWith, state.buffer.length);
}
_f.label = 17;
case 17:
if (!(state.instances.size === 0)) return [3 /*break*/, 19];
return [4 /*yield*/, state.result.next(nextValue)];
case 18:
_f.sent();
return [3 /*break*/, 20];
case 19:
state.buffer.push(nextValue);
_f.label = 20;
case 20: return [2 /*return*/, state];
}
});
}); }, function (state, _, halted) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (state.done === halted) {
return [2 /*return*/, async_1.AsyncStream.empty()];
}
if (!halted) return [3 /*break*/, 2];
return [4 /*yield*/, async_1.AsyncStream.from(state.buffer).forEachPure(state.result.next)];
case 1:
_a.sent();
state.buffer = [];
_a.label = 2;
case 2: return [2 /*return*/, async_1.AsyncStream.of(state.result.getOutput())];
}
});
}); });
}
AsyncTransformer.splitOnSlice = splitOnSlice;
})(AsyncTransformer || (exports.AsyncTransformer = AsyncTransformer = {}));
//# sourceMappingURL=async-transformer.cjs.map