fast-equals 3.0.3 → 4.0.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,139 +4,193 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["fast-equals"] = {}));
5
5
  })(this, (function (exports) { 'use strict';
6
6
 
7
- var HAS_WEAK_MAP_SUPPORT = typeof WeakMap === 'function';
8
- var keys = Object.keys;
9
7
  /**
10
- * are the values passed strictly equal or both NaN
11
- *
12
- * @param a the value to compare against
13
- * @param b the value to test
14
- * @returns are the values equal by the SameValueZero principle
8
+ * Default equality comparator pass-through, used as the standard `isEqual` creator for
9
+ * use inside the built comparator.
15
10
  */
16
- function sameValueZeroEqual(a, b) {
17
- return a === b || (a !== a && b !== b);
11
+ function createDefaultIsNestedEqual(comparator) {
12
+ return function isEqual(a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, meta) {
13
+ return comparator(a, b, meta);
14
+ };
18
15
  }
19
16
  /**
20
- * is the value a plain object
21
- *
22
- * @param value the value to test
23
- * @returns is the value a plain object
17
+ * Wrap the provided `areItemsEqual` method to manage the circular cache, allowing
18
+ * for circular references to be safely included in the comparison without creating
19
+ * stack overflows.
24
20
  */
25
- function isPlainObject(value) {
26
- return value.constructor === Object || value.constructor == null;
21
+ function createIsCircular(areItemsEqual) {
22
+ return function isCircular(a, b, isEqual, cache) {
23
+ if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {
24
+ return areItemsEqual(a, b, isEqual, cache);
25
+ }
26
+ var cachedA = cache.get(a);
27
+ var cachedB = cache.get(b);
28
+ if (cachedA && cachedB) {
29
+ return cachedA === b && cachedB === a;
30
+ }
31
+ cache.set(a, b);
32
+ cache.set(b, a);
33
+ var result = areItemsEqual(a, b, isEqual, cache);
34
+ cache.delete(a);
35
+ cache.delete(b);
36
+ return result;
37
+ };
27
38
  }
28
39
  /**
29
- * is the value promise-like (meaning it is thenable)
40
+ * Targeted shallow merge of two objects.
30
41
  *
31
- * @param value the value to test
32
- * @returns is the value promise-like
42
+ * @NOTE
43
+ * This exists as a tinier compiled version of the `__assign` helper that
44
+ * `tsc` injects in case of `Object.assign` not being present.
33
45
  */
34
- function isPromiseLike(value) {
35
- return !!value && typeof value.then === 'function';
46
+ function merge(a, b) {
47
+ var merged = {};
48
+ for (var key in a) {
49
+ merged[key] = a[key];
50
+ }
51
+ for (var key in b) {
52
+ merged[key] = b[key];
53
+ }
54
+ return merged;
36
55
  }
37
56
  /**
38
- * is the value passed a react element
57
+ * Whether the value is a plain object.
39
58
  *
40
- * @param value the value to test
41
- * @returns is the value a react element
59
+ * @NOTE
60
+ * This is a same-realm compariosn only.
42
61
  */
43
- function isReactElement(value) {
44
- return !!(value && value.$$typeof);
62
+ function isPlainObject(value) {
63
+ return value.constructor === Object || value.constructor == null;
45
64
  }
46
65
  /**
47
- * in cases where WeakMap is not supported, creates a new custom
48
- * object that mimics the necessary API aspects for cache purposes
49
- *
50
- * @returns the new cache object
66
+ * When the value is `Promise`-like, aka "then-able".
51
67
  */
52
- function getNewCacheFallback() {
53
- var entries = [];
54
- return {
55
- delete: function (key) {
56
- for (var index = 0; index < entries.length; ++index) {
57
- if (entries[index][0] === key) {
58
- entries.splice(index, 1);
59
- return;
60
- }
61
- }
62
- },
63
- get: function (key) {
64
- for (var index = 0; index < entries.length; ++index) {
65
- if (entries[index][0] === key) {
66
- return entries[index][1];
67
- }
68
- }
69
- },
70
- set: function (key, value) {
71
- for (var index = 0; index < entries.length; ++index) {
72
- if (entries[index][0] === key) {
73
- entries[index][1] = value;
74
- return;
75
- }
76
- }
77
- entries.push([key, value]);
78
- }
79
- };
68
+ function isPromiseLike(value) {
69
+ return typeof value.then === 'function';
80
70
  }
81
71
  /**
82
- * get a new cache object to prevent circular references
83
- *
84
- * @returns the new cache object
72
+ * Whether the values passed are strictly equal or both NaN.
85
73
  */
86
- var getNewCache = (function (canUseWeakMap) {
87
- if (canUseWeakMap) {
88
- return function _getNewCache() {
89
- return new WeakMap();
90
- };
74
+ function sameValueZeroEqual(a, b) {
75
+ return a === b || (a !== a && b !== b);
76
+ }
77
+
78
+ var ARGUMENTS_TAG = '[object Arguments]';
79
+ var BOOLEAN_TAG = '[object Boolean]';
80
+ var DATE_TAG = '[object Date]';
81
+ var REG_EXP_TAG = '[object RegExp]';
82
+ var MAP_TAG = '[object Map]';
83
+ var NUMBER_TAG = '[object Number]';
84
+ var OBJECT_TAG = '[object Object]';
85
+ var SET_TAG = '[object Set]';
86
+ var STRING_TAG = '[object String]';
87
+ var toString = Object.prototype.toString;
88
+ function createComparator(_a) {
89
+ var areArraysEqual = _a.areArraysEqual, areDatesEqual = _a.areDatesEqual, areMapsEqual = _a.areMapsEqual, areObjectsEqual = _a.areObjectsEqual, areRegExpsEqual = _a.areRegExpsEqual, areSetsEqual = _a.areSetsEqual, createIsNestedEqual = _a.createIsNestedEqual;
90
+ var isEqual = createIsNestedEqual(comparator);
91
+ /**
92
+ * compare the value of the two objects and return true if they are equivalent in values
93
+ */
94
+ function comparator(a, b, meta) {
95
+ // If the items are strictly equal, no need to do a value comparison.
96
+ if (a === b) {
97
+ return true;
98
+ }
99
+ // If the items are not non-nullish objects, then the only possibility
100
+ // of them being equal but not strictly is if they are both `NaN`. Since
101
+ // `NaN` is uniquely not equal to itself, we can use self-comparison of
102
+ // both objects, which is faster than `isNaN()`.
103
+ if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {
104
+ return a !== a && b !== b;
105
+ }
106
+ // Checks are listed in order of commonality of use-case:
107
+ // 1. Common complex object types (plain object, array)
108
+ // 2. Common data values (date, regexp)
109
+ // 3. Less-common complex object types (map, set)
110
+ // 4. Less-common data values (promise, primitive wrappers)
111
+ // Inherently this is both subjective and assumptive, however
112
+ // when reviewing comparable libraries in the wild this order
113
+ // appears to be generally consistent.
114
+ // `isPlainObject` only checks against the object's own realm. Cross-realm
115
+ // comparisons are rare, and will be handled in the ultimate fallback, so
116
+ // we can avoid the `toString.call()` cost unless necessary.
117
+ if (isPlainObject(a) && isPlainObject(b)) {
118
+ return areObjectsEqual(a, b, isEqual, meta);
119
+ }
120
+ // `isArray()` works on subclasses and is cross-realm, so we can again avoid
121
+ // the `toString.call()` cost unless necessary by just checking if either
122
+ // and then both are arrays.
123
+ var aArray = Array.isArray(a);
124
+ var bArray = Array.isArray(b);
125
+ if (aArray || bArray) {
126
+ return aArray === bArray && areArraysEqual(a, b, isEqual, meta);
127
+ }
128
+ // Since this is a custom object, use the classic `toString.call()` to get its
129
+ // type. This is reasonably performant in modern environments like v8 and
130
+ // SpiderMonkey, and allows for cross-realm comparison when other checks like
131
+ // `instanceof` do not.
132
+ var aTag = toString.call(a);
133
+ if (aTag !== toString.call(b)) {
134
+ return false;
135
+ }
136
+ if (aTag === DATE_TAG) {
137
+ // `getTime()` showed better results compared to alternatives like `valueOf()`
138
+ // or the unary `+` operator.
139
+ return areDatesEqual(a, b, isEqual, meta);
140
+ }
141
+ if (aTag === REG_EXP_TAG) {
142
+ return areRegExpsEqual(a, b, isEqual, meta);
143
+ }
144
+ if (aTag === MAP_TAG) {
145
+ return areMapsEqual(a, b, isEqual, meta);
146
+ }
147
+ if (aTag === SET_TAG) {
148
+ return areSetsEqual(a, b, isEqual, meta);
149
+ }
150
+ // If a simple object tag, then we can prioritize a simple object comparison because
151
+ // it is likely a custom class. If an arguments tag, it should be treated as a standard
152
+ // object.
153
+ if (aTag === OBJECT_TAG || aTag === ARGUMENTS_TAG) {
154
+ // The exception for value comparison is `Promise`-like contracts. These should be
155
+ // treated the same as standard `Promise` objects, which means strict equality.
156
+ return isPromiseLike(a) || isPromiseLike(b)
157
+ ? a === b
158
+ : areObjectsEqual(a, b, isEqual, meta);
159
+ }
160
+ // As the penultimate fallback, check if the values passed are primitive wrappers. This
161
+ // is very rare in modern JS, which is why it is deprioritized compared to all other object
162
+ // types.
163
+ if (aTag === BOOLEAN_TAG || aTag === NUMBER_TAG || aTag === STRING_TAG) {
164
+ return sameValueZeroEqual(a.valueOf(), b.valueOf());
165
+ }
166
+ // If not matching any tags that require a specific type of comparison, then use strict
167
+ // equality. This is for a few reasons:
168
+ // - For types that cannot be introspected (`Promise`, `WeakMap`, etc.), this is the only
169
+ // comparison that can be made.
170
+ // - For types that can be introspected, but rarely have requirements to be compared
171
+ // (`ArrayBuffer`, `DataView`, etc.), the cost is avoided to prioritize the common
172
+ // use-cases.
173
+ // - For types that can be introspected, but do not have an objective definition of what
174
+ // equality is (`Error`, etc.), the subjective decision was to be conservative.
175
+ // In all cases, these decisions should be reevaluated based on changes to the language and
176
+ // common development practices.
177
+ return a === b;
91
178
  }
92
- return getNewCacheFallback;
93
- })(HAS_WEAK_MAP_SUPPORT);
94
- /**
95
- * create a custom isEqual handler specific to circular objects
96
- *
97
- * @param [isEqual] the isEqual comparator to use instead of isDeepEqual
98
- * @returns the method to create the `isEqual` function
99
- */
100
- function createCircularEqualCreator(isEqual) {
101
- return function createCircularEqual(comparator) {
102
- var _comparator = isEqual || comparator;
103
- return function circularEqual(a, b, indexOrKeyA, indexOrKeyB, parentA, parentB, cache) {
104
- if (cache === void 0) { cache = getNewCache(); }
105
- var isCacheableA = !!a && typeof a === 'object';
106
- var isCacheableB = !!b && typeof b === 'object';
107
- if (isCacheableA !== isCacheableB) {
108
- return false;
109
- }
110
- if (!isCacheableA && !isCacheableB) {
111
- return _comparator(a, b, cache);
112
- }
113
- var cachedA = cache.get(a);
114
- if (cachedA && cache.get(b)) {
115
- return cachedA === b;
116
- }
117
- cache.set(a, b);
118
- cache.set(b, a);
119
- var result = _comparator(a, b, cache);
120
- cache.delete(a);
121
- cache.delete(b);
122
- return result;
123
- };
124
- };
125
- }
179
+ return comparator;
180
+ }
181
+
126
182
  /**
127
- * are the arrays equal in value
128
- *
129
- * @param a the array to test
130
- * @param b the array to test against
131
- * @param isEqual the comparator to determine equality
132
- * @param meta the meta object to pass through
133
- * @returns are the arrays equal
183
+ * Whether the arrays are equal in value.
134
184
  */
135
185
  function areArraysEqual(a, b, isEqual, meta) {
136
186
  var index = a.length;
137
187
  if (b.length !== index) {
138
188
  return false;
139
189
  }
190
+ // Decrementing `while` showed faster results than either incrementing or
191
+ // decrementing `for` loop and than an incrementing `while` loop. Declarative
192
+ // methods like `some` / `every` were not used to avoid incurring the garbage
193
+ // cost of anonymous callbacks.
140
194
  while (index-- > 0) {
141
195
  if (!isEqual(a[index], b[index], index, index, a, b, meta)) {
142
196
  return false;
@@ -145,210 +199,235 @@
145
199
  return true;
146
200
  }
147
201
  /**
148
- * are the maps equal in value
202
+ * Whether the arrays are equal in value, including circular references.
203
+ */
204
+ var areArraysEqualCircular = createIsCircular(areArraysEqual);
205
+
206
+ /**
207
+ * Whether the dates passed are equal in value.
149
208
  *
150
- * @param a the map to test
151
- * @param b the map to test against
152
- * @param isEqual the comparator to determine equality
153
- * @param meta the meta map to pass through
154
- * @returns are the maps equal
209
+ * @NOTE
210
+ * This is a standalone function instead of done inline in the comparator
211
+ * to allow for overrides.
212
+ */
213
+ function areDatesEqual(a, b) {
214
+ return sameValueZeroEqual(a.valueOf(), b.valueOf());
215
+ }
216
+
217
+ /**
218
+ * Whether the `Map`s are equal in value.
155
219
  */
156
220
  function areMapsEqual(a, b, isEqual, meta) {
157
221
  var isValueEqual = a.size === b.size;
158
- if (isValueEqual && a.size) {
159
- var matchedIndices_1 = {};
160
- var indexA_1 = 0;
161
- a.forEach(function (aValue, aKey) {
162
- if (isValueEqual) {
163
- var hasMatch_1 = false;
164
- var matchIndexB_1 = 0;
165
- b.forEach(function (bValue, bKey) {
166
- if (!hasMatch_1 && !matchedIndices_1[matchIndexB_1]) {
167
- hasMatch_1 =
168
- isEqual(aKey, bKey, indexA_1, matchIndexB_1, a, b, meta) &&
169
- isEqual(aValue, bValue, aKey, bKey, a, b, meta);
170
- if (hasMatch_1) {
171
- matchedIndices_1[matchIndexB_1] = true;
172
- }
173
- }
174
- matchIndexB_1++;
175
- });
176
- indexA_1++;
177
- isValueEqual = hasMatch_1;
222
+ if (!isValueEqual) {
223
+ return false;
224
+ }
225
+ if (!a.size) {
226
+ return true;
227
+ }
228
+ // The use of `forEach()` is to avoid the transpilation cost of `for...of` comparisons, and
229
+ // the inability to control the performance of the resulting code. It also avoids excessive
230
+ // iteration compared to doing comparisons of `keys()` and `values()`. As a result, though,
231
+ // we cannot short-circuit the iterations; bookkeeping must be done to short-circuit the
232
+ // equality checks themselves.
233
+ var matchedIndices = {};
234
+ var indexA = 0;
235
+ a.forEach(function (aValue, aKey) {
236
+ if (!isValueEqual) {
237
+ return;
238
+ }
239
+ var hasMatch = false;
240
+ var matchIndexB = 0;
241
+ b.forEach(function (bValue, bKey) {
242
+ if (!hasMatch &&
243
+ !matchedIndices[matchIndexB] &&
244
+ (hasMatch =
245
+ isEqual(aKey, bKey, indexA, matchIndexB, a, b, meta) &&
246
+ isEqual(aValue, bValue, aKey, bKey, a, b, meta))) {
247
+ matchedIndices[matchIndexB] = true;
178
248
  }
249
+ matchIndexB++;
179
250
  });
180
- }
251
+ indexA++;
252
+ isValueEqual = hasMatch;
253
+ });
181
254
  return isValueEqual;
182
255
  }
256
+ /**
257
+ * Whether the `Map`s are equal in value, including circular references.
258
+ */
259
+ var areMapsEqualCircular = createIsCircular(areMapsEqual);
260
+
183
261
  var OWNER = '_owner';
184
- var hasOwnProperty = Function.prototype.bind.call(Function.prototype.call, Object.prototype.hasOwnProperty);
262
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
185
263
  /**
186
- * are the objects equal in value
187
- *
188
- * @param a the object to test
189
- * @param b the object to test against
190
- * @param isEqual the comparator to determine equality
191
- * @param meta the meta object to pass through
192
- * @returns are the objects equal
264
+ * Whether the objects are equal in value.
193
265
  */
194
266
  function areObjectsEqual(a, b, isEqual, meta) {
195
- var keysA = keys(a);
267
+ var keysA = Object.keys(a);
196
268
  var index = keysA.length;
197
- if (keys(b).length !== index) {
269
+ if (Object.keys(b).length !== index) {
198
270
  return false;
199
271
  }
200
- if (index) {
201
- var key = void 0;
202
- while (index-- > 0) {
203
- key = keysA[index];
204
- if (key === OWNER) {
205
- var reactElementA = isReactElement(a);
206
- var reactElementB = isReactElement(b);
207
- if ((reactElementA || reactElementB) &&
208
- reactElementA !== reactElementB) {
209
- return false;
210
- }
211
- }
212
- if (!hasOwnProperty(b, key) ||
213
- !isEqual(a[key], b[key], key, key, a, b, meta)) {
272
+ var key;
273
+ // Decrementing `while` showed faster results than either incrementing or
274
+ // decrementing `for` loop and than an incrementing `while` loop. Declarative
275
+ // methods like `some` / `every` were not used to avoid incurring the garbage
276
+ // cost of anonymous callbacks.
277
+ while (index-- > 0) {
278
+ key = keysA[index];
279
+ if (key === OWNER) {
280
+ var reactElementA = !!a.$$typeof;
281
+ var reactElementB = !!b.$$typeof;
282
+ if ((reactElementA || reactElementB) && reactElementA !== reactElementB) {
214
283
  return false;
215
284
  }
216
285
  }
286
+ if (!hasOwnProperty.call(b, key) ||
287
+ !isEqual(a[key], b[key], key, key, a, b, meta)) {
288
+ return false;
289
+ }
217
290
  }
218
291
  return true;
219
292
  }
220
293
  /**
221
- * are the regExps equal in value
222
- *
223
- * @param a the regExp to test
224
- * @param b the regExp to test agains
225
- * @returns are the regExps equal
294
+ * Whether the objects are equal in value, including circular references.
226
295
  */
227
- var areRegExpsEqual = (function () {
228
- if (/foo/g.flags === 'g') {
229
- return function areRegExpsEqual(a, b) {
230
- return a.source === b.source && a.flags === b.flags;
231
- };
232
- }
233
- return function areRegExpsEqualFallback(a, b) {
234
- return (a.source === b.source &&
235
- a.global === b.global &&
236
- a.ignoreCase === b.ignoreCase &&
237
- a.multiline === b.multiline &&
238
- a.unicode === b.unicode &&
239
- a.sticky === b.sticky &&
240
- a.lastIndex === b.lastIndex);
241
- };
242
- })();
296
+ var areObjectsEqualCircular = createIsCircular(areObjectsEqual);
297
+
243
298
  /**
244
- * are the sets equal in value
299
+ * Whether the regexps passed are equal in value.
245
300
  *
246
- * @param a the set to test
247
- * @param b the set to test against
248
- * @param isEqual the comparator to determine equality
249
- * @param meta the meta set to pass through
250
- * @returns are the sets equal
301
+ * @NOTE
302
+ * This is a standalone function instead of done inline in the comparator
303
+ * to allow for overrides. An example of this would be supporting a
304
+ * pre-ES2015 environment where the `flags` property is not available.
305
+ */
306
+ function areRegExpsEqual(a, b) {
307
+ return a.source === b.source && a.flags === b.flags;
308
+ }
309
+
310
+ /**
311
+ * Whether the `Set`s are equal in value.
251
312
  */
252
313
  function areSetsEqual(a, b, isEqual, meta) {
253
314
  var isValueEqual = a.size === b.size;
254
- if (isValueEqual && a.size) {
255
- var matchedIndices_2 = {};
256
- a.forEach(function (aValue, aKey) {
257
- if (isValueEqual) {
258
- var hasMatch_2 = false;
259
- var matchIndex_1 = 0;
260
- b.forEach(function (bValue, bKey) {
261
- if (!hasMatch_2 && !matchedIndices_2[matchIndex_1]) {
262
- hasMatch_2 = isEqual(aValue, bValue, aKey, bKey, a, b, meta);
263
- if (hasMatch_2) {
264
- matchedIndices_2[matchIndex_1] = true;
265
- }
266
- }
267
- matchIndex_1++;
268
- });
269
- isValueEqual = hasMatch_2;
315
+ if (!isValueEqual) {
316
+ return false;
317
+ }
318
+ if (!a.size) {
319
+ return true;
320
+ }
321
+ // The use of `forEach()` is to avoid the transpilation cost of `for...of` comparisons, and
322
+ // the inability to control the performance of the resulting code. It also avoids excessive
323
+ // iteration compared to doing comparisons of `keys()` and `values()`. As a result, though,
324
+ // we cannot short-circuit the iterations; bookkeeping must be done to short-circuit the
325
+ // equality checks themselves.
326
+ var matchedIndices = {};
327
+ a.forEach(function (aValue, aKey) {
328
+ if (!isValueEqual) {
329
+ return;
330
+ }
331
+ var hasMatch = false;
332
+ var matchIndex = 0;
333
+ b.forEach(function (bValue, bKey) {
334
+ if (!hasMatch &&
335
+ !matchedIndices[matchIndex] &&
336
+ (hasMatch = isEqual(aValue, bValue, aKey, bKey, a, b, meta))) {
337
+ matchedIndices[matchIndex] = true;
270
338
  }
339
+ matchIndex++;
271
340
  });
272
- }
341
+ isValueEqual = hasMatch;
342
+ });
273
343
  return isValueEqual;
274
- }
344
+ }
345
+ /**
346
+ * Whether the `Set`s are equal in value, including circular references.
347
+ */
348
+ var areSetsEqualCircular = createIsCircular(areSetsEqual);
275
349
 
276
- var HAS_MAP_SUPPORT = typeof Map === 'function';
277
- var HAS_SET_SUPPORT = typeof Set === 'function';
278
- var valueOf = Object.prototype.valueOf;
279
- function createComparator(createIsEqual) {
280
- var isEqual =
281
- /* eslint-disable no-use-before-define */
282
- typeof createIsEqual === 'function'
283
- ? createIsEqual(comparator)
284
- : function (a, b, indexOrKeyA, indexOrKeyB, parentA, parentB, meta) { return comparator(a, b, meta); };
285
- /* eslint-enable */
286
- /**
287
- * compare the value of the two objects and return true if they are equivalent in values
288
- *
289
- * @param a the value to test against
290
- * @param b the value to test
291
- * @param [meta] an optional meta object that is passed through to all equality test calls
292
- * @returns are a and b equivalent in value
293
- */
294
- function comparator(a, b, meta) {
295
- if (a === b) {
296
- return true;
297
- }
298
- if (a && b && typeof a === 'object' && typeof b === 'object') {
299
- if (isPlainObject(a) && isPlainObject(b)) {
300
- return areObjectsEqual(a, b, isEqual, meta);
301
- }
302
- var aShape = Array.isArray(a);
303
- var bShape = Array.isArray(b);
304
- if (aShape || bShape) {
305
- return aShape === bShape && areArraysEqual(a, b, isEqual, meta);
306
- }
307
- aShape = a instanceof Date;
308
- bShape = b instanceof Date;
309
- if (aShape || bShape) {
310
- return (aShape === bShape && sameValueZeroEqual(a.getTime(), b.getTime()));
311
- }
312
- aShape = a instanceof RegExp;
313
- bShape = b instanceof RegExp;
314
- if (aShape || bShape) {
315
- return aShape === bShape && areRegExpsEqual(a, b);
316
- }
317
- if (isPromiseLike(a) || isPromiseLike(b)) {
318
- return a === b;
319
- }
320
- if (HAS_MAP_SUPPORT) {
321
- aShape = a instanceof Map;
322
- bShape = b instanceof Map;
323
- if (aShape || bShape) {
324
- return aShape === bShape && areMapsEqual(a, b, isEqual, meta);
325
- }
326
- }
327
- if (HAS_SET_SUPPORT) {
328
- aShape = a instanceof Set;
329
- bShape = b instanceof Set;
330
- if (aShape || bShape) {
331
- return aShape === bShape && areSetsEqual(a, b, isEqual, meta);
332
- }
333
- }
334
- if (a.valueOf !== valueOf || b.valueOf !== valueOf) {
335
- return sameValueZeroEqual(a.valueOf(), b.valueOf());
336
- }
337
- return areObjectsEqual(a, b, isEqual, meta);
338
- }
339
- return a !== a && b !== b;
340
- }
341
- return comparator;
350
+ var DEFAULT_CONFIG = Object.freeze({
351
+ areArraysEqual: areArraysEqual,
352
+ areDatesEqual: areDatesEqual,
353
+ areMapsEqual: areMapsEqual,
354
+ areObjectsEqual: areObjectsEqual,
355
+ areRegExpsEqual: areRegExpsEqual,
356
+ areSetsEqual: areSetsEqual,
357
+ createIsNestedEqual: createDefaultIsNestedEqual,
358
+ });
359
+ var DEFAULT_CIRCULAR_CONFIG = Object.freeze({
360
+ areArraysEqual: areArraysEqualCircular,
361
+ areDatesEqual: areDatesEqual,
362
+ areMapsEqual: areMapsEqualCircular,
363
+ areObjectsEqual: areObjectsEqualCircular,
364
+ areRegExpsEqual: areRegExpsEqual,
365
+ areSetsEqual: areSetsEqualCircular,
366
+ createIsNestedEqual: createDefaultIsNestedEqual,
367
+ });
368
+ var isDeepEqual = createComparator(DEFAULT_CONFIG);
369
+ /**
370
+ * Whether the items passed are deeply-equal in value.
371
+ */
372
+ function deepEqual(a, b) {
373
+ return isDeepEqual(a, b, undefined);
374
+ }
375
+ var isShallowEqual = createComparator(merge(DEFAULT_CONFIG, { createIsNestedEqual: function () { return sameValueZeroEqual; } }));
376
+ /**
377
+ * Whether the items passed are shallowly-equal in value.
378
+ */
379
+ function shallowEqual(a, b) {
380
+ return isShallowEqual(a, b, undefined);
381
+ }
382
+ var isCircularDeepEqual = createComparator(DEFAULT_CIRCULAR_CONFIG);
383
+ /**
384
+ * Whether the items passed are deeply-equal in value, including circular references.
385
+ */
386
+ function circularDeepEqual(a, b) {
387
+ return isCircularDeepEqual(a, b, new WeakMap());
388
+ }
389
+ var isCircularShallowEqual = createComparator(merge(DEFAULT_CIRCULAR_CONFIG, {
390
+ createIsNestedEqual: function () { return sameValueZeroEqual; },
391
+ }));
392
+ /**
393
+ * Whether the items passed are shallowly-equal in value, including circular references.
394
+ */
395
+ function circularShallowEqual(a, b) {
396
+ return isCircularShallowEqual(a, b, new WeakMap());
397
+ }
398
+ /**
399
+ * Create a custom equality comparison method.
400
+ *
401
+ * This can be done to create very targeted comparisons in extreme hot-path scenarios
402
+ * where the standard methods are not performant enough, but can also be used to provide
403
+ * support for legacy environments that do not support expected features like
404
+ * `RegExp.prototype.flags` out of the box.
405
+ */
406
+ function createCustomEqual(getComparatorOptions) {
407
+ return createComparator(merge(DEFAULT_CONFIG, getComparatorOptions(DEFAULT_CONFIG)));
408
+ }
409
+ /**
410
+ * Create a custom equality comparison method that handles circular references. This is very
411
+ * similar to `createCustomEqual`, with the only difference being that `meta` expects to be
412
+ * populated with a `WeakMap`-like contract.
413
+ *
414
+ * This can be done to create very targeted comparisons in extreme hot-path scenarios
415
+ * where the standard methods are not performant enough, but can also be used to provide
416
+ * support for legacy environments that do not support expected features like
417
+ * `WeakMap` out of the box.
418
+ */
419
+ function createCustomCircularEqual(getComparatorOptions) {
420
+ var comparator = createComparator(merge(DEFAULT_CIRCULAR_CONFIG, getComparatorOptions(DEFAULT_CIRCULAR_CONFIG)));
421
+ return (function (a, b, meta) {
422
+ if (meta === void 0) { meta = new WeakMap(); }
423
+ return comparator(a, b, meta);
424
+ });
342
425
  }
343
426
 
344
- var deepEqual = createComparator();
345
- var shallowEqual = createComparator(function () { return sameValueZeroEqual; });
346
- var circularDeepEqual = createComparator(createCircularEqualCreator());
347
- var circularShallowEqual = createComparator(createCircularEqualCreator(sameValueZeroEqual));
348
-
349
427
  exports.circularDeepEqual = circularDeepEqual;
350
428
  exports.circularShallowEqual = circularShallowEqual;
351
- exports.createCustomEqual = createComparator;
429
+ exports.createCustomCircularEqual = createCustomCircularEqual;
430
+ exports.createCustomEqual = createCustomEqual;
352
431
  exports.deepEqual = deepEqual;
353
432
  exports.sameValueZeroEqual = sameValueZeroEqual;
354
433
  exports.shallowEqual = shallowEqual;