UNPKG

immutable

Version:
1,459 lines (1,287 loc) 199 kB
/** * @license * MIT License * * Copyright (c) 2014-present, Lee Byron and other contributors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Immutable = {})); })(this, (function (exports) { 'use strict'; // Used for setting prototype methods that IE8 chokes on. var DELETE = 'delete'; // Constants describing the size of trie nodes. var SHIFT = 5; // Resulted in best performance after ______? var SIZE = 1 << SHIFT; var MASK = SIZE - 1; // A consistent shared value representing "not set" which equals nothing other // than itself, and nothing that could be provided externally. var NOT_SET = {}; // Boolean references, Rough equivalent of `bool &`. function MakeRef() { return { value: false }; } function SetRef(ref) { if (ref) { ref.value = true; } } // A function which returns a value representing an "owner" for transient writes // to tries. The return value will only ever equal itself, and will not equal // the return of any subsequent call of this function. function OwnerID() { } function ensureSize(iter) { // @ts-expect-error size should exists on Collection if (iter.size === undefined) { // @ts-expect-error size should exists on Collection, __iterate does exist on Collection iter.size = iter.__iterate(returnTrue); } // @ts-expect-error size should exists on Collection return iter.size; } function wrapIndex(iter, index) { // This implements "is array index" which the ECMAString spec defines as: // // A String property name P is an array index if and only if // ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal // to 2^32−1. // // http://www.ecma-international.org/ecma-262/6.0/#sec-array-exotic-objects if (typeof index !== 'number') { var uint32Index = index >>> 0; // N >>> 0 is shorthand for ToUint32 if ('' + uint32Index !== index || uint32Index === 4294967295) { return NaN; } index = uint32Index; } return index < 0 ? ensureSize(iter) + index : index; } function returnTrue() { return true; } function wholeSlice(begin, end, size) { return (((begin === 0 && !isNeg(begin)) || (size !== undefined && begin <= -size)) && (end === undefined || (size !== undefined && end >= size))); } function resolveBegin(begin, size) { return resolveIndex(begin, size, 0); } function resolveEnd(end, size) { return resolveIndex(end, size, size); } function resolveIndex(index, size, defaultIndex) { // Sanitize indices using this shorthand for ToInt32(argument) // http://www.ecma-international.org/ecma-262/6.0/#sec-toint32 return index === undefined ? defaultIndex : isNeg(index) ? size === Infinity ? size : Math.max(0, size + index) | 0 : size === undefined || size === index ? index : Math.min(size, index) | 0; } function isNeg(value) { // Account for -0 which is negative, but not less than 0. return value < 0 || (value === 0 && 1 / value === -Infinity); } // Note: value is unchanged to not break immutable-devtools. var IS_COLLECTION_SYMBOL = '@@__IMMUTABLE_ITERABLE__@@'; /** * True if `maybeCollection` is a Collection, or any of its subclasses. * * ```js * import { isCollection, Map, List, Stack } from 'immutable'; * * isCollection([]); // false * isCollection({}); // false * isCollection(Map()); // true * isCollection(List()); // true * isCollection(Stack()); // true * ``` */ function isCollection(maybeCollection) { return Boolean(maybeCollection && // @ts-expect-error: maybeCollection is typed as `{}`, need to change in 6.0 to `maybeCollection && typeof maybeCollection === 'object' && IS_COLLECTION_SYMBOL in maybeCollection` maybeCollection[IS_COLLECTION_SYMBOL]); } var IS_KEYED_SYMBOL = '@@__IMMUTABLE_KEYED__@@'; /** * True if `maybeKeyed` is a Collection.Keyed, or any of its subclasses. * * ```js * import { isKeyed, Map, List, Stack } from 'immutable'; * * isKeyed([]); // false * isKeyed({}); // false * isKeyed(Map()); // true * isKeyed(List()); // false * isKeyed(Stack()); // false * ``` */ function isKeyed(maybeKeyed) { return Boolean(maybeKeyed && // @ts-expect-error: maybeKeyed is typed as `{}`, need to change in 6.0 to `maybeKeyed && typeof maybeKeyed === 'object' && IS_KEYED_SYMBOL in maybeKeyed` maybeKeyed[IS_KEYED_SYMBOL]); } var IS_INDEXED_SYMBOL = '@@__IMMUTABLE_INDEXED__@@'; /** * True if `maybeIndexed` is a Collection.Indexed, or any of its subclasses. * * ```js * import { isIndexed, Map, List, Stack, Set } from 'immutable'; * * isIndexed([]); // false * isIndexed({}); // false * isIndexed(Map()); // false * isIndexed(List()); // true * isIndexed(Stack()); // true * isIndexed(Set()); // false * ``` */ function isIndexed(maybeIndexed) { return Boolean(maybeIndexed && // @ts-expect-error: maybeIndexed is typed as `{}`, need to change in 6.0 to `maybeIndexed && typeof maybeIndexed === 'object' && IS_INDEXED_SYMBOL in maybeIndexed` maybeIndexed[IS_INDEXED_SYMBOL]); } /** * True if `maybeAssociative` is either a Keyed or Indexed Collection. * * ```js * import { isAssociative, Map, List, Stack, Set } from 'immutable'; * * isAssociative([]); // false * isAssociative({}); // false * isAssociative(Map()); // true * isAssociative(List()); // true * isAssociative(Stack()); // true * isAssociative(Set()); // false * ``` */ function isAssociative(maybeAssociative) { return isKeyed(maybeAssociative) || isIndexed(maybeAssociative); } var Collection = function Collection(value) { // eslint-disable-next-line no-constructor-return return isCollection(value) ? value : Seq(value); }; var KeyedCollection = /*@__PURE__*/(function (Collection) { function KeyedCollection(value) { // eslint-disable-next-line no-constructor-return return isKeyed(value) ? value : KeyedSeq(value); } if ( Collection ) KeyedCollection.__proto__ = Collection; KeyedCollection.prototype = Object.create( Collection && Collection.prototype ); KeyedCollection.prototype.constructor = KeyedCollection; return KeyedCollection; }(Collection)); var IndexedCollection = /*@__PURE__*/(function (Collection) { function IndexedCollection(value) { // eslint-disable-next-line no-constructor-return return isIndexed(value) ? value : IndexedSeq(value); } if ( Collection ) IndexedCollection.__proto__ = Collection; IndexedCollection.prototype = Object.create( Collection && Collection.prototype ); IndexedCollection.prototype.constructor = IndexedCollection; return IndexedCollection; }(Collection)); var SetCollection = /*@__PURE__*/(function (Collection) { function SetCollection(value) { // eslint-disable-next-line no-constructor-return return isCollection(value) && !isAssociative(value) ? value : SetSeq(value); } if ( Collection ) SetCollection.__proto__ = Collection; SetCollection.prototype = Object.create( Collection && Collection.prototype ); SetCollection.prototype.constructor = SetCollection; return SetCollection; }(Collection)); Collection.Keyed = KeyedCollection; Collection.Indexed = IndexedCollection; Collection.Set = SetCollection; var IS_SEQ_SYMBOL = '@@__IMMUTABLE_SEQ__@@'; /** * True if `maybeSeq` is a Seq. */ function isSeq(maybeSeq) { return Boolean(maybeSeq && // @ts-expect-error: maybeSeq is typed as `{}`, need to change in 6.0 to `maybeSeq && typeof maybeSeq === 'object' && MAYBE_SEQ_SYMBOL in maybeSeq` maybeSeq[IS_SEQ_SYMBOL]); } var IS_RECORD_SYMBOL = '@@__IMMUTABLE_RECORD__@@'; /** * True if `maybeRecord` is a Record. */ function isRecord(maybeRecord) { return Boolean(maybeRecord && // @ts-expect-error: maybeRecord is typed as `{}`, need to change in 6.0 to `maybeRecord && typeof maybeRecord === 'object' && IS_RECORD_SYMBOL in maybeRecord` maybeRecord[IS_RECORD_SYMBOL]); } /** * True if `maybeImmutable` is an Immutable Collection or Record. * * Note: Still returns true even if the collections is within a `withMutations()`. * * ```js * import { isImmutable, Map, List, Stack } from 'immutable'; * isImmutable([]); // false * isImmutable({}); // false * isImmutable(Map()); // true * isImmutable(List()); // true * isImmutable(Stack()); // true * isImmutable(Map().asMutable()); // true * ``` */ function isImmutable(maybeImmutable) { return isCollection(maybeImmutable) || isRecord(maybeImmutable); } var IS_ORDERED_SYMBOL = '@@__IMMUTABLE_ORDERED__@@'; function isOrdered(maybeOrdered) { return Boolean(maybeOrdered && // @ts-expect-error: maybeOrdered is typed as `{}`, need to change in 6.0 to `maybeOrdered && typeof maybeOrdered === 'object' && IS_ORDERED_SYMBOL in maybeOrdered` maybeOrdered[IS_ORDERED_SYMBOL]); } var ITERATE_KEYS = 0; var ITERATE_VALUES = 1; var ITERATE_ENTRIES = 2; var REAL_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; var FAUX_ITERATOR_SYMBOL = '@@iterator'; var ITERATOR_SYMBOL = REAL_ITERATOR_SYMBOL || FAUX_ITERATOR_SYMBOL; var Iterator = function Iterator(next) { this.next = next; }; Iterator.prototype.toString = function toString () { return '[Iterator]'; }; Iterator.KEYS = ITERATE_KEYS; Iterator.VALUES = ITERATE_VALUES; Iterator.ENTRIES = ITERATE_ENTRIES; Iterator.prototype.inspect = Iterator.prototype.toSource = function () { return this.toString(); }; Iterator.prototype[ITERATOR_SYMBOL] = function () { return this; }; function iteratorValue(type, k, v, iteratorResult) { var value = type === ITERATE_KEYS ? k : type === ITERATE_VALUES ? v : [k, v]; // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- TODO enable eslint here iteratorResult ? (iteratorResult.value = value) : (iteratorResult = { value: value, done: false, }); return iteratorResult; } function iteratorDone() { return { value: undefined, done: true }; } function hasIterator(maybeIterable) { if (Array.isArray(maybeIterable)) { // IE11 trick as it does not support `Symbol.iterator` return true; } return !!getIteratorFn(maybeIterable); } function isIterator(maybeIterator) { return maybeIterator && typeof maybeIterator.next === 'function'; } function getIterator(iterable) { var iteratorFn = getIteratorFn(iterable); return iteratorFn && iteratorFn.call(iterable); } function getIteratorFn(iterable) { var iteratorFn = iterable && ((REAL_ITERATOR_SYMBOL && iterable[REAL_ITERATOR_SYMBOL]) || iterable[FAUX_ITERATOR_SYMBOL]); if (typeof iteratorFn === 'function') { return iteratorFn; } } function isEntriesIterable(maybeIterable) { var iteratorFn = getIteratorFn(maybeIterable); return iteratorFn && iteratorFn === maybeIterable.entries; } function isKeysIterable(maybeIterable) { var iteratorFn = getIteratorFn(maybeIterable); return iteratorFn && iteratorFn === maybeIterable.keys; } var hasOwnProperty = Object.prototype.hasOwnProperty; function isArrayLike(value) { if (Array.isArray(value) || typeof value === 'string') { return true; } // @ts-expect-error "Type 'unknown' is not assignable to type 'boolean'" : convert to Boolean return (value && typeof value === 'object' && // @ts-expect-error check that `'length' in value &&` Number.isInteger(value.length) && // @ts-expect-error check that `'length' in value &&` value.length >= 0 && // @ts-expect-error check that `'length' in value &&` (value.length === 0 ? // Only {length: 0} is considered Array-like. Object.keys(value).length === 1 : // An object is only Array-like if it has a property where the last value // in the array-like may be found (which could be undefined). // @ts-expect-error check that `'length' in value &&` value.hasOwnProperty(value.length - 1))); } var Seq = /*@__PURE__*/(function (Collection) { function Seq(value) { // eslint-disable-next-line no-constructor-return return value === undefined || value === null ? emptySequence() : isImmutable(value) ? value.toSeq() : seqFromValue(value); } if ( Collection ) Seq.__proto__ = Collection; Seq.prototype = Object.create( Collection && Collection.prototype ); Seq.prototype.constructor = Seq; Seq.prototype.toSeq = function toSeq () { return this; }; Seq.prototype.toString = function toString () { return this.__toString('Seq {', '}'); }; Seq.prototype.cacheResult = function cacheResult () { if (!this._cache && this.__iterateUncached) { this._cache = this.entrySeq().toArray(); this.size = this._cache.length; } return this; }; // abstract __iterateUncached(fn, reverse) Seq.prototype.__iterate = function __iterate (fn, reverse) { var cache = this._cache; if (cache) { var size = cache.length; var i = 0; while (i !== size) { var entry = cache[reverse ? size - ++i : i++]; if (fn(entry[1], entry[0], this) === false) { break; } } return i; } return this.__iterateUncached(fn, reverse); }; // abstract __iteratorUncached(type, reverse) Seq.prototype.__iterator = function __iterator (type, reverse) { var cache = this._cache; if (cache) { var size = cache.length; var i = 0; return new Iterator(function () { if (i === size) { return iteratorDone(); } var entry = cache[reverse ? size - ++i : i++]; return iteratorValue(type, entry[0], entry[1]); }); } return this.__iteratorUncached(type, reverse); }; return Seq; }(Collection)); var KeyedSeq = /*@__PURE__*/(function (Seq) { function KeyedSeq(value) { // eslint-disable-next-line no-constructor-return return value === undefined || value === null ? emptySequence().toKeyedSeq() : isCollection(value) ? isKeyed(value) ? value.toSeq() : value.fromEntrySeq() : isRecord(value) ? value.toSeq() : keyedSeqFromValue(value); } if ( Seq ) KeyedSeq.__proto__ = Seq; KeyedSeq.prototype = Object.create( Seq && Seq.prototype ); KeyedSeq.prototype.constructor = KeyedSeq; KeyedSeq.prototype.toKeyedSeq = function toKeyedSeq () { return this; }; return KeyedSeq; }(Seq)); var IndexedSeq = /*@__PURE__*/(function (Seq) { function IndexedSeq(value) { // eslint-disable-next-line no-constructor-return return value === undefined || value === null ? emptySequence() : isCollection(value) ? isKeyed(value) ? value.entrySeq() : value.toIndexedSeq() : isRecord(value) ? value.toSeq().entrySeq() : indexedSeqFromValue(value); } if ( Seq ) IndexedSeq.__proto__ = Seq; IndexedSeq.prototype = Object.create( Seq && Seq.prototype ); IndexedSeq.prototype.constructor = IndexedSeq; IndexedSeq.of = function of (/*...values*/) { return IndexedSeq(arguments); }; IndexedSeq.prototype.toIndexedSeq = function toIndexedSeq () { return this; }; IndexedSeq.prototype.toString = function toString () { return this.__toString('Seq [', ']'); }; return IndexedSeq; }(Seq)); var SetSeq = /*@__PURE__*/(function (Seq) { function SetSeq(value) { // eslint-disable-next-line no-constructor-return return ( isCollection(value) && !isAssociative(value) ? value : IndexedSeq(value) ).toSetSeq(); } if ( Seq ) SetSeq.__proto__ = Seq; SetSeq.prototype = Object.create( Seq && Seq.prototype ); SetSeq.prototype.constructor = SetSeq; SetSeq.of = function of (/*...values*/) { return SetSeq(arguments); }; SetSeq.prototype.toSetSeq = function toSetSeq () { return this; }; return SetSeq; }(Seq)); Seq.isSeq = isSeq; Seq.Keyed = KeyedSeq; Seq.Set = SetSeq; Seq.Indexed = IndexedSeq; Seq.prototype[IS_SEQ_SYMBOL] = true; // #pragma Root Sequences var ArraySeq = /*@__PURE__*/(function (IndexedSeq) { function ArraySeq(array) { this._array = array; this.size = array.length; } if ( IndexedSeq ) ArraySeq.__proto__ = IndexedSeq; ArraySeq.prototype = Object.create( IndexedSeq && IndexedSeq.prototype ); ArraySeq.prototype.constructor = ArraySeq; ArraySeq.prototype.get = function get (index, notSetValue) { return this.has(index) ? this._array[wrapIndex(this, index)] : notSetValue; }; ArraySeq.prototype.__iterate = function __iterate (fn, reverse) { var array = this._array; var size = array.length; var i = 0; while (i !== size) { var ii = reverse ? size - ++i : i++; if (fn(array[ii], ii, this) === false) { break; } } return i; }; ArraySeq.prototype.__iterator = function __iterator (type, reverse) { var array = this._array; var size = array.length; var i = 0; return new Iterator(function () { if (i === size) { return iteratorDone(); } var ii = reverse ? size - ++i : i++; return iteratorValue(type, ii, array[ii]); }); }; return ArraySeq; }(IndexedSeq)); var ObjectSeq = /*@__PURE__*/(function (KeyedSeq) { function ObjectSeq(object) { var keys = Object.keys(object).concat( Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(object) : [] ); this._object = object; this._keys = keys; this.size = keys.length; } if ( KeyedSeq ) ObjectSeq.__proto__ = KeyedSeq; ObjectSeq.prototype = Object.create( KeyedSeq && KeyedSeq.prototype ); ObjectSeq.prototype.constructor = ObjectSeq; ObjectSeq.prototype.get = function get (key, notSetValue) { if (notSetValue !== undefined && !this.has(key)) { return notSetValue; } return this._object[key]; }; ObjectSeq.prototype.has = function has (key) { return hasOwnProperty.call(this._object, key); }; ObjectSeq.prototype.__iterate = function __iterate (fn, reverse) { var object = this._object; var keys = this._keys; var size = keys.length; var i = 0; while (i !== size) { var key = keys[reverse ? size - ++i : i++]; if (fn(object[key], key, this) === false) { break; } } return i; }; ObjectSeq.prototype.__iterator = function __iterator (type, reverse) { var object = this._object; var keys = this._keys; var size = keys.length; var i = 0; return new Iterator(function () { if (i === size) { return iteratorDone(); } var key = keys[reverse ? size - ++i : i++]; return iteratorValue(type, key, object[key]); }); }; return ObjectSeq; }(KeyedSeq)); ObjectSeq.prototype[IS_ORDERED_SYMBOL] = true; var CollectionSeq = /*@__PURE__*/(function (IndexedSeq) { function CollectionSeq(collection) { this._collection = collection; this.size = collection.length || collection.size; } if ( IndexedSeq ) CollectionSeq.__proto__ = IndexedSeq; CollectionSeq.prototype = Object.create( IndexedSeq && IndexedSeq.prototype ); CollectionSeq.prototype.constructor = CollectionSeq; CollectionSeq.prototype.__iterateUncached = function __iterateUncached (fn, reverse) { if (reverse) { return this.cacheResult().__iterate(fn, reverse); } var collection = this._collection; var iterator = getIterator(collection); var iterations = 0; if (isIterator(iterator)) { var step; while (!(step = iterator.next()).done) { if (fn(step.value, iterations++, this) === false) { break; } } } return iterations; }; CollectionSeq.prototype.__iteratorUncached = function __iteratorUncached (type, reverse) { if (reverse) { return this.cacheResult().__iterator(type, reverse); } var collection = this._collection; var iterator = getIterator(collection); if (!isIterator(iterator)) { return new Iterator(iteratorDone); } var iterations = 0; return new Iterator(function () { var step = iterator.next(); return step.done ? step : iteratorValue(type, iterations++, step.value); }); }; return CollectionSeq; }(IndexedSeq)); // # pragma Helper functions var EMPTY_SEQ; function emptySequence() { return EMPTY_SEQ || (EMPTY_SEQ = new ArraySeq([])); } function keyedSeqFromValue(value) { var seq = maybeIndexedSeqFromValue(value); if (seq) { return seq.fromEntrySeq(); } if (typeof value === 'object') { return new ObjectSeq(value); } throw new TypeError( 'Expected Array or collection object of [k, v] entries, or keyed object: ' + value ); } function indexedSeqFromValue(value) { var seq = maybeIndexedSeqFromValue(value); if (seq) { return seq; } throw new TypeError( 'Expected Array or collection object of values: ' + value ); } function seqFromValue(value) { var seq = maybeIndexedSeqFromValue(value); if (seq) { return isEntriesIterable(value) ? seq.fromEntrySeq() : isKeysIterable(value) ? seq.toSetSeq() : seq; } if (typeof value === 'object') { return new ObjectSeq(value); } throw new TypeError( 'Expected Array or collection object of values, or keyed object: ' + value ); } function maybeIndexedSeqFromValue(value) { return isArrayLike(value) ? new ArraySeq(value) : hasIterator(value) ? new CollectionSeq(value) : undefined; } var IS_MAP_SYMBOL = '@@__IMMUTABLE_MAP__@@'; /** * True if `maybeMap` is a Map. * * Also true for OrderedMaps. */ function isMap(maybeMap) { return Boolean(maybeMap && // @ts-expect-error: maybeMap is typed as `{}`, need to change in 6.0 to `maybeMap && typeof maybeMap === 'object' && IS_MAP_SYMBOL in maybeMap` maybeMap[IS_MAP_SYMBOL]); } /** * True if `maybeOrderedMap` is an OrderedMap. */ function isOrderedMap(maybeOrderedMap) { return isMap(maybeOrderedMap) && isOrdered(maybeOrderedMap); } /** * True if `maybeValue` is a JavaScript Object which has *both* `equals()` * and `hashCode()` methods. * * Any two instances of *value objects* can be compared for value equality with * `Immutable.is()` and can be used as keys in a `Map` or members in a `Set`. */ function isValueObject(maybeValue) { return Boolean(maybeValue && // @ts-expect-error: maybeValue is typed as `{}` typeof maybeValue.equals === 'function' && // @ts-expect-error: maybeValue is typed as `{}` typeof maybeValue.hashCode === 'function'); } /** * An extension of the "same-value" algorithm as [described for use by ES6 Map * and Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Key_equality) * * NaN is considered the same as NaN, however -0 and 0 are considered the same * value, which is different from the algorithm described by * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is). * * This is extended further to allow Objects to describe the values they * represent, by way of `valueOf` or `equals` (and `hashCode`). * * Note: because of this extension, the key equality of Immutable.Map and the * value equality of Immutable.Set will differ from ES6 Map and Set. * * ### Defining custom values * * The easiest way to describe the value an object represents is by implementing * `valueOf`. For example, `Date` represents a value by returning a unix * timestamp for `valueOf`: * * var date1 = new Date(1234567890000); // Fri Feb 13 2009 ... * var date2 = new Date(1234567890000); * date1.valueOf(); // 1234567890000 * assert( date1 !== date2 ); * assert( Immutable.is( date1, date2 ) ); * * Note: overriding `valueOf` may have other implications if you use this object * where JavaScript expects a primitive, such as implicit string coercion. * * For more complex types, especially collections, implementing `valueOf` may * not be performant. An alternative is to implement `equals` and `hashCode`. * * `equals` takes another object, presumably of similar type, and returns true * if it is equal. Equality is symmetrical, so the same result should be * returned if this and the argument are flipped. * * assert( a.equals(b) === b.equals(a) ); * * `hashCode` returns a 32bit integer number representing the object which will * be used to determine how to store the value object in a Map or Set. You must * provide both or neither methods, one must not exist without the other. * * Also, an important relationship between these methods must be upheld: if two * values are equal, they *must* return the same hashCode. If the values are not * equal, they might have the same hashCode; this is called a hash collision, * and while undesirable for performance reasons, it is acceptable. * * if (a.equals(b)) { * assert( a.hashCode() === b.hashCode() ); * } * * All Immutable collections are Value Objects: they implement `equals()` * and `hashCode()`. */ function is(valueA, valueB) { if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) { return true; } if (!valueA || !valueB) { return false; } if (typeof valueA.valueOf === 'function' && typeof valueB.valueOf === 'function') { valueA = valueA.valueOf(); valueB = valueB.valueOf(); if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) { return true; } if (!valueA || !valueB) { return false; } } return !!(isValueObject(valueA) && isValueObject(valueB) && valueA.equals(valueB)); } var imul = typeof Math.imul === 'function' && Math.imul(0xffffffff, 2) === -2 ? Math.imul : function imul(a, b) { a |= 0; // int b |= 0; // int var c = a & 0xffff; var d = b & 0xffff; // Shift by 0 fixes the sign on the high part. return (c * d + ((((a >>> 16) * d + c * (b >>> 16)) << 16) >>> 0)) | 0; // int }; // v8 has an optimization for storing 31-bit signed numbers. // Values which have either 00 or 11 as the high order bits qualify. // This function drops the highest order bit in a signed number, maintaining // the sign bit. function smi(i32) { return ((i32 >>> 1) & 0x40000000) | (i32 & 0xbfffffff); } var defaultValueOf = Object.prototype.valueOf; function hash(o) { // eslint-disable-next-line eqeqeq if (o == null) { return hashNullish(o); } if (typeof o.hashCode === 'function') { // Drop any high bits from accidentally long hash codes. return smi(o.hashCode(o)); } var v = valueOf(o); // eslint-disable-next-line eqeqeq if (v == null) { return hashNullish(v); } switch (typeof v) { case 'boolean': // The hash values for built-in constants are a 1 value for each 5-byte // shift region expect for the first, which encodes the value. This // reduces the odds of a hash collision for these common values. return v ? 0x42108421 : 0x42108420; case 'number': return hashNumber(v); case 'string': return v.length > STRING_HASH_CACHE_MIN_STRLEN ? cachedHashString(v) : hashString(v); case 'object': case 'function': return hashJSObj(v); case 'symbol': return hashSymbol(v); default: if (typeof v.toString === 'function') { return hashString(v.toString()); } throw new Error('Value type ' + typeof v + ' cannot be hashed.'); } } function hashNullish(nullish) { return nullish === null ? 0x42108422 : /* undefined */ 0x42108423; } // Compress arbitrarily large numbers into smi hashes. function hashNumber(n) { if (n !== n || n === Infinity) { return 0; } var hash = n | 0; if (hash !== n) { hash ^= n * 0xffffffff; } while (n > 0xffffffff) { n /= 0xffffffff; hash ^= n; } return smi(hash); } function cachedHashString(string) { var hashed = stringHashCache[string]; if (hashed === undefined) { hashed = hashString(string); if (STRING_HASH_CACHE_SIZE === STRING_HASH_CACHE_MAX_SIZE) { STRING_HASH_CACHE_SIZE = 0; stringHashCache = {}; } STRING_HASH_CACHE_SIZE++; stringHashCache[string] = hashed; } return hashed; } // http://jsperf.com/hashing-strings function hashString(string) { // This is the hash from JVM // The hash code for a string is computed as // s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1], // where s[i] is the ith character of the string and n is the length of // the string. We "mod" the result to make it between 0 (inclusive) and 2^31 // (exclusive) by dropping high bits. var hashed = 0; for (var ii = 0; ii < string.length; ii++) { hashed = (31 * hashed + string.charCodeAt(ii)) | 0; } return smi(hashed); } function hashSymbol(sym) { var hashed = symbolMap[sym]; if (hashed !== undefined) { return hashed; } hashed = nextHash(); symbolMap[sym] = hashed; return hashed; } function hashJSObj(obj) { var hashed; if (usingWeakMap) { hashed = weakMap.get(obj); if (hashed !== undefined) { return hashed; } } hashed = obj[UID_HASH_KEY]; if (hashed !== undefined) { return hashed; } if (!canDefineProperty) { hashed = obj.propertyIsEnumerable && obj.propertyIsEnumerable[UID_HASH_KEY]; if (hashed !== undefined) { return hashed; } hashed = getIENodeHash(obj); if (hashed !== undefined) { return hashed; } } hashed = nextHash(); if (usingWeakMap) { weakMap.set(obj, hashed); } else if (isExtensible !== undefined && isExtensible(obj) === false) { throw new Error('Non-extensible objects are not allowed as keys.'); } else if (canDefineProperty) { Object.defineProperty(obj, UID_HASH_KEY, { enumerable: false, configurable: false, writable: false, value: hashed, }); } else if ( obj.propertyIsEnumerable !== undefined && obj.propertyIsEnumerable === obj.constructor.prototype.propertyIsEnumerable ) { // Since we can't define a non-enumerable property on the object // we'll hijack one of the less-used non-enumerable properties to // save our hash on it. Since this is a function it will not show up in // `JSON.stringify` which is what we want. obj.propertyIsEnumerable = function () { return this.constructor.prototype.propertyIsEnumerable.apply( this, arguments ); }; obj.propertyIsEnumerable[UID_HASH_KEY] = hashed; } else if (obj.nodeType !== undefined) { // At this point we couldn't get the IE `uniqueID` to use as a hash // and we couldn't use a non-enumerable property to exploit the // dontEnum bug so we simply add the `UID_HASH_KEY` on the node // itself. obj[UID_HASH_KEY] = hashed; } else { throw new Error('Unable to set a non-enumerable property on object.'); } return hashed; } // Get references to ES5 object methods. var isExtensible = Object.isExtensible; // True if Object.defineProperty works as expected. IE8 fails this test. var canDefineProperty = (function () { try { Object.defineProperty({}, '@', {}); return true; // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (e) { return false; } })(); // IE has a `uniqueID` property on DOM nodes. We can construct the hash from it // and avoid memory leaks from the IE cloneNode bug. function getIENodeHash(node) { if (node && node.nodeType > 0) { switch (node.nodeType) { case 1: // Element return node.uniqueID; case 9: // Document return node.documentElement && node.documentElement.uniqueID; } } } function valueOf(obj) { return obj.valueOf !== defaultValueOf && typeof obj.valueOf === 'function' ? obj.valueOf(obj) : obj; } function nextHash() { var nextHash = ++_objHashUID; if (_objHashUID & 0x40000000) { _objHashUID = 0; } return nextHash; } // If possible, use a WeakMap. var usingWeakMap = typeof WeakMap === 'function'; var weakMap; if (usingWeakMap) { weakMap = new WeakMap(); } var symbolMap = Object.create(null); var _objHashUID = 0; var UID_HASH_KEY = '__immutablehash__'; if (typeof Symbol === 'function') { UID_HASH_KEY = Symbol(UID_HASH_KEY); } var STRING_HASH_CACHE_MIN_STRLEN = 16; var STRING_HASH_CACHE_MAX_SIZE = 255; var STRING_HASH_CACHE_SIZE = 0; var stringHashCache = {}; var ToKeyedSequence = /*@__PURE__*/(function (KeyedSeq) { function ToKeyedSequence(indexed, useKeys) { this._iter = indexed; this._useKeys = useKeys; this.size = indexed.size; } if ( KeyedSeq ) ToKeyedSequence.__proto__ = KeyedSeq; ToKeyedSequence.prototype = Object.create( KeyedSeq && KeyedSeq.prototype ); ToKeyedSequence.prototype.constructor = ToKeyedSequence; ToKeyedSequence.prototype.get = function get (key, notSetValue) { return this._iter.get(key, notSetValue); }; ToKeyedSequence.prototype.has = function has (key) { return this._iter.has(key); }; ToKeyedSequence.prototype.valueSeq = function valueSeq () { return this._iter.valueSeq(); }; ToKeyedSequence.prototype.reverse = function reverse () { var this$1$1 = this; var reversedSequence = reverseFactory(this, true); if (!this._useKeys) { reversedSequence.valueSeq = function () { return this$1$1._iter.toSeq().reverse(); }; } return reversedSequence; }; ToKeyedSequence.prototype.map = function map (mapper, context) { var this$1$1 = this; var mappedSequence = mapFactory(this, mapper, context); if (!this._useKeys) { mappedSequence.valueSeq = function () { return this$1$1._iter.toSeq().map(mapper, context); }; } return mappedSequence; }; ToKeyedSequence.prototype.__iterate = function __iterate (fn, reverse) { var this$1$1 = this; return this._iter.__iterate(function (v, k) { return fn(v, k, this$1$1); }, reverse); }; ToKeyedSequence.prototype.__iterator = function __iterator (type, reverse) { return this._iter.__iterator(type, reverse); }; return ToKeyedSequence; }(KeyedSeq)); ToKeyedSequence.prototype[IS_ORDERED_SYMBOL] = true; var ToIndexedSequence = /*@__PURE__*/(function (IndexedSeq) { function ToIndexedSequence(iter) { this._iter = iter; this.size = iter.size; } if ( IndexedSeq ) ToIndexedSequence.__proto__ = IndexedSeq; ToIndexedSequence.prototype = Object.create( IndexedSeq && IndexedSeq.prototype ); ToIndexedSequence.prototype.constructor = ToIndexedSequence; ToIndexedSequence.prototype.includes = function includes (value) { return this._iter.includes(value); }; ToIndexedSequence.prototype.__iterate = function __iterate (fn, reverse) { var this$1$1 = this; var i = 0; // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- TODO enable eslint here reverse && ensureSize(this); return this._iter.__iterate( function (v) { return fn(v, reverse ? this$1$1.size - ++i : i++, this$1$1); }, reverse ); }; ToIndexedSequence.prototype.__iterator = function __iterator (type, reverse) { var this$1$1 = this; var iterator = this._iter.__iterator(ITERATE_VALUES, reverse); var i = 0; // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- TODO enable eslint here reverse && ensureSize(this); return new Iterator(function () { var step = iterator.next(); return step.done ? step : iteratorValue( type, reverse ? this$1$1.size - ++i : i++, step.value, step ); }); }; return ToIndexedSequence; }(IndexedSeq)); var ToSetSequence = /*@__PURE__*/(function (SetSeq) { function ToSetSequence(iter) { this._iter = iter; this.size = iter.size; } if ( SetSeq ) ToSetSequence.__proto__ = SetSeq; ToSetSequence.prototype = Object.create( SetSeq && SetSeq.prototype ); ToSetSequence.prototype.constructor = ToSetSequence; ToSetSequence.prototype.has = function has (key) { return this._iter.includes(key); }; ToSetSequence.prototype.__iterate = function __iterate (fn, reverse) { var this$1$1 = this; return this._iter.__iterate(function (v) { return fn(v, v, this$1$1); }, reverse); }; ToSetSequence.prototype.__iterator = function __iterator (type, reverse) { var iterator = this._iter.__iterator(ITERATE_VALUES, reverse); return new Iterator(function () { var step = iterator.next(); return step.done ? step : iteratorValue(type, step.value, step.value, step); }); }; return ToSetSequence; }(SetSeq)); var FromEntriesSequence = /*@__PURE__*/(function (KeyedSeq) { function FromEntriesSequence(entries) { this._iter = entries; this.size = entries.size; } if ( KeyedSeq ) FromEntriesSequence.__proto__ = KeyedSeq; FromEntriesSequence.prototype = Object.create( KeyedSeq && KeyedSeq.prototype ); FromEntriesSequence.prototype.constructor = FromEntriesSequence; FromEntriesSequence.prototype.entrySeq = function entrySeq () { return this._iter.toSeq(); }; FromEntriesSequence.prototype.__iterate = function __iterate (fn, reverse) { var this$1$1 = this; return this._iter.__iterate(function (entry) { // Check if entry exists first so array access doesn't throw for holes // in the parent iteration. if (entry) { validateEntry(entry); var indexedCollection = isCollection(entry); return fn( indexedCollection ? entry.get(1) : entry[1], indexedCollection ? entry.get(0) : entry[0], this$1$1 ); } }, reverse); }; FromEntriesSequence.prototype.__iterator = function __iterator (type, reverse) { var iterator = this._iter.__iterator(ITERATE_VALUES, reverse); return new Iterator(function () { while (true) { var step = iterator.next(); if (step.done) { return step; } var entry = step.value; // Check if entry exists first so array access doesn't throw for holes // in the parent iteration. if (entry) { validateEntry(entry); var indexedCollection = isCollection(entry); return iteratorValue( type, indexedCollection ? entry.get(0) : entry[0], indexedCollection ? entry.get(1) : entry[1], step ); } } }); }; return FromEntriesSequence; }(KeyedSeq)); ToIndexedSequence.prototype.cacheResult = ToKeyedSequence.prototype.cacheResult = ToSetSequence.prototype.cacheResult = FromEntriesSequence.prototype.cacheResult = cacheResultThrough; function flipFactory(collection) { var flipSequence = makeSequence(collection); flipSequence._iter = collection; flipSequence.size = collection.size; flipSequence.flip = function () { return collection; }; flipSequence.reverse = function () { var reversedSequence = collection.reverse.apply(this); // super.reverse() reversedSequence.flip = function () { return collection.reverse(); }; return reversedSequence; }; flipSequence.has = function (key) { return collection.includes(key); }; flipSequence.includes = function (key) { return collection.has(key); }; flipSequence.cacheResult = cacheResultThrough; flipSequence.__iterateUncached = function (fn, reverse) { var this$1$1 = this; return collection.__iterate(function (v, k) { return fn(k, v, this$1$1) !== false; }, reverse); }; flipSequence.__iteratorUncached = function (type, reverse) { if (type === ITERATE_ENTRIES) { var iterator = collection.__iterator(type, reverse); return new Iterator(function () { var step = iterator.next(); if (!step.done) { var k = step.value[0]; step.value[0] = step.value[1]; step.value[1] = k; } return step; }); } return collection.__iterator( type === ITERATE_VALUES ? ITERATE_KEYS : ITERATE_VALUES, reverse ); }; return flipSequence; } function mapFactory(collection, mapper, context) { var mappedSequence = makeSequence(collection); mappedSequence.size = collection.size; mappedSequence.has = function (key) { return collection.has(key); }; mappedSequence.get = function (key, notSetValue) { var v = collection.get(key, NOT_SET); return v === NOT_SET ? notSetValue : mapper.call(context, v, key, collection); }; mappedSequence.__iterateUncached = function (fn, reverse) { var this$1$1 = this; return collection.__iterate( function (v, k, c) { return fn(mapper.call(context, v, k, c), k, this$1$1) !== false; }, reverse ); }; mappedSequence.__iteratorUncached = function (type, reverse) { var iterator = collection.__iterator(ITERATE_ENTRIES, reverse); return new Iterator(function () { var step = iterator.next(); if (step.done) { return step; } var entry = step.value; var key = entry[0]; return iteratorValue( type, key, mapper.call(context, entry[1], key, collection), step ); }); }; return mappedSequence; } function reverseFactory(collection, useKeys) { var this$1$1 = this; var reversedSequence = makeSequence(collection); reversedSequence._iter = collection; reversedSequence.size = collection.size; reversedSequence.reverse = function () { return collection; }; if (collection.flip) { reversedSequence.flip = function () { var flipSequence = flipFactory(collection); flipSequence.reverse = function () { return collection.flip(); }; return flipSequence; }; } reversedSequence.get = function (key, notSetValue) { return collection.get(useKeys ? key : -1 - key, notSetValue); }; reversedSequence.has = function (key) { return collection.has(useKeys ? key : -1 - key); }; reversedSequence.includes = function (value) { return collection.includes(value); }; reversedSequence.cacheResult = cacheResultThrough; reversedSequence.__iterate = function (fn, reverse) { var this$1$1 = this; var i = 0; // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- TODO enable eslint here reverse && ensureSize(collection); return collection.__iterate( function (v, k) { return fn(v, useKeys ? k : reverse ? this$1$1.size - ++i : i++, this$1$1); }, !reverse ); }; reversedSequence.__iterator = function (type, reverse) { var i = 0; // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- TODO enable eslint here reverse && ensureSize(collection); var iterator = collection.__iterator(ITERATE_ENTRIES, !reverse); return new Iterator(function () { var step = iterator.next(); if (step.done) { return step; } var entry = step.value; return iteratorValue( type, useKeys ? entry[0] : reverse ? this$1$1.size - ++i : i++, entry[1], step ); }); }; return reversedSequence; } function filterFactory(collection, predicate, context, useKeys) { var filterSequence = makeSequence(collection); if (useKeys) { filterSequence.has = function (key) { var v = collection.get(key, NOT_SET); return v !== NOT_SET && !!predicate.call(context, v, key, collecti