fast-equals 6.0.0-beta.1 → 6.0.0-rc.1
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 +87 -54
- package/dist/cjs/index.cjs +101 -124
- package/dist/cjs/index.d.cts +15 -7
- package/dist/es/index.d.mts +15 -7
- package/dist/es/index.mjs +101 -125
- package/index.d.ts +15 -7
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ customize any specific type comparison based on your application's use-cases.
|
|
|
34
34
|
- [deepEqual](#deepequal)
|
|
35
35
|
- [Comparing `Map`s](#comparing-maps)
|
|
36
36
|
- [shallowEqual](#shallowequal)
|
|
37
|
-
- [
|
|
37
|
+
- [sameValueEqual](#samevalueequal)
|
|
38
38
|
- [circularDeepEqual](#circulardeepequal)
|
|
39
39
|
- [circularShallowEqual](#circularshallowequal)
|
|
40
40
|
- [strictDeepEqual](#strictdeepequal)
|
|
@@ -42,7 +42,7 @@ customize any specific type comparison based on your application's use-cases.
|
|
|
42
42
|
- [strictCircularDeepEqual](#strictcirculardeepequal)
|
|
43
43
|
- [strictCircularShallowEqual](#strictcircularshallowequal)
|
|
44
44
|
- [createCustomEqual](#createcustomequal)
|
|
45
|
-
- [
|
|
45
|
+
- [getUnsupportedCustomComparator](#getunsupportedcustomcomparator)
|
|
46
46
|
- [Recipes](#recipes)
|
|
47
47
|
- [Benchmarks](#benchmarks)
|
|
48
48
|
- [Development](#development)
|
|
@@ -120,14 +120,44 @@ console.log(shallowEqual(objectA, objectB)); // true
|
|
|
120
120
|
console.log(shallowEqual(objectA, objectC)); // false
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
+
### sameValueEqual
|
|
124
|
+
|
|
125
|
+
Performs a [`SameValue`](http://ecma-international.org/ecma-262/7.0/#sec-samevalue) comparison on the two objects passed
|
|
126
|
+
and returns a boolean representing the value equivalency of the objects. In simple terms, this means:
|
|
127
|
+
|
|
128
|
+
- `+0` and `-0` are not equal
|
|
129
|
+
- `NaN` is equal to `NaN`
|
|
130
|
+
- All other items are based on referential equality (`a === b`)
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { sameValueEqual } from 'fast-equals';
|
|
134
|
+
|
|
135
|
+
const mainObject = { foo: NaN, bar: 'baz' };
|
|
136
|
+
|
|
137
|
+
const objectA = 'baz';
|
|
138
|
+
const objectB = NaN;
|
|
139
|
+
const objectC = { foo: NaN, bar: 'baz' };
|
|
140
|
+
|
|
141
|
+
console.log(sameValueEqual(mainObject.bar, objectA)); // true
|
|
142
|
+
console.log(sameValueEqual(mainObject.foo, objectB)); // true
|
|
143
|
+
console.log(sameValueEqual(mainObject, objectC)); // false
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**NOTE**: In environments that support
|
|
147
|
+
[`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is),
|
|
148
|
+
`sameValueEqual` is just a re-export of that method.
|
|
149
|
+
|
|
123
150
|
### sameValueZeroEqual
|
|
124
151
|
|
|
125
152
|
Performs a [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) comparison on the two
|
|
126
|
-
objects passed and returns a boolean representing the value equivalency of the objects. In simple terms, this means
|
|
127
|
-
|
|
153
|
+
objects passed and returns a boolean representing the value equivalency of the objects. In simple terms, this means:
|
|
154
|
+
|
|
155
|
+
- `+0` and `-0` are equal
|
|
156
|
+
- `NaN` is equal to `NaN`
|
|
157
|
+
- All other items are based on referential equality (`a === b`)
|
|
128
158
|
|
|
129
159
|
```ts
|
|
130
|
-
import {
|
|
160
|
+
import { sameValueEqual } from 'fast-equals';
|
|
131
161
|
|
|
132
162
|
const mainObject = { foo: NaN, bar: 'baz' };
|
|
133
163
|
|
|
@@ -135,9 +165,9 @@ const objectA = 'baz';
|
|
|
135
165
|
const objectB = NaN;
|
|
136
166
|
const objectC = { foo: NaN, bar: 'baz' };
|
|
137
167
|
|
|
138
|
-
console.log(
|
|
139
|
-
console.log(
|
|
140
|
-
console.log(
|
|
168
|
+
console.log(sameValueEqual(mainObject.bar, objectA)); // true
|
|
169
|
+
console.log(sameValueEqual(mainObject.foo, objectB)); // true
|
|
170
|
+
console.log(sameValueEqual(mainObject, objectC)); // false
|
|
141
171
|
```
|
|
142
172
|
|
|
143
173
|
### circularDeepEqual
|
|
@@ -298,18 +328,21 @@ interface Cache<Key extends object, Value> {
|
|
|
298
328
|
}
|
|
299
329
|
|
|
300
330
|
interface ComparatorConfig<Meta> {
|
|
301
|
-
|
|
331
|
+
areArrayBuffersEcqual: TypeEqualityComparator<ArrayBuffer, Meta>;
|
|
332
|
+
areArraysEcqual: TypeEqualityComparator<any[], Meta>;
|
|
333
|
+
areDataViewsEqual: TypeEqualityComparator<DataView, Meta>;
|
|
302
334
|
areDatesEqual: TypeEqualityComparator<Date, Meta>;
|
|
303
335
|
areErrorsEqual: TypeEqualityComparator<Error, Meta>;
|
|
304
336
|
areFunctionsEqual: TypeEqualityComparator<(...args: any[]) => any, Meta>;
|
|
305
337
|
areMapsEqual: TypeEqualityComparator<Map<any, any>, Meta>;
|
|
338
|
+
areNumbersEqual: TypeEqualityComparator<number, Meta>;
|
|
306
339
|
areObjectsEqual: TypeEqualityComparator<Record<string, any>, Meta>;
|
|
307
|
-
arePrimitiveWrappersEqual: TypeEqualityComparator<
|
|
340
|
+
arePrimitiveWrappersEqual: TypeEqualityComparator<Boolean | Number | String, Meta>;
|
|
308
341
|
areRegExpsEqual: TypeEqualityComparator<RegExp, Meta>;
|
|
309
342
|
areSetsEqual: TypeEqualityComparator<Set<any>, Meta>;
|
|
310
343
|
areTypedArraysEqual: TypeEqualityComparator<TypedArray, Meta>;
|
|
311
344
|
areUrlsEqual: TypeEqualityComparator<URL, Meta>;
|
|
312
|
-
|
|
345
|
+
getUnsupportedCustomComparator: <Type>(a: Type, b: Type, tag: string) => TypeEqualityComparator<Type, Meta>;
|
|
313
346
|
}
|
|
314
347
|
|
|
315
348
|
function createCustomEqual<Meta>(options: {
|
|
@@ -332,10 +365,11 @@ _**NOTE**: `Map` implementations compare equality for both keys and value. When
|
|
|
332
365
|
equality of the keys, the iteration index is provided as both `indexOrKeyA` and `indexOrKeyB` to help use-cases where
|
|
333
366
|
ordering of keys matters to equality._
|
|
334
367
|
|
|
335
|
-
####
|
|
368
|
+
#### getUnsupportedCustomComparator
|
|
336
369
|
|
|
337
370
|
If you want to compare objects that have a custom `@@toStringTag`, you can provide a map of the custom tags you want to
|
|
338
|
-
support via the `
|
|
371
|
+
support via the `getUnsupportedCustomComparator` option. See [this recipe]('./recipes/special-objects.md) for an
|
|
372
|
+
example.
|
|
339
373
|
|
|
340
374
|
#### Recipes
|
|
341
375
|
|
|
@@ -348,12 +382,12 @@ to the problem you are solving, they can offer guidance of how to structure your
|
|
|
348
382
|
- [Comparing non-standard properties](./recipes/non-standard-properties.md)
|
|
349
383
|
- [Strict property descriptor comparison](./recipes/strict-property-descriptor-check.md)
|
|
350
384
|
- [Legacy environment support for circualr equal comparators](./recipes/legacy-circular-equal-support.md)
|
|
351
|
-
- [Custom
|
|
385
|
+
- [Custom comparator support](./recipes/special-objects.md)
|
|
352
386
|
|
|
353
387
|
## Benchmarks
|
|
354
388
|
|
|
355
389
|
All benchmarks were performed on an i9-11900H Ubuntu Linux 24.04 laptop with 64GB of memory using NodeJS version
|
|
356
|
-
`
|
|
390
|
+
`24.11.1`, and are based on averages of running comparisons based deep equality on the following object types:
|
|
357
391
|
|
|
358
392
|
- Primitives (`String`, `Number`, `null`, `undefined`)
|
|
359
393
|
- `Function`
|
|
@@ -365,74 +399,73 @@ All benchmarks were performed on an i9-11900H Ubuntu Linux 24.04 laptop with 64G
|
|
|
365
399
|
- A mixed object with a combination of all the above types
|
|
366
400
|
|
|
367
401
|
```bash
|
|
368
|
-
Testing mixed objects equal...
|
|
369
402
|
┌────────────────────────────────────────┬────────────────┐
|
|
370
403
|
│ Name │ Ops / sec │
|
|
371
404
|
├────────────────────────────────────────┼────────────────┤
|
|
372
|
-
│ fast-equals (passed) │
|
|
405
|
+
│ fast-equals (passed) │ 1544237.29413 │
|
|
373
406
|
├────────────────────────────────────────┼────────────────┤
|
|
374
|
-
│ fast-deep-equal (passed) │
|
|
407
|
+
│ fast-deep-equal (passed) │ 1328583.767745 │
|
|
375
408
|
├────────────────────────────────────────┼────────────────┤
|
|
376
|
-
│ react-fast-compare (passed) │
|
|
409
|
+
│ react-fast-compare (passed) │ 1301727.296375 │
|
|
377
410
|
├────────────────────────────────────────┼────────────────┤
|
|
378
|
-
│ shallow-equal-fuzzy (passed) │
|
|
411
|
+
│ shallow-equal-fuzzy (passed) │ 1225981.400919 │
|
|
379
412
|
├────────────────────────────────────────┼────────────────┤
|
|
380
|
-
│ nano-equal (failed) │
|
|
413
|
+
│ nano-equal (failed) │ 969495.538753 │
|
|
381
414
|
├────────────────────────────────────────┼────────────────┤
|
|
382
|
-
│
|
|
415
|
+
│ fast-equals (circular) (passed) │ 813716.49516 │
|
|
383
416
|
├────────────────────────────────────────┼────────────────┤
|
|
384
|
-
│ dequal (passed)
|
|
417
|
+
│ dequal/lite (passed) │ 780805.627339 │
|
|
385
418
|
├────────────────────────────────────────┼────────────────┤
|
|
386
|
-
│
|
|
419
|
+
│ dequal (passed) │ 767208.995048 │
|
|
387
420
|
├────────────────────────────────────────┼────────────────┤
|
|
388
|
-
│ underscore.isEqual (passed) │
|
|
421
|
+
│ underscore.isEqual (passed) │ 490695.830468 │
|
|
389
422
|
├────────────────────────────────────────┼────────────────┤
|
|
390
|
-
│ assert.deepStrictEqual (passed) │
|
|
423
|
+
│ assert.deepStrictEqual (passed) │ 471011.425391 │
|
|
391
424
|
├────────────────────────────────────────┼────────────────┤
|
|
392
|
-
│ lodash.isEqual (passed) │
|
|
425
|
+
│ lodash.isEqual (passed) │ 296064.057382 │
|
|
393
426
|
├────────────────────────────────────────┼────────────────┤
|
|
394
|
-
│ fast-equals (strict) (passed) │
|
|
427
|
+
│ fast-equals (strict) (passed) │ 225894.800964 │
|
|
395
428
|
├────────────────────────────────────────┼────────────────┤
|
|
396
|
-
│ fast-equals (strict circular) (passed) │
|
|
429
|
+
│ fast-equals (strict circular) (passed) │ 195657.732354 │
|
|
397
430
|
├────────────────────────────────────────┼────────────────┤
|
|
398
|
-
│ deep-eql (passed) │
|
|
431
|
+
│ deep-eql (passed) │ 162718.102328 │
|
|
399
432
|
├────────────────────────────────────────┼────────────────┤
|
|
400
|
-
│ deep-equal (passed) │
|
|
433
|
+
│ deep-equal (passed) │ 954.172311 │
|
|
401
434
|
└────────────────────────────────────────┴────────────────┘
|
|
402
435
|
|
|
403
436
|
Testing mixed objects not equal...
|
|
404
437
|
┌────────────────────────────────────────┬────────────────┐
|
|
405
438
|
│ Name │ Ops / sec │
|
|
406
439
|
├────────────────────────────────────────┼────────────────┤
|
|
407
|
-
│ fast-equals (passed) │
|
|
440
|
+
│ fast-equals (passed) │ 5112341.000979 │
|
|
408
441
|
├────────────────────────────────────────┼────────────────┤
|
|
409
|
-
│ fast-
|
|
442
|
+
│ fast-equals (circular) (passed) │ 3501225.300307 │
|
|
410
443
|
├────────────────────────────────────────┼────────────────┤
|
|
411
|
-
│
|
|
444
|
+
│ fast-deep-equal (passed) │ 3471838.735181 │
|
|
412
445
|
├────────────────────────────────────────┼────────────────┤
|
|
413
|
-
│ fast-
|
|
446
|
+
│ react-fast-compare (passed) │ 3439612.908273 │
|
|
414
447
|
├────────────────────────────────────────┼────────────────┤
|
|
415
|
-
│ fast-equals (strict) (passed) │
|
|
448
|
+
│ fast-equals (strict) (passed) │ 1797319.423491 │
|
|
416
449
|
├────────────────────────────────────────┼────────────────┤
|
|
417
|
-
│ fast-equals (strict circular) (passed) │
|
|
450
|
+
│ fast-equals (strict circular) (passed) │ 1534168.229167 │
|
|
418
451
|
├────────────────────────────────────────┼────────────────┤
|
|
419
|
-
│ dequal/lite (passed) │
|
|
452
|
+
│ dequal/lite (passed) │ 1357981.758571 │
|
|
420
453
|
├────────────────────────────────────────┼────────────────┤
|
|
421
|
-
│ dequal (passed) │
|
|
454
|
+
│ dequal (passed) │ 1328078.173967 │
|
|
422
455
|
├────────────────────────────────────────┼────────────────┤
|
|
423
|
-
│ shallow-equal-fuzzy (failed) │
|
|
456
|
+
│ shallow-equal-fuzzy (failed) │ 1224747.272118 │
|
|
424
457
|
├────────────────────────────────────────┼────────────────┤
|
|
425
|
-
│ nano-equal (passed) │
|
|
458
|
+
│ nano-equal (passed) │ 1087373.99615 │
|
|
426
459
|
├────────────────────────────────────────┼────────────────┤
|
|
427
|
-
│ underscore.isEqual (passed) │
|
|
460
|
+
│ underscore.isEqual (passed) │ 927298.592729 │
|
|
428
461
|
├────────────────────────────────────────┼────────────────┤
|
|
429
|
-
│ lodash.isEqual (passed) │
|
|
462
|
+
│ lodash.isEqual (passed) │ 387294.235476 │
|
|
430
463
|
├────────────────────────────────────────┼────────────────┤
|
|
431
|
-
│ deep-eql (passed) │
|
|
464
|
+
│ deep-eql (passed) │ 186028.168827 │
|
|
432
465
|
├────────────────────────────────────────┼────────────────┤
|
|
433
|
-
│ assert.deepStrictEqual (passed) │
|
|
466
|
+
│ assert.deepStrictEqual (passed) │ 21261.312424 │
|
|
434
467
|
├────────────────────────────────────────┼────────────────┤
|
|
435
|
-
│ deep-equal (passed) │
|
|
468
|
+
│ deep-equal (passed) │ 3782.329948 │
|
|
436
469
|
└────────────────────────────────────────┴────────────────┘
|
|
437
470
|
```
|
|
438
471
|
|
|
@@ -442,17 +475,17 @@ Caveats that impact the benchmark (and accuracy of comparison):
|
|
|
442
475
|
fully supported their comparison
|
|
443
476
|
- `fast-deep-equal`, `react-fast-compare` and `nano-equal` throw on objects with `null` as prototype
|
|
444
477
|
(`Object.create(null)`)
|
|
445
|
-
- `assert.deepStrictEqual` does not support `NaN` or `
|
|
446
|
-
- `deep-eql` does not support `
|
|
478
|
+
- `assert.deepStrictEqual` does not support `NaN` or `SameValue` equality for dates
|
|
479
|
+
- `deep-eql` does not support `SameValue` equality for zero equality (positive and negative zero are not equal)
|
|
447
480
|
- `deep-equal` does not support `NaN` and does not strictly compare object type, or date / regexp values, nor uses
|
|
448
|
-
`
|
|
449
|
-
- `fast-deep-equal` does not support `NaN` or `
|
|
450
|
-
- `nano-equal` does not strictly compare object property structure, array length, or object type, nor `
|
|
481
|
+
`SameValue` equality for dates
|
|
482
|
+
- `fast-deep-equal` does not support `NaN` or `SameValue` equality for dates
|
|
483
|
+
- `nano-equal` does not strictly compare object property structure, array length, or object type, nor `SameValue`
|
|
451
484
|
equality for dates
|
|
452
|
-
- `react-fast-compare` does not support `NaN` or `
|
|
485
|
+
- `react-fast-compare` does not support `NaN` or `SameValue` equality for dates, and does not compare `function`
|
|
453
486
|
equality
|
|
454
|
-
- `shallow-equal-fuzzy` does not strictly compare object type or regexp values, nor `
|
|
455
|
-
- `underscore.isEqual` does not support `
|
|
487
|
+
- `shallow-equal-fuzzy` does not strictly compare object type or regexp values, nor `SameValue` equality for dates
|
|
488
|
+
- `underscore.isEqual` does not support `SameValue` equality for primitives or dates
|
|
456
489
|
|
|
457
490
|
All of these have the potential of inflating the respective library's numbers in comparison to `fast-equals`, but it was
|
|
458
491
|
the closest apples-to-apples comparison I could create of a reasonable sample size. It should be noted that `react`
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -35,12 +35,6 @@ function createIsCircular(areItemsEqual) {
|
|
|
35
35
|
return result;
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Get the `@@toStringTag` of the value, if it exists.
|
|
40
|
-
*/
|
|
41
|
-
function getShortTag(value) {
|
|
42
|
-
return value != null ? value[Symbol.toStringTag] : undefined;
|
|
43
|
-
}
|
|
44
38
|
/**
|
|
45
39
|
* Get the properties to strictly examine, which include both own properties that are
|
|
46
40
|
* not enumerable and symbol properties.
|
|
@@ -54,17 +48,33 @@ function getStrictProperties(object) {
|
|
|
54
48
|
const hasOwn =
|
|
55
49
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
56
50
|
Object.hasOwn || ((object, property) => hasOwnProperty.call(object, property));
|
|
57
|
-
/**
|
|
58
|
-
* Whether the values passed are strictly equal or both NaN.
|
|
59
|
-
*/
|
|
60
|
-
function sameValueZeroEqual(a, b) {
|
|
61
|
-
return a === b || (!a && !b && a !== a && b !== b);
|
|
62
|
-
}
|
|
63
51
|
|
|
64
52
|
const PREACT_VNODE = '__v';
|
|
65
53
|
const PREACT_OWNER = '__o';
|
|
66
54
|
const REACT_OWNER = '_owner';
|
|
67
55
|
const { getOwnPropertyDescriptor, keys } = Object;
|
|
56
|
+
/**
|
|
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.
|
|
63
|
+
*/
|
|
64
|
+
const sameValueEqual =
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
66
|
+
Object.is
|
|
67
|
+
|| function sameValueEqual(a, b) {
|
|
68
|
+
return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;
|
|
69
|
+
};
|
|
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
|
+
}
|
|
68
78
|
/**
|
|
69
79
|
* Whether the array buffers are equal in value.
|
|
70
80
|
*/
|
|
@@ -97,7 +107,7 @@ function areDataViewsEqual(a, b) {
|
|
|
97
107
|
* Whether the dates passed are equal in value.
|
|
98
108
|
*/
|
|
99
109
|
function areDatesEqual(a, b) {
|
|
100
|
-
return
|
|
110
|
+
return sameValueEqual(a.getTime(), b.getTime());
|
|
101
111
|
}
|
|
102
112
|
/**
|
|
103
113
|
* Whether the errors passed are equal in value.
|
|
@@ -163,7 +173,7 @@ function areMapsEqual(a, b, state) {
|
|
|
163
173
|
/**
|
|
164
174
|
* Whether the numbers are equal in value.
|
|
165
175
|
*/
|
|
166
|
-
const areNumbersEqual =
|
|
176
|
+
const areNumbersEqual = sameValueEqual;
|
|
167
177
|
/**
|
|
168
178
|
* Whether the objects are equal in value.
|
|
169
179
|
*/
|
|
@@ -222,7 +232,7 @@ function areObjectsEqualStrict(a, b, state) {
|
|
|
222
232
|
* Whether the primitive wrappers passed are equal in value.
|
|
223
233
|
*/
|
|
224
234
|
function arePrimitiveWrappersEqual(a, b) {
|
|
225
|
-
return
|
|
235
|
+
return sameValueEqual(a.valueOf(), b.valueOf());
|
|
226
236
|
}
|
|
227
237
|
/**
|
|
228
238
|
* Whether the regexps passed are equal in value.
|
|
@@ -306,39 +316,14 @@ function isPropertyEqual(a, b, state, property) {
|
|
|
306
316
|
return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);
|
|
307
317
|
}
|
|
308
318
|
|
|
309
|
-
const ARRAY_BUFFER_TAG = '[object ArrayBuffer]';
|
|
310
|
-
const ARGUMENTS_TAG = '[object Arguments]';
|
|
311
|
-
const BOOLEAN_TAG = '[object Boolean]';
|
|
312
|
-
const DATA_VIEW_TAG = '[object DataView]';
|
|
313
|
-
const DATE_TAG = '[object Date]';
|
|
314
|
-
const ERROR_TAG = '[object Error]';
|
|
315
|
-
const MAP_TAG = '[object Map]';
|
|
316
|
-
const NUMBER_TAG = '[object Number]';
|
|
317
|
-
const OBJECT_TAG = '[object Object]';
|
|
318
|
-
const REG_EXP_TAG = '[object RegExp]';
|
|
319
|
-
const SET_TAG = '[object Set]';
|
|
320
|
-
const STRING_TAG = '[object String]';
|
|
321
|
-
const TYPED_ARRAY_TAGS = {
|
|
322
|
-
'[object Int8Array]': true,
|
|
323
|
-
'[object Uint8Array]': true,
|
|
324
|
-
'[object Uint8ClampedArray]': true,
|
|
325
|
-
'[object Int16Array]': true,
|
|
326
|
-
'[object Uint16Array]': true,
|
|
327
|
-
'[object Int32Array]': true,
|
|
328
|
-
'[object Uint32Array]': true,
|
|
329
|
-
'[object Float16Array]': true,
|
|
330
|
-
'[object Float32Array]': true,
|
|
331
|
-
'[object Float64Array]': true,
|
|
332
|
-
'[object BigInt64Array]': true,
|
|
333
|
-
'[object BigUint64Array]': true,
|
|
334
|
-
};
|
|
335
|
-
const URL_TAG = '[object URL]';
|
|
336
319
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
337
320
|
const toString = Object.prototype.toString;
|
|
338
321
|
/**
|
|
339
322
|
* Create a comparator method based on the type-specific equality comparators passed.
|
|
340
323
|
*/
|
|
341
|
-
function createEqualityComparator(
|
|
324
|
+
function createEqualityComparator(config) {
|
|
325
|
+
const supportedComparatorMap = createSupportedComparatorMap(config);
|
|
326
|
+
const { areArraysEqual, areDatesEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, areRegExpsEqual, areSetsEqual, getUnsupportedCustomComparator, } = config;
|
|
342
327
|
/**
|
|
343
328
|
* compare the value of the two objects and return true if they are equivalent in values
|
|
344
329
|
*/
|
|
@@ -357,7 +342,7 @@ function createEqualityComparator({ areArrayBuffersEqual, areArraysEqual, areDat
|
|
|
357
342
|
return false;
|
|
358
343
|
}
|
|
359
344
|
if (type !== 'object') {
|
|
360
|
-
if (type === 'number') {
|
|
345
|
+
if (type === 'number' || type === 'bigint') {
|
|
361
346
|
return areNumbersEqual(a, b, state);
|
|
362
347
|
}
|
|
363
348
|
if (type === 'function') {
|
|
@@ -380,22 +365,17 @@ function createEqualityComparator({ areArrayBuffersEqual, areArraysEqual, areDat
|
|
|
380
365
|
if (constructor !== b.constructor) {
|
|
381
366
|
return false;
|
|
382
367
|
}
|
|
383
|
-
// `isPlainObject` only checks against the object's own realm. Cross-realm
|
|
384
|
-
// comparisons are rare, and will be handled in the ultimate fallback, so
|
|
385
|
-
// we can avoid capturing the string tag.
|
|
386
|
-
if (constructor === Object) {
|
|
387
|
-
return areObjectsEqual(a, b, state);
|
|
388
|
-
}
|
|
389
|
-
// `isArray()` works on subclasses and is cross-realm, so we can avoid capturing
|
|
390
|
-
// the string tag or doing an `instanceof` check.
|
|
391
|
-
if (Array.isArray(a)) {
|
|
392
|
-
return areArraysEqual(a, b, state);
|
|
393
|
-
}
|
|
394
368
|
// Try to fast-path equality checks for other complex object types in the
|
|
395
369
|
// same realm to avoid capturing the string tag. Strict equality is used
|
|
396
370
|
// instead of `instanceof` because it is more performant for the common
|
|
397
371
|
// use-case. If someone is subclassing a native class, it will be handled
|
|
398
372
|
// with the string tag comparison.
|
|
373
|
+
if (constructor === Object) {
|
|
374
|
+
return areObjectsEqual(a, b, state);
|
|
375
|
+
}
|
|
376
|
+
if (constructor === Array) {
|
|
377
|
+
return areArraysEqual(a, b, state);
|
|
378
|
+
}
|
|
399
379
|
if (constructor === Date) {
|
|
400
380
|
return areDatesEqual(a, b, state);
|
|
401
381
|
}
|
|
@@ -408,79 +388,31 @@ function createEqualityComparator({ areArrayBuffersEqual, areArraysEqual, areDat
|
|
|
408
388
|
if (constructor === Set) {
|
|
409
389
|
return areSetsEqual(a, b, state);
|
|
410
390
|
}
|
|
391
|
+
if (constructor === Promise) {
|
|
392
|
+
// Avoid tag checks for promise values, since we know if they are not referentially equal
|
|
393
|
+
// then they are not equal.
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
// `isArray()` works on subclasses and is cross-realm, so we can avoid capturing
|
|
397
|
+
// the string tag or doing an `instanceof` in edge cases.
|
|
398
|
+
if (Array.isArray(a)) {
|
|
399
|
+
return areArraysEqual(a, b, state);
|
|
400
|
+
}
|
|
411
401
|
// Since this is a custom object, capture the string tag to determing its type.
|
|
412
402
|
// This is reasonably performant in modern environments like v8 and SpiderMonkey.
|
|
413
403
|
const tag = toString.call(a);
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
// For RegExp, the properties are not enumerable, and therefore will give false positives if
|
|
418
|
-
// tested like a standard object.
|
|
419
|
-
if (tag === REG_EXP_TAG) {
|
|
420
|
-
return areRegExpsEqual(a, b, state);
|
|
421
|
-
}
|
|
422
|
-
if (tag === MAP_TAG) {
|
|
423
|
-
return areMapsEqual(a, b, state);
|
|
424
|
-
}
|
|
425
|
-
if (tag === SET_TAG) {
|
|
426
|
-
return areSetsEqual(a, b, state);
|
|
427
|
-
}
|
|
428
|
-
if (tag === OBJECT_TAG) {
|
|
429
|
-
// The exception for value comparison is custom `Promise`-like class instances. These should
|
|
430
|
-
// be treated the same as standard `Promise` objects, which means strict equality, and if
|
|
431
|
-
// it reaches this point then that strict equality comparison has already failed.
|
|
432
|
-
return typeof a.then !== 'function' && typeof b.then !== 'function' && areObjectsEqual(a, b, state);
|
|
433
|
-
}
|
|
434
|
-
// If a URL tag, it should be tested explicitly. Like RegExp, the properties are not
|
|
435
|
-
// enumerable, and therefore will give false positives if tested like a standard object.
|
|
436
|
-
if (tag === URL_TAG) {
|
|
437
|
-
return areUrlsEqual(a, b, state);
|
|
438
|
-
}
|
|
439
|
-
// If an error tag, it should be tested explicitly. Like RegExp, the properties are not
|
|
440
|
-
// enumerable, and therefore will give false positives if tested like a standard object.
|
|
441
|
-
if (tag === ERROR_TAG) {
|
|
442
|
-
return areErrorsEqual(a, b, state);
|
|
443
|
-
}
|
|
444
|
-
// If an arguments tag, it should be treated as a standard object.
|
|
445
|
-
if (tag === ARGUMENTS_TAG) {
|
|
446
|
-
return areObjectsEqual(a, b, state);
|
|
447
|
-
}
|
|
448
|
-
if (TYPED_ARRAY_TAGS[tag]) {
|
|
449
|
-
return areTypedArraysEqual(a, b, state);
|
|
404
|
+
const supportedComparator = supportedComparatorMap[tag];
|
|
405
|
+
if (supportedComparator) {
|
|
406
|
+
return supportedComparator(a, b, state);
|
|
450
407
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
if (tag === DATA_VIEW_TAG) {
|
|
455
|
-
return areDataViewsEqual(a, b, state);
|
|
456
|
-
}
|
|
457
|
-
// As the penultimate fallback, check if the values passed are primitive wrappers. This
|
|
458
|
-
// is very rare in modern JS, which is why it is deprioritized compared to all other object
|
|
459
|
-
// types.
|
|
460
|
-
if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {
|
|
461
|
-
return arePrimitiveWrappersEqual(a, b, state);
|
|
462
|
-
}
|
|
463
|
-
if (unknownTagComparators) {
|
|
464
|
-
let unknownTagComparator = unknownTagComparators[tag];
|
|
465
|
-
if (!unknownTagComparator) {
|
|
466
|
-
const shortTag = getShortTag(a);
|
|
467
|
-
if (shortTag) {
|
|
468
|
-
unknownTagComparator = unknownTagComparators[shortTag];
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
// If the custom config has an unknown tag comparator that matches the captured tag or the
|
|
472
|
-
// @@toStringTag, it is the source of truth for whether the values are equal.
|
|
473
|
-
if (unknownTagComparator) {
|
|
474
|
-
return unknownTagComparator(a, b, state);
|
|
475
|
-
}
|
|
408
|
+
const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, tag);
|
|
409
|
+
if (unsupportedCustomComparator) {
|
|
410
|
+
return unsupportedCustomComparator(a, b, state);
|
|
476
411
|
}
|
|
477
412
|
// If not matching any tags that require a specific type of comparison, then we hard-code false because
|
|
478
413
|
// the only thing remaining is strict equality, which has already been compared. This is for a few reasons:
|
|
479
414
|
// - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only
|
|
480
415
|
// comparison that can be made.
|
|
481
|
-
// - For types that can be introspected, but rarely have requirements to be compared
|
|
482
|
-
// (`ArrayBuffer`, `DataView`, etc.), the cost is avoided to prioritize the common
|
|
483
|
-
// use-cases (may be included in a future release, if requested enough).
|
|
484
416
|
// - For types that can be introspected but do not have an objective definition of what
|
|
485
417
|
// equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.
|
|
486
418
|
// In all cases, these decisions should be reevaluated based on changes to the language and
|
|
@@ -509,7 +441,7 @@ function createEqualityComparatorConfig({ circular, createCustomConfig, strict,
|
|
|
509
441
|
? combineComparators(areTypedArraysEqual, areObjectsEqualStrict)
|
|
510
442
|
: areTypedArraysEqual,
|
|
511
443
|
areUrlsEqual: areUrlsEqual,
|
|
512
|
-
|
|
444
|
+
getUnsupportedCustomComparator: undefined,
|
|
513
445
|
};
|
|
514
446
|
if (createCustomConfig) {
|
|
515
447
|
config = Object.assign({}, config, createCustomConfig(config));
|
|
@@ -572,6 +504,50 @@ function createIsEqual({ circular, comparator, createState, equals, strict }) {
|
|
|
572
504
|
return comparator(a, b, state);
|
|
573
505
|
};
|
|
574
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Create a map of `toString()` values to their respective handlers for `tag`-based lookups.
|
|
509
|
+
*/
|
|
510
|
+
function createSupportedComparatorMap({ areArrayBuffersEqual, areArraysEqual, areDataViewsEqual, areDatesEqual, areErrorsEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, arePrimitiveWrappersEqual, areRegExpsEqual, areSetsEqual, areTypedArraysEqual, areUrlsEqual, }) {
|
|
511
|
+
return {
|
|
512
|
+
'[object Arguments]': areObjectsEqual,
|
|
513
|
+
'[object Array]': areArraysEqual,
|
|
514
|
+
'[object ArrayBuffer]': areArrayBuffersEqual,
|
|
515
|
+
'[object BigInt]': areNumbersEqual,
|
|
516
|
+
'[object BigInt64Array]': areTypedArraysEqual,
|
|
517
|
+
'[object BigUint64Array]': areTypedArraysEqual,
|
|
518
|
+
'[object Boolean]': arePrimitiveWrappersEqual,
|
|
519
|
+
'[object DataView]': areDataViewsEqual,
|
|
520
|
+
'[object Date]': areDatesEqual,
|
|
521
|
+
// If an error tag, it should be tested explicitly. Like RegExp, the properties are not
|
|
522
|
+
// enumerable, and therefore will give false positives if tested like a standard object.
|
|
523
|
+
'[object Error]': areErrorsEqual,
|
|
524
|
+
'[object Float16Array]': areTypedArraysEqual,
|
|
525
|
+
'[object Float32Array]': areTypedArraysEqual,
|
|
526
|
+
'[object Float64Array]': areTypedArraysEqual,
|
|
527
|
+
'[object Function]': areFunctionsEqual,
|
|
528
|
+
'[object GeneratorFunction]': areFunctionsEqual,
|
|
529
|
+
'[object Int8Array]': areTypedArraysEqual,
|
|
530
|
+
'[object Int16Array]': areTypedArraysEqual,
|
|
531
|
+
'[object Int32Array]': areTypedArraysEqual,
|
|
532
|
+
'[object Map]': areMapsEqual,
|
|
533
|
+
'[object Number]': arePrimitiveWrappersEqual,
|
|
534
|
+
'[object Object]': (a, b, state) =>
|
|
535
|
+
// The exception for value comparison is custom `Promise`-like class instances. These should
|
|
536
|
+
// be treated the same as standard `Promise` objects, which means strict equality, and if
|
|
537
|
+
// it reaches this point then that strict equality comparison has already failed.
|
|
538
|
+
typeof a.then !== 'function' && typeof b.then !== 'function' && areObjectsEqual(a, b, state),
|
|
539
|
+
// For RegExp, the properties are not enumerable, and therefore will give false positives if
|
|
540
|
+
// tested like a standard object.
|
|
541
|
+
'[object RegExp]': areRegExpsEqual,
|
|
542
|
+
'[object Set]': areSetsEqual,
|
|
543
|
+
'[object String]': arePrimitiveWrappersEqual,
|
|
544
|
+
'[object URL]': areUrlsEqual,
|
|
545
|
+
'[object Uint8Array]': areTypedArraysEqual,
|
|
546
|
+
'[object Uint8ClampedArray]': areTypedArraysEqual,
|
|
547
|
+
'[object Uint16Array]': areTypedArraysEqual,
|
|
548
|
+
'[object Uint32Array]': areTypedArraysEqual,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
575
551
|
|
|
576
552
|
/**
|
|
577
553
|
* Whether the items passed are deeply-equal in value.
|
|
@@ -597,21 +573,21 @@ const strictCircularDeepEqual = createCustomEqual({
|
|
|
597
573
|
* Whether the items passed are shallowly-equal in value.
|
|
598
574
|
*/
|
|
599
575
|
const shallowEqual = createCustomEqual({
|
|
600
|
-
createInternalComparator: () =>
|
|
576
|
+
createInternalComparator: () => sameValueEqual,
|
|
601
577
|
});
|
|
602
578
|
/**
|
|
603
579
|
* Whether the items passed are shallowly-equal in value based on strict comparison
|
|
604
580
|
*/
|
|
605
581
|
const strictShallowEqual = createCustomEqual({
|
|
606
582
|
strict: true,
|
|
607
|
-
createInternalComparator: () =>
|
|
583
|
+
createInternalComparator: () => sameValueEqual,
|
|
608
584
|
});
|
|
609
585
|
/**
|
|
610
586
|
* Whether the items passed are shallowly-equal in value, including circular references.
|
|
611
587
|
*/
|
|
612
588
|
const circularShallowEqual = createCustomEqual({
|
|
613
589
|
circular: true,
|
|
614
|
-
createInternalComparator: () =>
|
|
590
|
+
createInternalComparator: () => sameValueEqual,
|
|
615
591
|
});
|
|
616
592
|
/**
|
|
617
593
|
* Whether the items passed are shallowly-equal in value, including circular references,
|
|
@@ -619,7 +595,7 @@ const circularShallowEqual = createCustomEqual({
|
|
|
619
595
|
*/
|
|
620
596
|
const strictCircularShallowEqual = createCustomEqual({
|
|
621
597
|
circular: true,
|
|
622
|
-
createInternalComparator: () =>
|
|
598
|
+
createInternalComparator: () => sameValueEqual,
|
|
623
599
|
strict: true,
|
|
624
600
|
});
|
|
625
601
|
/**
|
|
@@ -644,6 +620,7 @@ exports.circularDeepEqual = circularDeepEqual;
|
|
|
644
620
|
exports.circularShallowEqual = circularShallowEqual;
|
|
645
621
|
exports.createCustomEqual = createCustomEqual;
|
|
646
622
|
exports.deepEqual = deepEqual;
|
|
623
|
+
exports.sameValueEqual = sameValueEqual;
|
|
647
624
|
exports.sameValueZeroEqual = sameValueZeroEqual;
|
|
648
625
|
exports.shallowEqual = shallowEqual;
|
|
649
626
|
exports.strictCircularDeepEqual = strictCircularDeepEqual;
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -101,12 +101,9 @@ interface ComparatorConfig<Meta> {
|
|
|
101
101
|
*/
|
|
102
102
|
areUrlsEqual: TypeEqualityComparator<any, Meta>;
|
|
103
103
|
/**
|
|
104
|
-
*
|
|
105
|
-
* called when no other comparator applies.
|
|
106
|
-
*
|
|
107
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag
|
|
104
|
+
* Get a custom comparator based on the objects passed.
|
|
108
105
|
*/
|
|
109
|
-
|
|
106
|
+
getUnsupportedCustomComparator: ((a: any, b: any, tag: string) => TypeEqualityComparator<any, Meta> | undefined) | undefined;
|
|
110
107
|
}
|
|
111
108
|
type CreateCustomComparatorConfig<Meta> = (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
|
|
112
109
|
type CreateState<Meta> = () => {
|
|
@@ -159,7 +156,18 @@ interface CustomEqualCreatorOptions<Meta> {
|
|
|
159
156
|
}
|
|
160
157
|
|
|
161
158
|
/**
|
|
162
|
-
* Whether the values passed are
|
|
159
|
+
* Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
|
|
160
|
+
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
|
|
161
|
+
*
|
|
162
|
+
* @note
|
|
163
|
+
* When available in the environment, this is just a re-export of the global
|
|
164
|
+
* [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
|
|
165
|
+
*/
|
|
166
|
+
declare const sameValueEqual: (value1: any, value2: any) => boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
|
|
169
|
+
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
|
|
170
|
+
* are either positive or negative zero.
|
|
163
171
|
*/
|
|
164
172
|
declare function sameValueZeroEqual(a: any, b: any): boolean;
|
|
165
173
|
|
|
@@ -207,5 +215,5 @@ declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
|
|
|
207
215
|
*/
|
|
208
216
|
declare function createCustomEqual<Meta = undefined>(options?: CustomEqualCreatorOptions<Meta>): <A, B>(a: A, b: B) => boolean;
|
|
209
217
|
|
|
210
|
-
export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
|
|
218
|
+
export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
|
|
211
219
|
export type { AnyEqualityComparator, Cache, CircularState, ComparatorConfig, CreateCustomComparatorConfig, CreateState, CustomEqualCreatorOptions, DefaultState, Dictionary, EqualityComparator, EqualityComparatorCreator, InternalEqualityComparator, PrimitiveWrapper, State, TypeEqualityComparator, TypedArray };
|
package/dist/es/index.d.mts
CHANGED
|
@@ -101,12 +101,9 @@ interface ComparatorConfig<Meta> {
|
|
|
101
101
|
*/
|
|
102
102
|
areUrlsEqual: TypeEqualityComparator<any, Meta>;
|
|
103
103
|
/**
|
|
104
|
-
*
|
|
105
|
-
* called when no other comparator applies.
|
|
106
|
-
*
|
|
107
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag
|
|
104
|
+
* Get a custom comparator based on the objects passed.
|
|
108
105
|
*/
|
|
109
|
-
|
|
106
|
+
getUnsupportedCustomComparator: ((a: any, b: any, tag: string) => TypeEqualityComparator<any, Meta> | undefined) | undefined;
|
|
110
107
|
}
|
|
111
108
|
type CreateCustomComparatorConfig<Meta> = (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
|
|
112
109
|
type CreateState<Meta> = () => {
|
|
@@ -159,7 +156,18 @@ interface CustomEqualCreatorOptions<Meta> {
|
|
|
159
156
|
}
|
|
160
157
|
|
|
161
158
|
/**
|
|
162
|
-
* Whether the values passed are
|
|
159
|
+
* Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
|
|
160
|
+
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
|
|
161
|
+
*
|
|
162
|
+
* @note
|
|
163
|
+
* When available in the environment, this is just a re-export of the global
|
|
164
|
+
* [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
|
|
165
|
+
*/
|
|
166
|
+
declare const sameValueEqual: (value1: any, value2: any) => boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
|
|
169
|
+
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
|
|
170
|
+
* are either positive or negative zero.
|
|
163
171
|
*/
|
|
164
172
|
declare function sameValueZeroEqual(a: any, b: any): boolean;
|
|
165
173
|
|
|
@@ -207,5 +215,5 @@ declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
|
|
|
207
215
|
*/
|
|
208
216
|
declare function createCustomEqual<Meta = undefined>(options?: CustomEqualCreatorOptions<Meta>): <A, B>(a: A, b: B) => boolean;
|
|
209
217
|
|
|
210
|
-
export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
|
|
218
|
+
export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
|
|
211
219
|
export type { AnyEqualityComparator, Cache, CircularState, ComparatorConfig, CreateCustomComparatorConfig, CreateState, CustomEqualCreatorOptions, DefaultState, Dictionary, EqualityComparator, EqualityComparatorCreator, InternalEqualityComparator, PrimitiveWrapper, State, TypeEqualityComparator, TypedArray };
|
package/dist/es/index.mjs
CHANGED
|
@@ -33,12 +33,6 @@ function createIsCircular(areItemsEqual) {
|
|
|
33
33
|
return result;
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Get the `@@toStringTag` of the value, if it exists.
|
|
38
|
-
*/
|
|
39
|
-
function getShortTag(value) {
|
|
40
|
-
return value != null ? value[Symbol.toStringTag] : undefined;
|
|
41
|
-
}
|
|
42
36
|
/**
|
|
43
37
|
* Get the properties to strictly examine, which include both own properties that are
|
|
44
38
|
* not enumerable and symbol properties.
|
|
@@ -52,17 +46,33 @@ function getStrictProperties(object) {
|
|
|
52
46
|
const hasOwn =
|
|
53
47
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
54
48
|
Object.hasOwn || ((object, property) => hasOwnProperty.call(object, property));
|
|
55
|
-
/**
|
|
56
|
-
* Whether the values passed are strictly equal or both NaN.
|
|
57
|
-
*/
|
|
58
|
-
function sameValueZeroEqual(a, b) {
|
|
59
|
-
return a === b || (!a && !b && a !== a && b !== b);
|
|
60
|
-
}
|
|
61
49
|
|
|
62
50
|
const PREACT_VNODE = '__v';
|
|
63
51
|
const PREACT_OWNER = '__o';
|
|
64
52
|
const REACT_OWNER = '_owner';
|
|
65
53
|
const { getOwnPropertyDescriptor, keys } = Object;
|
|
54
|
+
/**
|
|
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.
|
|
61
|
+
*/
|
|
62
|
+
const sameValueEqual =
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
64
|
+
Object.is
|
|
65
|
+
|| function sameValueEqual(a, b) {
|
|
66
|
+
return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;
|
|
67
|
+
};
|
|
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
|
+
}
|
|
66
76
|
/**
|
|
67
77
|
* Whether the array buffers are equal in value.
|
|
68
78
|
*/
|
|
@@ -95,7 +105,7 @@ function areDataViewsEqual(a, b) {
|
|
|
95
105
|
* Whether the dates passed are equal in value.
|
|
96
106
|
*/
|
|
97
107
|
function areDatesEqual(a, b) {
|
|
98
|
-
return
|
|
108
|
+
return sameValueEqual(a.getTime(), b.getTime());
|
|
99
109
|
}
|
|
100
110
|
/**
|
|
101
111
|
* Whether the errors passed are equal in value.
|
|
@@ -161,7 +171,7 @@ function areMapsEqual(a, b, state) {
|
|
|
161
171
|
/**
|
|
162
172
|
* Whether the numbers are equal in value.
|
|
163
173
|
*/
|
|
164
|
-
const areNumbersEqual =
|
|
174
|
+
const areNumbersEqual = sameValueEqual;
|
|
165
175
|
/**
|
|
166
176
|
* Whether the objects are equal in value.
|
|
167
177
|
*/
|
|
@@ -220,7 +230,7 @@ function areObjectsEqualStrict(a, b, state) {
|
|
|
220
230
|
* Whether the primitive wrappers passed are equal in value.
|
|
221
231
|
*/
|
|
222
232
|
function arePrimitiveWrappersEqual(a, b) {
|
|
223
|
-
return
|
|
233
|
+
return sameValueEqual(a.valueOf(), b.valueOf());
|
|
224
234
|
}
|
|
225
235
|
/**
|
|
226
236
|
* Whether the regexps passed are equal in value.
|
|
@@ -304,39 +314,14 @@ function isPropertyEqual(a, b, state, property) {
|
|
|
304
314
|
return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);
|
|
305
315
|
}
|
|
306
316
|
|
|
307
|
-
const ARRAY_BUFFER_TAG = '[object ArrayBuffer]';
|
|
308
|
-
const ARGUMENTS_TAG = '[object Arguments]';
|
|
309
|
-
const BOOLEAN_TAG = '[object Boolean]';
|
|
310
|
-
const DATA_VIEW_TAG = '[object DataView]';
|
|
311
|
-
const DATE_TAG = '[object Date]';
|
|
312
|
-
const ERROR_TAG = '[object Error]';
|
|
313
|
-
const MAP_TAG = '[object Map]';
|
|
314
|
-
const NUMBER_TAG = '[object Number]';
|
|
315
|
-
const OBJECT_TAG = '[object Object]';
|
|
316
|
-
const REG_EXP_TAG = '[object RegExp]';
|
|
317
|
-
const SET_TAG = '[object Set]';
|
|
318
|
-
const STRING_TAG = '[object String]';
|
|
319
|
-
const TYPED_ARRAY_TAGS = {
|
|
320
|
-
'[object Int8Array]': true,
|
|
321
|
-
'[object Uint8Array]': true,
|
|
322
|
-
'[object Uint8ClampedArray]': true,
|
|
323
|
-
'[object Int16Array]': true,
|
|
324
|
-
'[object Uint16Array]': true,
|
|
325
|
-
'[object Int32Array]': true,
|
|
326
|
-
'[object Uint32Array]': true,
|
|
327
|
-
'[object Float16Array]': true,
|
|
328
|
-
'[object Float32Array]': true,
|
|
329
|
-
'[object Float64Array]': true,
|
|
330
|
-
'[object BigInt64Array]': true,
|
|
331
|
-
'[object BigUint64Array]': true,
|
|
332
|
-
};
|
|
333
|
-
const URL_TAG = '[object URL]';
|
|
334
317
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
335
318
|
const toString = Object.prototype.toString;
|
|
336
319
|
/**
|
|
337
320
|
* Create a comparator method based on the type-specific equality comparators passed.
|
|
338
321
|
*/
|
|
339
|
-
function createEqualityComparator(
|
|
322
|
+
function createEqualityComparator(config) {
|
|
323
|
+
const supportedComparatorMap = createSupportedComparatorMap(config);
|
|
324
|
+
const { areArraysEqual, areDatesEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, areRegExpsEqual, areSetsEqual, getUnsupportedCustomComparator, } = config;
|
|
340
325
|
/**
|
|
341
326
|
* compare the value of the two objects and return true if they are equivalent in values
|
|
342
327
|
*/
|
|
@@ -355,7 +340,7 @@ function createEqualityComparator({ areArrayBuffersEqual, areArraysEqual, areDat
|
|
|
355
340
|
return false;
|
|
356
341
|
}
|
|
357
342
|
if (type !== 'object') {
|
|
358
|
-
if (type === 'number') {
|
|
343
|
+
if (type === 'number' || type === 'bigint') {
|
|
359
344
|
return areNumbersEqual(a, b, state);
|
|
360
345
|
}
|
|
361
346
|
if (type === 'function') {
|
|
@@ -378,22 +363,17 @@ function createEqualityComparator({ areArrayBuffersEqual, areArraysEqual, areDat
|
|
|
378
363
|
if (constructor !== b.constructor) {
|
|
379
364
|
return false;
|
|
380
365
|
}
|
|
381
|
-
// `isPlainObject` only checks against the object's own realm. Cross-realm
|
|
382
|
-
// comparisons are rare, and will be handled in the ultimate fallback, so
|
|
383
|
-
// we can avoid capturing the string tag.
|
|
384
|
-
if (constructor === Object) {
|
|
385
|
-
return areObjectsEqual(a, b, state);
|
|
386
|
-
}
|
|
387
|
-
// `isArray()` works on subclasses and is cross-realm, so we can avoid capturing
|
|
388
|
-
// the string tag or doing an `instanceof` check.
|
|
389
|
-
if (Array.isArray(a)) {
|
|
390
|
-
return areArraysEqual(a, b, state);
|
|
391
|
-
}
|
|
392
366
|
// Try to fast-path equality checks for other complex object types in the
|
|
393
367
|
// same realm to avoid capturing the string tag. Strict equality is used
|
|
394
368
|
// instead of `instanceof` because it is more performant for the common
|
|
395
369
|
// use-case. If someone is subclassing a native class, it will be handled
|
|
396
370
|
// with the string tag comparison.
|
|
371
|
+
if (constructor === Object) {
|
|
372
|
+
return areObjectsEqual(a, b, state);
|
|
373
|
+
}
|
|
374
|
+
if (constructor === Array) {
|
|
375
|
+
return areArraysEqual(a, b, state);
|
|
376
|
+
}
|
|
397
377
|
if (constructor === Date) {
|
|
398
378
|
return areDatesEqual(a, b, state);
|
|
399
379
|
}
|
|
@@ -406,79 +386,31 @@ function createEqualityComparator({ areArrayBuffersEqual, areArraysEqual, areDat
|
|
|
406
386
|
if (constructor === Set) {
|
|
407
387
|
return areSetsEqual(a, b, state);
|
|
408
388
|
}
|
|
389
|
+
if (constructor === Promise) {
|
|
390
|
+
// Avoid tag checks for promise values, since we know if they are not referentially equal
|
|
391
|
+
// then they are not equal.
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
// `isArray()` works on subclasses and is cross-realm, so we can avoid capturing
|
|
395
|
+
// the string tag or doing an `instanceof` in edge cases.
|
|
396
|
+
if (Array.isArray(a)) {
|
|
397
|
+
return areArraysEqual(a, b, state);
|
|
398
|
+
}
|
|
409
399
|
// Since this is a custom object, capture the string tag to determing its type.
|
|
410
400
|
// This is reasonably performant in modern environments like v8 and SpiderMonkey.
|
|
411
401
|
const tag = toString.call(a);
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
// For RegExp, the properties are not enumerable, and therefore will give false positives if
|
|
416
|
-
// tested like a standard object.
|
|
417
|
-
if (tag === REG_EXP_TAG) {
|
|
418
|
-
return areRegExpsEqual(a, b, state);
|
|
419
|
-
}
|
|
420
|
-
if (tag === MAP_TAG) {
|
|
421
|
-
return areMapsEqual(a, b, state);
|
|
422
|
-
}
|
|
423
|
-
if (tag === SET_TAG) {
|
|
424
|
-
return areSetsEqual(a, b, state);
|
|
425
|
-
}
|
|
426
|
-
if (tag === OBJECT_TAG) {
|
|
427
|
-
// The exception for value comparison is custom `Promise`-like class instances. These should
|
|
428
|
-
// be treated the same as standard `Promise` objects, which means strict equality, and if
|
|
429
|
-
// it reaches this point then that strict equality comparison has already failed.
|
|
430
|
-
return typeof a.then !== 'function' && typeof b.then !== 'function' && areObjectsEqual(a, b, state);
|
|
431
|
-
}
|
|
432
|
-
// If a URL tag, it should be tested explicitly. Like RegExp, the properties are not
|
|
433
|
-
// enumerable, and therefore will give false positives if tested like a standard object.
|
|
434
|
-
if (tag === URL_TAG) {
|
|
435
|
-
return areUrlsEqual(a, b, state);
|
|
436
|
-
}
|
|
437
|
-
// If an error tag, it should be tested explicitly. Like RegExp, the properties are not
|
|
438
|
-
// enumerable, and therefore will give false positives if tested like a standard object.
|
|
439
|
-
if (tag === ERROR_TAG) {
|
|
440
|
-
return areErrorsEqual(a, b, state);
|
|
441
|
-
}
|
|
442
|
-
// If an arguments tag, it should be treated as a standard object.
|
|
443
|
-
if (tag === ARGUMENTS_TAG) {
|
|
444
|
-
return areObjectsEqual(a, b, state);
|
|
445
|
-
}
|
|
446
|
-
if (TYPED_ARRAY_TAGS[tag]) {
|
|
447
|
-
return areTypedArraysEqual(a, b, state);
|
|
402
|
+
const supportedComparator = supportedComparatorMap[tag];
|
|
403
|
+
if (supportedComparator) {
|
|
404
|
+
return supportedComparator(a, b, state);
|
|
448
405
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
if (tag === DATA_VIEW_TAG) {
|
|
453
|
-
return areDataViewsEqual(a, b, state);
|
|
454
|
-
}
|
|
455
|
-
// As the penultimate fallback, check if the values passed are primitive wrappers. This
|
|
456
|
-
// is very rare in modern JS, which is why it is deprioritized compared to all other object
|
|
457
|
-
// types.
|
|
458
|
-
if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {
|
|
459
|
-
return arePrimitiveWrappersEqual(a, b, state);
|
|
460
|
-
}
|
|
461
|
-
if (unknownTagComparators) {
|
|
462
|
-
let unknownTagComparator = unknownTagComparators[tag];
|
|
463
|
-
if (!unknownTagComparator) {
|
|
464
|
-
const shortTag = getShortTag(a);
|
|
465
|
-
if (shortTag) {
|
|
466
|
-
unknownTagComparator = unknownTagComparators[shortTag];
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
// If the custom config has an unknown tag comparator that matches the captured tag or the
|
|
470
|
-
// @@toStringTag, it is the source of truth for whether the values are equal.
|
|
471
|
-
if (unknownTagComparator) {
|
|
472
|
-
return unknownTagComparator(a, b, state);
|
|
473
|
-
}
|
|
406
|
+
const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, tag);
|
|
407
|
+
if (unsupportedCustomComparator) {
|
|
408
|
+
return unsupportedCustomComparator(a, b, state);
|
|
474
409
|
}
|
|
475
410
|
// If not matching any tags that require a specific type of comparison, then we hard-code false because
|
|
476
411
|
// the only thing remaining is strict equality, which has already been compared. This is for a few reasons:
|
|
477
412
|
// - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only
|
|
478
413
|
// comparison that can be made.
|
|
479
|
-
// - For types that can be introspected, but rarely have requirements to be compared
|
|
480
|
-
// (`ArrayBuffer`, `DataView`, etc.), the cost is avoided to prioritize the common
|
|
481
|
-
// use-cases (may be included in a future release, if requested enough).
|
|
482
414
|
// - For types that can be introspected but do not have an objective definition of what
|
|
483
415
|
// equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.
|
|
484
416
|
// In all cases, these decisions should be reevaluated based on changes to the language and
|
|
@@ -507,7 +439,7 @@ function createEqualityComparatorConfig({ circular, createCustomConfig, strict,
|
|
|
507
439
|
? combineComparators(areTypedArraysEqual, areObjectsEqualStrict)
|
|
508
440
|
: areTypedArraysEqual,
|
|
509
441
|
areUrlsEqual: areUrlsEqual,
|
|
510
|
-
|
|
442
|
+
getUnsupportedCustomComparator: undefined,
|
|
511
443
|
};
|
|
512
444
|
if (createCustomConfig) {
|
|
513
445
|
config = Object.assign({}, config, createCustomConfig(config));
|
|
@@ -570,6 +502,50 @@ function createIsEqual({ circular, comparator, createState, equals, strict }) {
|
|
|
570
502
|
return comparator(a, b, state);
|
|
571
503
|
};
|
|
572
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Create a map of `toString()` values to their respective handlers for `tag`-based lookups.
|
|
507
|
+
*/
|
|
508
|
+
function createSupportedComparatorMap({ areArrayBuffersEqual, areArraysEqual, areDataViewsEqual, areDatesEqual, areErrorsEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, arePrimitiveWrappersEqual, areRegExpsEqual, areSetsEqual, areTypedArraysEqual, areUrlsEqual, }) {
|
|
509
|
+
return {
|
|
510
|
+
'[object Arguments]': areObjectsEqual,
|
|
511
|
+
'[object Array]': areArraysEqual,
|
|
512
|
+
'[object ArrayBuffer]': areArrayBuffersEqual,
|
|
513
|
+
'[object BigInt]': areNumbersEqual,
|
|
514
|
+
'[object BigInt64Array]': areTypedArraysEqual,
|
|
515
|
+
'[object BigUint64Array]': areTypedArraysEqual,
|
|
516
|
+
'[object Boolean]': arePrimitiveWrappersEqual,
|
|
517
|
+
'[object DataView]': areDataViewsEqual,
|
|
518
|
+
'[object Date]': areDatesEqual,
|
|
519
|
+
// If an error tag, it should be tested explicitly. Like RegExp, the properties are not
|
|
520
|
+
// enumerable, and therefore will give false positives if tested like a standard object.
|
|
521
|
+
'[object Error]': areErrorsEqual,
|
|
522
|
+
'[object Float16Array]': areTypedArraysEqual,
|
|
523
|
+
'[object Float32Array]': areTypedArraysEqual,
|
|
524
|
+
'[object Float64Array]': areTypedArraysEqual,
|
|
525
|
+
'[object Function]': areFunctionsEqual,
|
|
526
|
+
'[object GeneratorFunction]': areFunctionsEqual,
|
|
527
|
+
'[object Int8Array]': areTypedArraysEqual,
|
|
528
|
+
'[object Int16Array]': areTypedArraysEqual,
|
|
529
|
+
'[object Int32Array]': areTypedArraysEqual,
|
|
530
|
+
'[object Map]': areMapsEqual,
|
|
531
|
+
'[object Number]': arePrimitiveWrappersEqual,
|
|
532
|
+
'[object Object]': (a, b, state) =>
|
|
533
|
+
// The exception for value comparison is custom `Promise`-like class instances. These should
|
|
534
|
+
// be treated the same as standard `Promise` objects, which means strict equality, and if
|
|
535
|
+
// it reaches this point then that strict equality comparison has already failed.
|
|
536
|
+
typeof a.then !== 'function' && typeof b.then !== 'function' && areObjectsEqual(a, b, state),
|
|
537
|
+
// For RegExp, the properties are not enumerable, and therefore will give false positives if
|
|
538
|
+
// tested like a standard object.
|
|
539
|
+
'[object RegExp]': areRegExpsEqual,
|
|
540
|
+
'[object Set]': areSetsEqual,
|
|
541
|
+
'[object String]': arePrimitiveWrappersEqual,
|
|
542
|
+
'[object URL]': areUrlsEqual,
|
|
543
|
+
'[object Uint8Array]': areTypedArraysEqual,
|
|
544
|
+
'[object Uint8ClampedArray]': areTypedArraysEqual,
|
|
545
|
+
'[object Uint16Array]': areTypedArraysEqual,
|
|
546
|
+
'[object Uint32Array]': areTypedArraysEqual,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
573
549
|
|
|
574
550
|
/**
|
|
575
551
|
* Whether the items passed are deeply-equal in value.
|
|
@@ -595,21 +571,21 @@ const strictCircularDeepEqual = createCustomEqual({
|
|
|
595
571
|
* Whether the items passed are shallowly-equal in value.
|
|
596
572
|
*/
|
|
597
573
|
const shallowEqual = createCustomEqual({
|
|
598
|
-
createInternalComparator: () =>
|
|
574
|
+
createInternalComparator: () => sameValueEqual,
|
|
599
575
|
});
|
|
600
576
|
/**
|
|
601
577
|
* Whether the items passed are shallowly-equal in value based on strict comparison
|
|
602
578
|
*/
|
|
603
579
|
const strictShallowEqual = createCustomEqual({
|
|
604
580
|
strict: true,
|
|
605
|
-
createInternalComparator: () =>
|
|
581
|
+
createInternalComparator: () => sameValueEqual,
|
|
606
582
|
});
|
|
607
583
|
/**
|
|
608
584
|
* Whether the items passed are shallowly-equal in value, including circular references.
|
|
609
585
|
*/
|
|
610
586
|
const circularShallowEqual = createCustomEqual({
|
|
611
587
|
circular: true,
|
|
612
|
-
createInternalComparator: () =>
|
|
588
|
+
createInternalComparator: () => sameValueEqual,
|
|
613
589
|
});
|
|
614
590
|
/**
|
|
615
591
|
* Whether the items passed are shallowly-equal in value, including circular references,
|
|
@@ -617,7 +593,7 @@ const circularShallowEqual = createCustomEqual({
|
|
|
617
593
|
*/
|
|
618
594
|
const strictCircularShallowEqual = createCustomEqual({
|
|
619
595
|
circular: true,
|
|
620
|
-
createInternalComparator: () =>
|
|
596
|
+
createInternalComparator: () => sameValueEqual,
|
|
621
597
|
strict: true,
|
|
622
598
|
});
|
|
623
599
|
/**
|
|
@@ -638,4 +614,4 @@ function createCustomEqual(options = {}) {
|
|
|
638
614
|
return createIsEqual({ circular, comparator, createState, equals, strict });
|
|
639
615
|
}
|
|
640
616
|
|
|
641
|
-
export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
|
|
617
|
+
export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
|
package/index.d.ts
CHANGED
|
@@ -101,12 +101,9 @@ interface ComparatorConfig<Meta> {
|
|
|
101
101
|
*/
|
|
102
102
|
areUrlsEqual: TypeEqualityComparator<any, Meta>;
|
|
103
103
|
/**
|
|
104
|
-
*
|
|
105
|
-
* called when no other comparator applies.
|
|
106
|
-
*
|
|
107
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag
|
|
104
|
+
* Get a custom comparator based on the objects passed.
|
|
108
105
|
*/
|
|
109
|
-
|
|
106
|
+
getUnsupportedCustomComparator: ((a: any, b: any, tag: string) => TypeEqualityComparator<any, Meta> | undefined) | undefined;
|
|
110
107
|
}
|
|
111
108
|
type CreateCustomComparatorConfig<Meta> = (config: ComparatorConfig<Meta>) => Partial<ComparatorConfig<Meta>>;
|
|
112
109
|
type CreateState<Meta> = () => {
|
|
@@ -159,7 +156,18 @@ interface CustomEqualCreatorOptions<Meta> {
|
|
|
159
156
|
}
|
|
160
157
|
|
|
161
158
|
/**
|
|
162
|
-
* Whether the values passed are
|
|
159
|
+
* Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
|
|
160
|
+
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
|
|
161
|
+
*
|
|
162
|
+
* @note
|
|
163
|
+
* When available in the environment, this is just a re-export of the global
|
|
164
|
+
* [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
|
|
165
|
+
*/
|
|
166
|
+
declare const sameValueEqual: (value1: any, value2: any) => boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.
|
|
169
|
+
* Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both
|
|
170
|
+
* are either positive or negative zero.
|
|
163
171
|
*/
|
|
164
172
|
declare function sameValueZeroEqual(a: any, b: any): boolean;
|
|
165
173
|
|
|
@@ -207,5 +215,5 @@ declare const strictCircularShallowEqual: <A, B>(a: A, b: B) => boolean;
|
|
|
207
215
|
*/
|
|
208
216
|
declare function createCustomEqual<Meta = undefined>(options?: CustomEqualCreatorOptions<Meta>): <A, B>(a: A, b: B) => boolean;
|
|
209
217
|
|
|
210
|
-
export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
|
|
218
|
+
export { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictShallowEqual };
|
|
211
219
|
export type { AnyEqualityComparator, Cache, CircularState, ComparatorConfig, CreateCustomComparatorConfig, CreateState, CustomEqualCreatorOptions, DefaultState, Dictionary, EqualityComparator, EqualityComparatorCreator, InternalEqualityComparator, PrimitiveWrapper, State, TypeEqualityComparator, TypedArray };
|
package/package.json
CHANGED
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
},
|
|
10
10
|
"description": "A blazing fast equality comparison, either shallow or deep",
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@planttheidea/build-tools": "^2.0.0
|
|
12
|
+
"@planttheidea/build-tools": "^2.0.0",
|
|
13
13
|
"@types/lodash": "^4.17.21",
|
|
14
|
-
"@types/node": "^24.10.
|
|
14
|
+
"@types/node": "^24.10.4",
|
|
15
15
|
"@types/ramda": "^0.31.1",
|
|
16
16
|
"@types/react": "^19.2.7",
|
|
17
17
|
"@types/react-dom": "^19.2.3",
|
|
18
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
19
|
-
"@typescript-eslint/parser": "^8.
|
|
18
|
+
"@typescript-eslint/eslint-plugin": "^8.50.0",
|
|
19
|
+
"@typescript-eslint/parser": "^8.50.0",
|
|
20
20
|
"@vitest/coverage-v8": "^4.0.15",
|
|
21
21
|
"cli-table3": "^0.6.5",
|
|
22
22
|
"decircularize": "^1.0.0",
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
"react-dom": "^19.2.3",
|
|
36
36
|
"react-fast-compare": "^3.2.2",
|
|
37
37
|
"release-it": "^19.1.0",
|
|
38
|
-
"rollup": "^4.53.
|
|
38
|
+
"rollup": "^4.53.5",
|
|
39
39
|
"shallow-equal-fuzzy": "^0.0.2",
|
|
40
40
|
"tinybench": "^6.0.0",
|
|
41
41
|
"typescript": "^5.9.3",
|
|
42
|
-
"typescript-eslint": "^8.
|
|
42
|
+
"typescript-eslint": "^8.50.0",
|
|
43
43
|
"underscore": "^1.13.7",
|
|
44
|
-
"vite": "^7.
|
|
44
|
+
"vite": "^7.3.0",
|
|
45
45
|
"vitest": "^4.0.15"
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
"sideEffects": false,
|
|
110
110
|
"type": "module",
|
|
111
111
|
"types": "./index.d.ts",
|
|
112
|
-
"version": "6.0.0-
|
|
112
|
+
"version": "6.0.0-rc.1"
|
|
113
113
|
}
|