fast-equals 3.0.3 → 4.0.1-beta.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/.prettierrc ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "all"
4
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # fast-equals CHANGELOG
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Breaking Changes
6
+
7
+ #### Certain ES2015 features are now required
8
+
9
+ In previous versions, there were automatic fallbacks for certain ES2015 features if they did not exist:
10
+
11
+ - [`RegExp.prototype.flags`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags)
12
+ - [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)
13
+
14
+ Due to the omnipresence of support in both browser and NodeJS, these have been deprecated. There is still an option if you require support for these legacy environments, however; see [`createCustomEqual`](./README.md#createcustomequal) and [`createCustomCircularEqual`](./README.md#createcustomcircularequal) for more details.
15
+
16
+ #### `createCustomEqual` contract has changed
17
+
18
+ To allow more flexibility and customizability for a variety of edge cases, `createCustomEqual` now allows override of specific type value comparisons in addition to the general comparator it did prior. See [the documentation](./README.md#createcustomequal) for more details.
19
+
20
+ ### Enhancements
21
+
22
+ #### `createCustomCircularEqual` added
23
+
24
+ Like `createCustomEqual`, it will create a custom equality comparator, with the exception that it will handle circular references. See [the documentation](./README.md#createcustomcircularequal) for more details.
25
+
26
+ #### Cross-realm comparisons are now supported
27
+
28
+ Prior to `4.x.x.`, `instanceof` was used internally for checking of object classes, which only worked when comparing objects from the same [Realm](https://262.ecma-international.org/6.0/#sec-code-realms). This has changed to instead use an object's [StringTag](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag), which is not realm-specific.
29
+
30
+ #### TypeScript typings improved
31
+
32
+ For better typing in edge-case scenarios like custom comparators with `meta` values, typings have been refactored for accuracy and better narrow flow-through.
33
+
3
34
  ## 3.0.3
4
35
 
5
36
  - Fix [#77](https://github.com/planttheidea/fast-equals/issues/73) - better circular object validation
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 ~1kB 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 ~1.26kB when minified and gzipped.
8
8
 
9
9
  Unlike most equality validation libraries, the following types are handled out-of-the-box:
10
10
 
@@ -31,27 +31,20 @@ Starting with version `1.5.0`, circular objects are supported for both deep and
31
31
  - [circularDeepEqual](#circulardeepequal)
32
32
  - [circularShallowEqual](#circularshallowequal)
33
33
  - [createCustomEqual](#createcustomequal)
34
+ - [Recipes](#recipes)
35
+ - [`createCustomCircularEqual`](#createcustomcircularequal)
36
+ - [Recipes](#recipes-1)
34
37
  - [Benchmarks](#benchmarks)
35
38
  - [Development](#development)
36
39
 
37
40
  ## Usage
38
41
 
39
- You can either import the individual functions desired:
40
-
41
- ```javascript
42
+ ```ts
42
43
  import { deepEqual } from 'fast-equals';
43
44
 
44
45
  console.log(deepEqual({ foo: 'bar' }, { foo: 'bar' })); // true
45
46
  ```
46
47
 
47
- Or if you want to import all functions under a namespace:
48
-
49
- ```javascript
50
- import * as fe from 'fast-equals';
51
-
52
- console.log(fe.deep({ foo: 'bar' }, { foo: 'bar' })); // true
53
- ```
54
-
55
48
  ### Specific builds
56
49
 
57
50
  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:
@@ -60,9 +53,6 @@ There are three builds, an ESM build for modern build systems / runtimes, a Comm
60
53
  - For older `nodejs` versions that do not allow ESM with file extensions other than `.mjs` => `fast-equals/dist/fast-equals.mjs`
61
54
  - CommonJS => `fast-equals/dist/fast-equals.cjs.js`
62
55
  - UMD => `fast-equals/dist/fast-equals.js`
63
-
64
- There is also a pre-minified version of the UMD build available:
65
-
66
56
  - Minified UMD => `fast-equals/dist/fast-equals.min.js`
67
57
 
68
58
  ## Available methods
@@ -71,7 +61,7 @@ There is also a pre-minified version of the UMD build available:
71
61
 
72
62
  Performs a deep equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
73
63
 
74
- ```javascript
64
+ ```ts
75
65
  import { deepEqual } from 'fast-equals';
76
66
 
77
67
  const objectA = { foo: { bar: 'baz' } };
@@ -85,7 +75,7 @@ console.log(deepEqual(objectA, objectB)); // true
85
75
 
86
76
  `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
77
 
88
- ```javascript
78
+ ```ts
89
79
  const mapA = new Map([[{ foo: 'bar' }, { baz: 'quz' }]]);
90
80
  const mapB = new Map([[{ foo: 'bar' }, { baz: 'quz' }]]);
91
81
 
@@ -98,7 +88,7 @@ To support true deep equality of all contents, `fast-equals` will perform a deep
98
88
 
99
89
  Performs a shallow equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
100
90
 
101
- ```javascript
91
+ ```ts
102
92
  import { shallowEqual } from 'fast-equals';
103
93
 
104
94
  const nestedObject = { bar: 'baz' };
@@ -116,7 +106,7 @@ console.log(shallowEqual(objectA, objectC)); // false
116
106
 
117
107
  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`.
118
108
 
119
- ```javascript
109
+ ```ts
120
110
  import { sameValueZeroEqual } from 'fast-equals';
121
111
 
122
112
  const mainObject = { foo: NaN, bar: 'baz' };
@@ -134,7 +124,7 @@ console.log(sameValueZeroEqual(mainObject, objectC)); // false
134
124
 
135
125
  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.
136
126
 
137
- ```javascript
127
+ ```ts
138
128
  function Circular(value) {
139
129
  this.me = {
140
130
  deeply: {
@@ -156,7 +146,7 @@ Just as with `deepEqual`, [both keys and values are compared for deep equality](
156
146
 
157
147
  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.
158
148
 
159
- ```javascript
149
+ ```ts
160
150
  const array = ['foo'];
161
151
 
162
152
  array.push(array);
@@ -167,44 +157,70 @@ console.log(circularShallowEqual(array, [array])); // false
167
157
 
168
158
  ### createCustomEqual
169
159
 
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.
160
+ Creates a custom equality comparator that will be used on nested values in the object. Unlike `deepEqual` and `shallowEqual`, this is a factory method that receives the default options used internally, and allows you to override the defaults as needed. This is generally for extreme edge-cases, or supporting legacy environments.
171
161
 
172
162
  The signature is as follows:
173
163
 
174
- ```typescript
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;
177
- type EqualityComparatorCreator = (
178
- deepEqual: EqualityComparator,
179
- ) => InternalEqualityComparator;
164
+ ```ts
165
+ type InternalEqualityComparator = (
166
+ a: any,
167
+ b: any,
168
+ indexOrKeyA: any,
169
+ indexOrKeyB: any,
170
+ parentA: any,
171
+ parentB: any,
172
+ meta: any,
173
+ ) => boolean;
174
+
175
+ type TypeEqualityComparator = <Type, Meta>(
176
+ a: Type,
177
+ b: Type,
178
+ isEqual: InternalEqualityComparator,
179
+ meta: Meta,
180
+ ) => boolean;
181
+
182
+ interface CreateComparatorCreatorOptions<Meta> {
183
+ areArraysEqual: TypeEqualityComparator<any[], Meta>;
184
+ areDatesEqual: TypeEqualityComparator<Date, Meta>;
185
+ areMapsEqual: TypeEqualityComparator<Map<any, any>, Meta>;
186
+ areObjectsEqual: TypeEqualityComparator<Record<string, any>, Meta>;
187
+ areRegExpsEqual: TypeEqualityComparator<RegExp, Meta>;
188
+ areSetsEqual: TypeEqualityComparator<Set<any>, Meta>;
189
+ createIsNestedEqual?: (
190
+ comparator: <A, B>(a: A, b: B, meta: Meta) => boolean,
191
+ ) => InternalEqualityComparator;
192
+ }
180
193
 
181
194
  function createCustomEqual(
182
- createIsEqual?: EqualityComparatorCreator,
195
+ getComparatorOptions: (
196
+ defaultOptions: CreateComparatorOptions,
197
+ ) => Partial<CreateComparatorOptions>,
183
198
  ): EqualityComparator;
184
199
  ```
185
200
 
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.
201
+ The `meta` parameter above 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. You also only need to return the override handlers; absent being provided, the defaults are used.
187
202
 
188
203
  _**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._
189
204
 
190
- An example for a custom equality comparison that also checks against values in the meta object:
205
+ #### Recipes
191
206
 
192
- ```javascript
193
- import { createCustomEqual } from 'fast-equals';
207
+ Some recipes have been created to provide examples of use-cases for `createCustomEqual`. Even if not directly applicable to the problem you are solving, they can offer guidance of how to structure your solution.
194
208
 
195
- const isDeepEqualOrFooMatchesMeta = createCustomEqual(
196
- (deepEqual) => (objectA, objectB, indexOrKeyA, indexOrKeyB, parentA, parentB, meta) =>
197
- objectA.foo === meta ||
198
- objectB.foo === meta ||
199
- deepEqual(objectA, objectB, meta),
200
- );
209
+ - [Legacy environment support for `RegExp` comparators](./recipes/legacy-regexp-support.md)
210
+ - [Explicit property check](./recipes/explicit-property-check.md)
211
+ - [Using `meta` in comparison](./recipes//using-meta-in-comparison.md)
212
+ - [Comparing non-standard properties](./recipes/non-standard-properties.md)
213
+ - [Strict property descriptor comparison](./recipes/strict-equality-checks.md)
201
214
 
202
- const objectA = { foo: 'bar' };
203
- const objectB = { foo: 'baz' };
204
- const meta = 'bar';
215
+ ### `createCustomCircularEqual`
205
216
 
206
- console.log(isDeepEqualOrFooMatchesMeta(objectA, objectB, meta)); // true
207
- ```
217
+ Operates nearly identically to [`createCustomEqual`](#createcustomequal), with the difference being that the `meta` property expected by the comparator is expected to have a `WeakMap` contract. This is because it is used for caching accessed objects to avoid maximum stack exceeded errors. The most common use for this method is a simple way to support circular checks for references that do not have `WeakMap` natively.
218
+
219
+ #### Recipes
220
+
221
+ Some recipes have been created to provide examples of use-cases for `createCustomEqual`. Even if not directly applicable to the problem you are solving, they can offer guidance of how to structure your solution.
222
+
223
+ - [Legacy environment support for circualr equal comparators](./recipes/legacy-circular-equal-support.md)
208
224
 
209
225
  ## Benchmarks
210
226