fast-equals 6.0.0-rc.0 → 6.0.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.
package/README.md CHANGED
@@ -1,12 +1,7 @@
1
- # fast-equals
1
+ > fast-equals
2
2
 
3
- <img src="https://img.shields.io/badge/build-passing-brightgreen.svg"/>
4
- <img src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg"/>
5
- <img src="https://img.shields.io/badge/license-MIT-blue.svg"/>
6
-
7
- Perform [blazing fast](#benchmarks) equality comparisons (either deep or shallow) on two objects passed, while also
8
- maintaining a high degree of flexibility for various implementation use-cases. It has no dependencies, and is ~2kB when
9
- minified and gzipped.
3
+ Perform [blazing fast](#benchmarks) equality comparisons between two objects, while also allowing for flexibility for
4
+ various use-cases. It has no dependencies, and is ~2kB when minified and gzipped.
10
5
 
11
6
  The following types are handled out-of-the-box:
12
7
 
@@ -16,36 +11,43 @@ The following types are handled out-of-the-box:
16
11
  - `Date` objects
17
12
  - `RegExp` objects
18
13
  - `Map` / `Set` iterables
19
- - `Promise` objects
14
+ - `Promise` objects and then-ables
20
15
  - Primitive wrappers (`new Boolean()` / `new Number()` / `new String()`)
21
16
  - Custom class instances, including subclasses of native classes
22
17
 
23
- Methods are available for deep, shallow, or referential equality comparison. In addition, you can opt into support for
24
- circular objects, or performing a "strict" comparison with unconventional property definition, or both. You can also
25
- customize any specific type comparison based on your application's use-cases.
26
-
27
- ## Table of contents
28
-
29
- - [fast-equals](#fast-equals)
30
- - [Table of contents](#table-of-contents)
31
- - [Usage](#usage)
32
- - [Specific builds](#specific-builds)
33
- - [Available methods](#available-methods)
34
- - [deepEqual](#deepequal)
35
- - [Comparing `Map`s](#comparing-maps)
36
- - [shallowEqual](#shallowequal)
37
- - [sameValueEqual](#samevalueequal)
38
- - [circularDeepEqual](#circulardeepequal)
39
- - [circularShallowEqual](#circularshallowequal)
40
- - [strictDeepEqual](#strictdeepequal)
41
- - [strictShallowEqual](#strictshallowequal)
42
- - [strictCircularDeepEqual](#strictcirculardeepequal)
43
- - [strictCircularShallowEqual](#strictcircularshallowequal)
44
- - [createCustomEqual](#createcustomequal)
45
- - [getUnsupportedCustomComparator](#getunsupportedcustomcomparator)
46
- - [Recipes](#recipes)
47
- - [Benchmarks](#benchmarks)
48
- - [Development](#development)
18
+ Methods are available for deep, shallow, [`SameValue`](http://ecma-international.org/ecma-262/7.0/#sec-samevalue),
19
+ [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero), or
20
+ [strict equality](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) comparison. In addition, you
21
+ can opt into support for circular objects, or performing a "strict" comparison with unconventional property definition,
22
+ or both. You can also customize any specific type comparison based on your application's use-cases.
23
+
24
+ By default, npm should resolve the correct build of the package based on your consumption (ESM vs CommonJS). However, if
25
+ you want to force use of a specific build, they can be located here:
26
+
27
+ - ESM => `fast-equals/dist/es/index.mjs`
28
+ - CommonJS => `fast-equals/dist/cjs/index.cjs`
29
+
30
+ If you are having any problems, want to request a new feature, or have any questions,
31
+ [please file an issue](https://github.com/planttheidea/fast-equals/issues).
32
+
33
+ - [Usage](#usage)
34
+ - [Available methods](#available-methods)
35
+ - [deepEqual](#deepequal)
36
+ - [Comparing `Map`s](#comparing-maps)
37
+ - [shallowEqual](#shallowequal)
38
+ - [sameValueEqual](#samevalueequal)
39
+ - [sameValueZeroEqual](#samevaluezeroequal)
40
+ - [strictEqual](#strictequal)
41
+ - [circularDeepEqual](#circulardeepequal)
42
+ - [circularShallowEqual](#circularshallowequal)
43
+ - [strictDeepEqual](#strictdeepequal)
44
+ - [strictShallowEqual](#strictshallowequal)
45
+ - [strictCircularDeepEqual](#strictcirculardeepequal)
46
+ - [strictCircularShallowEqual](#strictcircularshallowequal)
47
+ - [createCustomEqual](#createcustomequal)
48
+ - [getUnsupportedCustomComparator](#getunsupportedcustomcomparator)
49
+ - [Recipes](#recipes)
50
+ - [Benchmarks](#benchmarks)
49
51
 
50
52
  ## Usage
51
53
 
@@ -55,19 +57,6 @@ import { deepEqual } from 'fast-equals';
55
57
  console.log(deepEqual({ foo: 'bar' }, { foo: 'bar' })); // true
56
58
  ```
57
59
 
58
- ### Specific builds
59
-
60
- By default, npm should resolve the correct build of the package based on your consumption (ESM vs CommonJS). However, if
61
- you want to force use of a specific build, they can be located here:
62
-
63
- - ESM => `fast-equals/dist/esm/index.mjs`
64
- - CommonJS => `fast-equals/dist/cjs/index.cjs`
65
- - UMD => `fast-equals/dist/umd/index.js`
66
- - Minified UMD => `fast-equals/dist/min/index.js`
67
-
68
- If you are having issues loading a specific build type,
69
- [please file an issue](https://github.com/planttheidea/fast-equals/issues).
70
-
71
60
  ## Available methods
72
61
 
73
62
  ### deepEqual
@@ -99,7 +88,7 @@ deepEqual(mapA, mapB);
99
88
  ```
100
89
 
101
90
  To support true deep equality of all contents, `fast-equals` will perform a deep equality comparison for key and value
102
- parirs. Therefore, the above would be `true`.
91
+ pairs. Therefore, the above would be `true`.
103
92
 
104
93
  ### shallowEqual
105
94
 
@@ -143,9 +132,59 @@ console.log(sameValueEqual(mainObject.foo, objectB)); // true
143
132
  console.log(sameValueEqual(mainObject, objectC)); // false
144
133
  ```
145
134
 
146
- **NOTE**: In environments that support
147
- [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is), this is just
148
- a re-export of that method.
135
+ _**NOTE**: In environments that support
136
+ [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is),
137
+ `sameValueEqual` is just a re-export of that method._
138
+
139
+ ### sameValueZeroEqual
140
+
141
+ Performs a [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) comparison on the two
142
+ objects passed and returns a boolean representing the value equivalency of the objects. In simple terms, this means:
143
+
144
+ - `+0` and `-0` are equal
145
+ - `NaN` is equal to `NaN`
146
+ - All other items are based on referential equality (`a === b`)
147
+
148
+ ```ts
149
+ import { sameValueEqual } from 'fast-equals';
150
+
151
+ const mainObject = { foo: NaN, bar: 'baz' };
152
+
153
+ const objectA = 'baz';
154
+ const objectB = NaN;
155
+ const objectC = { foo: NaN, bar: 'baz' };
156
+
157
+ console.log(sameValueEqual(mainObject.bar, objectA)); // true
158
+ console.log(sameValueEqual(mainObject.foo, objectB)); // true
159
+ console.log(sameValueEqual(mainObject, objectC)); // false
160
+ ```
161
+
162
+ ### strictEqual
163
+
164
+ Performs a [Strict Equality](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) comparison on the
165
+ two objects passed and returns a boolean representing the referential equality of the objects. In simple terms, this
166
+ means:
167
+
168
+ - `+0` and `-0` are equal
169
+ - `NaN` is not equal to `NaN`
170
+ - All other items are based on referential equality (`a === b`)
171
+
172
+ ```ts
173
+ import { strictEqual } from 'fast-equals';
174
+
175
+ const mainObject = { foo: NaN, bar: 'baz' };
176
+
177
+ const objectA = 'baz';
178
+ const objectB = NaN;
179
+ const objectC = { foo: NaN, bar: 'baz' };
180
+
181
+ console.log(sameValueEqual(mainObject.bar, objectA)); // true
182
+ console.log(sameValueEqual(mainObject.foo, objectB)); // false
183
+ console.log(sameValueEqual(mainObject, objectC)); // false
184
+ ```
185
+
186
+ _**NOTE**: This is mainly a convenience function, such as needing a default functional equality comparator. Naturally,
187
+ it is faster to simply compare `a === b`. :)_
149
188
 
150
189
  ### circularDeepEqual
151
190
 
@@ -305,21 +344,21 @@ interface Cache<Key extends object, Value> {
305
344
  }
306
345
 
307
346
  interface ComparatorConfig<Meta> {
308
- areArrayBuffersEcqual: TypeEqualityComparator<ArrayBuffer, Meta>;
309
- areArraysEcqual: TypeEqualityComparator<any[], Meta>;
310
- areDataViewsEqual: TypeEqualityComparator<DataView, Meta>;
311
- areDatesEqual: TypeEqualityComparator<Date, Meta>;
312
- areErrorsEqual: TypeEqualityComparator<Error, Meta>;
313
- areFunctionsEqual: TypeEqualityComparator<(...args: any[]) => any, Meta>;
314
- areMapsEqual: TypeEqualityComparator<Map<any, any>, Meta>;
315
- areNumbersEqual: TypeEqualityComparator<number, Meta>;
316
- areObjectsEqual: TypeEqualityComparator<Record<string, any>, Meta>;
317
- arePrimitiveWrappersEqual: TypeEqualityComparator<Boolean | Number | String, Meta>;
318
- areRegExpsEqual: TypeEqualityComparator<RegExp, Meta>;
319
- areSetsEqual: TypeEqualityComparator<Set<any>, Meta>;
320
- areTypedArraysEqual: TypeEqualityComparator<TypedArray, Meta>;
321
- areUrlsEqual: TypeEqualityComparator<URL, Meta>;
322
- getUnsupportedCustomComparator: <Type>(a: Type, b: Type, tag: string) => TypeEqualityComparator<Type, Meta>;
347
+ areArrayBuffersEqual: EqualityComparator<Meta>;
348
+ areArraysEqual: EqualityComparator<Meta>;
349
+ areDataViewsEqual: EqualityComparator<Meta>;
350
+ areDatesEqual: EqualityComparator<Meta>;
351
+ areErrorsEqual: EqualityComparator<Meta>;
352
+ areFunctionsEqual: EqualityComparator<Meta>;
353
+ areMapsEqual: EqualityComparator<Meta>;
354
+ areNumbersEqual: EqualityComparator<Meta>;
355
+ areObjectsEqual: EqualityComparator<Meta>;
356
+ arePrimitiveWrappersEqual: EqualityComparator<Meta>;
357
+ areRegExpsEqual: EqualityComparator<Meta>;
358
+ areSetsEqual: EqualityComparator<Meta>;
359
+ areTypedArraysEqual: EqualityComparator<Meta>;
360
+ areUrlsEqual: EqualityComparator<Meta>;
361
+ getUnsupportedCustomComparator: <Type>(a: Type, b: Type, state: State<Meta>, tag: string) => EqualityComparator<Meta>;
323
362
  }
324
363
 
325
364
  function createCustomEqual<Meta>(options: {
@@ -358,7 +397,7 @@ to the problem you are solving, they can offer guidance of how to structure your
358
397
  - [Using `meta` in comparison](./recipes//using-meta-in-comparison.md)
359
398
  - [Comparing non-standard properties](./recipes/non-standard-properties.md)
360
399
  - [Strict property descriptor comparison](./recipes/strict-property-descriptor-check.md)
361
- - [Legacy environment support for circualr equal comparators](./recipes/legacy-circular-equal-support.md)
400
+ - [Legacy environment support for circular equal comparators](./recipes/legacy-circular-equal-support.md)
362
401
  - [Custom comparator support](./recipes/special-objects.md)
363
402
 
364
403
  ## Benchmarks
@@ -468,20 +507,3 @@ All of these have the potential of inflating the respective library's numbers in
468
507
  the closest apples-to-apples comparison I could create of a reasonable sample size. It should be noted that `react`
469
508
  elements can be circular objects, however simple elements are not; I kept the `react` comparison very basic to allow it
470
509
  to be included.
471
-
472
- ## Development
473
-
474
- Standard practice, clone the repo and `npm i` to get the dependencies. The following npm scripts are available:
475
-
476
- - benchmark => run benchmark tests against other equality libraries
477
- - build => build `main`, `module`, and `browser` distributables with `rollup`
478
- - clean => run `rimraf` on the `dist` folder
479
- - dev => start `vite` playground App
480
- - dist => run `build`
481
- - lint => run ESLint on all files in `src` folder (also runs on `dev` script)
482
- - lint:fix => run `lint` script, but with auto-fixer
483
- - prepublish:compile => run `lint`, `test:coverage`, `transpile:lib`, `transpile:es`, and `dist` scripts
484
- - start => run `dev`
485
- - test => run AVA with NODE_ENV=test on all files in `test` folder
486
- - test:coverage => run same script as `test` with code coverage calculation via `nyc`
487
- - test:watch => run same script as `test` but keep persistent watcher
@@ -48,8 +48,18 @@ function getStrictProperties(object) {
48
48
  const hasOwn =
49
49
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
50
50
  Object.hasOwn || ((object, property) => hasOwnProperty.call(object, property));
51
+
52
+ const PREACT_VNODE = '__v';
53
+ const PREACT_OWNER = '__o';
54
+ const REACT_OWNER = '_owner';
55
+ const { getOwnPropertyDescriptor, keys } = Object;
51
56
  /**
52
- * Whether the values passed are strictly equal or both NaN.
57
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
58
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
59
+ *
60
+ * @note
61
+ * When available in the environment, this is just a re-export of the global
62
+ * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
53
63
  */
54
64
  const sameValueEqual =
55
65
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -57,11 +67,26 @@ Object.is
57
67
  || function sameValueEqual(a, b) {
58
68
  return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;
59
69
  };
60
-
61
- const PREACT_VNODE = '__v';
62
- const PREACT_OWNER = '__o';
63
- const REACT_OWNER = '_owner';
64
- const { getOwnPropertyDescriptor, keys } = Object;
70
+ /**
71
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
72
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
73
+ * are either positive or negative zero.
74
+ */
75
+ function sameValueZeroEqual(a, b) {
76
+ return a === b || (a !== a && b !== b);
77
+ }
78
+ /**
79
+ * Whether the values passed are equal based on a
80
+ * [Strict Equality Comparison](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) basis.
81
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`).
82
+ *
83
+ * @note
84
+ * This is mainly available as a convenience function, such as being a default when a function to determine equality between
85
+ * two objects is used.
86
+ */
87
+ function strictEqual(a, b) {
88
+ return a === b;
89
+ }
65
90
  /**
66
91
  * Whether the array buffers are equal in value.
67
92
  */
@@ -102,12 +127,6 @@ function areDatesEqual(a, b) {
102
127
  function areErrorsEqual(a, b) {
103
128
  return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;
104
129
  }
105
- /**
106
- * Whether the functions passed are equal in value.
107
- */
108
- function areFunctionsEqual(a, b) {
109
- return a === b;
110
- }
111
130
  /**
112
131
  * Whether the `Map`s are equal in value.
113
132
  */
@@ -157,10 +176,6 @@ function areMapsEqual(a, b, state) {
157
176
  }
158
177
  return true;
159
178
  }
160
- /**
161
- * Whether the numbers are equal in value.
162
- */
163
- const areNumbersEqual = sameValueEqual;
164
179
  /**
165
180
  * Whether the objects are equal in value.
166
181
  */
@@ -355,8 +370,8 @@ function createEqualityComparator(config) {
355
370
  // Try to fast-path equality checks for other complex object types in the
356
371
  // same realm to avoid capturing the string tag. Strict equality is used
357
372
  // instead of `instanceof` because it is more performant for the common
358
- // use-case. If someone is subclassing a native class, it will be handled
359
- // with the string tag comparison.
373
+ // use-case. If someone is creating a subclass from a native class, it will be
374
+ // handled with the string tag comparison.
360
375
  if (constructor === Object) {
361
376
  return areObjectsEqual(a, b, state);
362
377
  }
@@ -385,14 +400,14 @@ function createEqualityComparator(config) {
385
400
  if (Array.isArray(a)) {
386
401
  return areArraysEqual(a, b, state);
387
402
  }
388
- // Since this is a custom object, capture the string tag to determing its type.
403
+ // Since this is a custom object, capture the string tag to determining its type.
389
404
  // This is reasonably performant in modern environments like v8 and SpiderMonkey.
390
405
  const tag = toString.call(a);
391
406
  const supportedComparator = supportedComparatorMap[tag];
392
407
  if (supportedComparator) {
393
408
  return supportedComparator(a, b, state);
394
409
  }
395
- const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, tag);
410
+ const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, state, tag);
396
411
  if (unsupportedCustomComparator) {
397
412
  return unsupportedCustomComparator(a, b, state);
398
413
  }
@@ -400,9 +415,6 @@ function createEqualityComparator(config) {
400
415
  // the only thing remaining is strict equality, which has already been compared. This is for a few reasons:
401
416
  // - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only
402
417
  // comparison that can be made.
403
- // - For types that can be introspected, but rarely have requirements to be compared
404
- // (`ArrayBuffer`, `DataView`, etc.), the cost is avoided to prioritize the common
405
- // use-cases (may be included in a future release, if requested enough).
406
418
  // - For types that can be introspected but do not have an objective definition of what
407
419
  // equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.
408
420
  // In all cases, these decisions should be reevaluated based on changes to the language and
@@ -420,9 +432,9 @@ function createEqualityComparatorConfig({ circular, createCustomConfig, strict,
420
432
  areDataViewsEqual,
421
433
  areDatesEqual: areDatesEqual,
422
434
  areErrorsEqual: areErrorsEqual,
423
- areFunctionsEqual: areFunctionsEqual,
435
+ areFunctionsEqual: strictEqual,
424
436
  areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
425
- areNumbersEqual: areNumbersEqual,
437
+ areNumbersEqual: sameValueEqual,
426
438
  areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
427
439
  arePrimitiveWrappersEqual: arePrimitiveWrappersEqual,
428
440
  areRegExpsEqual: areRegExpsEqual,
@@ -502,6 +514,7 @@ function createSupportedComparatorMap({ areArrayBuffersEqual, areArraysEqual, ar
502
514
  '[object Arguments]': areObjectsEqual,
503
515
  '[object Array]': areArraysEqual,
504
516
  '[object ArrayBuffer]': areArrayBuffersEqual,
517
+ '[object AsyncGeneratorFunction]': areFunctionsEqual,
505
518
  '[object BigInt]': areNumbersEqual,
506
519
  '[object BigInt64Array]': areTypedArraysEqual,
507
520
  '[object BigUint64Array]': areTypedArraysEqual,
@@ -611,8 +624,10 @@ exports.circularShallowEqual = circularShallowEqual;
611
624
  exports.createCustomEqual = createCustomEqual;
612
625
  exports.deepEqual = deepEqual;
613
626
  exports.sameValueEqual = sameValueEqual;
627
+ exports.sameValueZeroEqual = sameValueZeroEqual;
614
628
  exports.shallowEqual = shallowEqual;
615
629
  exports.strictCircularDeepEqual = strictCircularDeepEqual;
616
630
  exports.strictCircularShallowEqual = strictCircularShallowEqual;
617
631
  exports.strictDeepEqual = strictDeepEqual;
632
+ exports.strictEqual = strictEqual;
618
633
  exports.strictShallowEqual = strictShallowEqual;
@@ -27,92 +27,75 @@ interface State<Meta> {
27
27
  */
28
28
  readonly strict: boolean;
29
29
  }
30
- interface CircularState<Meta> extends State<Meta> {
31
- readonly cache: Cache<any, any>;
32
- }
33
- interface DefaultState<Meta> extends State<Meta> {
34
- readonly cache: undefined;
35
- }
36
- interface Dictionary<Value = any> {
37
- [key: string | symbol]: Value;
38
- $$typeof?: any;
39
- }
40
30
  interface ComparatorConfig<Meta> {
41
31
  /**
42
32
  * Whether the array buffers passed are equal in value. In strict mode, this includes
43
33
  * additional properties added to the array.
44
34
  */
45
- areArrayBuffersEqual: TypeEqualityComparator<any, Meta>;
35
+ areArrayBuffersEqual: EqualityComparator<Meta>;
46
36
  /**
47
37
  * Whether the arrays passed are equal in value. In strict mode, this includes
48
38
  * additional properties added to the array.
49
39
  */
50
- areArraysEqual: TypeEqualityComparator<any, Meta>;
40
+ areArraysEqual: EqualityComparator<Meta>;
51
41
  /**
52
42
  * Whether the data views passed are equal in value.
53
43
  */
54
- areDataViewsEqual: TypeEqualityComparator<any, Meta>;
44
+ areDataViewsEqual: EqualityComparator<Meta>;
55
45
  /**
56
46
  * Whether the dates passed are equal in value.
57
47
  */
58
- areDatesEqual: TypeEqualityComparator<any, Meta>;
48
+ areDatesEqual: EqualityComparator<Meta>;
59
49
  /**
60
50
  * Whether the errors passed are equal in value.
61
51
  */
62
- areErrorsEqual: TypeEqualityComparator<any, Meta>;
52
+ areErrorsEqual: EqualityComparator<Meta>;
63
53
  /**
64
54
  * Whether the functions passed are equal in value.
65
55
  */
66
- areFunctionsEqual: TypeEqualityComparator<any, Meta>;
56
+ areFunctionsEqual: EqualityComparator<Meta>;
67
57
  /**
68
58
  * Whether the maps passed are equal in value. In strict mode, this includes
69
59
  * additional properties added to the map.
70
60
  */
71
- areMapsEqual: TypeEqualityComparator<any, Meta>;
61
+ areMapsEqual: EqualityComparator<Meta>;
72
62
  /**
73
63
  * Whether the numbers passed are equal in value.
74
64
  */
75
- areNumbersEqual: TypeEqualityComparator<any, Meta>;
65
+ areNumbersEqual: EqualityComparator<Meta>;
76
66
  /**
77
67
  * Whether the objects passed are equal in value. In strict mode, this includes
78
68
  * non-enumerable properties added to the map, as well as symbol properties.
79
69
  */
80
- areObjectsEqual: TypeEqualityComparator<any, Meta>;
70
+ areObjectsEqual: EqualityComparator<Meta>;
81
71
  /**
82
72
  * Whether the primitive wrappers passed are equal in value.
83
73
  */
84
- arePrimitiveWrappersEqual: TypeEqualityComparator<any, Meta>;
74
+ arePrimitiveWrappersEqual: EqualityComparator<Meta>;
85
75
  /**
86
76
  * Whether the regexps passed are equal in value.
87
77
  */
88
- areRegExpsEqual: TypeEqualityComparator<any, Meta>;
78
+ areRegExpsEqual: EqualityComparator<Meta>;
89
79
  /**
90
80
  * Whether the sets passed are equal in value. In strict mode, this includes
91
81
  * additional properties added to the set.
92
82
  */
93
- areSetsEqual: TypeEqualityComparator<any, Meta>;
83
+ areSetsEqual: EqualityComparator<Meta>;
94
84
  /**
95
85
  * Whether the typed arrays passed are equal in value. In strict mode, this includes
96
86
  * additional properties added to the typed array.
97
87
  */
98
- areTypedArraysEqual: TypeEqualityComparator<any, Meta>;
88
+ areTypedArraysEqual: EqualityComparator<Meta>;
99
89
  /**
100
90
  * Whether the URLs passed are equal in value.
101
91
  */
102
- areUrlsEqual: TypeEqualityComparator<any, Meta>;
92
+ areUrlsEqual: EqualityComparator<Meta>;
103
93
  /**
104
94
  * Get a custom comparator based on the objects passed.
105
95
  */
106
- getUnsupportedCustomComparator: ((a: any, b: any, tag: string) => TypeEqualityComparator<any, Meta> | undefined) | undefined;
96
+ getUnsupportedCustomComparator: ((a: any, b: any, state: State<Meta>, tag: string) => EqualityComparator<Meta> | undefined) | undefined;
107
97
  }
108
- type CreateCustomComparatorConfig<Meta> = (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
109
- type CreateState<Meta> = () => {
110
- cache?: Cache<any, any> | undefined;
111
- meta?: Meta;
112
- };
113
- type EqualityComparator<Meta> = <A, B>(a: A, b: B, state: State<Meta>) => boolean;
114
- type AnyEqualityComparator<Meta> = (a: any, b: any, state: State<Meta>) => boolean;
115
- type EqualityComparatorCreator<Meta> = (fn: EqualityComparator<Meta>) => InternalEqualityComparator<Meta>;
98
+ type EqualityComparator<Meta> = (a: any, b: any, state: State<Meta>) => boolean;
116
99
  type InternalEqualityComparator<Meta> = (a: any, b: any, indexOrKeyA: any, indexOrKeyB: any, parentA: any, parentB: any, state: State<Meta>) => boolean;
117
100
  type PrimitiveWrapper = Boolean | Number | String;
118
101
  /**
@@ -120,7 +103,6 @@ type PrimitiveWrapper = Boolean | Number | String;
120
103
  * classes.
121
104
  */
122
105
  type TypedArray = BigInt64Array | BigUint64Array | Float32Array | Float64Array | Int8Array | Int16Array | Int32Array | Uint16Array | Uint32Array | Uint8Array | Uint8ClampedArray;
123
- type TypeEqualityComparator<Type, Meta = undefined> = (a: Type, b: Type, state: State<Meta>) => boolean;
124
106
  interface CustomEqualCreatorOptions<Meta> {
125
107
  /**
126
108
  * Whether circular references should be supported. It causes the
@@ -131,9 +113,9 @@ interface CustomEqualCreatorOptions<Meta> {
131
113
  /**
132
114
  * Create a custom configuration of type-specific equality comparators.
133
115
  * This receives the default configuration, which allows either replacement
134
- * or supersetting of the default methods.
116
+ * or a superset of the default methods.
135
117
  */
136
- createCustomConfig?: CreateCustomComparatorConfig<Meta>;
118
+ createCustomConfig?: (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
137
119
  /**
138
120
  * Create a custom internal comparator, which is used as an override to the
139
121
  * default entry point for nested value equality comparisons. This is often
@@ -146,7 +128,10 @@ interface CustomEqualCreatorOptions<Meta> {
146
128
  * Create a custom `state` object passed between the methods. This allows for
147
129
  * custom `cache` and/or `meta` values to be used.
148
130
  */
149
- createState?: CreateState<Meta>;
131
+ createState?: () => {
132
+ cache?: Cache<any, any> | undefined;
133
+ meta?: Meta;
134
+ };
150
135
  /**
151
136
  * Whether the equality comparison is strict, meaning it matches
152
137
  * all properties (including symbols and non-enumerable properties)
@@ -156,9 +141,30 @@ interface CustomEqualCreatorOptions<Meta> {
156
141
  }
157
142
 
158
143
  /**
159
- * Whether the values passed are strictly equal or both NaN.
144
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
145
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
146
+ *
147
+ * @note
148
+ * When available in the environment, this is just a re-export of the global
149
+ * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
160
150
  */
161
151
  declare const sameValueEqual: (value1: any, value2: any) => boolean;
152
+ /**
153
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
154
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
155
+ * are either positive or negative zero.
156
+ */
157
+ declare function sameValueZeroEqual(a: any, b: any): boolean;
158
+ /**
159
+ * Whether the values passed are equal based on a
160
+ * [Strict Equality Comparison](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) basis.
161
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`).
162
+ *
163
+ * @note
164
+ * This is mainly available as a convenience function, such as being a default when a function to determine equality between
165
+ * two objects is used.
166
+ */
167
+ declare function strictEqual(a: any, b: any): boolean;
162
168
 
163
169
  /**
164
170
  * Whether the items passed are deeply-equal in value.
@@ -204,5 +210,5 @@ declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
204
210
  */
205
211
  declare function createCustomEqual<Meta = undefined>(options?: CustomEqualCreatorOptions<Meta>): <A, B>(a: A, b: B) => boolean;
206
212
 
207
- export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
208
- export type { AnyEqualityComparator, Cache, CircularState, ComparatorConfig, CreateCustomComparatorConfig, CreateState, CustomEqualCreatorOptions, DefaultState, Dictionary, EqualityComparator, EqualityComparatorCreator, InternalEqualityComparator, PrimitiveWrapper, State, TypeEqualityComparator, TypedArray };
213
+ export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictEqual, strictShallowEqual };
214
+ export type { Cache, ComparatorConfig, CustomEqualCreatorOptions, EqualityComparator, InternalEqualityComparator, PrimitiveWrapper, State, TypedArray };
@@ -27,92 +27,75 @@ interface State<Meta> {
27
27
  */
28
28
  readonly strict: boolean;
29
29
  }
30
- interface CircularState<Meta> extends State<Meta> {
31
- readonly cache: Cache<any, any>;
32
- }
33
- interface DefaultState<Meta> extends State<Meta> {
34
- readonly cache: undefined;
35
- }
36
- interface Dictionary<Value = any> {
37
- [key: string | symbol]: Value;
38
- $$typeof?: any;
39
- }
40
30
  interface ComparatorConfig<Meta> {
41
31
  /**
42
32
  * Whether the array buffers passed are equal in value. In strict mode, this includes
43
33
  * additional properties added to the array.
44
34
  */
45
- areArrayBuffersEqual: TypeEqualityComparator<any, Meta>;
35
+ areArrayBuffersEqual: EqualityComparator<Meta>;
46
36
  /**
47
37
  * Whether the arrays passed are equal in value. In strict mode, this includes
48
38
  * additional properties added to the array.
49
39
  */
50
- areArraysEqual: TypeEqualityComparator<any, Meta>;
40
+ areArraysEqual: EqualityComparator<Meta>;
51
41
  /**
52
42
  * Whether the data views passed are equal in value.
53
43
  */
54
- areDataViewsEqual: TypeEqualityComparator<any, Meta>;
44
+ areDataViewsEqual: EqualityComparator<Meta>;
55
45
  /**
56
46
  * Whether the dates passed are equal in value.
57
47
  */
58
- areDatesEqual: TypeEqualityComparator<any, Meta>;
48
+ areDatesEqual: EqualityComparator<Meta>;
59
49
  /**
60
50
  * Whether the errors passed are equal in value.
61
51
  */
62
- areErrorsEqual: TypeEqualityComparator<any, Meta>;
52
+ areErrorsEqual: EqualityComparator<Meta>;
63
53
  /**
64
54
  * Whether the functions passed are equal in value.
65
55
  */
66
- areFunctionsEqual: TypeEqualityComparator<any, Meta>;
56
+ areFunctionsEqual: EqualityComparator<Meta>;
67
57
  /**
68
58
  * Whether the maps passed are equal in value. In strict mode, this includes
69
59
  * additional properties added to the map.
70
60
  */
71
- areMapsEqual: TypeEqualityComparator<any, Meta>;
61
+ areMapsEqual: EqualityComparator<Meta>;
72
62
  /**
73
63
  * Whether the numbers passed are equal in value.
74
64
  */
75
- areNumbersEqual: TypeEqualityComparator<any, Meta>;
65
+ areNumbersEqual: EqualityComparator<Meta>;
76
66
  /**
77
67
  * Whether the objects passed are equal in value. In strict mode, this includes
78
68
  * non-enumerable properties added to the map, as well as symbol properties.
79
69
  */
80
- areObjectsEqual: TypeEqualityComparator<any, Meta>;
70
+ areObjectsEqual: EqualityComparator<Meta>;
81
71
  /**
82
72
  * Whether the primitive wrappers passed are equal in value.
83
73
  */
84
- arePrimitiveWrappersEqual: TypeEqualityComparator<any, Meta>;
74
+ arePrimitiveWrappersEqual: EqualityComparator<Meta>;
85
75
  /**
86
76
  * Whether the regexps passed are equal in value.
87
77
  */
88
- areRegExpsEqual: TypeEqualityComparator<any, Meta>;
78
+ areRegExpsEqual: EqualityComparator<Meta>;
89
79
  /**
90
80
  * Whether the sets passed are equal in value. In strict mode, this includes
91
81
  * additional properties added to the set.
92
82
  */
93
- areSetsEqual: TypeEqualityComparator<any, Meta>;
83
+ areSetsEqual: EqualityComparator<Meta>;
94
84
  /**
95
85
  * Whether the typed arrays passed are equal in value. In strict mode, this includes
96
86
  * additional properties added to the typed array.
97
87
  */
98
- areTypedArraysEqual: TypeEqualityComparator<any, Meta>;
88
+ areTypedArraysEqual: EqualityComparator<Meta>;
99
89
  /**
100
90
  * Whether the URLs passed are equal in value.
101
91
  */
102
- areUrlsEqual: TypeEqualityComparator<any, Meta>;
92
+ areUrlsEqual: EqualityComparator<Meta>;
103
93
  /**
104
94
  * Get a custom comparator based on the objects passed.
105
95
  */
106
- getUnsupportedCustomComparator: ((a: any, b: any, tag: string) => TypeEqualityComparator<any, Meta> | undefined) | undefined;
96
+ getUnsupportedCustomComparator: ((a: any, b: any, state: State<Meta>, tag: string) => EqualityComparator<Meta> | undefined) | undefined;
107
97
  }
108
- type CreateCustomComparatorConfig<Meta> = (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
109
- type CreateState<Meta> = () => {
110
- cache?: Cache<any, any> | undefined;
111
- meta?: Meta;
112
- };
113
- type EqualityComparator<Meta> = <A, B>(a: A, b: B, state: State<Meta>) => boolean;
114
- type AnyEqualityComparator<Meta> = (a: any, b: any, state: State<Meta>) => boolean;
115
- type EqualityComparatorCreator<Meta> = (fn: EqualityComparator<Meta>) => InternalEqualityComparator<Meta>;
98
+ type EqualityComparator<Meta> = (a: any, b: any, state: State<Meta>) => boolean;
116
99
  type InternalEqualityComparator<Meta> = (a: any, b: any, indexOrKeyA: any, indexOrKeyB: any, parentA: any, parentB: any, state: State<Meta>) => boolean;
117
100
  type PrimitiveWrapper = Boolean | Number | String;
118
101
  /**
@@ -120,7 +103,6 @@ type PrimitiveWrapper = Boolean | Number | String;
120
103
  * classes.
121
104
  */
122
105
  type TypedArray = BigInt64Array | BigUint64Array | Float32Array | Float64Array | Int8Array | Int16Array | Int32Array | Uint16Array | Uint32Array | Uint8Array | Uint8ClampedArray;
123
- type TypeEqualityComparator<Type, Meta = undefined> = (a: Type, b: Type, state: State<Meta>) => boolean;
124
106
  interface CustomEqualCreatorOptions<Meta> {
125
107
  /**
126
108
  * Whether circular references should be supported. It causes the
@@ -131,9 +113,9 @@ interface CustomEqualCreatorOptions<Meta> {
131
113
  /**
132
114
  * Create a custom configuration of type-specific equality comparators.
133
115
  * This receives the default configuration, which allows either replacement
134
- * or supersetting of the default methods.
116
+ * or a superset of the default methods.
135
117
  */
136
- createCustomConfig?: CreateCustomComparatorConfig<Meta>;
118
+ createCustomConfig?: (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
137
119
  /**
138
120
  * Create a custom internal comparator, which is used as an override to the
139
121
  * default entry point for nested value equality comparisons. This is often
@@ -146,7 +128,10 @@ interface CustomEqualCreatorOptions<Meta> {
146
128
  * Create a custom `state` object passed between the methods. This allows for
147
129
  * custom `cache` and/or `meta` values to be used.
148
130
  */
149
- createState?: CreateState<Meta>;
131
+ createState?: () => {
132
+ cache?: Cache<any, any> | undefined;
133
+ meta?: Meta;
134
+ };
150
135
  /**
151
136
  * Whether the equality comparison is strict, meaning it matches
152
137
  * all properties (including symbols and non-enumerable properties)
@@ -156,9 +141,30 @@ interface CustomEqualCreatorOptions<Meta> {
156
141
  }
157
142
 
158
143
  /**
159
- * Whether the values passed are strictly equal or both NaN.
144
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
145
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
146
+ *
147
+ * @note
148
+ * When available in the environment, this is just a re-export of the global
149
+ * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
160
150
  */
161
151
  declare const sameValueEqual: (value1: any, value2: any) => boolean;
152
+ /**
153
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
154
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
155
+ * are either positive or negative zero.
156
+ */
157
+ declare function sameValueZeroEqual(a: any, b: any): boolean;
158
+ /**
159
+ * Whether the values passed are equal based on a
160
+ * [Strict Equality Comparison](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) basis.
161
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`).
162
+ *
163
+ * @note
164
+ * This is mainly available as a convenience function, such as being a default when a function to determine equality between
165
+ * two objects is used.
166
+ */
167
+ declare function strictEqual(a: any, b: any): boolean;
162
168
 
163
169
  /**
164
170
  * Whether the items passed are deeply-equal in value.
@@ -204,5 +210,5 @@ declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
204
210
  */
205
211
  declare function createCustomEqual<Meta = undefined>(options?: CustomEqualCreatorOptions<Meta>): <A, B>(a: A, b: B) => boolean;
206
212
 
207
- export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
208
- export type { AnyEqualityComparator, Cache, CircularState, ComparatorConfig, CreateCustomComparatorConfig, CreateState, CustomEqualCreatorOptions, DefaultState, Dictionary, EqualityComparator, EqualityComparatorCreator, InternalEqualityComparator, PrimitiveWrapper, State, TypeEqualityComparator, TypedArray };
213
+ export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictEqual, strictShallowEqual };
214
+ export type { Cache, ComparatorConfig, CustomEqualCreatorOptions, EqualityComparator, InternalEqualityComparator, PrimitiveWrapper, State, TypedArray };
package/dist/es/index.mjs CHANGED
@@ -46,8 +46,18 @@ function getStrictProperties(object) {
46
46
  const hasOwn =
47
47
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
48
48
  Object.hasOwn || ((object, property) => hasOwnProperty.call(object, property));
49
+
50
+ const PREACT_VNODE = '__v';
51
+ const PREACT_OWNER = '__o';
52
+ const REACT_OWNER = '_owner';
53
+ const { getOwnPropertyDescriptor, keys } = Object;
49
54
  /**
50
- * Whether the values passed are strictly equal or both NaN.
55
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
56
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
57
+ *
58
+ * @note
59
+ * When available in the environment, this is just a re-export of the global
60
+ * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
51
61
  */
52
62
  const sameValueEqual =
53
63
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -55,11 +65,26 @@ Object.is
55
65
  || function sameValueEqual(a, b) {
56
66
  return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;
57
67
  };
58
-
59
- const PREACT_VNODE = '__v';
60
- const PREACT_OWNER = '__o';
61
- const REACT_OWNER = '_owner';
62
- const { getOwnPropertyDescriptor, keys } = Object;
68
+ /**
69
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
70
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
71
+ * are either positive or negative zero.
72
+ */
73
+ function sameValueZeroEqual(a, b) {
74
+ return a === b || (a !== a && b !== b);
75
+ }
76
+ /**
77
+ * Whether the values passed are equal based on a
78
+ * [Strict Equality Comparison](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) basis.
79
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`).
80
+ *
81
+ * @note
82
+ * This is mainly available as a convenience function, such as being a default when a function to determine equality between
83
+ * two objects is used.
84
+ */
85
+ function strictEqual(a, b) {
86
+ return a === b;
87
+ }
63
88
  /**
64
89
  * Whether the array buffers are equal in value.
65
90
  */
@@ -100,12 +125,6 @@ function areDatesEqual(a, b) {
100
125
  function areErrorsEqual(a, b) {
101
126
  return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;
102
127
  }
103
- /**
104
- * Whether the functions passed are equal in value.
105
- */
106
- function areFunctionsEqual(a, b) {
107
- return a === b;
108
- }
109
128
  /**
110
129
  * Whether the `Map`s are equal in value.
111
130
  */
@@ -155,10 +174,6 @@ function areMapsEqual(a, b, state) {
155
174
  }
156
175
  return true;
157
176
  }
158
- /**
159
- * Whether the numbers are equal in value.
160
- */
161
- const areNumbersEqual = sameValueEqual;
162
177
  /**
163
178
  * Whether the objects are equal in value.
164
179
  */
@@ -353,8 +368,8 @@ function createEqualityComparator(config) {
353
368
  // Try to fast-path equality checks for other complex object types in the
354
369
  // same realm to avoid capturing the string tag. Strict equality is used
355
370
  // instead of `instanceof` because it is more performant for the common
356
- // use-case. If someone is subclassing a native class, it will be handled
357
- // with the string tag comparison.
371
+ // use-case. If someone is creating a subclass from a native class, it will be
372
+ // handled with the string tag comparison.
358
373
  if (constructor === Object) {
359
374
  return areObjectsEqual(a, b, state);
360
375
  }
@@ -383,14 +398,14 @@ function createEqualityComparator(config) {
383
398
  if (Array.isArray(a)) {
384
399
  return areArraysEqual(a, b, state);
385
400
  }
386
- // Since this is a custom object, capture the string tag to determing its type.
401
+ // Since this is a custom object, capture the string tag to determining its type.
387
402
  // This is reasonably performant in modern environments like v8 and SpiderMonkey.
388
403
  const tag = toString.call(a);
389
404
  const supportedComparator = supportedComparatorMap[tag];
390
405
  if (supportedComparator) {
391
406
  return supportedComparator(a, b, state);
392
407
  }
393
- const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, tag);
408
+ const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, state, tag);
394
409
  if (unsupportedCustomComparator) {
395
410
  return unsupportedCustomComparator(a, b, state);
396
411
  }
@@ -398,9 +413,6 @@ function createEqualityComparator(config) {
398
413
  // the only thing remaining is strict equality, which has already been compared. This is for a few reasons:
399
414
  // - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only
400
415
  // comparison that can be made.
401
- // - For types that can be introspected, but rarely have requirements to be compared
402
- // (`ArrayBuffer`, `DataView`, etc.), the cost is avoided to prioritize the common
403
- // use-cases (may be included in a future release, if requested enough).
404
416
  // - For types that can be introspected but do not have an objective definition of what
405
417
  // equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.
406
418
  // In all cases, these decisions should be reevaluated based on changes to the language and
@@ -418,9 +430,9 @@ function createEqualityComparatorConfig({ circular, createCustomConfig, strict,
418
430
  areDataViewsEqual,
419
431
  areDatesEqual: areDatesEqual,
420
432
  areErrorsEqual: areErrorsEqual,
421
- areFunctionsEqual: areFunctionsEqual,
433
+ areFunctionsEqual: strictEqual,
422
434
  areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
423
- areNumbersEqual: areNumbersEqual,
435
+ areNumbersEqual: sameValueEqual,
424
436
  areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
425
437
  arePrimitiveWrappersEqual: arePrimitiveWrappersEqual,
426
438
  areRegExpsEqual: areRegExpsEqual,
@@ -500,6 +512,7 @@ function createSupportedComparatorMap({ areArrayBuffersEqual, areArraysEqual, ar
500
512
  '[object Arguments]': areObjectsEqual,
501
513
  '[object Array]': areArraysEqual,
502
514
  '[object ArrayBuffer]': areArrayBuffersEqual,
515
+ '[object AsyncGeneratorFunction]': areFunctionsEqual,
503
516
  '[object BigInt]': areNumbersEqual,
504
517
  '[object BigInt64Array]': areTypedArraysEqual,
505
518
  '[object BigUint64Array]': areTypedArraysEqual,
@@ -604,4 +617,4 @@ function createCustomEqual(options = {}) {
604
617
  return createIsEqual({ circular, comparator, createState, equals, strict });
605
618
  }
606
619
 
607
- export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
620
+ export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictEqual, strictShallowEqual };
package/index.d.ts CHANGED
@@ -27,92 +27,75 @@ interface State<Meta> {
27
27
  */
28
28
  readonly strict: boolean;
29
29
  }
30
- interface CircularState<Meta> extends State<Meta> {
31
- readonly cache: Cache<any, any>;
32
- }
33
- interface DefaultState<Meta> extends State<Meta> {
34
- readonly cache: undefined;
35
- }
36
- interface Dictionary<Value = any> {
37
- [key: string | symbol]: Value;
38
- $$typeof?: any;
39
- }
40
30
  interface ComparatorConfig<Meta> {
41
31
  /**
42
32
  * Whether the array buffers passed are equal in value. In strict mode, this includes
43
33
  * additional properties added to the array.
44
34
  */
45
- areArrayBuffersEqual: TypeEqualityComparator<any, Meta>;
35
+ areArrayBuffersEqual: EqualityComparator<Meta>;
46
36
  /**
47
37
  * Whether the arrays passed are equal in value. In strict mode, this includes
48
38
  * additional properties added to the array.
49
39
  */
50
- areArraysEqual: TypeEqualityComparator<any, Meta>;
40
+ areArraysEqual: EqualityComparator<Meta>;
51
41
  /**
52
42
  * Whether the data views passed are equal in value.
53
43
  */
54
- areDataViewsEqual: TypeEqualityComparator<any, Meta>;
44
+ areDataViewsEqual: EqualityComparator<Meta>;
55
45
  /**
56
46
  * Whether the dates passed are equal in value.
57
47
  */
58
- areDatesEqual: TypeEqualityComparator<any, Meta>;
48
+ areDatesEqual: EqualityComparator<Meta>;
59
49
  /**
60
50
  * Whether the errors passed are equal in value.
61
51
  */
62
- areErrorsEqual: TypeEqualityComparator<any, Meta>;
52
+ areErrorsEqual: EqualityComparator<Meta>;
63
53
  /**
64
54
  * Whether the functions passed are equal in value.
65
55
  */
66
- areFunctionsEqual: TypeEqualityComparator<any, Meta>;
56
+ areFunctionsEqual: EqualityComparator<Meta>;
67
57
  /**
68
58
  * Whether the maps passed are equal in value. In strict mode, this includes
69
59
  * additional properties added to the map.
70
60
  */
71
- areMapsEqual: TypeEqualityComparator<any, Meta>;
61
+ areMapsEqual: EqualityComparator<Meta>;
72
62
  /**
73
63
  * Whether the numbers passed are equal in value.
74
64
  */
75
- areNumbersEqual: TypeEqualityComparator<any, Meta>;
65
+ areNumbersEqual: EqualityComparator<Meta>;
76
66
  /**
77
67
  * Whether the objects passed are equal in value. In strict mode, this includes
78
68
  * non-enumerable properties added to the map, as well as symbol properties.
79
69
  */
80
- areObjectsEqual: TypeEqualityComparator<any, Meta>;
70
+ areObjectsEqual: EqualityComparator<Meta>;
81
71
  /**
82
72
  * Whether the primitive wrappers passed are equal in value.
83
73
  */
84
- arePrimitiveWrappersEqual: TypeEqualityComparator<any, Meta>;
74
+ arePrimitiveWrappersEqual: EqualityComparator<Meta>;
85
75
  /**
86
76
  * Whether the regexps passed are equal in value.
87
77
  */
88
- areRegExpsEqual: TypeEqualityComparator<any, Meta>;
78
+ areRegExpsEqual: EqualityComparator<Meta>;
89
79
  /**
90
80
  * Whether the sets passed are equal in value. In strict mode, this includes
91
81
  * additional properties added to the set.
92
82
  */
93
- areSetsEqual: TypeEqualityComparator<any, Meta>;
83
+ areSetsEqual: EqualityComparator<Meta>;
94
84
  /**
95
85
  * Whether the typed arrays passed are equal in value. In strict mode, this includes
96
86
  * additional properties added to the typed array.
97
87
  */
98
- areTypedArraysEqual: TypeEqualityComparator<any, Meta>;
88
+ areTypedArraysEqual: EqualityComparator<Meta>;
99
89
  /**
100
90
  * Whether the URLs passed are equal in value.
101
91
  */
102
- areUrlsEqual: TypeEqualityComparator<any, Meta>;
92
+ areUrlsEqual: EqualityComparator<Meta>;
103
93
  /**
104
94
  * Get a custom comparator based on the objects passed.
105
95
  */
106
- getUnsupportedCustomComparator: ((a: any, b: any, tag: string) => TypeEqualityComparator<any, Meta> | undefined) | undefined;
96
+ getUnsupportedCustomComparator: ((a: any, b: any, state: State<Meta>, tag: string) => EqualityComparator<Meta> | undefined) | undefined;
107
97
  }
108
- type CreateCustomComparatorConfig<Meta> = (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
109
- type CreateState<Meta> = () => {
110
- cache?: Cache<any, any> | undefined;
111
- meta?: Meta;
112
- };
113
- type EqualityComparator<Meta> = <A, B>(a: A, b: B, state: State<Meta>) => boolean;
114
- type AnyEqualityComparator<Meta> = (a: any, b: any, state: State<Meta>) => boolean;
115
- type EqualityComparatorCreator<Meta> = (fn: EqualityComparator<Meta>) => InternalEqualityComparator<Meta>;
98
+ type EqualityComparator<Meta> = (a: any, b: any, state: State<Meta>) => boolean;
116
99
  type InternalEqualityComparator<Meta> = (a: any, b: any, indexOrKeyA: any, indexOrKeyB: any, parentA: any, parentB: any, state: State<Meta>) => boolean;
117
100
  type PrimitiveWrapper = Boolean | Number | String;
118
101
  /**
@@ -120,7 +103,6 @@ type PrimitiveWrapper = Boolean | Number | String;
120
103
  * classes.
121
104
  */
122
105
  type TypedArray = BigInt64Array | BigUint64Array | Float32Array | Float64Array | Int8Array | Int16Array | Int32Array | Uint16Array | Uint32Array | Uint8Array | Uint8ClampedArray;
123
- type TypeEqualityComparator<Type, Meta = undefined> = (a: Type, b: Type, state: State<Meta>) => boolean;
124
106
  interface CustomEqualCreatorOptions<Meta> {
125
107
  /**
126
108
  * Whether circular references should be supported. It causes the
@@ -131,9 +113,9 @@ interface CustomEqualCreatorOptions<Meta> {
131
113
  /**
132
114
  * Create a custom configuration of type-specific equality comparators.
133
115
  * This receives the default configuration, which allows either replacement
134
- * or supersetting of the default methods.
116
+ * or a superset of the default methods.
135
117
  */
136
- createCustomConfig?: CreateCustomComparatorConfig<Meta>;
118
+ createCustomConfig?: (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
137
119
  /**
138
120
  * Create a custom internal comparator, which is used as an override to the
139
121
  * default entry point for nested value equality comparisons. This is often
@@ -146,7 +128,10 @@ interface CustomEqualCreatorOptions<Meta> {
146
128
  * Create a custom `state` object passed between the methods. This allows for
147
129
  * custom `cache` and/or `meta` values to be used.
148
130
  */
149
- createState?: CreateState<Meta>;
131
+ createState?: () => {
132
+ cache?: Cache<any, any> | undefined;
133
+ meta?: Meta;
134
+ };
150
135
  /**
151
136
  * Whether the equality comparison is strict, meaning it matches
152
137
  * all properties (including symbols and non-enumerable properties)
@@ -156,9 +141,30 @@ interface CustomEqualCreatorOptions<Meta> {
156
141
  }
157
142
 
158
143
  /**
159
- * Whether the values passed are strictly equal or both NaN.
144
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
145
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
146
+ *
147
+ * @note
148
+ * When available in the environment, this is just a re-export of the global
149
+ * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
160
150
  */
161
151
  declare const sameValueEqual: (value1: any, value2: any) => boolean;
152
+ /**
153
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
154
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
155
+ * are either positive or negative zero.
156
+ */
157
+ declare function sameValueZeroEqual(a: any, b: any): boolean;
158
+ /**
159
+ * Whether the values passed are equal based on a
160
+ * [Strict Equality Comparison](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) basis.
161
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`).
162
+ *
163
+ * @note
164
+ * This is mainly available as a convenience function, such as being a default when a function to determine equality between
165
+ * two objects is used.
166
+ */
167
+ declare function strictEqual(a: any, b: any): boolean;
162
168
 
163
169
  /**
164
170
  * Whether the items passed are deeply-equal in value.
@@ -204,5 +210,5 @@ declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
204
210
  */
205
211
  declare function createCustomEqual<Meta = undefined>(options?: CustomEqualCreatorOptions<Meta>): <A, B>(a: A, b: B) => boolean;
206
212
 
207
- export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
208
- export type { AnyEqualityComparator, Cache, CircularState, ComparatorConfig, CreateCustomComparatorConfig, CreateState, CustomEqualCreatorOptions, DefaultState, Dictionary, EqualityComparator, EqualityComparatorCreator, InternalEqualityComparator, PrimitiveWrapper, State, TypeEqualityComparator, TypedArray };
213
+ export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictEqual, strictShallowEqual };
214
+ export type { Cache, ComparatorConfig, CustomEqualCreatorOptions, EqualityComparator, InternalEqualityComparator, PrimitiveWrapper, State, TypedArray };
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "bugs": {
8
8
  "url": "https://github.com/planttheidea/fast-equals/issues"
9
9
  },
10
- "description": "A blazing fast equality comparison, either shallow or deep",
10
+ "description": "A blazing-fast equality comparison utility for a variety of use-cases",
11
11
  "devDependencies": {
12
12
  "@planttheidea/build-tools": "^2.0.0",
13
13
  "@types/lodash": "^4.17.21",
@@ -17,7 +17,7 @@
17
17
  "@types/react-dom": "^19.2.3",
18
18
  "@typescript-eslint/eslint-plugin": "^8.50.0",
19
19
  "@typescript-eslint/parser": "^8.50.0",
20
- "@vitest/coverage-v8": "^4.0.15",
20
+ "@vitest/coverage-v8": "^4.0.16",
21
21
  "cli-table3": "^0.6.5",
22
22
  "decircularize": "^1.0.0",
23
23
  "deep-eql": "^5.0.2",
@@ -42,7 +42,7 @@
42
42
  "typescript-eslint": "^8.50.0",
43
43
  "underscore": "^1.13.7",
44
44
  "vite": "^7.3.0",
45
- "vitest": "^4.0.15"
45
+ "vitest": "^4.0.16"
46
46
  },
47
47
  "engines": {
48
48
  "node": ">=6.0.0"
@@ -109,5 +109,5 @@
109
109
  "sideEffects": false,
110
110
  "type": "module",
111
111
  "types": "./index.d.ts",
112
- "version": "6.0.0-rc.0"
112
+ "version": "6.0.0"
113
113
  }