@solid/community-server
Version:
Community Solid Server: an open and modular implementation of the Solid specifications
180 lines • 6.14 kB
JavaScript
;
// Utility functions for iterables that avoid array conversion
Object.defineProperty(exports, "__esModule", { value: true });
exports.map = map;
exports.filter = filter;
exports.concat = concat;
exports.find = find;
exports.reduce = reduce;
exports.sortedAsyncMerge = sortedAsyncMerge;
exports.asyncToArray = asyncToArray;
/**
* Creates a new iterable with the results of calling a provided function on every element in the calling array.
* Similar to the {@link Array.prototype.map} function.
* See the documentation of the above function for more details.
*
* @param iterable - Iterable on which to call the map function.
* @param callbackFn - Function that is called for every element.
* @param thisArg - Value to use as `this` when executing `callbackFn`.
*/
function* map(iterable, callbackFn, thisArg) {
const boundMapFn = callbackFn.bind(thisArg);
let count = 0;
for (const value of iterable) {
yield boundMapFn(value, count);
count += 1;
}
}
/**
* Creates a new iterable with all elements that pass the test implemented by the provided function.
* Similar to the {@link Array.prototype.filter} function.
* See the documentation of the above function for more details.
*
* @param iterable - Iterable on which to call the map function.
* @param callbackFn - Function that is called to test every element.
* @param thisArg - Value to use as `this` when executing `callbackFn`.
*/
function* filter(iterable, callbackFn, thisArg) {
const boundFilterFn = callbackFn.bind(thisArg);
let count = 0;
for (const value of iterable) {
if (boundFilterFn(value, count)) {
yield value;
}
count += 1;
}
}
/**
* Creates a new iterable that is a concatenation of all the iterables in the input.
*
* @param iterables - An iterable of which the contents will be concatenated into a new iterable.
*/
function* concat(iterables) {
for (const iterable of iterables) {
yield* iterable;
}
}
/**
* Returns the first element in the provided iterable that satisfies the provided testing function.
* If no values satisfy the testing function, `undefined` is returned.
* Similar to the {@link Array.prototype.find} function.
* See the documentation of the above function for more details.
*
* @param iterable - Iterable on which to call the map function.
* @param callbackFn - Function that is called to test every element.
* @param thisArg - Value to use as `this` when executing `callbackFn`.
*/
function find(iterable, callbackFn, thisArg) {
const boundMapFn = callbackFn.bind(thisArg);
const count = 0;
for (const value of iterable) {
if (boundMapFn(value, count)) {
return value;
}
}
}
function reduce(iterable, callbackFn, initialValue) {
const iterator = iterable[Symbol.iterator]();
let count = 0;
if (!initialValue) {
const next = iterator.next();
if (next.done) {
throw new TypeError('Iterable is empty and no initial value was provided.');
}
// `initialValue` being undefined means the first signature was used where TIn === TOut
initialValue = next.value;
count += 1;
}
let previousValue = initialValue;
let next = iterator.next();
while (!next.done) {
previousValue = callbackFn(previousValue, next.value, count);
next = iterator.next();
count += 1;
}
return previousValue;
}
/**
* Helper function for {@link sortedAsyncMerge}.
*
* Returns the next result of an AsyncIterator, or undefined if the iterator is finished.
*/
async function nextAsyncEntry(iterator) {
const result = await iterator.next();
if (result.done) {
return;
}
return result.value;
}
/**
* Helper function for {@link sortedAsyncMerge}.
*
* Compares the next results of all `iterators` and returns the first one,
* determined by the provided `comparator`.
*
* `results` should contain the first result of all these iterators.
* This array will also be updated, replacing the result of the iterator whose result was chosen by the next one.
*/
async function findNextSorted(iterators, results, comparator) {
let best;
// For every iterator: see if their next result is the best one so far
for (let i = 0; i < iterators.length; ++i) {
const value = results[i];
if (typeof value !== 'undefined') {
let compare = 1;
if (best) {
compare = comparator(best.value, value);
}
if (compare > 0) {
best = { idx: i, value };
}
}
}
if (best) {
// Advance the iterator that returned the new result
results[best.idx] = await nextAsyncEntry(iterators[best.idx]);
}
// Will return undefined if `best` was never initialized above
return best?.value;
}
/**
* Merges the results of several sorted iterators.
* In case the results of the individual iterators are not sorted the outcome results will also not be sorted.
*
* @param iterators - The iterators whose results need to be merged.
* @param comparator - The comparator to use to compare the results.
*/
async function* sortedAsyncMerge(iterators, comparator) {
if (!comparator) {
comparator = (left, right) => {
if (left < right) {
return -1;
}
return left > right ? 1 : 0;
};
}
// Initialize the array to the first result of every iterator
const results = [];
for (const iterator of iterators) {
results.push(await nextAsyncEntry(iterator));
}
// Keep returning results as long as we find them
while (true) {
const next = await findNextSorted(iterators, results, comparator);
if (typeof next === 'undefined') {
return;
}
yield next;
}
}
/**
* Converts an `AsyncIterator` to an array.
*/
async function asyncToArray(iterable) {
const arr = [];
for await (const result of iterable) {
arr.push(result);
}
return arr;
}
//# sourceMappingURL=IterableUtil.js.map