fast-equals 1.6.3 → 2.0.3

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/BUILD.md ADDED
@@ -0,0 +1,37 @@
1
+ # Reproducing a build
2
+
3
+ ## Clone version
4
+
5
+ ```
6
+ git clone https://github.com/planttheidea/fast-equals.git
7
+ cd fast-equals
8
+ git checkout {version}
9
+ ```
10
+
11
+ Replace `{version}` above with the appropriate package version. If you want to compare a version older than `1.6.2`, you'll need to use a commit hash directly.
12
+
13
+ ## Install
14
+
15
+ ```
16
+ yarn install
17
+ ```
18
+
19
+ We use `yarn` for our package management, so to ensure that exact dependencies you should also use it.
20
+
21
+ ## Build artifacts
22
+
23
+ ```
24
+ yarn run build
25
+ ```
26
+
27
+ **NOTE**: To get an exact checksum match with the versions released on npm, it may be necessary to change line endings. For example, on Linux you might run:
28
+
29
+ ```
30
+ unix2dos dist/fast-equals.min.js
31
+ ```
32
+
33
+ ## Get checksum
34
+
35
+ ```
36
+ sha256sum dist/fast-equals.min.js
37
+ ```
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # fast-equals CHANGELOG
2
2
 
3
+ ## 2.0.3
4
+
5
+ - Fix [#50](https://github.com/planttheidea/fast-equals/pull/50) - copy-pasta in cacheable check
6
+
7
+ ## 2.0.2
8
+
9
+ - Optimize iterables comparisons to not double-iterate
10
+ - Optimize loop-based comparisons for speed
11
+ - Improve cache handling in circular handlers
12
+ - Improve stability of memory by reducing variable instantiation
13
+
14
+ ## 2.0.1
15
+
16
+ - 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))
17
+
18
+ ## 2.0.0
19
+
20
+ #### Breaking changes
21
+
22
+ - There are longer `fast-equals/es`, `fast-equals/lib`, `fast-equals/mjs` locations
23
+ - Instead, there are 3 builds in `dist` for different consumption types:
24
+ - `fast-equals.js` (UMD / `browser`)
25
+ - `fast-equals.esm.js` (ESM / `module`)
26
+ - `fast-equals.cjs.js` (CommonJS / `main`)
27
+ - There is no default export anymore, only the previously-existing named exports
28
+ - To get all into a namespace, use `import * as fe from 'fast-equals`
29
+
30
+ #### Updates
31
+
32
+ - Rewritten completely in TypeScript
33
+ - Improve speed of `Map` / `Set` comparisons
34
+ - Improve speed of React element comparisons
35
+
36
+ #### Fixes
37
+
38
+ - Consider pure objects (`Object.create(null)`) to be plain objects
39
+ - Fix typings for `createCustomEqual`
40
+
3
41
  ## 1.6.3
4
42
 
5
43
  - Check the size of the iterable before converting to arrays
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 ~1.3kB when minified and gzipped.
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,69 +19,62 @@ Starting with version `1.5.0`, circular objects are supported for both deep and
19
19
 
20
20
  ## Table of contents
21
21
 
