fast-equals 5.0.0-beta.4 → 5.0.0-beta.6

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +30 -34
  3. package/dist/cjs/index.cjs +169 -141
  4. package/dist/cjs/index.cjs.map +1 -1
  5. package/dist/cjs/types/comparator.d.ts +20 -3
  6. package/dist/cjs/types/equals.d.ts +5 -2
  7. package/dist/cjs/types/index.d.ts +9 -9
  8. package/dist/cjs/types/internalTypes.d.ts +16 -12
  9. package/dist/cjs/types/utils.d.ts +1 -7
  10. package/dist/esm/index.mjs +169 -141
  11. package/dist/esm/index.mjs.map +1 -1
  12. package/dist/esm/types/comparator.d.ts +20 -3
  13. package/dist/esm/types/equals.d.ts +5 -2
  14. package/dist/esm/types/index.d.ts +9 -9
  15. package/dist/esm/types/internalTypes.d.ts +16 -12
  16. package/dist/esm/types/utils.d.ts +1 -7
  17. package/dist/min/index.js +1 -1
  18. package/dist/min/types/comparator.d.ts +20 -3
  19. package/dist/min/types/equals.d.ts +5 -2
  20. package/dist/min/types/index.d.ts +9 -9
  21. package/dist/min/types/internalTypes.d.ts +16 -12
  22. package/dist/min/types/utils.d.ts +1 -7
  23. package/dist/umd/index.js +169 -141
  24. package/dist/umd/index.js.map +1 -1
  25. package/dist/umd/types/comparator.d.ts +20 -3
  26. package/dist/umd/types/equals.d.ts +5 -2
  27. package/dist/umd/types/index.d.ts +9 -9
  28. package/dist/umd/types/internalTypes.d.ts +16 -12
  29. package/dist/umd/types/utils.d.ts +1 -7
  30. package/package.json +7 -7
  31. package/recipes/legacy-circular-equal-support.md +3 -2
  32. package/recipes/legacy-regexp-support.md +2 -3
  33. package/recipes/non-standard-properties.md +4 -2
  34. package/src/comparator.ts +131 -35
  35. package/src/equals.ts +97 -63
  36. package/src/index.ts +21 -65
  37. package/src/internalTypes.ts +20 -16
  38. package/src/utils.ts +2 -31
package/CHANGELOG.md CHANGED
@@ -4,9 +4,21 @@
4
4
 
5
5
  ### Breaking changes
6
6
 
7
+ #### `constructor` equality now required
8
+
9
+ To align with other implementations common in the community, but also to be more functionally correct, the two objects being compared now must have equal `constructor`s.
10
+
11
+ #### `Map` / `Set` comparisons no longer support IE11
12
+
13
+ In previous verisons, `.forEach()` was used to ensure that support for `Symbol` was not required, as IE11 did not have `Symbol` and therefore both `Map` and `Set` did not have iterator-based methods such as `.values()` or `.entries()`. Since IE11 is no longer a supported browser, and support for those methods is present in all browsers and Node for quite a while, the comparison has moved to use these methods. This results in a ~20% performance increase.
14
+
7
15
  #### `createCustomEqual` contract has changed
8
16
 
