UNPKG

@rimbu/common

Version:

Common types and objects used in many other Rimbu packages

382 lines 12.8 kB
"use strict"; 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