fast-equals 2.0.1 → 3.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/CHANGELOG.md +49 -3
- package/README.md +58 -37
- package/dist/fast-equals.cjs.js +106 -213
- package/dist/fast-equals.cjs.js.map +1 -1
- package/dist/fast-equals.esm.js +106 -213
- package/dist/fast-equals.esm.js.map +1 -1
- package/dist/fast-equals.js +108 -215
- package/dist/fast-equals.js.map +1 -1
- package/dist/fast-equals.min.js +1 -1
- package/dist/fast-equals.mjs +106 -213
- package/dist/fast-equals.mjs.map +1 -1
- package/index.d.ts +10 -1
- package/package.json +40 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,54 @@
|
|
|
1
1
|
# fast-equals CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
When creating a custom equality comparator via `createCustomEqual`, the equality method has an expanded contract:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// Before
|
|
11
|
+
type EqualityComparator = (objectA: any, objectB: any, meta: any) => boolean;
|
|
12
|
+
|
|
13
|
+
// After
|
|
14
|
+
type InternalEqualityComparator = (
|
|
15
|
+
objectA: any,
|
|
16
|
+
objectB: any,
|
|
17
|
+
indexOrKeyA: any,
|
|
18
|
+
indexOrKeyB: any,
|
|
19
|
+
parentA: any,
|
|
20
|
+
parentB: any,
|
|
21
|
+
meta: any,
|
|
22
|
+
) => boolean;
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you have a custom equality comparator, you can ignore the differences by just passing additional `undefined` parameters, or you can use the parameters to further improve / clarify the logic.
|
|
26
|
+
|
|
27
|
+
- Add [#57](https://github.com/planttheidea/fast-equals/pull/57) - support additional metadata for custom equality comparators
|
|
28
|
+
|
|
29
|
+
## 2.0.4
|
|
30
|
+
|
|
31
|
+
- Fix [#58](https://github.com/planttheidea/fast-equals/issues/58) - duplicate entries in `Map` / `Set` can create false equality success
|
|
32
|
+
- [#60](https://github.com/planttheidea/fast-equals/issues/60) - Add documentation for key equality of `Map` being a part of `deepEqual`
|
|
33
|
+
|
|
34
|
+
## 2.0.3
|
|
35
|
+
|
|
36
|
+
- Fix [#50](https://github.com/planttheidea/fast-equals/pull/50) - copy-pasta in cacheable check
|
|
37
|
+
|
|
38
|
+
## 2.0.2
|
|
39
|
+
|
|
40
|
+
- Optimize iterables comparisons to not double-iterate
|
|
41
|
+
- Optimize loop-based comparisons for speed
|
|
42
|
+
- Improve cache handling in circular handlers
|
|
43
|
+
- Improve stability of memory by reducing variable instantiation
|
|
44
|
+
|
|
3
45
|
## 2.0.1
|
|
4
46
|
|
|
5
47
|
- Fix [#41](https://github.com/planttheidea/fast-equals/pull/41) - prevent `.rpt2_cache` directory from being published for better CI environment support (thanks [@herberttn](https://github.com/herberttn))
|
|
6
48
|
|
|
7
49
|
## 2.0.0
|
|
8
50
|
|
|
9
|
-
|
|
51
|
+
### Breaking changes
|
|
10
52
|
|
|
11
53
|
- There are longer `fast-equals/es`, `fast-equals/lib`, `fast-equals/mjs` locations
|
|
12
54
|
- Instead, there are 3 builds in `dist` for different consumption types:
|
|
@@ -16,13 +58,13 @@
|
|
|
16
58
|
- There is no default export anymore, only the previously-existing named exports
|
|
17
59
|
- To get all into a namespace, use `import * as fe from 'fast-equals`
|
|
18
60
|
|
|
19
|
-
|
|
61
|
+
### Updates
|
|
20
62
|
|
|
21
63
|
- Rewritten completely in TypeScript
|
|
22
64
|
- Improve speed of `Map` / `Set` comparisons
|
|
23
65
|
- Improve speed of React element comparisons
|
|
24
66
|
|
|
25
|
-
|
|
67
|
+
### Fixes
|
|
26
68
|
|
|
27
69
|
- Consider pure objects (`Object.create(null)`) to be plain objects
|
|
28
70
|
- Fix typings for `createCustomEqual`
|
|
@@ -122,3 +164,7 @@
|
|
|
122
164
|
## 1.0.0
|
|
123
165
|
|
|
124
166
|
- Initial release
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<img src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg"/>
|
|
5
5
|
<img src="https://img.shields.io/badge/license-MIT-blue.svg"/>
|
|
6
6
|
|
|
7
|
-
Perform [blazing fast](#benchmarks) equality comparisons (either deep or shallow) on two objects passed. It has no dependencies, and is ~
|
|
7
|
+
Perform [blazing fast](#benchmarks) equality comparisons (either deep or shallow) on two objects passed. It has no dependencies, and is ~1kB when minified and gzipped.
|
|
8
8
|
|
|
9
9
|
Unlike most equality validation libraries, the following types are handled out-of-the-box:
|
|
10
10
|
|
|
@@ -19,17 +19,20 @@ Starting with version `1.5.0`, circular objects are supported for both deep and
|
|
|
19
19
|
|
|
20
20
|
## Table of contents
|
|
21
21
|
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
|
|
26
|
-
- [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- [
|
|
32
|
-
- [
|
|
22
|
+
- [fast-equals](#fast-equals)
|
|
23
|
+
- [Table of contents](#table-of-contents)
|
|
24
|
+
- [Usage](#usage)
|
|
25
|
+
- [Specific builds](#specific-builds)
|
|
26
|
+
- [Available methods](#available-methods)
|
|
27
|
+
- [deepEqual](#deepequal)
|
|
28
|
+
- [Comparing `Map`s](#comparing-maps)
|
|
29
|
+
- [shallowEqual](#shallowequal)
|
|
30
|
+
- [sameValueZeroEqual](#samevaluezeroequal)
|
|
31
|
+
- [circularDeepEqual](#circulardeepequal)
|
|
32
|
+
- [circularShallowEqual](#circularshallowequal)
|
|
33
|
+
- [createCustomEqual](#createcustomequal)
|
|
34
|
+
- [Benchmarks](#benchmarks)
|
|
35
|
+
- [Development](#development)
|
|
33
36
|
|
|
34
37
|
## Usage
|
|
35
38
|
|
|
@@ -49,7 +52,7 @@ import * as fe from 'fast-equals';
|
|
|
49
52
|
console.log(fe.deep({ foo: 'bar' }, { foo: 'bar' })); // true
|
|
50
53
|
```
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
### Specific builds
|
|
53
56
|
|
|
54
57
|
There are three builds, an ESM build for modern build systems / runtimes, a CommonJS build for traditional NodeJS environments, and a UMD build for legacy implementations. The ideal one will likely be chosen for you automatically, however if you want to use a specific build you can always import it directly:
|
|
55
58
|
|
|
@@ -64,7 +67,7 @@ There is also a pre-minified version of the UMD build available:
|
|
|
64
67
|
|
|
65
68
|
## Available methods
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
### deepEqual
|
|
68
71
|
|
|
69
72
|
Performs a deep equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
|
|
70
73
|
|
|
@@ -78,7 +81,20 @@ console.log(objectA === objectB); // false
|
|
|
78
81
|
console.log(deepEqual(objectA, objectB)); // true
|
|
79
82
|
```
|
|
80
83
|
|
|
81
|
-
####
|
|
84
|
+
#### Comparing `Map`s
|
|
85
|
+
|
|
86
|
+
`Map` objects support complex keys (objects, Arrays, etc.), however [the spec for key lookups in `Map` are based on `SameZeroValue`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#key_equality). If the spec were followed for comparison, the following would always be `false`:
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
const mapA = new Map([[{ foo: 'bar' }, { baz: 'quz' }]]);
|
|
90
|
+
const mapB = new Map([[{ foo: 'bar' }, { baz: 'quz' }]]);
|
|
91
|
+
|
|
92
|
+
deepEqual(mapA, mapB);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
To support true deep equality of all contents, `fast-equals` will perform a deep equality comparison for key and value parirs. Therefore, the above would be `true`.
|
|
96
|
+
|
|
97
|
+
### shallowEqual
|
|
82
98
|
|
|
83
99
|
Performs a shallow equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
|
|
84
100
|
|
|
@@ -96,7 +112,7 @@ console.log(shallowEqual(objectA, objectB)); // true
|
|
|
96
112
|
console.log(shallowEqual(objectA, objectC)); // false
|
|
97
113
|
```
|
|
98
114
|
|
|
99
|
-
|
|
115
|
+
### sameValueZeroEqual
|
|
100
116
|
|
|
101
117
|
Performs a [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) comparison on the two objects passed and returns a boolean representing the value equivalency of the objects. In simple terms, this means either strictly equal or both `NaN`.
|
|
102
118
|
|
|
@@ -114,7 +130,7 @@ console.log(sameValueZeroEqual(mainObject.foo, objectB)); // true
|
|
|
114
130
|
console.log(sameValueZeroEqual(mainObject, objectC)); // false
|
|
115
131
|
```
|
|
116
132
|
|
|
117
|
-
|
|
133
|
+
### circularDeepEqual
|
|
118
134
|
|
|
119
135
|
Performs the same comparison as `deepEqual` but supports circular objects. It is slower than `deepEqual`, so only use if you know circular objects are present.
|
|
120
136
|
|
|
@@ -134,7 +150,9 @@ console.log(circularDeepEqual(new Circular('foo'), new Circular('foo'))); // tru
|
|
|
134
150
|
console.log(circularDeepEqual(new Circular('foo'), new Circular('bar'))); // false
|
|
135
151
|
```
|
|
136
152
|
|
|
137
|
-
|
|
153
|
+
Just as with `deepEqual`, [both keys and values are compared for deep equality](#comparing-maps).
|
|
154
|
+
|
|
155
|
+
### circularShallowEqual
|
|
138
156
|
|
|
139
157
|
Performs the same comparison as `shallowequal` but supports circular objects. It is slower than `shallowEqual`, so only use if you know circular objects are present.
|
|
140
158
|
|
|
@@ -147,7 +165,7 @@ console.log(circularShallowEqual(array, ['foo', array])); // true
|
|
|
147
165
|
console.log(circularShallowEqual(array, [array])); // false
|
|
148
166
|
```
|
|
149
167
|
|
|
150
|
-
|
|
168
|
+
### createCustomEqual
|
|
151
169
|
|
|
152
170
|
Creates a custom equality comparator that will be used on nested values in the object. Unlike `deepEqual` and `shallowEqual`, this is a partial-application function that will receive the internal comparator and should return a function that compares two objects.
|
|
153
171
|
|
|
@@ -155,16 +173,19 @@ The signature is as follows:
|
|
|
155
173
|
|
|
156
174
|
```typescript
|
|
157
175
|
type EqualityComparator = (a: any, b: any, meta?: any) => boolean;
|
|
176
|
+
type InternalEqualityComparator = (a: any, b: any, indexOrKeyA: any, indexOrKeyB: any, parentA: any, parentB: any, meta: any) => boolean;
|
|
158
177
|
type EqualityComparatorCreator = (
|
|
159
178
|
deepEqual: EqualityComparator,
|
|
160
|
-
) =>
|
|
179
|
+
) => InternalEqualityComparator;
|
|
161
180
|
|
|
162
181
|
function createCustomEqual(
|
|
163
182
|
createIsEqual?: EqualityComparatorCreator,
|
|
164
183
|
): EqualityComparator;
|
|
165
184
|
```
|
|
166
185
|
|
|
167
|
-
The `meta` parameter in `EqualityComparator` is whatever you want it to be. It will be passed through to all equality checks, and is meant specifically for use with custom equality methods. For example, with the `circularDeepEqual` and `circularShallowEqual` methods, it is used to pass through a cache of processed objects.
|
|
186
|
+
The `meta` parameter in `EqualityComparator` and `InternalEqualityComparator` is whatever you want it to be. It will be passed through to all equality checks, and is meant specifically for use with custom equality methods. For example, with the `circularDeepEqual` and `circularShallowEqual` methods, it is used to pass through a cache of processed objects.
|
|
187
|
+
|
|
188
|
+
_**NOTE**: `Map` implementations compare equality for both keys and value. When using a custom comparator and comparing equality of the keys, the iteration index is provided as both `indexOrKeyA` and `indexOrKeyB` to help use-cases where ordering of keys matters to equality._
|
|
168
189
|
|
|
169
190
|
An example for a custom equality comparison that also checks against values in the meta object:
|
|
170
191
|
|
|
@@ -172,11 +193,10 @@ An example for a custom equality comparison that also checks against values in t
|
|
|
172
193
|
import { createCustomEqual } from 'fast-equals';
|
|
173
194
|
|
|
174
195
|
const isDeepEqualOrFooMatchesMeta = createCustomEqual(
|
|
175
|
-
(deepEqual) => (objectA, objectB, meta) =>
|
|
196
|
+
(deepEqual) => (objectA, objectB, indexOrKeyA, indexOrKeyB, parentA, parentB, meta) =>
|
|
176
197
|
objectA.foo === meta ||
|
|
177
198
|
objectB.foo === meta ||
|
|
178
|
-
deepEqual(objectA, objectB, meta)
|
|
179
|
-
)
|
|
199
|
+
deepEqual(objectA, objectB, meta),
|
|
180
200
|
);
|
|
181
201
|
|
|
182
202
|
const objectA = { foo: 'bar' };
|
|
@@ -188,7 +208,7 @@ console.log(isDeepEqualOrFooMatchesMeta(objectA, objectB, meta)); // true
|
|
|
188
208
|
|
|
189
209
|
## Benchmarks
|
|
190
210
|
|
|
191
|
-
All benchmarks were performed on an i7
|
|
211
|
+
All benchmarks were performed on an i7-8650U Ubuntu Linux laptop with 24GB of memory using NodeJS version `12.19.1`, and are based on averages of running comparisons based deep equality on the following object types:
|
|
192
212
|
|
|
193
213
|
- Primitives (`String`, `Number`, `null`, `undefined`)
|
|
194
214
|
- `Function`
|
|
@@ -201,20 +221,21 @@ All benchmarks were performed on an i7 8-core Arch Linux laptop with 16GB of mem
|
|
|
201
221
|
|
|
202
222
|
| | Operations / second |
|
|
203
223
|
| -------------------------- | ------------------- |
|
|
204
|
-
| **fast-equals** | **
|
|
205
|
-
|
|
|
206
|
-
|
|
|
207
|
-
|
|
|
208
|
-
|
|
|
209
|
-
|
|
|
210
|
-
| underscore.isEqual |
|
|
211
|
-
|
|
|
212
|
-
|
|
|
213
|
-
|
|
|
214
|
-
|
|
|
224
|
+
| **fast-equals** | **153,880** |
|
|
225
|
+
| fast-deep-equal | 144,035 |
|
|
226
|
+
| react-fast-compare | 130,324 |
|
|
227
|
+
| nano-equal | 104,624 |
|
|
228
|
+
| **fast-equals (circular)** | **97,610** |
|
|
229
|
+
| shallow-equal-fuzzy | 83,946 |
|
|
230
|
+
| underscore.isEqual | 47,370 |
|
|
231
|
+
| lodash.isEqual | 25,053 |
|
|
232
|
+
| deep-eql | 22,146 |
|
|
233
|
+
| assert.deepStrictEqual | 532 |
|
|
234
|
+
| deep-equal | 209 |
|
|
215
235
|
|
|
216
236
|
Caveats that impact the benchmark (and accuracy of comparison):
|
|
217
237
|
|
|
238
|
+
- `Map`s, `Promise`s, and `Set`s were excluded from the benchmark entirely because no library other than `deep-eql` fully supported their comparison
|
|
218
239
|
- `assert.deepStrictEqual` does not support `NaN` or `SameValueZero` equality for dates
|
|
219
240
|
- `deep-eql` does not support `SameValueZero` equality for zero equality (positive and negative zero are not equal)
|
|
220
241
|
- `deep-equal` does not support `NaN` and does not strictly compare object type, or date / regexp values, nor uses `SameValueZero` equality for dates
|
|
@@ -224,7 +245,7 @@ Caveats that impact the benchmark (and accuracy of comparison):
|
|
|
224
245
|
- `shallow-equal-fuzzy` does not strictly compare object type or regexp values, nor `SameValueZero` equality for dates
|
|
225
246
|
- `underscore.isEqual` does not support `SameValueZero` equality for primitives or dates
|
|
226
247
|
|
|
227
|
-
All of these have the potential of inflating the respective library's numbers in comparison to `fast-equals`, but it was the closest apples-to-apples comparison I could create of a reasonable sample size.
|
|
248
|
+
All of these have the potential of inflating the respective library's numbers in comparison to `fast-equals`, but it was the closest apples-to-apples comparison I could create of a reasonable sample size. It should be noted that `react` elements can be circular objects, however simple elements are not; I kept the `react` comparison very basic to allow it to be included.
|
|
228
249
|
|
|
229
250
|
## Development
|
|
230
251
|
|