@codibre/fluent-iterable
Version:
Provides LINQ-like fluent api operations for iterables and async iterables (ES2018+).
305 lines (304 loc) • 8.47 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.iterate = void 0;
exports.isPromise = isPromise;
exports.asc = asc;
exports.desc = desc;
exports.assureOrder = assureOrder;
exports.assureOrderDescending = assureOrderDescending;
exports.constant = constant;
exports.empty = empty;
exports.emptyAsync = emptyAsync;
exports.identity = identity;
exports.truth = truth;
exports.falsity = falsity;
exports.negation = negation;
exports.asyncNegation = asyncNegation;
exports.fluentGroup = fluentGroup;
exports.getAverageStepper = getAverageStepper;
exports.eq = eq;
exports.ge = ge;
exports.gt = gt;
exports.le = le;
exports.lt = lt;
exports.iterateAsync = iterateAsync;
exports.iterateAllAsync = iterateAllAsync;
exports.iterateAll = iterateAll;
exports.iterateObjProps = iterateObjProps;
exports.iterateObjEntries = iterateObjEntries;
/* eslint-disable guard-for-in */
/* eslint-disable @typescript-eslint/no-empty-function */
const fluent_1 = __importDefault(require("../fluent"));
const types_internal_1 = require("../types-internal");
const string_wrapper_1 = require("../types-internal/string-wrapper");
const map_1 = require("../sync/map");
const fluent_class_1 = require("../fluent-class");
const valueTypes = ['string', 'number', 'boolean'];
/**
* Returns exactly the informed parameter
* @param param The informed parameter to be returned
*/
function identity(param) {
return param;
}
/**
* @internal
*/
async function* promiseIterateAsync(a) {
const resolved = await a;
yield* resolved;
}
function iteratorIterateAsync(a) {
return {
[Symbol.asyncIterator]() {
const iterator = a[Symbol.iterator]();
return {
next() {
const { done, value } = iterator.next();
return Promise.resolve({ done, value: done ? undefined : value });
},
return: iterator.return
? () => Promise.resolve(iterator.return(iterator))
: undefined,
throw: iterator.throw
? () => Promise.resolve(iterator.throw(iterator))
: undefined,
};
},
};
}
function isPromise(t) {
return !!(t && typeof t.then === 'function');
}
/**
* Iterates all element of an async iterable
* @typeparam T the item type of the [[Iterable]]
* @param a The async iterable
*/
function iterateAsync(a) {
if (isPromise(a))
return promiseIterateAsync(a);
return a[Symbol.iterator]
? iteratorIterateAsync(a)
: a;
}
/**
* Iterates in all elements of an async iterable of iterables or async iterables
* @typeparam T the item type of the internal [[Iterable/AsyncIterable]]
* @param a The async iterable
*/
async function* iterateAllAsync(a) {
for await (const it of a) {
yield* it;
}
}
/**
* Iterates all element of an iterable
* @typeparam T the item type of the [[Iterable]]
* @param a The iterable
*/
const iterate = identity;
exports.iterate = iterate;
/**
* Returns a function that always returns the informed value
* @param value the constant value
*/
function constant(value) {
return function constantValue() {
return value;
};
}
/**
* Iterates in all elements of an iterable of iterables
* @typeparam T the item type of the internal [[Iterable]]
* @param a The iterable
*/
function* iterateAll(a) {
for (const it of a) {
yield* it;
}
}
/**
* Iterates over all owned properties of the given object
* @param obj The object to iterate with
*/
function* iterateObjProps(obj) {
for (const property in obj) {
yield property;
}
}
/**
* Iterates over all owned entries of given object
* @param obj The object to iterate with
*/
function iterateObjEntries(obj) {
return map_1.map.call(iterateObjProps(obj), (property) => [
property,
obj[property],
]);
}
/**
* Provides a "equals" comparer
* @typeparam T the type of b
* @param b the value for comparison
*/
function eq(b) {
return (a) => a === b;
}
/**
* Provides a "greater than" comparer
* @typeparam T the type of b
* @param b the value for comparison
*/
function gt(b) {
return (a) => a > b;
}
/**
* Provides a "greater or equal" comparer
* @typeparam T the type of b
* @param b the value for comparison
*/
function ge(b) {
return (a) => a >= b;
}
/**
* Provides a "lesser than" comparer
* @typeparam T the type of b
* @param b the value for comparison
*/
function lt(b) {
return (a) => a < b;
}
/**
* Provides a "lesser or equal" comparer
* @typeparam T the type of b
* @param b the value for comparison
*/
function le(b) {
return (a) => a <= b;
}
/**
* Provides an empty iterable
*/
function* empty() { }
/**
* Provides an empty async iterable
*/
async function* emptyAsync() { }
/**
* Always returns true
*/
function truth() {
return true;
}
/**
* Always returns false
*/
function falsity() {
return false;
}
/**
* Provides a function that negates the informed predicate
* @typeparam T the item type of the [[Predicate]]
* @param predicate The predicate to be negated
*/
function negation(predicate) {
return (...item) => !predicate.apply(this, item);
}
/**
* Provides a function that negates the informed async predicate
* @typeparam T the item type of the [[AsyncPredicate]]
* @param predicate The async predicate to be negated
*/
function asyncNegation(predicate) {
return async (item) => !(await predicate(item));
}
/**
* Convert a simple [[Group]] to a [[FluentGroup]]
* @typeparam Key The type of the key
* @typeparam Value the type of the items of the value property
* @param {Group} grp the [[Group]] to be converted
*/
function fluentGroup(grp) {
return {
...grp,
values: (0, fluent_1.default)(grp.values),
};
}
/**
* Returns an object to calculates incremental average/iterative means
*/
function getAverageStepper() {
let avg = 0;
let count = 0;
const wrapper = {
get avg() {
return count ? avg : NaN;
},
get count() {
return count;
},
step: (y) => (avg = avg + (y - avg) / ++count),
};
return wrapper;
}
function getItemToAssure(f) {
return typeof f === 'function' && !(f instanceof fluent_class_1.FluentClass)
? (...args) => f(...args)
: f;
}
/**
* Returns a new instance of a function with a order assuring mark.
* Fluent Iterable will treat order Assuring marked function as if
* they're guaranteed to return ordered result in regard some iterable
* where they're applied. The actual order, though, is of responsibility
* of the code using this package.
*
* This is useful to have access to faster versions of some algorithms, but
* the output may not match expectation if the resulting order is not actually right.
*
* @param f the function to assure order
*/
function assureOrder(f) {
const result = getItemToAssure(f);
result[types_internal_1.orderAssured] = 1;
return result;
}
/**
* Returns a new instance of a function with a descending order assuring mark.
* Fluent Iterable will treat descending order assuring marked functions as if
* they're guaranteed to return descending ordered results in regard some iterable
* where they're applied. The actual order, though, is of responsibility
* of the code using this package.
*
* This is useful to have access to faster versions of some algorithms, but
* the output may not match expectation if the resulting order is not actually right.
*
* @param f the function to assure order
*/
function assureOrderDescending(f) {
const result = getItemToAssure(f);
result[types_internal_1.orderAssured] = -1;
return result;
}
function isValueType(f) {
const tp = typeof f;
return valueTypes.includes(tp);
}
/**
* Mark a field name or a mapper as ascending, for use with sortBy
* @param f the mapper or the field name
*/
function asc(f) {
return assureOrder((isValueType(f) ? { [string_wrapper_1.valueTypeWrapper]: f } : f));
}
/**
* Mark a field name or a mapper as descending, for use with sortBy
* @param f the mapper or the field name
*/
function desc(f) {
return assureOrderDescending((isValueType(f) ? { [string_wrapper_1.valueTypeWrapper]: f } : f));
}