@rimbu/common
Advanced tools
Comparing version 0.9.4 to 0.10.0
@@ -11,2 +11,3 @@ "use strict"; | ||
(function (AsyncReducer) { | ||
var _this = this; | ||
/** | ||
@@ -199,3 +200,561 @@ * A base class that can be used to easily create `AsyncReducer` instances. | ||
AsyncReducer.from = from; | ||
/** | ||
* A `Reducer` that sums all given numeric input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ amount: 5 }).reduce(Reducer.sum)) | ||
* // => 10 | ||
* ``` | ||
*/ | ||
AsyncReducer.sum = createMono(0, function (state, next) { return state + next; }); | ||
/** | ||
* A `Reducer` that calculates the product of all given numeric input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ start: 1, amount: 5 }).reduce(product)) | ||
* // => 120 | ||
* ``` | ||
*/ | ||
AsyncReducer.product = createMono(1, function (state, next, _, halt) { | ||
if (0 === next) | ||
halt(); | ||
return state * next; | ||
}); | ||
/** | ||
* A `Reducer` that calculates the average of all given numberic input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ amount: 5 }).reduce(Reducer.average)); | ||
* // => 2 | ||
* ``` | ||
*/ | ||
AsyncReducer.average = createMono(0, function (avg, value, index) { return avg + (value - avg) / (index + 1); }); | ||
/** | ||
* Returns a `Reducer` that remembers the minimum value of the inputs using the given `compFun` to compare input values | ||
* @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller | ||
* @param otherwise - (default: undefineds) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* const stream = Stream.of('abc', 'a', 'abcde', 'ab') | ||
* console.log(stream.minBy((s1, s2) => s1.length - s2.length)) | ||
* // 'a' | ||
* ``` | ||
*/ | ||
AsyncReducer.minBy = function (compFun, otherwise) { | ||
var token = Symbol(); | ||
return create(token, function (state, next) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (token === state) | ||
return [2 /*return*/, next]; | ||
return [4 /*yield*/, compFun(state, next)]; | ||
case 1: return [2 /*return*/, (_a.sent()) < 0 ? state : next]; | ||
} | ||
}); | ||
}); }, function (state) { | ||
return token === state ? internal_1.AsyncOptLazy.toMaybePromise(otherwise) : state; | ||
}); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the minimum value of the numberic inputs. | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.min())) | ||
* // => 3 | ||
* ``` | ||
*/ | ||
AsyncReducer.min = function (otherwise) { | ||
return create(undefined, function (state, next) { | ||
return undefined !== state && state < next ? state : next; | ||
}, function (state) { | ||
return state !== null && state !== void 0 ? state : internal_1.AsyncOptLazy.toMaybePromise(otherwise); | ||
}); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the maximum value of the inputs using the given `compFun` to compare input values | ||
* @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* const stream = Stream.of('abc', 'a', 'abcde', 'ab') | ||
* console.log(stream.maxBy((s1, s2) => s1.length - s2.length)) | ||
* // 'abcde' | ||
* ``` | ||
*/ | ||
AsyncReducer.maxBy = function (compFun, otherwise) { | ||
var token = Symbol(); | ||
return create(token, function (state, next) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (token === state) | ||
return [2 /*return*/, next]; | ||
return [4 /*yield*/, compFun(state, next)]; | ||
case 1: return [2 /*return*/, (_a.sent()) > 0 ? state : next]; | ||
} | ||
}); | ||
}); }, function (state) { | ||
return token === state ? internal_1.AsyncOptLazy.toMaybePromise(otherwise) : state; | ||
}); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the maximum value of the numberic inputs. | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.max())) | ||
* // => 7 | ||
* ``` | ||
*/ | ||
AsyncReducer.max = function (otherwise) { | ||
return create(undefined, function (state, next) { | ||
return undefined !== state && state > next ? state : next; | ||
}, function (state) { | ||
return state !== null && state !== void 0 ? state : internal_1.AsyncOptLazy.toMaybePromise(otherwise); | ||
}); | ||
}; | ||
/** | ||
* Returns a `Reducer` that joins the given input values into a string using the given options. | ||
* @param options - an object containing:<br/> | ||
* - sep: (optional) a seperator string value between values in the output<br/> | ||
* - start: (optional) a start string to prepend to the output<br/> | ||
* - end: (optional) an end string to append to the output<br/> | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(1, 2, 3).reduce(Reducer.join({ sep: '-' }))) | ||
* // => '1-2-3' | ||
* ``` | ||
*/ | ||
function join(_a) { | ||
var _b = _a === void 0 ? {} : _a, _c = _b.sep, sep = _c === void 0 ? '' : _c, _d = _b.start, start = _d === void 0 ? '' : _d, _e = _b.end, end = _e === void 0 ? '' : _e, _f = _b.valueToString, valueToString = _f === void 0 ? String : _f; | ||
var curSep = ''; | ||
var curStart = start; | ||
return create('', function (state, next) { | ||
var result = curStart.concat(state, curSep, valueToString(next)); | ||
curSep = sep; | ||
curStart = ''; | ||
return result; | ||
}, function (state) { return state.concat(end); }); | ||
} | ||
AsyncReducer.join = join; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the amount of input items provided. | ||
* @param pred - (optional) a predicate that returns false if the item should not be counted given:<br/> | ||
* - value: the current input value<br/> | ||
* - index: the input value index | ||
* @example | ||
* ```ts | ||
* const stream = AsyncStream.from(Stream.range({ amount: 10 })) | ||
* console.log(await stream.reduce(AsyncReducer.count())) | ||
* // => 10 | ||
* console.log(await stream.reduce(AsyncReducer.count(async v => v < 5))) | ||
* // => 5 | ||
* ``` | ||
*/ | ||
AsyncReducer.count = function (pred) { | ||
if (undefined === pred) | ||
return createMono(0, function (_, __, i) { return i + 1; }); | ||
return createOutput(0, function (state, next, i) { 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 === null || pred === void 0 ? void 0 : pred(next, i))]; | ||
case 1: | ||
if (_a.sent()) | ||
return [2 /*return*/, state + 1]; | ||
return [2 /*return*/, state]; | ||
} | ||
}); | ||
}); }); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the first input value for which the given `pred` function returns true. | ||
* @param pred - a function taking an input value and its index, and returning true if the value should be remembered | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value yet has satisfied the given predicate | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.firstWhere(async v => v > 5))) | ||
* // => 6 | ||
* ``` | ||
*/ | ||
AsyncReducer.firstWhere = function (pred, otherwise) { | ||
var token = Symbol(); | ||
return create(token, function (state, next, i, halt) { 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 = token === state; | ||
if (!_a) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, pred(next, i)]; | ||
case 1: | ||
_a = (_b.sent()); | ||
_b.label = 2; | ||
case 2: | ||
if (_a) { | ||
halt(); | ||
return [2 /*return*/, next]; | ||
} | ||
return [2 /*return*/, state]; | ||
} | ||
}); | ||
}); }, function (state) { | ||
return token === state ? internal_1.AsyncOptLazy.toMaybePromise(otherwise) : state; | ||
}); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the first input value. | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value has been provided | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.first()) | ||
* // => 0 | ||
* ``` | ||
*/ | ||
AsyncReducer.first = function (otherwise) { | ||
var token = Symbol(); | ||
return create(token, function (state, next, _, halt) { | ||
halt(); | ||
if (token === state) | ||
return next; | ||
return state; | ||
}, function (state) { | ||
return token === state ? internal_1.AsyncOptLazy.toMaybePromise(otherwise) : state; | ||
}); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the last input value for which the given `pred` function returns true. | ||
* @param pred - a function taking an input value and its index, and returning true if the value should be remembered | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value yet has satisfied the given predicate | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.lastWhere(async v => v > 5))) | ||
* // => 9 | ||
* ``` | ||
*/ | ||
AsyncReducer.lastWhere = function (pred, otherwise) { | ||
var token = Symbol(); | ||
return create(token, function (state, next, i) { 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(next, i)]; | ||
case 1: | ||
if (_a.sent()) | ||
return [2 /*return*/, next]; | ||
return [2 /*return*/, state]; | ||
} | ||
}); | ||
}); }, function (state) { | ||
return token === state ? internal_1.AsyncOptLazy.toMaybePromise(otherwise) : state; | ||
}); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the last input value. | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value has been provided | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.last()) | ||
* // => 9 | ||
* ``` | ||
*/ | ||
AsyncReducer.last = function (otherwise) { | ||
var token = Symbol(); | ||
return create(function () { return token; }, function (_, next) { return next; }, function (state) { | ||
return token === state ? internal_1.AsyncOptLazy.toMaybePromise(otherwise) : state; | ||
}); | ||
}; | ||
/** | ||
* Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.some(async v => v > 5)) | ||
* // => true | ||
* ``` | ||
*/ | ||
function some(pred) { | ||
var _this = this; | ||
return createOutput(false, function (state, next, i, halt) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var satisfies; | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (state) | ||
return [2 /*return*/, state]; | ||
return [4 /*yield*/, pred(next, i)]; | ||
case 1: | ||
satisfies = _a.sent(); | ||
if (satisfies) { | ||
halt(); | ||
} | ||
return [2 /*return*/, satisfies]; | ||
} | ||
}); | ||
}); }); | ||
} | ||
AsyncReducer.some = some; | ||
/** | ||
* Returns an `AsyncReducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.every(async v => v < 5)) | ||
* // => false | ||
* ``` | ||
*/ | ||
function every(pred) { | ||
var _this = this; | ||
return createOutput(true, function (state, next, i, halt) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var satisfies; | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!state) | ||
return [2 /*return*/, state]; | ||
return [4 /*yield*/, pred(next, i)]; | ||
case 1: | ||
satisfies = _a.sent(); | ||
if (!satisfies) { | ||
halt(); | ||
} | ||
return [2 /*return*/, satisfies]; | ||
} | ||
}); | ||
}); }); | ||
} | ||
AsyncReducer.every = every; | ||
/** | ||
* Returns an `AsyncReducer` that outputs false as long as the given `elem` has not been encountered in the input values, true otherwise. | ||
* @typeparam T - the element type | ||
* @param elem - the element to search for | ||
* @param eq - (optional) a comparison function that returns true if te two given input values are considered equal | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.contains(5))) | ||
* // => true | ||
* ``` | ||
*/ | ||
function contains(elem, eq) { | ||
if (eq === void 0) { eq = Object.is; } | ||
return createOutput(false, function (state, next, _, halt) { | ||
if (state) | ||
return state; | ||
var satisfies = eq(next, elem); | ||
if (satisfies) { | ||
halt(); | ||
} | ||
return satisfies; | ||
}); | ||
} | ||
AsyncReducer.contains = contains; | ||
/** | ||
* Returns an `AsyncReducer` that takes boolean values and outputs true if all input values are true, and false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(true, false, true)).reduce(AsyncReducer.and)) | ||
* // => false | ||
* ``` | ||
*/ | ||
AsyncReducer.and = createMono(true, function (state, next, _, halt) { | ||
if (!state) | ||
return state; | ||
if (!next) | ||
halt(); | ||
return next; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that takes boolean values and outputs true if one or more input values are true, and false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(true, false, true)).reduce(AsyncReducer.or)) | ||
* // => true | ||
* ``` | ||
*/ | ||
AsyncReducer.or = createMono(false, function (state, next, _, halt) { | ||
if (state) | ||
return state; | ||
if (next) | ||
halt(); | ||
return next; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that outputs true if no input values are received, false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.isEmpty)) | ||
* // => false | ||
* ``` | ||
*/ | ||
AsyncReducer.isEmpty = createOutput(true, function (_, __, ___, halt) { | ||
halt(); | ||
return false; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that outputs true if one or more input values are received, false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.nonEmpty)) | ||
* // => true | ||
* ``` | ||
*/ | ||
AsyncReducer.nonEmpty = createOutput(false, function (_, __, ___, halt) { | ||
halt(); | ||
return true; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that collects received input values in an array, and returns a copy of that array as an output value when requested. | ||
* @typeparam T - the element type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.toArray())) | ||
* // => [1, 2, 3] | ||
* ``` | ||
*/ | ||
function toArray() { | ||
return create(function () { return []; }, function (state, next) { | ||
state.push(next); | ||
return state; | ||
}, function (state) { return state.slice(); }); | ||
} | ||
AsyncReducer.toArray = toArray; | ||
/** | ||
* Returns a `AsyncReducer` that collects received input tuples into a mutable JS Map, and returns | ||
* a copy of that map when output is requested. | ||
* @typeparam K - the map key type | ||
* @typeparam V - the map value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of([1, 'a'], [2, 'b']).reduce(AsyncReducer.toJSMap())) | ||
* // Map { 1 => 'a', 2 => 'b' } | ||
* ``` | ||
*/ | ||
function toJSMap() { | ||
return create(function () { return new Map(); }, function (state, next) { | ||
state.set(next[0], next[1]); | ||
return state; | ||
}, function (s) { return new Map(s); }); | ||
} | ||
AsyncReducer.toJSMap = toJSMap; | ||
/** | ||
* Returns an `AsyncReducer` that collects received input values into a mutable JS Set, and returns | ||
* a copy of that map when output is requested. | ||
* @typeparam T - the element type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.toJSSet())) | ||
* // Set {1, 2, 3} | ||
* ``` | ||
*/ | ||
function toJSSet() { | ||
return create(function () { return new Set(); }, function (state, next) { | ||
state.add(next); | ||
return state; | ||
}, function (s) { return new Set(s); }); | ||
} | ||
AsyncReducer.toJSSet = toJSSet; | ||
/** | ||
* Returns an `AsyncReducer` that collects 2-tuples containing keys and values into a plain JS object, and | ||
* returns a copy of that object when output is requested. | ||
* @typeparam K - the result object key type | ||
* @typeparam V - the result object value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(['a', 1], ['b', true]).reduce(AsyncReducer.toJSObject())) | ||
* // { a: 1, b: true } | ||
* ``` | ||
*/ | ||
function toJSObject() { | ||
return create(function () { return ({}); }, function (state, entry) { | ||
state[entry[0]] = entry[1]; | ||
return state; | ||
}, function (s) { return (tslib_1.__assign({}, s)); }); | ||
} | ||
AsyncReducer.toJSObject = toJSObject; | ||
/** | ||
* Returns a `Reducer` that combines multiple input `reducers` by providing input values to all of them and collecting the outputs in an array. | ||
* @param reducers - 2 or more reducers to combine | ||
* @example | ||
* ```ts | ||
* const red = Reducer.combine(Reducer.sum, Reducer.average) | ||
* console.log(Stream.range({amount: 9 }).reduce(red)) | ||
* // => [36, 4] | ||
* ``` | ||
*/ | ||
function combine() { | ||
var _this = this; | ||
var reducers = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
reducers[_i] = arguments[_i]; | ||
} | ||
var createState = function () { | ||
return Promise.all(reducers.map(function (reducer) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var result; | ||
var _a; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_a = { | ||
reducer: reducer, | ||
halted: false, | ||
halt: function () { | ||
result.halted = true; | ||
} | ||
}; | ||
return [4 /*yield*/, internal_1.AsyncOptLazy.toMaybePromise(reducer.init)]; | ||
case 1: | ||
result = (_a.state = _b.sent(), | ||
_a); | ||
return [2 /*return*/, result]; | ||
} | ||
}); | ||
}); })); | ||
}; | ||
return create(createState, function (allState, next, index, halt) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var anyNotHalted; | ||
var _this = this; | ||
return tslib_1.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
anyNotHalted = false; | ||
return [4 /*yield*/, Promise.all(allState.map(function (red) { 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 (red.halted) | ||
return [2 /*return*/]; | ||
_a = red; | ||
return [4 /*yield*/, red.reducer.next(red.state, next, index, red.halt)]; | ||
case 1: | ||
_a.state = _b.sent(); | ||
if (!red.halted) | ||
anyNotHalted = true; | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }))]; | ||
case 1: | ||
_a.sent(); | ||
if (!anyNotHalted) | ||
halt(); | ||
return [2 /*return*/, allState]; | ||
} | ||
}); | ||
}); }, function (allState) { | ||
return Promise.all(allState.map(function (st) { return st.reducer.stateToResult(st.state); })); | ||
}); | ||
} | ||
AsyncReducer.combine = combine; | ||
})(AsyncReducer = exports.AsyncReducer || (exports.AsyncReducer = {})); | ||
//# sourceMappingURL=async-reducer.js.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Reducer = void 0; | ||
var tslib_1 = require("tslib"); | ||
var internal_1 = require("./internal"); | ||
@@ -11,12 +12,2 @@ function identity(value) { | ||
/** | ||
* Returns the contained value for an `Init` instance. | ||
* @param init - the `Init` value container | ||
*/ | ||
function Init(init) { | ||
if (init instanceof Function) | ||
return init(); | ||
return init; | ||
} | ||
Reducer.Init = Init; | ||
/** | ||
* A base class that can be used to easily create `Reducer` instances. | ||
@@ -37,3 +28,3 @@ * @typeparam I - the input value type | ||
nextIndex: 0, | ||
state: Init(_this.init), | ||
state: (0, internal_1.OptLazy)(_this.init), | ||
}); }, function (state, elem, index, halt) { | ||
@@ -56,3 +47,3 @@ if (pred(elem, index, halt)) { | ||
nextIndex: 0, | ||
state: Init(_this.init), | ||
state: (0, internal_1.OptLazy)(_this.init), | ||
}); }, function (state, elem, index, halt) { | ||
@@ -393,4 +384,4 @@ var nextElem = collectFun(elem, index, internal_1.CollectFun.Skip, halt); | ||
* ```ts | ||
* console.log(Stream.range{ amount: 10 }).reduce(Reducer.first()) | ||
* // => 0 | ||
* console.log(Stream.range{ amount: 10 }).reduce(Reducer.last()) | ||
* // => 9 | ||
* ``` | ||
@@ -400,6 +391,7 @@ */ | ||
var token = Symbol(); | ||
return create(token, function (_, next) { return next; }, function (state) { return (token === state ? (0, internal_1.OptLazy)(otherwise) : state); }); | ||
return create(function () { return token; }, function (_, next) { return next; }, function (state) { return (token === state ? (0, internal_1.OptLazy)(otherwise) : state); }); | ||
}; | ||
/** | ||
* Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
@@ -426,2 +418,3 @@ * @example | ||
* Returns a `Reducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
@@ -448,2 +441,3 @@ * @example | ||
* Returns a `Reducer` that outputs false as long as the given `elem` has not been encountered in the input values, true otherwise. | ||
* @typeparam T - the element type | ||
* @param elem - the element to search for | ||
@@ -526,2 +520,3 @@ * @param eq - (optional) a comparison function that returns true if te two given input values are considered equal | ||
* Returns a `Reducer` that collects received input values in an array, and returns a copy of that array as an output value when requested. | ||
* @typeparam T - the element type | ||
* @example | ||
@@ -543,2 +538,4 @@ * ```ts | ||
* a copy of that map when output is requested. | ||
* @typeparam K - the map key type | ||
* @typeparam V - the map value type | ||
* @example | ||
@@ -560,2 +557,3 @@ * ```ts | ||
* a copy of that map when output is requested. | ||
* @typeparam T - the element type | ||
* @example | ||
@@ -575,2 +573,20 @@ * ```ts | ||
/** | ||
* Returns a `Reducer` that collects 2-tuples containing keys and values into a plain JS object, and | ||
* returns a copy of that object when output is requested. | ||
* @typeparam K - the result object key type | ||
* @typeparam V - the result object value type | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(['a', 1], ['b', true]).reduce(Reducer.toJSObject())) | ||
* // { a: 1, b: true } | ||
* ``` | ||
*/ | ||
function toJSObject() { | ||
return create(function () { return ({}); }, function (state, entry) { | ||
state[entry[0]] = entry[1]; | ||
return state; | ||
}, function (s) { return (tslib_1.__assign({}, s)); }); | ||
} | ||
Reducer.toJSObject = toJSObject; | ||
/** | ||
* Returns a `Reducer` that combines multiple input `reducers` by providing input values to all of them and collecting the outputs in an array. | ||
@@ -598,3 +614,3 @@ * @param reducers - 2 or more reducers to combine | ||
}, | ||
state: Init(reducer.init), | ||
state: (0, internal_1.OptLazy)(reducer.init), | ||
}; | ||
@@ -601,0 +617,0 @@ return result; |
@@ -139,3 +139,448 @@ import { __awaiter } from "tslib"; | ||
AsyncReducer.from = from; | ||
/** | ||
* A `Reducer` that sums all given numeric input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ amount: 5 }).reduce(Reducer.sum)) | ||
* // => 10 | ||
* ``` | ||
*/ | ||
AsyncReducer.sum = createMono(0, (state, next) => state + next); | ||
/** | ||
* A `Reducer` that calculates the product of all given numeric input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ start: 1, amount: 5 }).reduce(product)) | ||
* // => 120 | ||
* ``` | ||
*/ | ||
AsyncReducer.product = createMono(1, (state, next, _, halt) => { | ||
if (0 === next) | ||
halt(); | ||
return state * next; | ||
}); | ||
/** | ||
* A `Reducer` that calculates the average of all given numberic input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ amount: 5 }).reduce(Reducer.average)); | ||
* // => 2 | ||
* ``` | ||
*/ | ||
AsyncReducer.average = createMono(0, (avg, value, index) => avg + (value - avg) / (index + 1)); | ||
/** | ||
* Returns a `Reducer` that remembers the minimum value of the inputs using the given `compFun` to compare input values | ||
* @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller | ||
* @param otherwise - (default: undefineds) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* const stream = Stream.of('abc', 'a', 'abcde', 'ab') | ||
* console.log(stream.minBy((s1, s2) => s1.length - s2.length)) | ||
* // 'a' | ||
* ``` | ||
*/ | ||
AsyncReducer.minBy = (compFun, otherwise) => { | ||
const token = Symbol(); | ||
return create(token, (state, next) => __awaiter(this, void 0, void 0, function* () { | ||
if (token === state) | ||
return next; | ||
return (yield compFun(state, next)) < 0 ? state : next; | ||
}), (state) => token === state ? AsyncOptLazy.toMaybePromise(otherwise) : state); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the minimum value of the numberic inputs. | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.min())) | ||
* // => 3 | ||
* ``` | ||
*/ | ||
AsyncReducer.min = (otherwise) => { | ||
return create(undefined, (state, next) => undefined !== state && state < next ? state : next, (state) => state !== null && state !== void 0 ? state : AsyncOptLazy.toMaybePromise(otherwise)); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the maximum value of the inputs using the given `compFun` to compare input values | ||
* @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* const stream = Stream.of('abc', 'a', 'abcde', 'ab') | ||
* console.log(stream.maxBy((s1, s2) => s1.length - s2.length)) | ||
* // 'abcde' | ||
* ``` | ||
*/ | ||
AsyncReducer.maxBy = (compFun, otherwise) => { | ||
const token = Symbol(); | ||
return create(token, (state, next) => __awaiter(this, void 0, void 0, function* () { | ||
if (token === state) | ||
return next; | ||
return (yield compFun(state, next)) > 0 ? state : next; | ||
}), (state) => token === state ? AsyncOptLazy.toMaybePromise(otherwise) : state); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the maximum value of the numberic inputs. | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.max())) | ||
* // => 7 | ||
* ``` | ||
*/ | ||
AsyncReducer.max = (otherwise) => { | ||
return create(undefined, (state, next) => undefined !== state && state > next ? state : next, (state) => state !== null && state !== void 0 ? state : AsyncOptLazy.toMaybePromise(otherwise)); | ||
}; | ||
/** | ||
* Returns a `Reducer` that joins the given input values into a string using the given options. | ||
* @param options - an object containing:<br/> | ||
* - sep: (optional) a seperator string value between values in the output<br/> | ||
* - start: (optional) a start string to prepend to the output<br/> | ||
* - end: (optional) an end string to append to the output<br/> | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(1, 2, 3).reduce(Reducer.join({ sep: '-' }))) | ||
* // => '1-2-3' | ||
* ``` | ||
*/ | ||
function join({ sep = '', start = '', end = '', valueToString = String, } = {}) { | ||
let curSep = ''; | ||
let curStart = start; | ||
return create('', (state, next) => { | ||
const result = curStart.concat(state, curSep, valueToString(next)); | ||
curSep = sep; | ||
curStart = ''; | ||
return result; | ||
}, (state) => state.concat(end)); | ||
} | ||
AsyncReducer.join = join; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the amount of input items provided. | ||
* @param pred - (optional) a predicate that returns false if the item should not be counted given:<br/> | ||
* - value: the current input value<br/> | ||
* - index: the input value index | ||
* @example | ||
* ```ts | ||
* const stream = AsyncStream.from(Stream.range({ amount: 10 })) | ||
* console.log(await stream.reduce(AsyncReducer.count())) | ||
* // => 10 | ||
* console.log(await stream.reduce(AsyncReducer.count(async v => v < 5))) | ||
* // => 5 | ||
* ``` | ||
*/ | ||
AsyncReducer.count = (pred) => { | ||
if (undefined === pred) | ||
return createMono(0, (_, __, i) => i + 1); | ||
return createOutput(0, (state, next, i) => __awaiter(this, void 0, void 0, function* () { | ||
if (yield (pred === null || pred === void 0 ? void 0 : pred(next, i))) | ||
return state + 1; | ||
return state; | ||
})); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the first input value for which the given `pred` function returns true. | ||
* @param pred - a function taking an input value and its index, and returning true if the value should be remembered | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value yet has satisfied the given predicate | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.firstWhere(async v => v > 5))) | ||
* // => 6 | ||
* ``` | ||
*/ | ||
AsyncReducer.firstWhere = (pred, otherwise) => { | ||
const token = Symbol(); | ||
return create(token, (state, next, i, halt) => __awaiter(this, void 0, void 0, function* () { | ||
if (token === state && (yield pred(next, i))) { | ||
halt(); | ||
return next; | ||
} | ||
return state; | ||
}), (state) => token === state ? AsyncOptLazy.toMaybePromise(otherwise) : state); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the first input value. | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value has been provided | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.first()) | ||
* // => 0 | ||
* ``` | ||
*/ | ||
AsyncReducer.first = (otherwise) => { | ||
const token = Symbol(); | ||
return create(token, (state, next, _, halt) => { | ||
halt(); | ||
if (token === state) | ||
return next; | ||
return state; | ||
}, (state) => token === state ? AsyncOptLazy.toMaybePromise(otherwise) : state); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the last input value for which the given `pred` function returns true. | ||
* @param pred - a function taking an input value and its index, and returning true if the value should be remembered | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value yet has satisfied the given predicate | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.lastWhere(async v => v > 5))) | ||
* // => 9 | ||
* ``` | ||
*/ | ||
AsyncReducer.lastWhere = (pred, otherwise) => { | ||
const token = Symbol(); | ||
return create(token, (state, next, i) => __awaiter(this, void 0, void 0, function* () { | ||
if (yield pred(next, i)) | ||
return next; | ||
return state; | ||
}), (state) => token === state ? AsyncOptLazy.toMaybePromise(otherwise) : state); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the last input value. | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value has been provided | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.last()) | ||
* // => 9 | ||
* ``` | ||
*/ | ||
AsyncReducer.last = (otherwise) => { | ||
const token = Symbol(); | ||
return create(() => token, (_, next) => next, (state) => token === state ? AsyncOptLazy.toMaybePromise(otherwise) : state); | ||
}; | ||
/** | ||
* Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.some(async v => v > 5)) | ||
* // => true | ||
* ``` | ||
*/ | ||
function some(pred) { | ||
return createOutput(false, (state, next, i, halt) => __awaiter(this, void 0, void 0, function* () { | ||
if (state) | ||
return state; | ||
const satisfies = yield pred(next, i); | ||
if (satisfies) { | ||
halt(); | ||
} | ||
return satisfies; | ||
})); | ||
} | ||
AsyncReducer.some = some; | ||
/** | ||
* Returns an `AsyncReducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.every(async v => v < 5)) | ||
* // => false | ||
* ``` | ||
*/ | ||
function every(pred) { | ||
return createOutput(true, (state, next, i, halt) => __awaiter(this, void 0, void 0, function* () { | ||
if (!state) | ||
return state; | ||
const satisfies = yield pred(next, i); | ||
if (!satisfies) { | ||
halt(); | ||
} | ||
return satisfies; | ||
})); | ||
} | ||
AsyncReducer.every = every; | ||
/** | ||
* Returns an `AsyncReducer` that outputs false as long as the given `elem` has not been encountered in the input values, true otherwise. | ||
* @typeparam T - the element type | ||
* @param elem - the element to search for | ||
* @param eq - (optional) a comparison function that returns true if te two given input values are considered equal | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.contains(5))) | ||
* // => true | ||
* ``` | ||
*/ | ||
function contains(elem, eq = Object.is) { | ||
return createOutput(false, (state, next, _, halt) => { | ||
if (state) | ||
return state; | ||
const satisfies = eq(next, elem); | ||
if (satisfies) { | ||
halt(); | ||
} | ||
return satisfies; | ||
}); | ||
} | ||
AsyncReducer.contains = contains; | ||
/** | ||
* Returns an `AsyncReducer` that takes boolean values and outputs true if all input values are true, and false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(true, false, true)).reduce(AsyncReducer.and)) | ||
* // => false | ||
* ``` | ||
*/ | ||
AsyncReducer.and = createMono(true, (state, next, _, halt) => { | ||
if (!state) | ||
return state; | ||
if (!next) | ||
halt(); | ||
return next; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that takes boolean values and outputs true if one or more input values are true, and false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(true, false, true)).reduce(AsyncReducer.or)) | ||
* // => true | ||
* ``` | ||
*/ | ||
AsyncReducer.or = createMono(false, (state, next, _, halt) => { | ||
if (state) | ||
return state; | ||
if (next) | ||
halt(); | ||
return next; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that outputs true if no input values are received, false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.isEmpty)) | ||
* // => false | ||
* ``` | ||
*/ | ||
AsyncReducer.isEmpty = createOutput(true, (_, __, ___, halt) => { | ||
halt(); | ||
return false; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that outputs true if one or more input values are received, false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.nonEmpty)) | ||
* // => true | ||
* ``` | ||
*/ | ||
AsyncReducer.nonEmpty = createOutput(false, (_, __, ___, halt) => { | ||
halt(); | ||
return true; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that collects received input values in an array, and returns a copy of that array as an output value when requested. | ||
* @typeparam T - the element type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.toArray())) | ||
* // => [1, 2, 3] | ||
* ``` | ||
*/ | ||
function toArray() { | ||
return create(() => [], (state, next) => { | ||
state.push(next); | ||
return state; | ||
}, (state) => state.slice()); | ||
} | ||
AsyncReducer.toArray = toArray; | ||
/** | ||
* Returns a `AsyncReducer` that collects received input tuples into a mutable JS Map, and returns | ||
* a copy of that map when output is requested. | ||
* @typeparam K - the map key type | ||
* @typeparam V - the map value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of([1, 'a'], [2, 'b']).reduce(AsyncReducer.toJSMap())) | ||
* // Map { 1 => 'a', 2 => 'b' } | ||
* ``` | ||
*/ | ||
function toJSMap() { | ||
return create(() => new Map(), (state, next) => { | ||
state.set(next[0], next[1]); | ||
return state; | ||
}, (s) => new Map(s)); | ||
} | ||
AsyncReducer.toJSMap = toJSMap; | ||
/** | ||
* Returns an `AsyncReducer` that collects received input values into a mutable JS Set, and returns | ||
* a copy of that map when output is requested. | ||
* @typeparam T - the element type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.toJSSet())) | ||
* // Set {1, 2, 3} | ||
* ``` | ||
*/ | ||
function toJSSet() { | ||
return create(() => new Set(), (state, next) => { | ||
state.add(next); | ||
return state; | ||
}, (s) => new Set(s)); | ||
} | ||
AsyncReducer.toJSSet = toJSSet; | ||
/** | ||
* Returns an `AsyncReducer` that collects 2-tuples containing keys and values into a plain JS object, and | ||
* returns a copy of that object when output is requested. | ||
* @typeparam K - the result object key type | ||
* @typeparam V - the result object value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(['a', 1], ['b', true]).reduce(AsyncReducer.toJSObject())) | ||
* // { a: 1, b: true } | ||
* ``` | ||
*/ | ||
function toJSObject() { | ||
return create(() => ({}), (state, entry) => { | ||
state[entry[0]] = entry[1]; | ||
return state; | ||
}, (s) => (Object.assign({}, s))); | ||
} | ||
AsyncReducer.toJSObject = toJSObject; | ||
/** | ||
* Returns a `Reducer` that combines multiple input `reducers` by providing input values to all of them and collecting the outputs in an array. | ||
* @param reducers - 2 or more reducers to combine | ||
* @example | ||
* ```ts | ||
* const red = Reducer.combine(Reducer.sum, Reducer.average) | ||
* console.log(Stream.range({amount: 9 }).reduce(red)) | ||
* // => [36, 4] | ||
* ``` | ||
*/ | ||
function combine(...reducers) { | ||
const createState = () => { | ||
return Promise.all(reducers.map((reducer) => __awaiter(this, void 0, void 0, function* () { | ||
const result = { | ||
reducer, | ||
halted: false, | ||
halt() { | ||
result.halted = true; | ||
}, | ||
state: yield AsyncOptLazy.toMaybePromise(reducer.init), | ||
}; | ||
return result; | ||
}))); | ||
}; | ||
return create(createState, (allState, next, index, halt) => __awaiter(this, void 0, void 0, function* () { | ||
let anyNotHalted = false; | ||
yield Promise.all(allState.map((red) => __awaiter(this, void 0, void 0, function* () { | ||
if (red.halted) | ||
return; | ||
red.state = yield red.reducer.next(red.state, next, index, red.halt); | ||
if (!red.halted) | ||
anyNotHalted = true; | ||
}))); | ||
if (!anyNotHalted) | ||
halt(); | ||
return allState; | ||
}), (allState) => Promise.all(allState.map((st) => st.reducer.stateToResult(st.state)))); | ||
} | ||
AsyncReducer.combine = combine; | ||
})(AsyncReducer || (AsyncReducer = {})); | ||
//# sourceMappingURL=async-reducer.js.map |
@@ -8,12 +8,2 @@ import { CollectFun, OptLazy } from './internal'; | ||
/** | ||
* Returns the contained value for an `Init` instance. | ||
* @param init - the `Init` value container | ||
*/ | ||
function Init(init) { | ||
if (init instanceof Function) | ||
return init(); | ||
return init; | ||
} | ||
Reducer.Init = Init; | ||
/** | ||
* A base class that can be used to easily create `Reducer` instances. | ||
@@ -33,3 +23,3 @@ * @typeparam I - the input value type | ||
nextIndex: 0, | ||
state: Init(this.init), | ||
state: OptLazy(this.init), | ||
}), (state, elem, index, halt) => { | ||
@@ -48,3 +38,3 @@ if (pred(elem, index, halt)) { | ||
nextIndex: 0, | ||
state: Init(this.init), | ||
state: OptLazy(this.init), | ||
}), (state, elem, index, halt) => { | ||
@@ -377,4 +367,4 @@ const nextElem = collectFun(elem, index, CollectFun.Skip, halt); | ||
* ```ts | ||
* console.log(Stream.range{ amount: 10 }).reduce(Reducer.first()) | ||
* // => 0 | ||
* console.log(Stream.range{ amount: 10 }).reduce(Reducer.last()) | ||
* // => 9 | ||
* ``` | ||
@@ -384,6 +374,7 @@ */ | ||
const token = Symbol(); | ||
return create(token, (_, next) => next, (state) => (token === state ? OptLazy(otherwise) : state)); | ||
return create(() => token, (_, next) => next, (state) => (token === state ? OptLazy(otherwise) : state)); | ||
}; | ||
/** | ||
* Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
@@ -410,2 +401,3 @@ * @example | ||
* Returns a `Reducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
@@ -432,2 +424,3 @@ * @example | ||
* Returns a `Reducer` that outputs false as long as the given `elem` has not been encountered in the input values, true otherwise. | ||
* @typeparam T - the element type | ||
* @param elem - the element to search for | ||
@@ -509,2 +502,3 @@ * @param eq - (optional) a comparison function that returns true if te two given input values are considered equal | ||
* Returns a `Reducer` that collects received input values in an array, and returns a copy of that array as an output value when requested. | ||
* @typeparam T - the element type | ||
* @example | ||
@@ -526,2 +520,4 @@ * ```ts | ||
* a copy of that map when output is requested. | ||
* @typeparam K - the map key type | ||
* @typeparam V - the map value type | ||
* @example | ||
@@ -543,2 +539,3 @@ * ```ts | ||
* a copy of that map when output is requested. | ||
* @typeparam T - the element type | ||
* @example | ||
@@ -558,2 +555,20 @@ * ```ts | ||
/** | ||
* Returns a `Reducer` that collects 2-tuples containing keys and values into a plain JS object, and | ||
* returns a copy of that object when output is requested. | ||
* @typeparam K - the result object key type | ||
* @typeparam V - the result object value type | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(['a', 1], ['b', true]).reduce(Reducer.toJSObject())) | ||
* // { a: 1, b: true } | ||
* ``` | ||
*/ | ||
function toJSObject() { | ||
return create(() => ({}), (state, entry) => { | ||
state[entry[0]] = entry[1]; | ||
return state; | ||
}, (s) => (Object.assign({}, s))); | ||
} | ||
Reducer.toJSObject = toJSObject; | ||
/** | ||
* Returns a `Reducer` that combines multiple input `reducers` by providing input values to all of them and collecting the outputs in an array. | ||
@@ -577,3 +592,3 @@ * @param reducers - 2 or more reducers to combine | ||
}, | ||
state: Init(reducer.init), | ||
state: OptLazy(reducer.init), | ||
}; | ||
@@ -580,0 +595,0 @@ return result; |
@@ -1,2 +0,2 @@ | ||
import { AsyncCollectFun, AsyncOptLazy, MaybePromise, Reducer } from './internal'; | ||
import { AsyncCollectFun, AsyncOptLazy, MaybePromise, Reducer, Eq } from './internal'; | ||
/** | ||
@@ -208,2 +208,311 @@ * An `AsyncReducer` is a stand-alone asynchronous calculation that takes input values of type I, | ||
function from<I, O>(reducer: Reducer<I, O>): AsyncReducer<I, O>; | ||
/** | ||
* A `Reducer` that sums all given numeric input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ amount: 5 }).reduce(Reducer.sum)) | ||
* // => 10 | ||
* ``` | ||
*/ | ||
const sum: AsyncReducer<number, number>; | ||
/** | ||
* A `Reducer` that calculates the product of all given numeric input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ start: 1, amount: 5 }).reduce(product)) | ||
* // => 120 | ||
* ``` | ||
*/ | ||
const product: AsyncReducer<number, number>; | ||
/** | ||
* A `Reducer` that calculates the average of all given numberic input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ amount: 5 }).reduce(Reducer.average)); | ||
* // => 2 | ||
* ``` | ||
*/ | ||
const average: AsyncReducer<number, number>; | ||
/** | ||
* Returns a `Reducer` that remembers the minimum value of the inputs using the given `compFun` to compare input values | ||
* @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller | ||
* @param otherwise - (default: undefineds) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* const stream = Stream.of('abc', 'a', 'abcde', 'ab') | ||
* console.log(stream.minBy((s1, s2) => s1.length - s2.length)) | ||
* // 'a' | ||
* ``` | ||
*/ | ||
const minBy: { | ||
<T>(compFun: (v1: T, v2: T) => MaybePromise<number>): AsyncReducer<T, T | undefined>; | ||
<T, O>(compFun: (v1: T, v2: T) => MaybePromise<number>, otherwise: AsyncOptLazy<O>): AsyncReducer<T, T | O>; | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the minimum value of the numberic inputs. | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.min())) | ||
* // => 3 | ||
* ``` | ||
*/ | ||
const min: { | ||
(): AsyncReducer<number, number | undefined>; | ||
<O>(otherwise: AsyncOptLazy<O>): AsyncReducer<number, number | O>; | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the maximum value of the inputs using the given `compFun` to compare input values | ||
* @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* const stream = Stream.of('abc', 'a', 'abcde', 'ab') | ||
* console.log(stream.maxBy((s1, s2) => s1.length - s2.length)) | ||
* // 'abcde' | ||
* ``` | ||
*/ | ||
const maxBy: { | ||
<T>(compFun: (v1: T, v2: T) => MaybePromise<number>): AsyncReducer<T, T | undefined>; | ||
<T, O>(compFun: (v1: T, v2: T) => MaybePromise<number>, otherwise: AsyncOptLazy<O>): AsyncReducer<T, T | O>; | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the maximum value of the numberic inputs. | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.max())) | ||
* // => 7 | ||
* ``` | ||
*/ | ||
const max: { | ||
(): AsyncReducer<number, number | undefined>; | ||
<O>(otherwise: AsyncOptLazy<O>): AsyncReducer<number, number | O>; | ||
}; | ||
/** | ||
* Returns a `Reducer` that joins the given input values into a string using the given options. | ||
* @param options - an object containing:<br/> | ||
* - sep: (optional) a seperator string value between values in the output<br/> | ||
* - start: (optional) a start string to prepend to the output<br/> | ||
* - end: (optional) an end string to append to the output<br/> | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(1, 2, 3).reduce(Reducer.join({ sep: '-' }))) | ||
* // => '1-2-3' | ||
* ``` | ||
*/ | ||
function join<T>({ sep, start, end, valueToString, }?: { | ||
sep?: string | undefined; | ||
start?: string | undefined; | ||
end?: string | undefined; | ||
valueToString?: ((value: T) => string) | undefined; | ||
}): AsyncReducer<T, string>; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the amount of input items provided. | ||
* @param pred - (optional) a predicate that returns false if the item should not be counted given:<br/> | ||
* - value: the current input value<br/> | ||
* - index: the input value index | ||
* @example | ||
* ```ts | ||
* const stream = AsyncStream.from(Stream.range({ amount: 10 })) | ||
* console.log(await stream.reduce(AsyncReducer.count())) | ||
* // => 10 | ||
* console.log(await stream.reduce(AsyncReducer.count(async v => v < 5))) | ||
* // => 5 | ||
* ``` | ||
*/ | ||
const count: { | ||
(): AsyncReducer<any, number>; | ||
<T>(pred: (value: T, index: number) => MaybePromise<boolean>): AsyncReducer<T, number>; | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the first input value for which the given `pred` function returns true. | ||
* @param pred - a function taking an input value and its index, and returning true if the value should be remembered | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value yet has satisfied the given predicate | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.firstWhere(async v => v > 5))) | ||
* // => 6 | ||
* ``` | ||
*/ | ||
const firstWhere: { | ||
<T>(pred: (value: T, index: number) => MaybePromise<boolean>): AsyncReducer<T, T | undefined>; | ||
<T, O>(pred: (value: T, index: number) => MaybePromise<boolean>, otherwise: AsyncOptLazy<O>): AsyncReducer<T, T | O>; | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the first input value. | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value has been provided | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.first()) | ||
* // => 0 | ||
* ``` | ||
*/ | ||
const first: { | ||
<T>(): AsyncReducer<T, T | undefined>; | ||
<T, O>(otherwise: AsyncOptLazy<O>): AsyncReducer<T, T | O>; | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the last input value for which the given `pred` function returns true. | ||
* @param pred - a function taking an input value and its index, and returning true if the value should be remembered | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value yet has satisfied the given predicate | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.lastWhere(async v => v > 5))) | ||
* // => 9 | ||
* ``` | ||
*/ | ||
const lastWhere: { | ||
<T>(pred: (value: T, index: number) => MaybePromise<boolean>): AsyncReducer<T, T | undefined>; | ||
<T, O>(pred: (value: T, index: number) => MaybePromise<boolean>, otherwise: AsyncOptLazy<O>): AsyncReducer<T, T | O>; | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the last input value. | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value has been provided | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.last()) | ||
* // => 9 | ||
* ``` | ||
*/ | ||
const last: { | ||
<T>(): AsyncReducer<T, T | undefined>; | ||
<T, O>(otherwise: AsyncOptLazy<O>): AsyncReducer<T, T | O>; | ||
}; | ||
/** | ||
* Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.some(async v => v > 5)) | ||
* // => true | ||
* ``` | ||
*/ | ||
function some<T>(pred: (value: T, index: number) => MaybePromise<boolean>): AsyncReducer<T, boolean>; | ||
/** | ||
* Returns an `AsyncReducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.every(async v => v < 5)) | ||
* // => false | ||
* ``` | ||
*/ | ||
function every<T>(pred: (value: T, index: number) => MaybePromise<boolean>): AsyncReducer<T, boolean>; | ||
/** | ||
* Returns an `AsyncReducer` that outputs false as long as the given `elem` has not been encountered in the input values, true otherwise. | ||
* @typeparam T - the element type | ||
* @param elem - the element to search for | ||
* @param eq - (optional) a comparison function that returns true if te two given input values are considered equal | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.contains(5))) | ||
* // => true | ||
* ``` | ||
*/ | ||
function contains<T>(elem: T, eq?: Eq<T>): AsyncReducer<T, boolean>; | ||
/** | ||
* Returns an `AsyncReducer` that takes boolean values and outputs true if all input values are true, and false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(true, false, true)).reduce(AsyncReducer.and)) | ||
* // => false | ||
* ``` | ||
*/ | ||
const and: AsyncReducer<boolean, boolean>; | ||
/** | ||
* Returns an `AsyncReducer` that takes boolean values and outputs true if one or more input values are true, and false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(true, false, true)).reduce(AsyncReducer.or)) | ||
* // => true | ||
* ``` | ||
*/ | ||
const or: AsyncReducer<boolean, boolean>; | ||
/** | ||
* Returns an `AsyncReducer` that outputs true if no input values are received, false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.isEmpty)) | ||
* // => false | ||
* ``` | ||
*/ | ||
const isEmpty: AsyncReducer<any, boolean>; | ||
/** | ||
* Returns an `AsyncReducer` that outputs true if one or more input values are received, false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.nonEmpty)) | ||
* // => true | ||
* ``` | ||
*/ | ||
const nonEmpty: AsyncReducer<any, boolean>; | ||
/** | ||
* Returns an `AsyncReducer` that collects received input values in an array, and returns a copy of that array as an output value when requested. | ||
* @typeparam T - the element type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.toArray())) | ||
* // => [1, 2, 3] | ||
* ``` | ||
*/ | ||
function toArray<T>(): AsyncReducer<T, T[]>; | ||
/** | ||
* Returns a `AsyncReducer` that collects received input tuples into a mutable JS Map, and returns | ||
* a copy of that map when output is requested. | ||
* @typeparam K - the map key type | ||
* @typeparam V - the map value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of([1, 'a'], [2, 'b']).reduce(AsyncReducer.toJSMap())) | ||
* // Map { 1 => 'a', 2 => 'b' } | ||
* ``` | ||
*/ | ||
function toJSMap<K, V>(): AsyncReducer<[K, V], Map<K, V>>; | ||
/** | ||
* Returns an `AsyncReducer` that collects received input values into a mutable JS Set, and returns | ||
* a copy of that map when output is requested. | ||
* @typeparam T - the element type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.toJSSet())) | ||
* // Set {1, 2, 3} | ||
* ``` | ||
*/ | ||
function toJSSet<T>(): AsyncReducer<T, Set<T>>; | ||
/** | ||
* Returns an `AsyncReducer` that collects 2-tuples containing keys and values into a plain JS object, and | ||
* returns a copy of that object when output is requested. | ||
* @typeparam K - the result object key type | ||
* @typeparam V - the result object value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(['a', 1], ['b', true]).reduce(AsyncReducer.toJSObject())) | ||
* // { a: 1, b: true } | ||
* ``` | ||
*/ | ||
function toJSObject<K extends string | number | symbol, V>(): AsyncReducer<[K, V], Record<K, V>>; | ||
/** | ||
* Returns a `Reducer` that combines multiple input `reducers` by providing input values to all of them and collecting the outputs in an array. | ||
* @param reducers - 2 or more reducers to combine | ||
* @example | ||
* ```ts | ||
* const red = Reducer.combine(Reducer.sum, Reducer.average) | ||
* console.log(Stream.range({amount: 9 }).reduce(red)) | ||
* // => [36, 4] | ||
* ``` | ||
*/ | ||
function combine<T, R extends readonly [unknown, unknown, ...unknown[]]>(...reducers: { | ||
[K in keyof R]: AsyncReducer<T, R[K]>; | ||
} & AsyncReducer<T, unknown>[]): AsyncReducer<T, R>; | ||
} |
@@ -10,11 +10,2 @@ import { CollectFun, Eq, OptLazy } from './internal'; | ||
/** | ||
* Ensures that all non-primitive type use lazy initialization to prevent accidental instance sharing. | ||
*/ | ||
type Init<T> = T extends object | (() => any) ? () => T : T; | ||
/** | ||
* Returns the contained value for an `Init` instance. | ||
* @param init - the `Init` value container | ||
*/ | ||
function Init<T>(init: Reducer.Init<T>): T; | ||
/** | ||
* The Implementation interface for a `Reducer`, which also exposes the internal state type. | ||
@@ -29,3 +20,3 @@ * @typeparam I - the input value type | ||
*/ | ||
readonly init: Reducer.Init<S>; | ||
readonly init: OptLazy<S>; | ||
/** | ||
@@ -59,2 +50,3 @@ * Returns the next state based on the given input values | ||
* Returns a `Reducer` instance that converts its input values using given `mapFun` before passing them to the reducer. | ||
* @typeparam I2 - the resulting reducer input type | ||
* @param mapFun - a function that returns a new value to pass to the reducer based on the following inputs:<br/> | ||
@@ -72,2 +64,3 @@ * - value: the current input value<br/> | ||
* Returns a `Reducer` instance that converts or filters its input values using given `collectFun` before passing them to the reducer. | ||
* @typeparam I2 - the resulting reducer input type | ||
* @param collectFun - a function receiving<br/> | ||
@@ -88,2 +81,3 @@ * - `value`: the next value<br/> | ||
* Returns a `Reducer` instance that converts its output values using given `mapFun`. | ||
* @typeparam O2 - the resulting reducer output type | ||
* @param mapFun - a function that takes the current output value and converts it to a new output value | ||
@@ -136,6 +130,6 @@ * @example | ||
class Base<I, O, S> implements Reducer.Impl<I, O, S> { | ||
readonly init: Reducer.Init<S>; | ||
readonly init: OptLazy<S>; | ||
readonly next: (state: S, elem: I, index: number, halt: () => void) => S; | ||
readonly stateToResult: (state: S) => O; | ||
constructor(init: Reducer.Init<S>, next: (state: S, elem: I, index: number, halt: () => void) => S, stateToResult: (state: S) => O); | ||
constructor(init: OptLazy<S>, next: (state: S, elem: I, index: number, halt: () => void) => S, stateToResult: (state: S) => O); | ||
filterInput(pred: (value: I, index: number, halt: () => void) => boolean): Reducer<I, O>; | ||
@@ -173,3 +167,3 @@ mapInput<I2>(mapFun: (value: I2, index: number) => I): Reducer<I2, O>; | ||
*/ | ||
function create<I, O = I, S = O>(init: Reducer.Init<S>, next: (current: S, next: I, index: number, halt: () => void) => S, stateToResult: (state: S) => O): Reducer<I, O>; | ||
function create<I, O = I, S = O>(init: OptLazy<S>, next: (current: S, next: I, index: number, halt: () => void) => S, stateToResult: (state: S) => O): Reducer<I, O>; | ||
/** | ||
@@ -197,3 +191,3 @@ * Returns a `Reducer` of which the input, state, and output types are the same. | ||
*/ | ||
function createMono<T>(init: Reducer.Init<T>, next: (current: T, next: T, index: number, halt: () => void) => T, stateToResult?: (state: T) => T): Reducer<T>; | ||
function createMono<T>(init: OptLazy<T>, next: (current: T, next: T, index: number, halt: () => void) => T, stateToResult?: (state: T) => T): Reducer<T>; | ||
/** | ||
@@ -222,3 +216,3 @@ * Returns a `Reducer` of which the state and output types are the same. | ||
*/ | ||
function createOutput<I, O = I>(init: Reducer.Init<O>, next: (current: O, next: I, index: number, halt: () => void) => O, stateToResult?: (state: O) => O): Reducer<I, O>; | ||
function createOutput<I, O = I>(init: OptLazy<O>, next: (current: O, next: I, index: number, halt: () => void) => O, stateToResult?: (state: O) => O): Reducer<I, O>; | ||
/** | ||
@@ -397,4 +391,4 @@ * A `Reducer` that sums all given numeric input values. | ||
* ```ts | ||
* console.log(Stream.range{ amount: 10 }).reduce(Reducer.first()) | ||
* // => 0 | ||
* console.log(Stream.range{ amount: 10 }).reduce(Reducer.last()) | ||
* // => 9 | ||
* ``` | ||
@@ -408,2 +402,3 @@ */ | ||
* Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
@@ -419,2 +414,3 @@ * @example | ||
* Returns a `Reducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
@@ -430,2 +426,3 @@ * @example | ||
* Returns a `Reducer` that outputs false as long as the given `elem` has not been encountered in the input values, true otherwise. | ||
* @typeparam T - the element type | ||
* @param elem - the element to search for | ||
@@ -478,2 +475,3 @@ * @param eq - (optional) a comparison function that returns true if te two given input values are considered equal | ||
* Returns a `Reducer` that collects received input values in an array, and returns a copy of that array as an output value when requested. | ||
* @typeparam T - the element type | ||
* @example | ||
@@ -489,2 +487,4 @@ * ```ts | ||
* a copy of that map when output is requested. | ||
* @typeparam K - the map key type | ||
* @typeparam V - the map value type | ||
* @example | ||
@@ -500,2 +500,3 @@ * ```ts | ||
* a copy of that map when output is requested. | ||
* @typeparam T - the element type | ||
* @example | ||
@@ -509,2 +510,17 @@ * ```ts | ||
/** | ||
* Returns a `Reducer` that collects 2-tuples containing keys and values into a plain JS object, and | ||
* returns a copy of that object when output is requested. | ||
* @typeparam K - the result object key type | ||
* @typeparam V - the result object value type | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(['a', 1], ['b', true]).reduce(Reducer.toJSObject())) | ||
* // { a: 1, b: true } | ||
* ``` | ||
*/ | ||
function toJSObject<K extends string | number | symbol, V>(): Reducer<[ | ||
K, | ||
V | ||
], Record<K, V>>; | ||
/** | ||
* Returns a `Reducer` that combines multiple input `reducers` by providing input values to all of them and collecting the outputs in an array. | ||
@@ -511,0 +527,0 @@ * @param reducers - 2 or more reducers to combine |
{ | ||
"name": "@rimbu/common", | ||
"version": "0.9.4", | ||
"version": "0.10.0", | ||
"description": "Common types and objects used in many other Rimbu packages", | ||
@@ -66,3 +66,3 @@ "keywords": [ | ||
}, | ||
"gitHead": "60d3b52050fc30f10921cbf92d637362d663d7e0" | ||
"gitHead": "4d6b7411c36f599331185b1bc597e58f34954d1a" | ||
} |
@@ -7,2 +7,3 @@ import { | ||
Reducer, | ||
Eq, | ||
} from './internal'; | ||
@@ -376,2 +377,664 @@ | ||
} | ||
/** | ||
* A `Reducer` that sums all given numeric input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ amount: 5 }).reduce(Reducer.sum)) | ||
* // => 10 | ||
* ``` | ||
*/ | ||
export const sum = createMono(0, (state, next): number => state + next); | ||
/** | ||
* A `Reducer` that calculates the product of all given numeric input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ start: 1, amount: 5 }).reduce(product)) | ||
* // => 120 | ||
* ``` | ||
*/ | ||
export const product = createMono(1, (state, next, _, halt): number => { | ||
if (0 === next) halt(); | ||
return state * next; | ||
}); | ||
/** | ||
* A `Reducer` that calculates the average of all given numberic input values. | ||
* @example | ||
* ```ts | ||
* console.log(Stream.range({ amount: 5 }).reduce(Reducer.average)); | ||
* // => 2 | ||
* ``` | ||
*/ | ||
export const average = createMono( | ||
0, | ||
(avg, value, index): number => avg + (value - avg) / (index + 1) | ||
); | ||
/** | ||
* Returns a `Reducer` that remembers the minimum value of the inputs using the given `compFun` to compare input values | ||
* @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller | ||
* @param otherwise - (default: undefineds) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* const stream = Stream.of('abc', 'a', 'abcde', 'ab') | ||
* console.log(stream.minBy((s1, s2) => s1.length - s2.length)) | ||
* // 'a' | ||
* ``` | ||
*/ | ||
export const minBy: { | ||
<T>(compFun: (v1: T, v2: T) => MaybePromise<number>): AsyncReducer< | ||
T, | ||
T | undefined | ||
>; | ||
<T, O>( | ||
compFun: (v1: T, v2: T) => MaybePromise<number>, | ||
otherwise: AsyncOptLazy<O> | ||
): AsyncReducer<T, T | O>; | ||
} = <T, O>( | ||
compFun: (v1: T, v2: T) => MaybePromise<number>, | ||
otherwise?: AsyncOptLazy<O> | ||
) => { | ||
const token = Symbol(); | ||
return create<T, T | O, T | typeof token>( | ||
token, | ||
async (state, next): Promise<T> => { | ||
if (token === state) return next; | ||
return (await compFun(state, next)) < 0 ? state : next; | ||
}, | ||
(state): MaybePromise<T | O> => | ||
token === state ? AsyncOptLazy.toMaybePromise(otherwise!) : state | ||
); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the minimum value of the numberic inputs. | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.min())) | ||
* // => 3 | ||
* ``` | ||
*/ | ||
export const min: { | ||
(): AsyncReducer<number, number | undefined>; | ||
<O>(otherwise: AsyncOptLazy<O>): AsyncReducer<number, number | O>; | ||
} = <O>(otherwise?: AsyncOptLazy<O>) => { | ||
return create<number, number | O, number | undefined>( | ||
undefined, | ||
(state, next): number => | ||
undefined !== state && state < next ? state : next, | ||
(state): MaybePromise<number | O> => | ||
state ?? AsyncOptLazy.toMaybePromise(otherwise!) | ||
); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the maximum value of the inputs using the given `compFun` to compare input values | ||
* @param compFun - a comparison function for two input values, returning 0 when equal, positive when greater, negetive when smaller | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* const stream = Stream.of('abc', 'a', 'abcde', 'ab') | ||
* console.log(stream.maxBy((s1, s2) => s1.length - s2.length)) | ||
* // 'abcde' | ||
* ``` | ||
*/ | ||
export const maxBy: { | ||
<T>(compFun: (v1: T, v2: T) => MaybePromise<number>): AsyncReducer< | ||
T, | ||
T | undefined | ||
>; | ||
<T, O>( | ||
compFun: (v1: T, v2: T) => MaybePromise<number>, | ||
otherwise: AsyncOptLazy<O> | ||
): AsyncReducer<T, T | O>; | ||
} = <T, O>( | ||
compFun: (v1: T, v2: T) => MaybePromise<number>, | ||
otherwise?: AsyncOptLazy<O> | ||
): AsyncReducer<T, T | O> => { | ||
const token = Symbol(); | ||
return create<T, T | O, T | typeof token>( | ||
token, | ||
async (state, next): Promise<T> => { | ||
if (token === state) return next; | ||
return (await compFun(state, next)) > 0 ? state : next; | ||
}, | ||
(state): MaybePromise<T | O> => | ||
token === state ? AsyncOptLazy.toMaybePromise(otherwise!) : state | ||
); | ||
}; | ||
/** | ||
* Returns a `Reducer` that remembers the maximum value of the numberic inputs. | ||
* @param otherwise - (default: undefined) a fallback value when there were no input values given | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(5, 3, 7, 4).reduce(Reducer.max())) | ||
* // => 7 | ||
* ``` | ||
*/ | ||
export const max: { | ||
(): AsyncReducer<number, number | undefined>; | ||
<O>(otherwise: AsyncOptLazy<O>): AsyncReducer<number, number | O>; | ||
} = <O>(otherwise?: AsyncOptLazy<O>): AsyncReducer<number, number | O> => { | ||
return create<number, number | O, number | undefined>( | ||
undefined, | ||
(state, next): number => | ||
undefined !== state && state > next ? state : next, | ||
(state): MaybePromise<number | O> => | ||
state ?? AsyncOptLazy.toMaybePromise(otherwise!) | ||
); | ||
}; | ||
/** | ||
* Returns a `Reducer` that joins the given input values into a string using the given options. | ||
* @param options - an object containing:<br/> | ||
* - sep: (optional) a seperator string value between values in the output<br/> | ||
* - start: (optional) a start string to prepend to the output<br/> | ||
* - end: (optional) an end string to append to the output<br/> | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(1, 2, 3).reduce(Reducer.join({ sep: '-' }))) | ||
* // => '1-2-3' | ||
* ``` | ||
*/ | ||
export function join<T>({ | ||
sep = '', | ||
start = '', | ||
end = '', | ||
valueToString = String as (value: T) => string, | ||
} = {}): AsyncReducer<T, string> { | ||
let curSep = ''; | ||
let curStart = start; | ||
return create( | ||
'', | ||
(state, next): string => { | ||
const result = curStart.concat(state, curSep, valueToString(next)); | ||
curSep = sep; | ||
curStart = ''; | ||
return result; | ||
}, | ||
(state): string => state.concat(end) | ||
); | ||
} | ||
/** | ||
* Returns an `AsyncReducer` that remembers the amount of input items provided. | ||
* @param pred - (optional) a predicate that returns false if the item should not be counted given:<br/> | ||
* - value: the current input value<br/> | ||
* - index: the input value index | ||
* @example | ||
* ```ts | ||
* const stream = AsyncStream.from(Stream.range({ amount: 10 })) | ||
* console.log(await stream.reduce(AsyncReducer.count())) | ||
* // => 10 | ||
* console.log(await stream.reduce(AsyncReducer.count(async v => v < 5))) | ||
* // => 5 | ||
* ``` | ||
*/ | ||
export const count: { | ||
(): AsyncReducer<any, number>; | ||
<T>(pred: (value: T, index: number) => MaybePromise<boolean>): AsyncReducer< | ||
T, | ||
number | ||
>; | ||
} = ( | ||
pred?: (value: any, index: number) => MaybePromise<boolean> | ||
): AsyncReducer<any, number> => { | ||
if (undefined === pred) return createMono(0, (_, __, i): number => i + 1); | ||
return createOutput(0, async (state, next, i): Promise<number> => { | ||
if (await pred?.(next, i)) return state + 1; | ||
return state; | ||
}); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the first input value for which the given `pred` function returns true. | ||
* @param pred - a function taking an input value and its index, and returning true if the value should be remembered | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value yet has satisfied the given predicate | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.firstWhere(async v => v > 5))) | ||
* // => 6 | ||
* ``` | ||
*/ | ||
export const firstWhere: { | ||
<T>(pred: (value: T, index: number) => MaybePromise<boolean>): AsyncReducer< | ||
T, | ||
T | undefined | ||
>; | ||
<T, O>( | ||
pred: (value: T, index: number) => MaybePromise<boolean>, | ||
otherwise: AsyncOptLazy<O> | ||
): AsyncReducer<T, T | O>; | ||
} = <T, O>( | ||
pred: (value: T, index: number) => MaybePromise<boolean>, | ||
otherwise?: AsyncOptLazy<O> | ||
) => { | ||
const token = Symbol(); | ||
return create<T, T | O, T | typeof token>( | ||
token, | ||
async (state, next, i, halt): Promise<T | typeof token> => { | ||
if (token === state && (await pred(next, i))) { | ||
halt(); | ||
return next; | ||
} | ||
return state; | ||
}, | ||
(state): MaybePromise<T | O> => | ||
token === state ? AsyncOptLazy.toMaybePromise(otherwise!) : state | ||
); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the first input value. | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value has been provided | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.first()) | ||
* // => 0 | ||
* ``` | ||
*/ | ||
export const first: { | ||
<T>(): AsyncReducer<T, T | undefined>; | ||
<T, O>(otherwise: AsyncOptLazy<O>): AsyncReducer<T, T | O>; | ||
} = <T, O>(otherwise?: AsyncOptLazy<O>): AsyncReducer<T, T | O> => { | ||
const token = Symbol(); | ||
return create<T, T | O, T | typeof token>( | ||
token, | ||
(state, next, _, halt): T => { | ||
halt(); | ||
if (token === state) return next; | ||
return state; | ||
}, | ||
(state): MaybePromise<T | O> => | ||
token === state ? AsyncOptLazy.toMaybePromise(otherwise!) : state | ||
); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the last input value for which the given `pred` function returns true. | ||
* @param pred - a function taking an input value and its index, and returning true if the value should be remembered | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value yet has satisfied the given predicate | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.lastWhere(async v => v > 5))) | ||
* // => 9 | ||
* ``` | ||
*/ | ||
export const lastWhere: { | ||
<T>(pred: (value: T, index: number) => MaybePromise<boolean>): AsyncReducer< | ||
T, | ||
T | undefined | ||
>; | ||
<T, O>( | ||
pred: (value: T, index: number) => MaybePromise<boolean>, | ||
otherwise: AsyncOptLazy<O> | ||
): AsyncReducer<T, T | O>; | ||
} = <T, O>( | ||
pred: (value: T, index: number) => MaybePromise<boolean>, | ||
otherwise?: AsyncOptLazy<O> | ||
) => { | ||
const token = Symbol(); | ||
return create<T, T | O, T | typeof token>( | ||
token, | ||
async (state, next, i): Promise<T | typeof token> => { | ||
if (await pred(next, i)) return next; | ||
return state; | ||
}, | ||
(state): MaybePromise<T | O> => | ||
token === state ? AsyncOptLazy.toMaybePromise(otherwise!) : state | ||
); | ||
}; | ||
/** | ||
* Returns an `AsyncReducer` that remembers the last input value. | ||
* @param otherwise - (default: undefined) a fallback value to output if no input value has been provided | ||
* @typeparam T - the input value type | ||
* @typeparam O - the fallback value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.last()) | ||
* // => 9 | ||
* ``` | ||
*/ | ||
export const last: { | ||
<T>(): AsyncReducer<T, T | undefined>; | ||
<T, O>(otherwise: AsyncOptLazy<O>): AsyncReducer<T, T | O>; | ||
} = <T, O>(otherwise?: AsyncOptLazy<O>): AsyncReducer<T, T | O> => { | ||
const token = Symbol(); | ||
return create<T, T | O, T | typeof token>( | ||
() => token, | ||
(_, next): T => next, | ||
(state): MaybePromise<T | O> => | ||
token === state ? AsyncOptLazy.toMaybePromise(otherwise!) : state | ||
); | ||
}; | ||
/** | ||
* Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.some(async v => v > 5)) | ||
* // => true | ||
* ``` | ||
*/ | ||
export function some<T>( | ||
pred: (value: T, index: number) => MaybePromise<boolean> | ||
): AsyncReducer<T, boolean> { | ||
return createOutput<T, boolean>( | ||
false, | ||
async (state, next, i, halt): Promise<boolean> => { | ||
if (state) return state; | ||
const satisfies = await pred(next, i); | ||
if (satisfies) { | ||
halt(); | ||
} | ||
return satisfies; | ||
} | ||
); | ||
} | ||
/** | ||
* Returns an `AsyncReducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range{ amount: 10 })).reduce(AsyncReducer.every(async v => v < 5)) | ||
* // => false | ||
* ``` | ||
*/ | ||
export function every<T>( | ||
pred: (value: T, index: number) => MaybePromise<boolean> | ||
): AsyncReducer<T, boolean> { | ||
return createOutput<T, boolean>( | ||
true, | ||
async (state, next, i, halt): Promise<boolean> => { | ||
if (!state) return state; | ||
const satisfies = await pred(next, i); | ||
if (!satisfies) { | ||
halt(); | ||
} | ||
return satisfies; | ||
} | ||
); | ||
} | ||
/** | ||
* Returns an `AsyncReducer` that outputs false as long as the given `elem` has not been encountered in the input values, true otherwise. | ||
* @typeparam T - the element type | ||
* @param elem - the element to search for | ||
* @param eq - (optional) a comparison function that returns true if te two given input values are considered equal | ||
* @example | ||
* ```ts | ||
* await AsyncStream.from(Stream.range({ amount: 10 })).reduce(AsyncReducer.contains(5))) | ||
* // => true | ||
* ``` | ||
*/ | ||
export function contains<T>( | ||
elem: T, | ||
eq: Eq<T> = Object.is | ||
): AsyncReducer<T, boolean> { | ||
return createOutput<T, boolean>(false, (state, next, _, halt): boolean => { | ||
if (state) return state; | ||
const satisfies = eq(next, elem); | ||
if (satisfies) { | ||
halt(); | ||
} | ||
return satisfies; | ||
}); | ||
} | ||
/** | ||
* Returns an `AsyncReducer` that takes boolean values and outputs true if all input values are true, and false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(true, false, true)).reduce(AsyncReducer.and)) | ||
* // => false | ||
* ``` | ||
*/ | ||
export const and = createMono(true, (state, next, _, halt): boolean => { | ||
if (!state) return state; | ||
if (!next) halt(); | ||
return next; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that takes boolean values and outputs true if one or more input values are true, and false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(true, false, true)).reduce(AsyncReducer.or)) | ||
* // => true | ||
* ``` | ||
*/ | ||
export const or = createMono(false, (state, next, _, halt): boolean => { | ||
if (state) return state; | ||
if (next) halt(); | ||
return next; | ||
}); | ||
/** | ||
* Returns an `AsyncReducer` that outputs true if no input values are received, false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.isEmpty)) | ||
* // => false | ||
* ``` | ||
*/ | ||
export const isEmpty = createOutput<any, boolean>( | ||
true, | ||
(_, __, ___, halt): false => { | ||
halt(); | ||
return false; | ||
} | ||
); | ||
/** | ||
* Returns an `AsyncReducer` that outputs true if one or more input values are received, false otherwise. | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.nonEmpty)) | ||
* // => true | ||
* ``` | ||
*/ | ||
export const nonEmpty = createOutput<any, boolean>( | ||
false, | ||
(_, __, ___, halt): true => { | ||
halt(); | ||
return true; | ||
} | ||
); | ||
/** | ||
* Returns an `AsyncReducer` that collects received input values in an array, and returns a copy of that array as an output value when requested. | ||
* @typeparam T - the element type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.toArray())) | ||
* // => [1, 2, 3] | ||
* ``` | ||
*/ | ||
export function toArray<T>(): AsyncReducer<T, T[]> { | ||
return create( | ||
(): T[] => [], | ||
(state, next): T[] => { | ||
state.push(next); | ||
return state; | ||
}, | ||
(state): T[] => state.slice() | ||
); | ||
} | ||
/** | ||
* Returns a `AsyncReducer` that collects received input tuples into a mutable JS Map, and returns | ||
* a copy of that map when output is requested. | ||
* @typeparam K - the map key type | ||
* @typeparam V - the map value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of([1, 'a'], [2, 'b']).reduce(AsyncReducer.toJSMap())) | ||
* // Map { 1 => 'a', 2 => 'b' } | ||
* ``` | ||
*/ | ||
export function toJSMap<K, V>(): AsyncReducer<[K, V], Map<K, V>> { | ||
return create( | ||
(): Map<K, V> => new Map(), | ||
(state, next): Map<K, V> => { | ||
state.set(next[0], next[1]); | ||
return state; | ||
}, | ||
(s): Map<K, V> => new Map(s) | ||
); | ||
} | ||
/** | ||
* Returns an `AsyncReducer` that collects received input values into a mutable JS Set, and returns | ||
* a copy of that map when output is requested. | ||
* @typeparam T - the element type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(1, 2, 3).reduce(AsyncReducer.toJSSet())) | ||
* // Set {1, 2, 3} | ||
* ``` | ||
*/ | ||
export function toJSSet<T>(): AsyncReducer<T, Set<T>> { | ||
return create( | ||
(): Set<T> => new Set<T>(), | ||
(state, next): Set<T> => { | ||
state.add(next); | ||
return state; | ||
}, | ||
(s): Set<T> => new Set(s) | ||
); | ||
} | ||
/** | ||
* Returns an `AsyncReducer` that collects 2-tuples containing keys and values into a plain JS object, and | ||
* returns a copy of that object when output is requested. | ||
* @typeparam K - the result object key type | ||
* @typeparam V - the result object value type | ||
* @example | ||
* ```ts | ||
* await AsyncStream.of(['a', 1], ['b', true]).reduce(AsyncReducer.toJSObject())) | ||
* // { a: 1, b: true } | ||
* ``` | ||
*/ | ||
export function toJSObject< | ||
K extends string | number | symbol, | ||
V | ||
>(): AsyncReducer<[K, V], Record<K, V>> { | ||
return create( | ||
() => ({} as Record<K, V>), | ||
(state, entry) => { | ||
state[entry[0]] = entry[1]; | ||
return state; | ||
}, | ||
(s) => ({ ...s }) | ||
); | ||
} | ||
/** | ||
* Returns a `Reducer` that combines multiple input `reducers` by providing input values to all of them and collecting the outputs in an array. | ||
* @param reducers - 2 or more reducers to combine | ||
* @example | ||
* ```ts | ||
* const red = Reducer.combine(Reducer.sum, Reducer.average) | ||
* console.log(Stream.range({amount: 9 }).reduce(red)) | ||
* // => [36, 4] | ||
* ``` | ||
*/ | ||
export function combine< | ||
T, | ||
R extends readonly [unknown, unknown, ...unknown[]] | ||
>( | ||
...reducers: { [K in keyof R]: AsyncReducer<T, R[K]> } & AsyncReducer< | ||
T, | ||
unknown | ||
>[] | ||
): AsyncReducer<T, R> { | ||
const createState = (): Promise< | ||
{ | ||
reducer: AsyncReducer<T, unknown>; | ||
halted: boolean; | ||
halt(): void; | ||
state: unknown; | ||
}[] | ||
> => { | ||
return Promise.all( | ||
reducers.map(async (reducer) => { | ||
const result = { | ||
reducer, | ||
halted: false, | ||
halt(): void { | ||
result.halted = true; | ||
}, | ||
state: await AsyncOptLazy.toMaybePromise(reducer.init), | ||
}; | ||
return result; | ||
}) | ||
); | ||
}; | ||
return create< | ||
T, | ||
R, | ||
{ | ||
reducer: AsyncReducer<T, unknown>; | ||
halted: boolean; | ||
halt(): void; | ||
state: unknown; | ||
}[] | ||
>( | ||
createState, | ||
async (allState, next, index, halt) => { | ||
let anyNotHalted = false; | ||
await Promise.all( | ||
allState.map(async (red) => { | ||
if (red.halted) return; | ||
red.state = await red.reducer.next( | ||
red.state, | ||
next, | ||
index, | ||
red.halt | ||
); | ||
if (!red.halted) anyNotHalted = true; | ||
}) | ||
); | ||
if (!anyNotHalted) halt(); | ||
return allState; | ||
}, | ||
(allState) => | ||
Promise.all( | ||
allState.map((st) => st.reducer.stateToResult(st.state)) | ||
) as any | ||
); | ||
} | ||
} |
@@ -16,17 +16,2 @@ import { CollectFun, Eq, OptLazy } from './internal'; | ||
/** | ||
* Ensures that all non-primitive type use lazy initialization to prevent accidental instance sharing. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
export type Init<T> = T extends object | (() => any) ? () => T : T; | ||
/** | ||
* Returns the contained value for an `Init` instance. | ||
* @param init - the `Init` value container | ||
*/ | ||
export function Init<T>(init: Reducer.Init<T>): T { | ||
if (init instanceof Function) return init(); | ||
return init as T; | ||
} | ||
/** | ||
* The Implementation interface for a `Reducer`, which also exposes the internal state type. | ||
@@ -41,3 +26,3 @@ * @typeparam I - the input value type | ||
*/ | ||
readonly init: Reducer.Init<S>; | ||
readonly init: OptLazy<S>; | ||
/** | ||
@@ -73,2 +58,3 @@ * Returns the next state based on the given input values | ||
* Returns a `Reducer` instance that converts its input values using given `mapFun` before passing them to the reducer. | ||
* @typeparam I2 - the resulting reducer input type | ||
* @param mapFun - a function that returns a new value to pass to the reducer based on the following inputs:<br/> | ||
@@ -86,2 +72,3 @@ * - value: the current input value<br/> | ||
* Returns a `Reducer` instance that converts or filters its input values using given `collectFun` before passing them to the reducer. | ||
* @typeparam I2 - the resulting reducer input type | ||
* @param collectFun - a function receiving<br/> | ||
@@ -102,2 +89,3 @@ * - `value`: the next value<br/> | ||
* Returns a `Reducer` instance that converts its output values using given `mapFun`. | ||
* @typeparam O2 - the resulting reducer output type | ||
* @param mapFun - a function that takes the current output value and converts it to a new output value | ||
@@ -152,3 +140,3 @@ * @example | ||
constructor( | ||
readonly init: Reducer.Init<S>, | ||
readonly init: OptLazy<S>, | ||
readonly next: (state: S, elem: I, index: number, halt: () => void) => S, | ||
@@ -164,3 +152,3 @@ readonly stateToResult: (state: S) => O | ||
nextIndex: 0, | ||
state: Init(this.init), | ||
state: OptLazy(this.init), | ||
}), | ||
@@ -190,3 +178,3 @@ (state, elem, index, halt): { state: S; nextIndex: number } => { | ||
nextIndex: 0, | ||
state: Init(this.init), | ||
state: OptLazy(this.init), | ||
}), | ||
@@ -270,3 +258,3 @@ (state, elem, index, halt): { state: S; nextIndex: number } => { | ||
export function create<I, O = I, S = O>( | ||
init: Reducer.Init<S>, | ||
init: OptLazy<S>, | ||
next: (current: S, next: I, index: number, halt: () => void) => S, | ||
@@ -301,3 +289,3 @@ stateToResult: (state: S) => O | ||
export function createMono<T>( | ||
init: Reducer.Init<T>, | ||
init: OptLazy<T>, | ||
next: (current: T, next: T, index: number, halt: () => void) => T, | ||
@@ -333,3 +321,3 @@ stateToResult?: (state: T) => T | ||
export function createOutput<I, O = I>( | ||
init: Reducer.Init<O>, | ||
init: OptLazy<O>, | ||
next: (current: O, next: I, index: number, halt: () => void) => O, | ||
@@ -644,4 +632,4 @@ stateToResult?: (state: O) => O | ||
* ```ts | ||
* console.log(Stream.range{ amount: 10 }).reduce(Reducer.first()) | ||
* // => 0 | ||
* console.log(Stream.range{ amount: 10 }).reduce(Reducer.last()) | ||
* // => 9 | ||
* ``` | ||
@@ -656,3 +644,3 @@ */ | ||
return create<T, T | O, T | typeof token>( | ||
token, | ||
() => token, | ||
(_, next): T => next, | ||
@@ -665,2 +653,3 @@ (state): T | O => (token === state ? OptLazy(otherwise!) : state) | ||
* Returns a `Reducer` that ouputs false as long as no input value satisfies given `pred`, true otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
@@ -690,2 +679,3 @@ * @example | ||
* Returns a `Reducer` that ouputs true as long as all input values satisfy the given `pred`, false otherwise. | ||
* @typeparam T - the element type | ||
* @param pred - a function taking an input value and its index, and returning true if the value satisfies the predicate | ||
@@ -716,2 +706,3 @@ * @example | ||
* Returns a `Reducer` that outputs false as long as the given `elem` has not been encountered in the input values, true otherwise. | ||
* @typeparam T - the element type | ||
* @param elem - the element to search for | ||
@@ -803,2 +794,3 @@ * @param eq - (optional) a comparison function that returns true if te two given input values are considered equal | ||
* Returns a `Reducer` that collects received input values in an array, and returns a copy of that array as an output value when requested. | ||
* @typeparam T - the element type | ||
* @example | ||
@@ -824,2 +816,4 @@ * ```ts | ||
* a copy of that map when output is requested. | ||
* @typeparam K - the map key type | ||
* @typeparam V - the map value type | ||
* @example | ||
@@ -845,2 +839,3 @@ * ```ts | ||
* a copy of that map when output is requested. | ||
* @typeparam T - the element type | ||
* @example | ||
@@ -864,2 +859,27 @@ * ```ts | ||
/** | ||
* Returns a `Reducer` that collects 2-tuples containing keys and values into a plain JS object, and | ||
* returns a copy of that object when output is requested. | ||
* @typeparam K - the result object key type | ||
* @typeparam V - the result object value type | ||
* @example | ||
* ```ts | ||
* console.log(Stream.of(['a', 1], ['b', true]).reduce(Reducer.toJSObject())) | ||
* // { a: 1, b: true } | ||
* ``` | ||
*/ | ||
export function toJSObject<K extends string | number | symbol, V>(): Reducer< | ||
[K, V], | ||
Record<K, V> | ||
> { | ||
return create( | ||
() => ({} as Record<K, V>), | ||
(state, entry) => { | ||
state[entry[0]] = entry[1]; | ||
return state; | ||
}, | ||
(s) => ({ ...s }) | ||
); | ||
} | ||
/** | ||
* Returns a `Reducer` that combines multiple input `reducers` by providing input values to all of them and collecting the outputs in an array. | ||
@@ -893,3 +913,3 @@ * @param reducers - 2 or more reducers to combine | ||
}, | ||
state: Init(reducer.init), | ||
state: OptLazy(reducer.init), | ||
}; | ||
@@ -896,0 +916,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
485500
10077