9
- To better facilitate strict comparisons, but also to allow for `meta` use separate from caching, the contract for `createCustomEqual` has changed. See the [README documentation](./README.md#createcustomequal) for more details.
17
+ To better facilitate strict comparisons, but also to allow for `meta` use separate from caching, the contract for `createCustomEqual` has changed. See the [README documentation](./README.md#createcustomequal) for more details, but froma high-level:
18
+
19
+ - `meta` is no longer passed through to equality comparators, but rather a general `state` object which contains `meta`
20
+ - `cache` now also lives on the `state` object, which allows for use of the `meta` property separate from but in parallel with the circular cache
21
+ - `equals` is now on `state`, which prevents the need to pass through the separate `isEqual` method for the equality comparator
10
22
 
11
23
  #### `createCustomCircularEqual` has been removed
12
24
 
package/README.md CHANGED
@@ -4,18 +4,21 @@
4
4
  <img src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg"/>
5
5
  <img src="https://img.shields.io/badge/license-MIT-blue.svg"/>
6
6
 
7
- Perform [blazing fast](#benchmarks) equality comparisons (either deep or shallow) on two objects passed. It has no dependencies, and is ~1.75kB when minified and gzipped.
7
+ Perform [blazing fast](#benchmarks) equality comparisons (either deep or shallow) on two objects passed, while also maintaining a high degree of flexibility for various implementation use-cases. It has no dependencies, and is ~1.8kB when minified and gzipped.
8
8
 
9
- Unlike most equality validation libraries, the following types are handled out-of-the-box:
9
+ The following types are handled out-of-the-box:
10
10
 
11
- - `NaN`
11
+ - Plain objects (including `react` elements and `Arguments`)
12
+ - Arrays
13
+ - Typed Arrays
12
14
  - `Date` objects
13
15
  - `RegExp` objects
14
16
  - `Map` / `Set` iterables
15
17
  - `Promise` objects
16
- - `react` elements
18
+ - Primitive wrappers (`new Boolean()` / `new Number()` / `new String()`)
19
+ - Custom class instances, including subclasses of native classes
17
20
 
18
- Starting with version `1.5.0`, circular objects are supported for both deep and shallow equality (see [`circularDeepEqual`](#circulardeepequal) and [`circularShallowEqual`](#circularshallowequal)). You can also create a custom nested comparator, for specific scenarios ([see below](#createcustomequal)).
21
+ Methods are available for deep, shallow, or referential equality comparison. In addition, you can opt into support for circular objects, or performing a "strict" comparison with unconventional property definition, or both. You can also customize any specific type comparison based on your application's use-cases.
19
22
 
20
23
  ## Table of contents
21
24
 
@@ -162,7 +165,6 @@ console.log(circularShallowEqual(array, [array])); // false
162
165
 
163
166
  Performs the same comparison as `deepEqual` but performs a strict comparison of the objects. In this includes:
164
167
 
165
- - Checking constructors match
166
168
  - Checking non-enumerable properties in object comparisons
167
169
  - Checking full descriptor of properties on the object to match
168
170
  - Checking non-index properties on arrays
@@ -269,24 +271,13 @@ Creates a custom equality comparator that will be used on nested values in the o
269
271
  The signature is as follows:
270
272
 
271
273
  ```ts
272
- interface BaseCircular extends Pick<WeakMap<any, any>, 'delete' | 'get'> {
273
- set(key: object, value: any): any;
274
- }
275
-
276
- interface DefaultState<Meta> {
277
- readonly cache: undefined | BaseCircular;
278
- readonly equals: InternalEqualityComparator<Meta>;
279
- meta: Meta;
280
- readonly strict: boolean;
274
+ interface Cache<Key extends object, Value> {
275
+ delete(key: Key): boolean;
276
+ get(key: Key): Value | undefined;
277
+ set(key: Key, value: any): any;
281
278
  }
282
279
 
283
- type EqualityComparator<Meta> = <A, B>(
284
- a: A,
285
- b: B,
286
- state: State<Meta>,
287
- ) => boolean;
288
-
289
- interface CreateComparatorCreatorOptions<Meta> {
280
+ interface ComparatorConfig<Meta> {
290
281
  areArraysEqual: TypeEqualityComparator<any[], Meta>;
291
282
  areDatesEqual: TypeEqualityComparator<Date, Meta>;
292
283
  areMapsEqual: TypeEqualityComparator<Map<any, any>, Meta>;
@@ -300,20 +291,25 @@ interface CreateComparatorCreatorOptions<Meta> {
300
291
  areTypedArraysEqual: TypeEqualityComparatory<TypedArray, Meta>;
301
292
  }
302
293
 
303
- interface CustomEqualCreatorOptions<Meta> {
294
+ function createCustomEqual<Meta>(options: {
304
295
  circular?: boolean;
305
- comparator?: EqualityComparator<Meta>;
306
- createCustomConfig?: CreateCustomComparatorConfig<Meta>;
307
- createInternalComparator?: <Meta>(
308
- compare: EqualityComparator<Meta>,
309
- ) => InternalEqualityComparator<Meta>;
310
- createState?: CreateState<Meta>;
296
+ createCustomConfig?: (
297
+ defaultConfig: ComparatorConfig<Meta>,
298
+ ) => Partial<ComparatorConfig<Meta>>;
299
+ createInternalComparator?: (
300
+ compare: <A, B>(a: A, b: B, state: State<Meta>) => boolean,
301
+ ) => (
302
+ a: any,
303
+ b: any,
304
+ indexOrKeyA: any,
305
+ indexOrKeyB: any,
306
+ parentA: any,
307
+ parentB: any,
308
+ state: State<Meta>,
309
+ ) => boolean;
310
+ createState?: () => { cache?: Cache; meta?: Meta };
311
311
  strict?: boolean;
312
- }
313
-
314
- function createCustomEqual(
315
- options: CustomEqualCreatorOptions<Meta>,
316
- ): <A, B>(a: A, b: B, metaOverride?: Meta) => boolean;
312
+ }): <A, B>(a: A, b: B, metaOverride?: Meta) => boolean;
317
313
  ```
318
314
 
319
315
  Create a custom equality comparator. This allows complete control over building a bespoke equality method, in case your use-case requires a higher degree of performance, legacy environment support, or any other non-standard usage. The [recipes](#recipes) provide examples of use in different use-cases, but if you have a specific goal in mind and would like assistance feel free to [file an issue](https://github.com/planttheidea/fast-equals/issues).
@@ -2,7 +2,6 @@
2
2
 
3
3
  var getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols;
4
4
  var hasOwnProperty = Object.prototype.hasOwnProperty;
5
- var SUPPORTS_ARRAY_BUFFER = typeof ArrayBuffer === 'function' && Boolean(ArrayBuffer.isView);
6
5
  /**
7
6
  * Combine two comparators into a single comparators.
8
7
  */
@@ -11,15 +10,6 @@ function combineComparators(comparatorA, comparatorB) {
11
10
  return comparatorA(a, b, state) && comparatorB(a, b, state);
12
11
  };
13
12
  }
14
- /**
15
- * Default equality comparator pass-through, used as the standard `isEqual` creator for
16
- * use inside the built comparator.
17
- */
18
- function createInternalComparator(compare) {
19
- return function (a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {
20
- return compare(a, b, state);
21
- };
22
- }
23
13
  /**
24
14
  * Wrap the provided `areItemsEqual` method to manage the circular state, allowing
25
15
  * for circular references to be safely included in the comparison without creating
@@ -58,9 +48,6 @@ var hasOwn = Object.hasOwn ||
58
48
  (function (object, property) {
59
49
  return hasOwnProperty.call(object, property);
60
50
  });
61
- function isArrayBuffer(value) {
62
- return SUPPORTS_ARRAY_BUFFER && ArrayBuffer.isView(value);
63
- }
64
51
  /**
65
52
  * Whether the values passed are strictly equal or both NaN.
66
53
  */
@@ -95,36 +82,42 @@ function areDatesEqual(a, b) {
95
82
  * Whether the `Map`s are equal in value.
96
83
  */
97
84
  function areMapsEqual(a, b, state) {
98
- var isValueEqual = a.size === b.size;
99
- if (isValueEqual && a.size) {
100
- // The use of `forEach()` is to avoid the transpilation cost of `for...of` comparisons, and
101
- // the inability to control the performance of the resulting code. It also avoids excessive
102
- // iteration compared to doing comparisons of `keys()` and `values()`. As a result, though,
103
- // we cannot short-circuit the iterations; bookkeeping must be done to short-circuit the
104
- // equality checks themselves.
105
- var matchedIndices_1 = {};
106
- var indexA_1 = 0;
107
- a.forEach(function (aValue, aKey) {
108
- if (!isValueEqual) {
109
- return;
85
+ if (a.size !== b.size) {
86
+ return false;
87
+ }
88
+ var matchedIndices = {};
89
+ var aIterable = a.entries();
90
+ var index = 0;
91
+ var aResult;
92
+ var bResult;
93
+ while ((aResult = aIterable.next())) {
94
+ if (aResult.done) {
95
+ break;
96
+ }
97
+ var bIterable = b.entries();
98
+ var hasMatch = false;
99
+ var matchIndex = 0;
100
+ while ((bResult = bIterable.next())) {
101
+ if (bResult.done) {
102
+ break;
110
103
  }
111
- var hasMatch = false;
112
- var matchIndexB = 0;
113
- b.forEach(function (bValue, bKey) {
114
- if (!hasMatch &&
115
- !matchedIndices_1[matchIndexB] &&
116
- (hasMatch =
117
- state.equals(aKey, bKey, indexA_1, matchIndexB, a, b, state) &&
118
- state.equals(aValue, bValue, aKey, bKey, a, b, state))) {
119
- matchedIndices_1[matchIndexB] = true;
120
- }
121
- matchIndexB++;
122
- });
123
- indexA_1++;
124
- isValueEqual = hasMatch;
125
- });
104
+ var _a = aResult.value, aKey = _a[0], aValue = _a[1];
105
+ var _b = bResult.value, bKey = _b[0], bValue = _b[1];
106
+ if (!hasMatch &&
107
+ !matchedIndices[matchIndex] &&
108
+ (hasMatch =
109
+ state.equals(aKey, bKey, index, matchIndex, a, b, state) &&
110
+ state.equals(aValue, bValue, aKey, bKey, a, b, state))) {
111
+ matchedIndices[matchIndex] = true;
112
+ }
113
+ matchIndex++;
114
+ }
115
+ if (!hasMatch) {
116
+ return false;
117
+ }
118
+ index++;
126
119
  }
127
- return isValueEqual;
120
+ return true;
128
121
  }
129
122
  /**
130
123
  * Whether the objects are equal in value.
@@ -212,33 +205,40 @@ function areRegExpsEqual(a, b) {
212
205
  * Whether the `Set`s are equal in value.
213
206
  */
214
207
  function areSetsEqual(a, b, state) {
215
- var isValueEqual = a.size === b.size;
216
- if (isValueEqual && a.size) {
217
- // The use of `forEach()` is to avoid the transpilation cost of `for...of` comparisons, and
218
- // the inability to control the performance of the resulting code. It also avoids excessive
219
- // iteration compared to doing comparisons of `keys()` and `values()`. As a result, though,
220
- // we cannot short-circuit the iterations; bookkeeping must be done to short-circuit the
221
- // equality checks themselves.
222
- var matchedIndices_2 = {};
223
- a.forEach(function (aValue, aKey) {
224
- if (!isValueEqual) {
225
- return;
208
+ if (a.size !== b.size) {
209
+ return false;
210
+ }
211
+ var matchedIndices = {};
212
+ var aIterable = a.values();
213
+ var aResult;
214
+ var bResult;
215
+ while ((aResult = aIterable.next())) {
216
+ if (aResult.done) {
217
+ break;
218
+ }
219
+ var bIterable = b.values();
220
+ var hasMatch = false;
221
+ var matchIndex = 0;
222
+ while ((bResult = bIterable.next())) {
223
+ if (bResult.done) {
224
+ break;
226
225
  }
227
- var hasMatch = false;
228
- var matchIndex = 0;
229
- b.forEach(function (bValue, bKey) {
230
- if (!hasMatch &&
231
- !matchedIndices_2[matchIndex] &&
232
- (hasMatch = state.equals(aValue, bValue, aKey, bKey, a, b, state))) {
233
- matchedIndices_2[matchIndex] = true;
234
- }
235
- matchIndex++;
236
- });
237
- isValueEqual = hasMatch;
238
- });
226
+ if (!hasMatch &&
227
+ !matchedIndices[matchIndex] &&
228
+ (hasMatch = state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state))) {
229
+ matchedIndices[matchIndex] = true;
230
+ }
231
+ matchIndex++;
232
+ }
233
+ if (!hasMatch) {
234
+ return false;
235
+ }
239
236
  }
240
- return isValueEqual;
237
+ return true;
241
238
  }
239
+ /**
240
+ * Whether the TypedArray instances are equal in value.
241
+ */
242
242
  function areTypedArraysEqual(a, b) {
243
243
  var index = a.length;
244
244
  if (b.length !== index) {
@@ -262,12 +262,15 @@ var REG_EXP_TAG = '[object RegExp]';
262
262
  var SET_TAG = '[object Set]';
263
263
  var STRING_TAG = '[object String]';
264
264
  var isArray = Array.isArray;
265
+ var isTypedArray = typeof ArrayBuffer === 'function' && ArrayBuffer.isView
266
+ ? ArrayBuffer.isView
267
+ : null;
265
268
  var assign = Object.assign;
266
269
  var getTag = Object.prototype.toString.call.bind(Object.prototype.toString);
267
270
  /**
268
271
  * Create a comparator method based on the type-specific equality comparators passed.
269
272
  */
270
- function createComparator(_a) {
273
+ function createEqualityComparator(_a) {
271
274
  var areArraysEqual = _a.areArraysEqual, areDatesEqual = _a.areDatesEqual, areMapsEqual = _a.areMapsEqual, areObjectsEqual = _a.areObjectsEqual, arePrimitiveWrappersEqual = _a.arePrimitiveWrappersEqual, areRegExpsEqual = _a.areRegExpsEqual, areSetsEqual = _a.areSetsEqual, areTypedArraysEqual = _a.areTypedArraysEqual;
272
275
  /**
273
276
  * compare the value of the two objects and return true if they are equivalent in values
@@ -281,9 +284,13 @@ function createComparator(_a) {
281
284
  // of them being equal but not strictly is if they are both `NaN`. Since
282
285
  // `NaN` is uniquely not equal to itself, we can use self-comparison of
283
286
  // both objects, which is faster than `isNaN()`.
284
- if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {
287
+ if (a == null ||
288
+ b == null ||
289
+ typeof a !== 'object' ||
290
+ typeof b !== 'object') {
285
291
  return a !== a && b !== b;
286
292
  }
293
+ var constructor = a.constructor;
287
294
  // Checks are listed in order of commonality of use-case:
288
295
  // 1. Common complex object types (plain object, array)
289
296
  // 2. Common data values (date, regexp)
@@ -292,39 +299,47 @@ function createComparator(_a) {
292
299
  // Inherently this is both subjective and assumptive, however
293
300
  // when reviewing comparable libraries in the wild this order
294
301
  // appears to be generally consistent.
302
+ // Constructors should match, otherwise there is potential for false positives
303
+ // between class and subclass or custom object and POJO.
304
+ if (constructor !== b.constructor) {
305
+ return false;
306
+ }
295
307
  // `isPlainObject` only checks against the object's own realm. Cross-realm
296
308
  // comparisons are rare, and will be handled in the ultimate fallback, so
297
- // we can avoid the `toString.call()` cost unless necessary.
298
- if (a.constructor === Object && b.constructor === Object) {
309
+ // we can avoid capturing the string tag.
310
+ if (constructor === Object) {
299
311
  return areObjectsEqual(a, b, state);
300
312
  }
301
- // In strict mode, constructors should match. We placed this after the plain object check
302
- // because the constructors must match to meet plain object requirements (must both be `Object`
303
- // in the given Realm), so it slightly improves performance on a very common use-case.
304
- if (state.strict && a.constructor !== b.constructor) {
305
- return false;
313
+ // `isArray()` works on subclasses and is cross-realm, so we can avoid capturing
314
+ // the string tag or doing an `instanceof` check.
315
+ if (isArray(a)) {
316
+ return areArraysEqual(a, b, state);
306
317
  }
307
- // `isArray()` works on subclasses and is cross-realm, so we can again avoid
308
- // the `toString.call()` cost unless necessary by just checking if either
309
- // and then both are arrays.
310
- var aArray = isArray(a);
311
- var bArray = isArray(b);
312
- if (aArray || bArray) {
313
- return aArray === bArray && areArraysEqual(a, b, state);
314
- }
315
- aArray = isArrayBuffer(a);
316
- bArray = isArrayBuffer(b);
317
- if (aArray || bArray) {
318
- return aArray === bArray && areTypedArraysEqual(a, b, state);
319
- }
320
- // Since this is a custom object, use the classic `toString.call()` to get its
321
- // type. This is reasonably performant in modern environments like v8 and
322
- // SpiderMonkey, and allows for cross-realm comparison when other checks like
323
- // `instanceof` do not.
324
- var tag = getTag(a);
325
- if (tag !== getTag(b)) {
326
- return false;
318
+ // `isTypedArray()` works on all possible TypedArray classes, so we can avoid
319
+ // capturing the string tag or comparing against all possible constructors.
320
+ if (isTypedArray != null && isTypedArray(a)) {
321
+ return areTypedArraysEqual(a, b, state);
322
+ }
323
+ // Try to fast-path equality checks for other complex object types in the
324
+ // same realm to avoid capturing the string tag. Strict equality is used
325
+ // instead of `instanceof` because it is more performant for the common
326
+ // use-case. If someone is subclassing a native class, it will be handled
327
+ // with the string tag comparison.
328
+ if (constructor === Date) {
329
+ return areDatesEqual(a, b, state);
327
330
  }
331
+ if (constructor === RegExp) {
332
+ return areRegExpsEqual(a, b, state);
333
+ }
334
+ if (constructor === Map) {
335
+ return areMapsEqual(a, b, state);
336
+ }
337
+ if (constructor === Set) {
338
+ return areSetsEqual(a, b, state);
339
+ }
340
+ // Since this is a custom object, capture the string tag to determing its type.
341
+ // This is reasonably performant in modern environments like v8 and SpiderMonkey.
342
+ var tag = getTag(a);
328
343
  if (tag === DATE_TAG) {
329
344
  return areDatesEqual(a, b, state);
330
345
  }
@@ -337,11 +352,9 @@ function createComparator(_a) {
337
352
  if (tag === SET_TAG) {
338
353
  return areSetsEqual(a, b, state);
339
354
  }
340
- // If a simple object tag, then we can prioritize a simple object comparison because
341
- // it is likely a custom class.
342
355
  if (tag === OBJECT_TAG) {
343
- // The exception for value comparison is `Promise`-like contracts. These should be
344
- // treated the same as standard `Promise` objects, which means strict equality, and if
356
+ // The exception for value comparison is custom `Promise`-like class instances. These should
357
+ // be treated the same as standard `Promise` objects, which means strict equality, and if
345
358
  // it reaches this point then that strict equality comparison has already failed.
346
359
  return (typeof a.then !== 'function' &&
347
360
  typeof b.then !== 'function' &&
@@ -374,7 +387,7 @@ function createComparator(_a) {
374
387
  /**
375
388
  * Create the configuration object used for building comparators.
376
389
  */
377
- function createComparatorConfig(_a) {
390
+ function createEqualityComparatorConfig(_a) {
378
391
  var circular = _a.circular, createCustomConfig = _a.createCustomConfig, strict = _a.strict;
379
392
  var config = {
380
393
  areArraysEqual: strict
@@ -393,7 +406,7 @@ function createComparatorConfig(_a) {
393
406
  ? combineComparators(areSetsEqual, areObjectsEqualStrict)
394
407
  : areSetsEqual,
395
408
  areTypedArraysEqual: strict
396
- ? combineComparators(areTypedArraysEqual, areObjectsEqualStrict)
409
+ ? areObjectsEqualStrict
397
410
  : areTypedArraysEqual,
398
411
  };
399
412
  if (createCustomConfig) {
@@ -413,6 +426,51 @@ function createComparatorConfig(_a) {
413
426
  }
414
427
  return config;
415
428
  }
429
+ /**
430
+ * Default equality comparator pass-through, used as the standard `isEqual` creator for
431
+ * use inside the built comparator.
432
+ */
433
+ function createInternalEqualityComparator(compare) {
434
+ return function (a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {
435
+ return compare(a, b, state);
436
+ };
437
+ }
438
+ /**
439
+ * Create the `isEqual` function used by the consuming application.
440
+ */
441
+ function createIsEqual(_a) {
442
+ var circular = _a.circular, comparator = _a.comparator, createState = _a.createState, equals = _a.equals, strict = _a.strict;
443
+ if (createState) {
444
+ return function isEqual(a, b) {
445
+ var _a = createState(), _b = _a.cache, cache = _b === void 0 ? circular ? new WeakMap() : undefined : _b, meta = _a.meta;
446
+ return comparator(a, b, {
447
+ cache: cache,
448
+ equals: equals,
449
+ meta: meta,
450
+ strict: strict,
451
+ });
452
+ };
453
+ }
454
+ if (circular) {
455
+ return function isEqual(a, b) {
456
+ return comparator(a, b, {
457
+ cache: new WeakMap(),
458
+ equals: equals,
459
+ meta: undefined,
460
+ strict: strict,
461
+ });
462
+ };
463
+ }
464
+ var state = {
465
+ cache: undefined,
466
+ equals: equals,
467
+ meta: undefined,
468
+ strict: strict,
469
+ };
470
+ return function isEqual(a, b) {
471
+ return comparator(a, b, state);
472
+ };
473
+ }
416
474
 
417
475
  /**
418
476
  * Whether the items passed are deeply-equal in value.
@@ -438,29 +496,29 @@ var strictCircularDeepEqual = createCustomEqual({
438
496
  * Whether the items passed are shallowly-equal in value.
439
497
  */
440
498
  var shallowEqual = createCustomEqual({
441
- comparator: sameValueZeroEqual,
499
+ createInternalComparator: function () { return sameValueZeroEqual; },
442
500
  });
443
501
  /**
444
502
  * Whether the items passed are shallowly-equal in value based on strict comparison
445
503
  */
446
504
  var strictShallowEqual = createCustomEqual({
447
- comparator: sameValueZeroEqual,
448
505
  strict: true,
506
+ createInternalComparator: function () { return sameValueZeroEqual; },
449
507
  });
450
508
  /**
451
509
  * Whether the items passed are shallowly-equal in value, including circular references.
452
510
  */
453
511
  var circularShallowEqual = createCustomEqual({
454
- comparator: sameValueZeroEqual,
455
512
  circular: true,
513
+ createInternalComparator: function () { return sameValueZeroEqual; },
456
514
  });
457
515
  /**
458
516
  * Whether the items passed are shallowly-equal in value, including circular references,
459
517
  * based on strict comparison.
460
518
  */
461
519
  var strictCircularShallowEqual = createCustomEqual({
462
- comparator: sameValueZeroEqual,
463
520
  circular: true,
521
+ createInternalComparator: function () { return sameValueZeroEqual; },
464
522
  strict: true,
465
523
  });
466
524
  /**
@@ -473,43 +531,13 @@ var strictCircularShallowEqual = createCustomEqual({
473
531
  */
474
532
  function createCustomEqual(options) {
475
533
  if (options === void 0) { options = {}; }
476
- var circular = options.circular, comparator = options.comparator, createCustomInternalComparator = options.createInternalComparator, createState = options.createState, _a = options.strict, baseStrict = _a === void 0 ? false : _a;
477
- var config = createComparatorConfig(options);
478
- var isEqualCustom = createComparator(config);
479
- var isEqualCustomComparator = comparator ||
480
- (createCustomInternalComparator
481
- ? createCustomInternalComparator(isEqualCustom)
482
- : createInternalComparator(isEqualCustom));
483
- if (createState) {
484
- return function isEqual(a, b, metaOverride) {
485
- var _a = createState(isEqualCustom), _b = _a.cache, cache = _b === void 0 ? circular ? new WeakMap() : undefined : _b, _c = _a.equals, equals = _c === void 0 ? isEqualCustomComparator : _c, meta = _a.meta, _d = _a.strict, strict = _d === void 0 ? baseStrict : _d;
486
- return isEqualCustom(a, b, {
487
- cache: cache,
488
- equals: equals,
489
- meta: metaOverride !== undefined ? metaOverride : meta,
490
- strict: strict,
491
- });
492
- };
493
- }
494
- if (circular) {
495
- return function equals(a, b) {
496
- return isEqualCustom(a, b, {
497
- cache: new WeakMap(),
498
- equals: isEqualCustomComparator,
499
- meta: undefined,
500
- strict: baseStrict,
501
- });
502
- };
503
- }
504
- var state = Object.freeze({
505
- cache: undefined,
506
- equals: isEqualCustomComparator,
507
- meta: undefined,
508
- strict: baseStrict,
509
- });
510
- return function equals(a, b) {
511
- return isEqualCustom(a, b, state);
512
- };
534
+ var _a = options.circular, circular = _a === void 0 ? false : _a, createCustomInternalComparator = options.createInternalComparator, createState = options.createState, _b = options.strict, strict = _b === void 0 ? false : _b;
535
+ var config = createEqualityComparatorConfig(options);
536
+ var comparator = createEqualityComparator(config);
537
+ var equals = createCustomInternalComparator
538
+ ? createCustomInternalComparator(comparator)
539
+ : createInternalEqualityComparator(comparator);
540
+ return createIsEqual({ circular: circular, comparator: comparator, createState: createState, equals: equals, strict: strict });
513
541
  }
514
542
 
515
543
  exports.circularDeepEqual = circularDeepEqual;