@rimbu/common
Version:
Common types and objects used in many other Rimbu packages
382 lines • 12.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.Eq = void 0;
var tslib_1 = require("tslib");
var Eq;
(function (Eq) {
function convertAnyToString(value) {
if (typeof value !== 'object' ||
null === value ||
!('toString' in value) ||
typeof value.toString !== 'function' ||
value.toString !== Object.prototype.toString) {
return String(value);
}
return JSON.stringify(value);
}
Eq.convertAnyToString = convertAnyToString;
var _anyFlatEq = createAnyEq('FLAT');
var _anyShallowEq = createAnyEq('SHALLOW');
var _anyDeepEq = createAnyEq('DEEP');
/**
* Returns the default Eq instance, which is the Eq.anyDeepEq() instance.
*/
function defaultEq() {
return _anyDeepEq;
}
Eq.defaultEq = defaultEq;
/**
* An Eq instance that uses `Object.is` to determine if two objects are equal.
* @example
* ```ts
* const eq = Eq.objectIs
* console.log(eq(5, 5))
* // => true
* console.log(eq(5, 'a'))
* // => false
* ```
*/
Eq.objectIs = Object.is;
var _valueOfEq = function (v1, v2) {
return Object.is(v1.valueOf(), v2.valueOf());
};
/**
* Returns an Eq instance for objects that have a `valueOf` method. It returns true if the `.valueOf` values of both given objects are equal.
* @typeparam T - the object type containing a valueOf function of type V
* @typeparam V - the valueOf result type
* @example
* ```ts
* const eq = Eq.valueOfEq()
* console.log(eq(new Number(5), new Number(5)))
* // => true
* console.log(eq(new Number(5), new Number(3)))
* // => false
* ```
*/
function valueOfEq() {
return _valueOfEq;
}
Eq.valueOfEq = valueOfEq;
/**
* Returns an Eq instance that compares Date objects according to their `valueOf` value.
* @example
* ```ts
* const eq = Eq.dateEq()
* console.log(eq(new Date(2020, 1, 1), new Date(2020, 1, 1))
* // => true
* console.log(eq(new Date(2020, 1, 1), new Date(2020, 2, 1))
* // => false
* ```
*/
function dateEq() {
return _valueOfEq;
}
Eq.dateEq = dateEq;
function createIterableEq(itemEq) {
return function (v1, v2) {
if (Object.is(v1, v2))
return true;
var iter1 = v1[Symbol.iterator]();
var iter2 = v2[Symbol.iterator]();
while (true) {
var value1 = iter1.next();
var value2 = iter2.next();
if (value1.done || value2.done)
return value1.done === value2.done;
if (!itemEq(value1.value, value2.value))
return false;
}
};
}
var _iterableAnyEq = createIterableEq(defaultEq());
/**
* Returns an Eq instance that compares Iterables by comparing their elements with the given `itemEq` Eq instance.
* @typeparam T - the Iterable element type
* @param itemEq - (optional) the Eq instance to use to compare the Iterable's elements
* @example
* ```ts
* const eq = Eq.iterableEq();
* console.log(eq([1, 2, 3], [1, 2, 3])
* // => true
* console.log(eq([1, 2, 3], [1, 3, 2])
* // => false
* ```
*/
function iterableEq(itemEq) {
if (undefined === itemEq)
return _iterableAnyEq;
return createIterableEq(itemEq);
}
Eq.iterableEq = iterableEq;
function createObjectEq(valueEq) {
return function (v1, v2) {
if (Object.is(v1, v2))
return true;
if (v1.constructor !== v2.constructor)
return false;
for (var key in v1) {
if (!(key in v2))
return false;
}
for (var key in v2) {
if (!(key in v1))
return false;
}
for (var key in v1) {
var value1 = v1[key];
var value2 = v2[key];
if (!valueEq(value1, value2))
return false;
}
return true;
};
}
var _objectEq = createObjectEq(defaultEq());
/**
* Returns an Eq instance that checks equality of objects containing property values of type V by iteratively
* applying given `valueEq` to each of the object's property values.
* @typeparam - the object property value type
* @param valueEq - (optional) the Eq instance to use to compare property values
* @example
* ```ts
* const eq = Eq.objectEq()
* console.log(eq({ a: 1, b: { c: 2 }}, { b: { c: 2 }, a: 1 }))
* // => true
* console.log(eq({ a: 1, b: { c: 2 }}, { a: 1, b: { c: 3 }}))
* // => false
* ```
*/
function objectEq(valueEq) {
if (undefined === valueEq)
return _objectEq;
return createObjectEq(valueEq);
}
Eq.objectEq = objectEq;
function createAnyEq(mode) {
var result = function (v1, v2) {
if (Object.is(v1, v2))
return true;
var type1 = typeof v1;
var type2 = typeof v2;
if (type1 !== type2)
return false;
switch (type1) {
case 'undefined':
case 'bigint':
case 'boolean':
case 'number':
case 'string':
case 'symbol':
case 'function':
return Object.is(v1, v2);
case 'object': {
if (v1 === null || v2 === null)
return false;
if (v1.constructor !== v2.constructor) {
return false;
}
if (v1 instanceof Boolean ||
v1 instanceof Date ||
v1 instanceof Number ||
v1 instanceof String) {
return _valueOfEq(v1, v2);
}
if (mode !== 'FLAT') {
if (Symbol.iterator in v1 && Symbol.iterator in v2) {
if (mode === 'SHALLOW') {
return createIterableEq(_anyFlatEq)(v1, v2);
}
return createIterableEq(result)(v1, v2);
}
if (mode === 'SHALLOW') {
return createObjectEq(_anyFlatEq)(v1, v2);
}
return _objectEq(v1, v2);
}
// cannot establish that they are equal in flat mode
return false;
}
}
};
return result;
}
/**
* Returns an Eq instance that checks equality of any values. For composed values (objects and iterables)
* it will compare with Object.is.
* @typeparam T - the value type
* @example
* ```ts
* const eq = anyFlatEq()
* console.log(eq(1, 'a'))
* // => false
* console.log(eq({ a: 1, b: 2 }, { b: 2, a: 1 }))
* // => false
* ```
*/
function anyFlatEq() {
return _anyFlatEq;
}
Eq.anyFlatEq = anyFlatEq;
/**
* Returns an Eq instance that checks equality of any values. For composed values (objects and iterables)
* it will enter 1 level, and if again compound values are found, they are compared
* with Object.is.
* @typeparam T - the value type
* @example
* ```ts
* const eq = anyFlatEq()
* console.log(eq(1, 'a'))
* // => false
* console.log(eq({ a: 1, b: 2 }, { b: 2, a: 1 }))
* // => true
* console.log(eq([{ a: 1, b: 2 }], [{ b: 2, a: 1 }]))
* // => false
* ```
*/
function anyShallowEq() {
return _anyShallowEq;
}
Eq.anyShallowEq = anyShallowEq;
/**
* Returns an Eq instance that checks equality of any values. For composed values (objects and iterables)
* it will recursively compare the contained values.
* @note may have poor performance for deeply nested types and large arrays, and objects with circular structures
* may cause infinite loops
* @typeparam T - the value type
* @example
* ```ts
* const eq = anyFlatEq()
* console.log(eq(1, 'a'))
* // => false
* console.log(eq({ a: 1, b: 2 }, { b: 2, a: 1 }))
* // => true
* console.log(eq([{ a: 1, b: 2 }], [{ b: 2, a: 1 }]))
* // => false
* ```
*/
function anyDeepEq() {
return _anyDeepEq;
}
Eq.anyDeepEq = anyDeepEq;
var _defaultCollator = Intl.Collator('und');
var _defaultStringCollatorEq = function (v1, v2) {
return _defaultCollator.compare(v1, v2) === 0;
};
/**
* Returns an Eq instance that considers strings equal taking the given or default locale into account.
* @param locales - (optional) a locale or list of locales
* @param options - (optional) see String.localeCompare for details
* @example
* ```ts
* const eq = Eq.createStringCollatorEq()
* console.log(eq('a', 'a'))
* // => true
* console.log(eq('abc', 'aBc'))
* // => false
* ```
*/
function createStringCollatorEq() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (args.length === 0)
return _defaultStringCollatorEq;
var collator = Intl.Collator.apply(Intl, tslib_1.__spreadArray([], tslib_1.__read(args), false));
return function (v1, v2) { return collator.compare(v1, v2) === 0; };
}
Eq.createStringCollatorEq = createStringCollatorEq;
var _stringCaseInsensitiveEq = createStringCollatorEq('und', {
sensitivity: 'accent',
});
/**
* Returns an Eq instance that considers strings equal regardless of their case.
* @example
* ```ts
* const eq = Eq.stringCaseInsentitiveEq()
* console.log(eq('aB', 'Ab'))
* // => true
* console.log(eq('aBc', 'abB'))
* // => false
* ```
*/
function stringCaseInsentitiveEq() {
return _stringCaseInsensitiveEq;
}
Eq.stringCaseInsentitiveEq = stringCaseInsentitiveEq;
var _stringCharCodeEq = function (v1, v2) {
var len = v1.length;
if (len !== v2.length)
return false;
var i = -1;
while (++i < len) {
if (v1.charCodeAt(i) !== v2.charCodeAt(i))
return false;
}
return true;
};
/**
* Returns an Eq instance that considers strings equal when all their charcodes are equal.
* @example
* ```ts
* const eq = Eq.stringCharCodeEq()
* console.log(eq('a', 'a'))
* // => true
* console.log(eq('abc', 'aBc'))
* // => false
* ```
*/
function stringCharCodeEq() {
return _stringCharCodeEq;
}
Eq.stringCharCodeEq = stringCharCodeEq;
var _anyToStringEq = function (v1, v2) {
return convertAnyToString(v1) === convertAnyToString(v2);
};
function anyToStringEq() {
return _anyToStringEq;
}
Eq.anyToStringEq = anyToStringEq;
var _anyJsonEq = function (v1, v2) {
return JSON.stringify(v1) === JSON.stringify(v2);
};
/**
* Returns an Eq instance that considers values equal their JSON.stringify values are equal.
* @example
* ```ts
* const eq = Eq.anyJsonEq()
* console.log(eq({ a: 1, b: 2 }, { a: 1, b: 2 }))
* // => true
* console.log(eq({ a: 1, b: 2 }, { b: 2, a: 1 }))
* // => false
* ```
*/
function anyJsonEq() {
return _anyJsonEq;
}
Eq.anyJsonEq = anyJsonEq;
/**
* Returns an `Eq` instance for tuples that considers two tuples [A, B] and [C, D] equal if [A, B] equals [C, D],
* or if [A, B] equals [D, C]
* @param eq - (optional) an alternative `Eq` instance to use for the values in the tuple
* @example
* ```ts
* const eq = Eq.tupleSymmetric()
* console.log(eq([1, 2], [1, 2]))
* // => true
* console.log(eq([1, 2], [2, 1]))
* // => true
* console.log(eq([1, 3], [2, 1]))
* // => false
* ```
*/
function tupleSymmetric(eq) {
if (eq === void 0) { eq = defaultEq(); }
return function (tup1, tup2) {
return (eq(tup1[0], tup2[0]) && eq(tup1[1], tup2[1])) ||
(eq(tup1[0], tup2[1]) && eq(tup1[1], tup2[0]));
};
}
Eq.tupleSymmetric = tupleSymmetric;
})(Eq || (exports.Eq = Eq = {}));
//# sourceMappingURL=eq.cjs.map
;