22
- - [Usage](#usage)
23
- - [Importing](#importing)
24
- - [Available methods](#available-methods)
25
- - [deepEqual](#deepequal)
26
- - [shallowEqual](#shallowequal)
27
- - [sameValueZeroEqual](#samevaluezeroequal)
28
- - [circularDeepEqual](#circulardeepequal)
29
- - [circularShallowEqual](#circularshallowequal)
30
- - [createCustomEqual](#createcustomequal)
31
- - [Benchmarks](#benchmarks)
32
- - [Development](#development)
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
+ - [shallowEqual](#shallowequal)
29
+ - [sameValueZeroEqual](#samevaluezeroequal)
30
+ - [circularDeepEqual](#circulardeepequal)
31
+ - [circularShallowEqual](#circularshallowequal)
32
+ - [createCustomEqual](#createcustomequal)
33
+ - [Benchmarks](#benchmarks)
34
+ - [Development](#development)
33
35
 
34
36
  ## Usage
35
37
 
36
- You can either import the full object:
38
+ You can either import the individual functions desired:
37
39
 
38
40
  ```javascript
39
- import fe from "fast-equals";
41
+ import { deepEqual } from 'fast-equals';
40
42
 
41
- console.log(fe.deep({ foo: "bar" }, { foo: "bar" })); // true
43
+ console.log(deepEqual({ foo: 'bar' }, { foo: 'bar' })); // true
42
44
  ```
43
45
 
44
- Or the individual imports desired:
46
+ Or if you want to import all functions under a namespace:
45
47
 
46
48
  ```javascript
47
- import { deepEqual } from "fast-equals";
49
+ import * as fe from 'fast-equals';
48
50
 
49
- console.log(deepEqual({ foo: "bar" }, { foo: "bar" })); // true
51
+ console.log(fe.deep({ foo: 'bar' }, { foo: 'bar' })); // true
50
52
  ```
51
53
 
52
- ## Importing
54
+ #### Specific builds
53
55
 
54
- ESM in browsers:
56
+ 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
57
 
56
- ```javascript
57
- import fe from "fast-equals";
58
- ```
58
+ - ESM => `fast-equals/dist/fast-equals.esm.js`
59
+ - For older `nodejs` versions that do not allow ESM with file extensions other than `.mjs` => `fast-equals/dist/fast-equals.mjs`
60
+ - CommonJS => `fast-equals/dist/fast-equals.cjs.js`
61
+ - UMD => `fast-equals/dist/fast-equals.js`
59
62
 
60
- ESM in NodeJS:
63
+ There is also a pre-minified version of the UMD build available:
61
64
 
62
- ```javascript
63
- import fe from "fast-equals/mjs";
64
- ```
65
-
66
- CommonJS:
67
-
68
- ```javascript
69
- const fe = require("fast-equals").default;
70
- ```
65
+ - Minified UMD => `fast-equals/dist/fast-equals.min.js`
71
66
 
72
67
  ## Available methods
73
68
 
74
69
  #### deepEqual
75
70
 
76
- _Aliased on the default export as `fe.deep`_
77
-
78
71
  Performs a deep equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
79
72
 
80
73
  ```javascript
81
- import { deepEqual } from "fast-equals";
74
+ import { deepEqual } from 'fast-equals';
82
75
 
83
- const objectA = { foo: { bar: "baz" } };
84
- const objectB = { foo: { bar: "baz" } };
76
+ const objectA = { foo: { bar: 'baz' } };
77
+ const objectB = { foo: { bar: 'baz' } };
85
78
 
86
79
  console.log(objectA === objectB); // false
87
80
  console.log(deepEqual(objectA, objectB)); // true
@@ -89,18 +82,16 @@ console.log(deepEqual(objectA, objectB)); // true
89
82
 
90
83
  #### shallowEqual
91
84
 
92
- _Aliased on the default export as `fe.shallow`_
93
-
94
85
  Performs a shallow equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
95
86
 
96
87
  ```javascript
97
- import { shallowEqual } from "fast-equals";
88
+ import { shallowEqual } from 'fast-equals';
98
89
 
99
- const nestedObject = { bar: "baz" };
90
+ const nestedObject = { bar: 'baz' };
100
91
 
101
92
  const objectA = { foo: nestedObject };
102
93
  const objectB = { foo: nestedObject };
103
- const objectC = { foo: { bar: "baz" } };
94
+ const objectC = { foo: { bar: 'baz' } };
104
95
 
105
96
  console.log(objectA === objectB); // false
106
97
  console.log(shallowEqual(objectA, objectB)); // true
@@ -109,18 +100,16 @@ console.log(shallowEqual(objectA, objectC)); // false
109
100
 
110
101
  #### sameValueZeroEqual
111
102
 
112
- _Aliased on the default export as `fe.sameValueZero`_
113
-
114
103
  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`.
115
104
 
116
105
  ```javascript
117
- import { sameValueZeroEqual } from "fast-equals";
106
+ import { sameValueZeroEqual } from 'fast-equals';
118
107
 
119
- const mainObject = { foo: NaN, bar: "baz" };
108
+ const mainObject = { foo: NaN, bar: 'baz' };
120
109
 
121
- const objectA = "baz";
110
+ const objectA = 'baz';
122
111
  const objectB = NaN;
123
- const objectC = { foo: NaN, bar: "baz" };
112
+ const objectC = { foo: NaN, bar: 'baz' };
124
113
 
125
114
  console.log(sameValueZeroEqual(mainObject.bar, objectA)); // true
126
115
  console.log(sameValueZeroEqual(mainObject.foo, objectB)); // true
@@ -129,8 +118,6 @@ console.log(sameValueZeroEqual(mainObject, objectC)); // false
129
118
 
130
119
  #### circularDeepEqual
131
120
 
132
- _Aliased on the default export as `fe.circularDeep`_
133
-
134
121
  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.
135
122
 
136
123
  ```javascript
@@ -138,71 +125,71 @@ function Circular(value) {
138
125
  this.me = {
139
126
  deeply: {
140
127
  nested: {
141
- reference: this
142
- }
128
+ reference: this,
129
+ },
143
130
  },
144
- value
131
+ value,
145
132
  };
146
133
  }
147
134
 
148
- console.log(circularDeepEqual(new Circular("foo"), new Circular("foo"))); // true
149
- console.log(circularDeepEqual(new Circular("foo"), new Circular("bar"))); // false
135
+ console.log(circularDeepEqual(new Circular('foo'), new Circular('foo'))); // true
136
+ console.log(circularDeepEqual(new Circular('foo'), new Circular('bar'))); // false
150
137
  ```
151
138
 
152
139
  #### circularShallowEqual
153
140
 
154
- _Aliased on the default export as `fe.circularShallow`_
155
-
156
141
  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.
157
142
 
158
143
  ```javascript
159
- const array = ["foo"];
144
+ const array = ['foo'];
160
145
 
161
146
  array.push(array);
162
147
 
163
- console.log(circularShallowEqual(array, ["foo", array])); // true
148
+ console.log(circularShallowEqual(array, ['foo', array])); // true
164
149
  console.log(circularShallowEqual(array, [array])); // false
165
150
  ```
166
151
 
167
152
  #### createCustomEqual
168
153
 
169
- _Aliased on the default export as `fe.createCustom`_
170
-
171
154
  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.
172
155
 
173
156
  The signature is as follows:
174
157
 
175
- ```javascript
176
- createCustomEqual(deepEqual: function) => (objectA: any, objectB: any, meta: any) => boolean;
158
+ ```typescript
159
+ type EqualityComparator = (a: any, b: any, meta?: any) => boolean;
160
+ type EqualityComparatorCreator = (
161
+ deepEqual: EqualityComparator,
162
+ ) => EqualityComparator;
163
+
164
+ function createCustomEqual(
165
+ createIsEqual?: EqualityComparatorCreator,
166
+ ): EqualityComparator;
177
167
  ```
178
168
 
179
- The `meta` parameter 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.
169
+ 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.
180
170
 
181
171
  An example for a custom equality comparison that also checks against values in the meta object:
182
172
 
183
173
  ```javascript
184
- import { createCustomEqual } from "fast-equals";
185
-
186
- const isDeepEqualOrFooMatchesMeta = createCustomEqual(deepEqual => {
187
- return (objectA, objectB, meta) => {
188
- return (
189
- objectA.foo === meta ||
190
- objectB.foo === meta ||
191
- deepEqual(objectA, objectB, meta)
192
- );
193
- };
194
- });
174
+ import { createCustomEqual } from 'fast-equals';
175
+
176
+ const isDeepEqualOrFooMatchesMeta = createCustomEqual(
177
+ (deepEqual) => (objectA, objectB, meta) =>
178
+ objectA.foo === meta ||
179
+ objectB.foo === meta ||
180
+ deepEqual(objectA, objectB, meta),
181
+ );
195
182
 
196
- const objectA = { foo: "bar" };
197
- const objectB = { foo: "baz" };
198
- const meta = "bar";
183
+ const objectA = { foo: 'bar' };
184
+ const objectB = { foo: 'baz' };
185
+ const meta = 'bar';
199
186
 
200
- console.log(isDeepEqualOrFooMatchesMeta(objectA, objectB)); // true
187
+ console.log(isDeepEqualOrFooMatchesMeta(objectA, objectB, meta)); // true
201
188
  ```
202
189
 
203
190
  ## Benchmarks
204
191
 
205
- All benchmarks were performed on an i7 8-core Arch Linux laptop with 16GB of memory using NodeJS version `10.15.0`, and are based on averages of running comparisons based deep equality on the following object types:
192
+ 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:
206
193
 
207
194
  - Primitives (`String`, `Number`, `null`, `undefined`)
208
195
  - `Function`
@@ -215,30 +202,31 @@ All benchmarks were performed on an i7 8-core Arch Linux laptop with 16GB of mem
215
202
 
216
203
  | | Operations / second |
217
204
  | -------------------------- | ------------------- |
218
- | **fast-equals** | **148,083** |
219
- | nano-equal | 114,146 |
220
- | shallow-equal-fuzzy | 99,097 |
221
- | fast-deep-equal | 98,452 |
222
- | react-fast-compare | 96,650 |
223
- | **fast-equals (circular)** | **80,575** |
224
- | underscore.isEqual | 62,572 |
225
- | deep-equal | 47,260 |
226
- | lodash.isEqual | 24,315 |
227
- | deep-eql | 23,962 |
228
- | assert.deepStrictEqual | 1,370 |
205
+ | **fast-equals** | **153,880** |
206
+ | fast-deep-equal | 144,035 |
207
+ | react-fast-compare | 130,324 |
208
+ | nano-equal | 104,624 |
209
+ | **fast-equals (circular)** | **97,610** |
210
+ | shallow-equal-fuzzy | 83,946 |
211
+ | underscore.isEqual | 47,370 |
212
+ | lodash.isEqual | 25,053 |
213
+ | deep-eql | 22,146 |
214
+ | assert.deepStrictEqual | 532 |
215
+ | deep-equal | 209 |
229
216
 
230
217
  Caveats that impact the benchmark (and accuracy of comparison):
231
218
 
232
- - `nano-equal` does not strictly compare object property structure, array length, or object type, nor `SameValueZero` equality for dates
233
- - `shallow-equal-fuzzy` does not strictly compare object type or regexp values, nor `SameValueZero` equality for dates
219
+ - `Map`s, `Promise`s, and `Set`s were excluded from the benchmark entirely because no library other than `deep-eql` fully supported their comparison
220
+ - `assert.deepStrictEqual` does not support `NaN` or `SameValueZero` equality for dates
221
+ - `deep-eql` does not support `SameValueZero` equality for zero equality (positive and negative zero are not equal)
222
+ - `deep-equal` does not support `NaN` and does not strictly compare object type, or date / regexp values, nor uses `SameValueZero` equality for dates
234
223
  - `fast-deep-equal` does not support `NaN` or `SameValueZero` equality for dates
224
+ - `nano-equal` does not strictly compare object property structure, array length, or object type, nor `SameValueZero` equality for dates
235
225
  - `react-fast-compare` does not support `NaN` or `SameValueZero` equality for dates, and does not compare `function` equality
226
+ - `shallow-equal-fuzzy` does not strictly compare object type or regexp values, nor `SameValueZero` equality for dates
236
227
  - `underscore.isEqual` does not support `SameValueZero` equality for primitives or dates
237
- - `deep-equal` does not support `NaN` and does not strictly compare object type, or date / regexp values, nor uses `SameValueZero` equality for dates
238
- - `deep-eql` does not support `SameValueZero` equality for zero equality (positive and negative zero are not equal)
239
- - `assert.deepStrictEqual` does not support `NaN` or `SameValueZero` equality for dates
240
228
 
241
- 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. `Map`s, `Promise`s, and `Set`s were excluded from the benchmark entirely because no library other than `lodash` supported their comparison. The same logic applies to `react` elements (which can be circular objects), but simple elements are non-circular objects so I kept the `react` comparison very basic to allow it to be included.
229
+ 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.
242
230
 
243
231
  ## Development
244
232
 
@@ -246,12 +234,7 @@ Standard practice, clone the repo and `npm i` to get the dependencies. The follo
246
234
 
247
235
  - benchmark => run benchmark tests against other equality libraries
248
236
  - build => build `main`, `module`, and `browser` distributables with `rollup`
249
- - clean => run `clean:dist`, `clean:es`, `clean:mjs`, and `clean:lib` scripts
250
- - clean:dist => run `rimraf` on the `dist` folder
251
- - clean:es => run `rimraf` on the `es` folder
252
- - clean:lib => run `rimraf` on the `lib` folder
253
- - clean:mjs => run `rimraf` on the `mjs` folder
254
- - copy:mjs => copy all files from `es` folder to `mjs` folder (for node ESM consumption)
237
+ - clean => run `rimraf` on the `dist` folder
255
238
  - dev => start webpack playground App
256
239
  - dist => run `build`
257
240
  - lint => run ESLint on all files in `src` folder (also runs on `dev` script)
@@ -261,5 +244,3 @@ Standard practice, clone the repo and `npm i` to get the dependencies. The follo
261
244
  - test => run AVA with NODE_ENV=test on all files in `test` folder
262
245
  - test:coverage => run same script as `test` with code coverage calculation via `nyc`
263
246
  - test:watch => run same script as `test` but keep persistent watcher
264
- - transpile:es => run Babel on all files, in `src` folder (transpiled to `es` folder without transpilation of ES2015 export syntax)
265
- - transpile:lib => run Babel on all files in `src` folder (transpiled to `lib` folder)