declarative-js
Version:
_declarative-js_ is modern JavaScript library, that helps to: - tackle array transformation with built in JavaScript array api (e.g. `array.filter(toBe.unique())`), - provide a type-level solution for representing optional values instead of null referen
342 lines (341 loc) • 14.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
var toObject_1 = require("../internal/toObject");
var toMap_1 = require("../internal/toMap");
var JMap_1 = require("../map/JMap");
var reducer_utils_1 = require("../internal/reducer.utils");
/**
* Functions to be used in {@link Array.prototype.reduce} as a callback.
* @see https://pavel-surinin.github.io/declarativejs/#/?id=reducers
*/
var Reducer;
(function (Reducer) {
function Map(data) {
return new JMap_1.JMap(data);
}
Reducer.Map = Map;
function ImmutableMap() {
var map = new JMap_1.JMap();
return Object.defineProperty(map, reducer_utils_1.IMMUTABLE, { value: true, enumerable: false });
}
Reducer.ImmutableMap = ImmutableMap;
function ImmutableObject() {
var object = {};
return Object.defineProperty(object, reducer_utils_1.IMMUTABLE, { value: true, enumerable: false });
}
Reducer.ImmutableObject = ImmutableObject;
function groupBy(getKey, transformer) {
if (transformer === void 0) { transformer = function (x) { return x; }; }
switch (typeof getKey) {
case 'string': {
var key_1 = getKey;
return function (agr, value, index, array) {
var derivedKey = value[key_1];
if (typeof derivedKey === 'string') {
var derivedValue = agr.get(derivedKey);
if (derivedValue) {
derivedValue.push(transformer(value));
}
else {
agr.put(derivedKey, [transformer(value)]);
}
return reducer_utils_1.isLastElement(array, index) ? reducer_utils_1.finalizeMap(agr) : agr;
}
// tslint:disable-next-line:max-line-length
throw new Error('Value of "' + key_1 + '" in groupBy ' + ' must be string, instead get: ' + typeof value[key_1]);
};
}
case 'function': {
return function (agr, value, index, array) {
var key = reducer_utils_1.valid(getKey(value));
var extractedValue = agr.get(key);
if (extractedValue !== void 0) {
extractedValue.push(transformer(value));
}
else {
agr.put(key, [transformer(value)]);
}
return reducer_utils_1.isLastElement(array, index) ? reducer_utils_1.finalizeMap(agr) : agr;
};
}
default:
// tslint:disable-next-line:max-line-length
throw new Error("Reducer.groupBy function accepts as a paramter string or callback, instead got " + typeof getKey);
}
}
Reducer.groupBy = groupBy;
/**
* Function to be used in {@link Array.prototype.reduce} as a callback
* to make from 2d array simple array
* As second parameter in reduce function need to pass <code>[]</code>
* @param {T[]} agr to collect in
* @param {T[]} value to concatenate with
* @returns {T[]} concatenated array
* @see https://pavel-surinin.github.io/declarativejs/#/?id=flat
*/
Reducer.flat = function (agr, value) {
if (Array.isArray(value)) {
for (var index = 0; index < value.length; index++) {
var element = value[index];
agr[agr.length] = element;
}
}
else {
agr[agr.length] = value;
}
return agr;
};
function toMap(getKey, valueGetter) {
var mapper = valueGetter === undefined
? toMap_1.toMapKeyMap(getKey)
: toMap_1.toMapAndValue(getKey, valueGetter);
return function _toMap(agr, value, index, array) {
return mapper(agr, value, index, array);
};
}
Reducer.toMap = toMap;
function toObject(getKey, valueGetter, merge) {
var onDuplicate = merge || reducer_utils_1.onDuplacateDefaultFunction;
var reducer = valueGetter === undefined
? toObject_1.toObjectValueObject(getKey)
: toObject_1.toObjectAndValue(getKey, valueGetter, onDuplicate);
return function _toObject(agr, value, index, array) {
return reducer(agr, value, index, array);
};
}
Reducer.toObject = toObject;
/**
* Function to be used in {@link Array.prototype.reduce} as a callback.
* Finds lowest value in array. Array must contain only numbers
* @returns {number} lowest value in array.
* @see https://pavel-surinin.github.io/declarativejs/#/?id=min
*/
// @ts-ignore
function min(agr, value, index, array) {
return reducer_utils_1.isLastElement(array, index) ? Math.min.apply(Math, array) : 0;
}
Reducer.min = min;
/**
* Function to be used in {@link Array.prototype.reduce} as a callback.
* Finds highest value in array. Array must contain only numbers
* @returns {number} highest value in array.
* @see https://pavel-surinin.github.io/declarativejs/#/?id=max
*/
// @ts-ignore
function max(agr, value, index, array) {
return reducer_utils_1.isLastElement(array, index) ? Math.max.apply(Math, array) : 0;
}
Reducer.max = max;
/**
* Function to be used in {@link Array.prototype.reduce} as a callback.
* Finds sum of values in array. Array must contain only numbers
* @returns {number} sum of values in array.
* @see https://pavel-surinin.github.io/declarativejs/#/?id=sum
*/
Reducer.sum = function (agr, value) {
return agr + value;
};
/**
* Object merging strategy used in {@link Reducer#toMergedObject}
* @see toMergedObject
*/
Reducer.MergeStrategy = {
/**
* Overrides value by duplicated key while merging objects
*/
OVERRIDE: function () { return true; },
/**
* Keys in objects must be unique
*/
UNIQUE: function (aggregatorValue) { return aggregatorValue == null; },
/**
* Keys in objects may have duplicates, but values in these key must be equal
*/
CHECKED: function (aggregatorValue, currentValue) { return aggregatorValue == null
|| fast_deep_equal_1.default(aggregatorValue, currentValue); }
};
/**
* Function to be used in {@link Array.prototype.reduce} as a callback.
* Reduces array of objects to one object, There is three merge strategies
* @param merge {@link MergeStrategy} = default is OVERRIDE
* @see MergeStrategy
* @see https://pavel-surinin.github.io/declarativejs/#/?id=tomergedobject
*/
function toMergedObject(isMergable) {
if (isMergable === void 0) { isMergable = Reducer.MergeStrategy.OVERRIDE; }
return function _toMergedObject(agr, value) {
for (var _i = 0, _a = Object.keys(value); _i < _a.length; _i++) {
var k = _a[_i];
var valueFromAggr = agr[k];
var valueFromObject = value[k];
if (!isMergable(valueFromAggr, valueFromObject, k)) {
// tslint:disable-next-line:max-line-length
throw new Error("Failed to merge objects. Check the merging predicate (\"strategy\") and objects in an array with key: " + k);
}
agr[k] = valueFromObject;
}
return agr;
};
}
Reducer.toMergedObject = toMergedObject;
function zip(array, withFx) {
var t = withFx
? withFx
: function (t1, t2) { return [t1, t2]; };
var isZipped = false;
var secondArrLength = array.length;
return function _zip(agr, value, index) {
if (isZipped) {
return agr;
}
var arrayValue = array[index];
if (secondArrLength == index) {
isZipped = true;
return agr;
}
agr.push(t(value, arrayValue));
return agr;
};
}
Reducer.zip = zip;
/**
* Function to be used in {@link Array.prototype.reduce} as a callback.
* Collects all arrays to arrays of arrays, with elements
* at being grouped with elements from other arrays by same index.
* The length of zipped array will be length of shortest array.
* Almost the same as {@link Reducer.zip}, except zipAll accepts
* multiple array to zip with.
*
* @export
* @param {...Array[]} arraysToZip
* @returns function to use in Array.reduce
* @see Reducer.zip
* @see https://pavel-surinin.github.io/declarativejs/#/?id=zipall
*/
function zipAll() {
var arraysToZip = [];
for (var _i = 0; _i < arguments.length; _i++) {
arraysToZip[_i] = arguments[_i];
}
var isZipped = false;
var lengthOfArrays = arraysToZip.length;
return function _zipAll(agr, currentValue, currentValueIndex) {
if (isZipped) {
return agr;
}
if (lengthOfArrays == currentValueIndex) {
isZipped = true;
return agr;
}
var zipee = [currentValue];
for (var index = 0; index < arraysToZip.length; index++) {
zipee.push(arraysToZip[index][currentValueIndex]);
}
agr.push(zipee);
return agr;
};
}
Reducer.zipAll = zipAll;
/**
* Function to be used in {@link Array.prototype.reduce} as a callback.
* It does the opposite as {@link Reducer.zip} or {@link Reducer.zipAll}.
* It collects from all zipped arrays one arrays, that was before zip.
* Takes from each nested arrays and element and for each index will
* collect to new array.
* The length of and array will be the shortest length of arrays to unzip
*
* @export
* @returns function to use in Array.reduce
* @see Reducer.zip
* @see Reducer.zipAll
* @see https://pavel-surinin.github.io/declarativejs/#/?id=unzip
*/
function unzip() {
var zippersLength;
// @ts-ignore
return function _unzip(agr, value, index, arrays) {
if (zippersLength == null) {
zippersLength = arrays.map(function (arr) { return arr.length; }).reduce(min);
}
for (var valueArrayIndex = 0; valueArrayIndex < zippersLength; valueArrayIndex++) {
var agrUnzipArray = agr[valueArrayIndex];
if (agrUnzipArray) {
agrUnzipArray.push(value[valueArrayIndex]);
}
else {
agr[valueArrayIndex] = [value[valueArrayIndex]];
}
}
return agr;
};
}
Reducer.unzip = unzip;
Reducer.Partition = function () { return [[], []]; };
function partitionBy(matches) {
// tslint:disable-next-line
var errorMessage = "Predicate for 'partitionBy' can be key of object, predicate function or partial object to match, instead got '" + matches + "'";
var predicate;
if (typeof matches === 'string') {
predicate = function (value) { return Boolean(value[matches]); };
}
else if (typeof matches === 'function') {
predicate = function (value) { return matches(value); };
}
else if (typeof matches === 'object') {
if (matches === null) {
throw new Error(errorMessage);
}
predicate = function (value) { return Object.keys(matches).every(function (key) { return value[key] === matches[key]; }); };
}
else {
throw new Error(errorMessage);
}
return function _partitionByProp(agr, value) {
if (predicate(value)) {
agr[0].push(value);
}
else {
agr[1].push(value);
}
return agr;
};
}
Reducer.partitionBy = partitionBy;
/**
* Function to be used in {@link Array.prototype.reduce} as a callback.
* Groups pairs of consecutive elements together and returns them as an array of two values.
* @see https://pavel-surinin.github.io/declarativejs/#/?id=pairwise
*/
function pairwise() {
// @ts-ignore
return function _pairwise(agr, value, index, array) {
if (array.length - 1 != index) {
agr.push([array[index], array[index + 1]]);
}
return agr;
};
}
Reducer.pairwise = pairwise;
/**
* Function to be used in {@link Array.prototype.reduce} as a callback.
* Applies an accumulator function over the current element
* and returns each intermediate result for accumulation
* @param {function} accFunction accumulator function
* @param {T} initial value
* @see https://pavel-surinin.github.io/declarativejs/#/?id=scan
*/
function scan(accFunction, initial) {
var acc = initial;
return function _scan(agr, value) {
var scanned = accFunction(acc, value);
acc = accFunction(acc, value);
agr.push(scanned);
return agr;
};
}
Reducer.scan = scan;
})(Reducer = exports.Reducer || (exports.Reducer = {}));