@ngxs/store
Version:
191 lines (180 loc) • 6.2 kB
JavaScript
const isArray = Array.isArray;
const isFunction = (value) => typeof value == 'function';
const isStateOperator = isFunction;
const isPredicate = isFunction;
const isNumber = (value) => typeof value === 'number';
const invalidIndex = (index) => Number.isNaN(index) || index === -1;
/**
* @param items - Specific items to append to the end of an array
*/
function append(items) {
return function appendOperator(existing) {
// If `items` is `undefined` or `null` or `[]` but `existing` is provided
// just return `existing`
const itemsNotProvidedButExistingIs = (!items || !items.length) && existing;
if (itemsNotProvidedButExistingIs) {
return existing;
}
if (isArray(existing)) {
return existing.concat(items);
}
// For example if some property is added dynamically
// and didn't exist before thus it's not `ArrayLike`
return items;
};
}
function compose(...operators) {
return function composeOperator(existing) {
return operators.reduce((accumulator, operator) => operator(accumulator), existing);
};
}
function retrieveValue(operatorOrValue, existing) {
// If state operator is a function
// then call it with an original value
if (isStateOperator(operatorOrValue)) {
const value = operatorOrValue(existing);
return value;
}
// If operator or value was not provided
// e.g. `elseOperatorOrValue` is `undefined`
// then we just return an original value
if (operatorOrValue === undefined) {
return existing;
}
return operatorOrValue;
}
/**
* @param condition - Condition can be a plain boolean value or a function,
* that returns boolean, also this function can take a value as an argument
* to which this state operator applies
* @param trueOperatorOrValue - Any value or a state operator
* @param elseOperatorOrValue - Any value or a state operator
*/
function iif(condition, trueOperatorOrValue, elseOperatorOrValue) {
return function iifOperator(existing) {
// Convert the value to a boolean
let result = !!condition;
// but if it is a function then run it to get the result
if (isPredicate(condition)) {
result = condition(existing);
}
if (result) {
return retrieveValue(trueOperatorOrValue, existing);
}
return retrieveValue(elseOperatorOrValue, existing);
};
}
/**
* @param value - Value to insert
* @param [beforePosition] - Specified index to insert value before, optional
*/
function insertItem(value, beforePosition) {
return function insertItemOperator(existing) {
// Have to check explicitly for `null` and `undefined`
// because `value` can be `0`, thus `!value` will return `true`
if (value == null && existing) {
return existing;
}
// Property may be dynamic and might not existed before
if (!isArray(existing)) {
return [value];
}
const clone = existing.slice();
let index = 0;
// No need to call `isNumber`
// as we are checking `> 0` not `>= 0`
// everything except number will return false here
if (beforePosition > 0) {
index = beforePosition;
}
clone.splice(index, 0, value);
return clone;
};
}
function patch(patchObject) {
return function patchStateOperator(existing) {
let clone = null;
for (const k in patchObject) {
const newValue = patchObject[k];
const existingPropValue = existing?.[k];
const newPropValue = isStateOperator(newValue)
? newValue(existingPropValue)
: newValue;
if (newPropValue !== existingPropValue) {
if (!clone) {
clone = { ...existing };
}
clone[k] = newPropValue;
}
}
return clone || existing;
};
}
/**
* @param selector - Index of item in the array or a predicate function
* that can be provided in `Array.prototype.findIndex`
* @param operatorOrValue - New value under the `selector` index or a
* function that can be applied to an existing value
*/
function updateItem(selector, operatorOrValue) {
return function updateItemOperator(existing) {
let index = -1;
if (isPredicate(selector)) {
index = existing.findIndex(selector);
}
else if (isNumber(selector)) {
index = selector;
}
if (invalidIndex(index)) {
return existing;
}
let value = null;
// Need to check if the new item value will change the existing item value
// then, only if it will change it then clone the array and set the item
const theOperatorOrValue = operatorOrValue;
if (isStateOperator(theOperatorOrValue)) {
value = theOperatorOrValue(existing[index]);
}
else {
value = theOperatorOrValue;
}
// If the value hasn't been mutated
// then we just return `existing` array
if (value === existing[index]) {
return existing;
}
const clone = existing.slice();
clone[index] = value;
return clone;
};
}
/**
* @param selector - index or predicate to remove an item from an array by
*/
function removeItem(selector) {
return function removeItemOperator(existing) {
let index = -1;
if (isPredicate(selector)) {
index = existing.findIndex(selector);
}
else if (isNumber(selector)) {
index = selector;
}
if (invalidIndex(index)) {
return existing;
}
const clone = existing.slice();
clone.splice(index, 1);
return clone;
};
}
/**
* @module
* @description
* Entry point for all public APIs of this package.
*/
/**
* Generated bundle index. Do not edit.
*/
export { append, compose, iif, insertItem, isPredicate, isStateOperator, patch, removeItem, updateItem };
//# sourceMappingURL=ngxs-store-operators.mjs.map