ts-data-forge 14.9.0 → 14.10.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 +5 -5
- package/dist/array/impl/array-utils-element-access.d.mts.map +1 -1
- package/dist/array/impl/array-utils-element-access.mjs +4 -4
- package/dist/array/impl/array-utils-element-access.mjs.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts +8 -8
- package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-array-cast.mjs +28 -28
- package/dist/array/impl/array-utils-length-bounded-array-cast.mjs.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-array-guard.mjs +4 -4
- package/dist/array/impl/array-utils-length-bounded-array-guard.mjs.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts +3 -4
- package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs +28 -29
- package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-tuple-guard.d.mts.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs +3 -3
- package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs.map +1 -1
- package/dist/array/impl/array-utils-modification.d.mts +1 -1
- package/dist/array/impl/array-utils-modification.d.mts.map +1 -1
- package/dist/array/impl/array-utils-modification.mjs +15 -15
- package/dist/array/impl/array-utils-modification.mjs.map +1 -1
- package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -1
- package/dist/array/impl/array-utils-reducing-value.mjs +12 -12
- package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
- package/dist/array/impl/array-utils-search.d.mts.map +1 -1
- package/dist/array/impl/array-utils-search.mjs +56 -56
- package/dist/array/impl/array-utils-search.mjs.map +1 -1
- package/dist/array/impl/array-utils-slicing.d.mts.map +1 -1
- package/dist/array/impl/array-utils-slicing.mjs +3 -3
- package/dist/array/impl/array-utils-slicing.mjs.map +1 -1
- package/dist/array/impl/array-utils-transformation.d.mts +25 -25
- package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-transformation.mjs +22 -22
- package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
- package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-validation.mjs +2 -2
- package/dist/array/impl/array-utils-validation.mjs.map +1 -1
- package/dist/collections/imap-mapped.d.mts +2 -2
- package/dist/collections/imap.d.mts +3 -4
- package/dist/collections/imap.d.mts.map +1 -1
- package/dist/collections/imap.mjs +0 -1
- package/dist/collections/imap.mjs.map +1 -1
- package/dist/collections/iset-mapped.d.mts +1 -2
- package/dist/collections/iset-mapped.d.mts.map +1 -1
- package/dist/collections/iset-mapped.mjs.map +1 -1
- package/dist/collections/iset.d.mts +4 -5
- package/dist/collections/iset.d.mts.map +1 -1
- package/dist/collections/iset.mjs +0 -1
- package/dist/collections/iset.mjs.map +1 -1
- package/dist/number/num.d.mts +2 -2
- package/dist/number/num.mjs.map +1 -1
- package/dist/object/object.d.mts +2 -2
- package/dist/others/fast-deep-equal.d.mts.map +1 -1
- package/dist/others/fast-deep-equal.mjs +10 -7
- package/dist/others/fast-deep-equal.mjs.map +1 -1
- package/dist/others/index.d.mts +1 -0
- package/dist/others/index.d.mts.map +1 -1
- package/dist/others/index.mjs +1 -0
- package/dist/others/index.mjs.map +1 -1
- package/dist/others/replace-equal-deep.d.mts +95 -0
- package/dist/others/replace-equal-deep.d.mts.map +1 -0
- package/dist/others/replace-equal-deep.mjs +156 -0
- package/dist/others/replace-equal-deep.mjs.map +1 -0
- package/dist/string/str.d.mts +2 -2
- package/package.json +12 -12
- package/src/array/impl/array-utils-element-access.mts +11 -11
- package/src/array/impl/array-utils-length-bounded-array-cast.mts +69 -69
- package/src/array/impl/array-utils-length-bounded-array-guard.mts +21 -21
- package/src/array/impl/array-utils-length-bounded-array-guard.test.mts +2 -2
- package/src/array/impl/array-utils-length-bounded-tuple-cast.mts +64 -65
- package/src/array/impl/array-utils-length-bounded-tuple-guard.mts +15 -15
- package/src/array/impl/array-utils-modification.mts +54 -54
- package/src/array/impl/array-utils-reducing-value.mts +55 -55
- package/src/array/impl/array-utils-search.mts +114 -114
- package/src/array/impl/array-utils-slicing.mts +16 -16
- package/src/array/impl/array-utils-transformation.mts +96 -96
- package/src/array/impl/array-utils-transformation.test.mts +2 -2
- package/src/array/impl/array-utils-validation.mts +19 -19
- package/src/array/impl/array-utils-validation.test.mts +1 -1
- package/src/collections/imap-mapped.mts +2 -2
- package/src/collections/imap.mts +3 -4
- package/src/collections/imap.test.mts +1 -1
- package/src/collections/iset-mapped.mts +1 -2
- package/src/collections/iset.mts +4 -5
- package/src/collections/iset.test.mts +1 -1
- package/src/number/num.mts +10 -10
- package/src/object/object.mts +2 -2
- package/src/others/fast-deep-equal.mts +17 -10
- package/src/others/fast-deep-equal.test.mts +141 -29
- package/src/others/index.mts +1 -0
- package/src/others/replace-equal-deep.mts +225 -0
- package/src/others/replace-equal-deep.test.mts +348 -0
- package/src/string/str.mts +2 -2
|
@@ -125,8 +125,8 @@ type IMapMappedInterface<K, V, KM extends MapSetKeyType> = Readonly<{
|
|
|
125
125
|
// Reducing a value
|
|
126
126
|
|
|
127
127
|
/**
|
|
128
|
-
* Checks if all elements in the map satisfy a predicate. Also supports a
|
|
129
|
-
*
|
|
128
|
+
* Checks if all elements in the map satisfy a predicate. Also supports a type
|
|
129
|
+
* predicate overload that narrows the type of values in the map if the
|
|
130
130
|
* predicate returns true for all elements.
|
|
131
131
|
*
|
|
132
132
|
* @example
|
package/src/collections/imap.mts
CHANGED
|
@@ -96,8 +96,8 @@ type IMapInterface<K extends MapSetKeyType, V> = Readonly<{
|
|
|
96
96
|
// Reducing a value
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
* Checks if all elements in the map satisfy a predicate. Also supports a
|
|
100
|
-
*
|
|
99
|
+
* Checks if all elements in the map satisfy a predicate. Also supports a type
|
|
100
|
+
* predicate overload that narrows the type of values in the map if the
|
|
101
101
|
* predicate returns true for all elements.
|
|
102
102
|
*
|
|
103
103
|
* @example
|
|
@@ -656,8 +656,7 @@ export namespace IMap {
|
|
|
656
656
|
*
|
|
657
657
|
* Two IMaps are considered equal if they have the same size and contain
|
|
658
658
|
* exactly the same key-value pairs. The order of entries does not matter for
|
|
659
|
-
* equality comparison. Values are compared using JavaScript's `===`
|
|
660
|
-
* operator.
|
|
659
|
+
* equality comparison. Values are compared using JavaScript's `===` operator.
|
|
661
660
|
*
|
|
662
661
|
* **Performance:** O(n) where n is the size of the smaller map.
|
|
663
662
|
*
|
|
@@ -138,8 +138,7 @@ type ISetMappedInterface<K, KM extends MapSetKeyType> = Readonly<{
|
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
140
|
* Checks if all elements in the set satisfy a type predicate. Narrows the
|
|
141
|
-
* type of elements in the set if the predicate returns true for all
|
|
142
|
-
* elements.
|
|
141
|
+
* type of elements in the set if the predicate returns true for all elements.
|
|
143
142
|
*
|
|
144
143
|
*
|
|
145
144
|
* @example
|
package/src/collections/iset.mts
CHANGED
|
@@ -89,9 +89,9 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
|
|
|
89
89
|
// Reducing a value
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
|
-
* Checks if all elements in the set satisfy a predicate. Also supports a
|
|
93
|
-
*
|
|
94
|
-
*
|
|
92
|
+
* Checks if all elements in the set satisfy a predicate. Also supports a type
|
|
93
|
+
* predicate overload that narrows the type of elements in the set if the
|
|
94
|
+
* predicate returns true for all elements.
|
|
95
95
|
*
|
|
96
96
|
* @example
|
|
97
97
|
*
|
|
@@ -539,8 +539,7 @@ export namespace ISet {
|
|
|
539
539
|
*
|
|
540
540
|
* This factory function accepts any iterable of elements, including arrays,
|
|
541
541
|
* JavaScript Sets, other ISets, or custom iterables. Duplicate elements in
|
|
542
|
-
* the input iterable will be automatically deduplicated in the resulting
|
|
543
|
-
* set.
|
|
542
|
+
* the input iterable will be automatically deduplicated in the resulting set.
|
|
544
543
|
*
|
|
545
544
|
* **Performance:** O(n) where n is the number of elements in the iterable.
|
|
546
545
|
*
|
package/src/number/num.mts
CHANGED
|
@@ -120,8 +120,8 @@ export namespace Num {
|
|
|
120
120
|
*
|
|
121
121
|
* assert.strictEqual(Result.unwrapOk(Num.safeParseInt(' ')), undefined);
|
|
122
122
|
*
|
|
123
|
-
* // A value that overflows to Infinity is not an integer either, even
|
|
124
|
-
* //
|
|
123
|
+
* // A value that overflows to Infinity is not an integer either, even though
|
|
124
|
+
* // native `parseInt` reads a 1 out of it.
|
|
125
125
|
*
|
|
126
126
|
* assert.strictEqual(Number.parseInt('1e400', 10), 1);
|
|
127
127
|
*
|
|
@@ -135,10 +135,10 @@ export namespace Num {
|
|
|
135
135
|
*/
|
|
136
136
|
export const safeParseInt = (s: string): Result<Int, Error> =>
|
|
137
137
|
// The parsing itself is `SafeNumber.parseInteger` (Sumi D-49 (c)): one
|
|
138
|
-
// implementation, in the package that owns the standard-library
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
138
|
+
// implementation, in the package that owns the standard-library boundary.
|
|
139
|
+
// What stays here is this function's own contract — the `Int` brand on the
|
|
140
|
+
// success side, and an `Error` rather than a tagged record on the failure
|
|
141
|
+
// side.
|
|
142
142
|
Result.match(SafeNumber.parseInteger(s), {
|
|
143
143
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
144
144
|
ok: (n) => Result.ok(n as Int),
|
|
@@ -213,10 +213,10 @@ export namespace Num {
|
|
|
213
213
|
*/
|
|
214
214
|
export const safeParseFloat = (s: string): Result<FiniteNumber, Error> =>
|
|
215
215
|
// The parsing itself is `SafeNumber.parse` (Sumi D-49 (c)): one
|
|
216
|
-
// implementation, in the package that owns the standard-library
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
216
|
+
// implementation, in the package that owns the standard-library boundary.
|
|
217
|
+
// What stays here is this function's own contract — the `FiniteNumber`
|
|
218
|
+
// brand on the success side, and an `Error` rather than a tagged record on
|
|
219
|
+
// the failure side.
|
|
220
220
|
Result.match(SafeNumber.parse(s), {
|
|
221
221
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
222
222
|
ok: (n) => Result.ok(n as FiniteNumber),
|
package/src/object/object.mts
CHANGED
|
@@ -337,8 +337,8 @@ export namespace Obj {
|
|
|
337
337
|
* This is what `Object.fromEntries(Object.entries(record).map(...))` cannot
|
|
338
338
|
* express: an entries array carries no evidence that it still covers every
|
|
339
339
|
* key of the record it came from, so its element type is all the return type
|
|
340
|
-
* can be built from. Going through a mapped type instead states the
|
|
341
|
-
*
|
|
340
|
+
* can be built from. Going through a mapped type instead states the invariant
|
|
341
|
+
* that a value-only transform preserves the key set.
|
|
342
342
|
*
|
|
343
343
|
* **Key handling**: keys reach the callback the way `Object.entries` yields
|
|
344
344
|
* them, so a numeric key `1` arrives as `'1'`. Symbol-keyed properties are
|
|
@@ -67,12 +67,20 @@ export const fastDeepEqual = <T,>(a: T, b: T): boolean => {
|
|
|
67
67
|
return isRegExp(b) && a.source === b.source && a.flags === b.flags;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
// A null-prototype object (`Object.create(null)`, `Object.groupBy`) has
|
|
71
|
+
// neither method, so it falls through to the key comparison.
|
|
72
|
+
if (
|
|
73
|
+
typeof a.valueOf === 'function' &&
|
|
74
|
+
a.valueOf !== Object.prototype.valueOf
|
|
75
|
+
) {
|
|
76
|
+
return typeof b.valueOf === 'function' && a.valueOf() === b.valueOf();
|
|
72
77
|
}
|
|
73
78
|
|
|
74
|
-
if (
|
|
75
|
-
|
|
79
|
+
if (
|
|
80
|
+
typeof a.toString === 'function' &&
|
|
81
|
+
a.toString !== Object.prototype.toString
|
|
82
|
+
) {
|
|
83
|
+
return typeof b.toString === 'function' && a.toString() === b.toString();
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
const aKeys: readonly string[] = Object.keys(a);
|
|
@@ -84,12 +92,11 @@ export const fastDeepEqual = <T,>(a: T, b: T): boolean => {
|
|
|
84
92
|
aKeys.every(
|
|
85
93
|
(key) =>
|
|
86
94
|
hasKey(b, key) &&
|
|
87
|
-
// React-specific:
|
|
88
|
-
//
|
|
89
|
-
// and is not
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
fastDeepEqual(a[key], b[key]),
|
|
95
|
+
// React-specific: a React element (marked by a symbol `$$typeof`)
|
|
96
|
+
// has its _owner skipped, i.e. treated as equal. It holds circular
|
|
97
|
+
// references and is not part of what the element renders.
|
|
98
|
+
((key === '_owner' && typeof a['$$typeof'] === 'symbol') ||
|
|
99
|
+
fastDeepEqual(a[key], b[key])),
|
|
93
100
|
)
|
|
94
101
|
);
|
|
95
102
|
}
|
|
@@ -203,6 +203,18 @@ describe(fastDeepEqual, () => {
|
|
|
203
203
|
y: { toString: () => 'Hello world!' } as any,
|
|
204
204
|
expected: '=',
|
|
205
205
|
},
|
|
206
|
+
{
|
|
207
|
+
name: 'objects whose own `valueOf` and `toString` are not functions are compared by key',
|
|
208
|
+
x: { valueOf: 1, toString: 'a' } as any,
|
|
209
|
+
y: { valueOf: 1, toString: 'a' } as any,
|
|
210
|
+
expected: '=',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: 'objects whose own `valueOf` that is not a function differs are not equal',
|
|
214
|
+
x: { valueOf: 1 } as any,
|
|
215
|
+
y: { valueOf: 2 } as any,
|
|
216
|
+
expected: '!=',
|
|
217
|
+
},
|
|
206
218
|
{
|
|
207
219
|
name: 'objects with `toString` functions returning different values are not equal',
|
|
208
220
|
x: { toString: () => 'Hello world!' } as any,
|
|
@@ -212,6 +224,54 @@ describe(fastDeepEqual, () => {
|
|
|
212
224
|
] as const satisfies readonly TestCase[])('$name', testFn);
|
|
213
225
|
});
|
|
214
226
|
|
|
227
|
+
describe('null-prototype objects', () => {
|
|
228
|
+
const withNullPrototype = (
|
|
229
|
+
entries: ReadonlyRecord<string, unknown>,
|
|
230
|
+
): unknown => Object.setPrototypeOf({ ...entries }, null);
|
|
231
|
+
|
|
232
|
+
const groupByParity = (xs: readonly number[]): unknown =>
|
|
233
|
+
Object.groupBy(xs, (x) => (x % 2 === 0 ? 'even' : 'odd'));
|
|
234
|
+
|
|
235
|
+
test.each([
|
|
236
|
+
{
|
|
237
|
+
name: 'empty null-prototype objects are equal',
|
|
238
|
+
x: Object.create(null),
|
|
239
|
+
y: Object.create(null),
|
|
240
|
+
expected: '=',
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: 'null-prototype objects with the same entries are equal',
|
|
244
|
+
x: withNullPrototype({ a: 1, b: [2] }),
|
|
245
|
+
y: withNullPrototype({ a: 1, b: [2] }),
|
|
246
|
+
expected: '=',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: 'null-prototype objects with different entries are not equal',
|
|
250
|
+
x: withNullPrototype({ a: 1 }),
|
|
251
|
+
y: withNullPrototype({ a: 2 }),
|
|
252
|
+
expected: '!=',
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
name: 'a null-prototype object and a plain object are not equal',
|
|
256
|
+
x: Object.create(null),
|
|
257
|
+
y: {},
|
|
258
|
+
expected: '!=',
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: 'Object.groupBy results with the same groups are equal',
|
|
262
|
+
x: groupByParity([1, 2, 3]),
|
|
263
|
+
y: groupByParity([1, 2, 3]),
|
|
264
|
+
expected: '=',
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: 'Object.groupBy results with different groups are not equal',
|
|
268
|
+
x: groupByParity([1, 2, 3]),
|
|
269
|
+
y: groupByParity([1, 2, 4]),
|
|
270
|
+
expected: '!=',
|
|
271
|
+
},
|
|
272
|
+
] as const satisfies readonly TestCase[])('$name', testFn);
|
|
273
|
+
});
|
|
274
|
+
|
|
215
275
|
describe('arrays', () => {
|
|
216
276
|
test.each([
|
|
217
277
|
{ name: 'two empty arrays are equal', x: [], y: [], expected: '=' },
|
|
@@ -382,13 +442,13 @@ describe(fastDeepEqual, () => {
|
|
|
382
442
|
test.each([
|
|
383
443
|
{
|
|
384
444
|
name: 'empty maps are equal',
|
|
385
|
-
x: new Map(),
|
|
386
|
-
y: new Map(),
|
|
445
|
+
x: new Map<unknown, unknown>(),
|
|
446
|
+
y: new Map<unknown, unknown>(),
|
|
387
447
|
expected: '=',
|
|
388
448
|
},
|
|
389
449
|
{
|
|
390
450
|
name: 'empty maps of different class are not equal',
|
|
391
|
-
x: new Map(),
|
|
451
|
+
x: new Map<unknown, unknown>(),
|
|
392
452
|
y: new MyMap(),
|
|
393
453
|
expected: '!=',
|
|
394
454
|
},
|
|
@@ -436,32 +496,44 @@ describe(fastDeepEqual, () => {
|
|
|
436
496
|
},
|
|
437
497
|
{
|
|
438
498
|
name: 'equal maps (same sub-keys)',
|
|
439
|
-
x: new Map
|
|
440
|
-
|
|
499
|
+
x: new Map<string, readonly ReadonlyMap<unknown, string>[]>([
|
|
500
|
+
['a', [createMap({ b: 'c' })]],
|
|
501
|
+
]),
|
|
502
|
+
y: new Map<string, readonly ReadonlyMap<unknown, string>[]>([
|
|
503
|
+
['a', [createMap({ b: 'c' })]],
|
|
504
|
+
]),
|
|
441
505
|
expected: '=',
|
|
442
506
|
},
|
|
443
507
|
{
|
|
444
508
|
name: 'not equal maps (different sub-key value)',
|
|
445
|
-
x: new Map
|
|
446
|
-
|
|
509
|
+
x: new Map<string, readonly ReadonlyMap<unknown, string>[]>([
|
|
510
|
+
['a', [createMap({ b: 'c' })]],
|
|
511
|
+
]),
|
|
512
|
+
y: new Map<string, readonly ReadonlyMap<unknown, string>[]>([
|
|
513
|
+
['a', [createMap({ b: 'd' })]],
|
|
514
|
+
]),
|
|
447
515
|
expected: '!=',
|
|
448
516
|
},
|
|
449
517
|
{
|
|
450
518
|
name: 'not equal maps (different sub-key)',
|
|
451
|
-
x: new Map
|
|
452
|
-
|
|
519
|
+
x: new Map<string, readonly ReadonlyMap<unknown, string>[]>([
|
|
520
|
+
['a', [createMap({ b: 'c' })]],
|
|
521
|
+
]),
|
|
522
|
+
y: new Map<string, readonly ReadonlyMap<unknown, string>[]>([
|
|
523
|
+
['a', [createMap({ c: 'c' })]],
|
|
524
|
+
]),
|
|
453
525
|
expected: '!=',
|
|
454
526
|
},
|
|
455
527
|
{
|
|
456
528
|
name: 'empty map and empty object are equal',
|
|
457
529
|
x: {},
|
|
458
|
-
y: new Map(),
|
|
530
|
+
y: new Map<unknown, unknown>(),
|
|
459
531
|
expected: '!=',
|
|
460
532
|
},
|
|
461
533
|
{
|
|
462
534
|
name: 'empty map and empty array are not equal',
|
|
463
535
|
x: [],
|
|
464
|
-
y: new Map(),
|
|
536
|
+
y: new Map<unknown, unknown>(),
|
|
465
537
|
expected: '!=',
|
|
466
538
|
},
|
|
467
539
|
{
|
|
@@ -514,13 +586,13 @@ describe(fastDeepEqual, () => {
|
|
|
514
586
|
test.each([
|
|
515
587
|
{
|
|
516
588
|
name: 'empty sets are equal',
|
|
517
|
-
x: new Set(),
|
|
518
|
-
y: new Set(),
|
|
589
|
+
x: new Set<unknown>(),
|
|
590
|
+
y: new Set<unknown>(),
|
|
519
591
|
expected: '=',
|
|
520
592
|
},
|
|
521
593
|
{
|
|
522
594
|
name: 'empty sets of different class are not equal',
|
|
523
|
-
x: new Set(),
|
|
595
|
+
x: new Set<unknown>(),
|
|
524
596
|
y: new MySet(),
|
|
525
597
|
expected: '!=',
|
|
526
598
|
},
|
|
@@ -575,13 +647,13 @@ describe(fastDeepEqual, () => {
|
|
|
575
647
|
{
|
|
576
648
|
name: 'empty set and empty object are not equal',
|
|
577
649
|
x: {},
|
|
578
|
-
y: new Set(),
|
|
650
|
+
y: new Set<unknown>(),
|
|
579
651
|
expected: '!=',
|
|
580
652
|
},
|
|
581
653
|
{
|
|
582
654
|
name: 'empty set and empty array are not equal',
|
|
583
655
|
x: [],
|
|
584
|
-
y: new Set(),
|
|
656
|
+
y: new Set<unknown>(),
|
|
585
657
|
expected: '!=',
|
|
586
658
|
},
|
|
587
659
|
{
|
|
@@ -598,7 +670,7 @@ describe(fastDeepEqual, () => {
|
|
|
598
670
|
},
|
|
599
671
|
{
|
|
600
672
|
name: 'set and pseudo set are not equal',
|
|
601
|
-
x: new Set(),
|
|
673
|
+
x: new Set<unknown>(),
|
|
602
674
|
y: {
|
|
603
675
|
constructor: Set,
|
|
604
676
|
size: 0,
|
|
@@ -702,15 +774,58 @@ describe(fastDeepEqual, () => {
|
|
|
702
774
|
'content',
|
|
703
775
|
);
|
|
704
776
|
|
|
705
|
-
|
|
706
|
-
// fastDeepEqual should skip _owner comparison and not cause infinite loop
|
|
707
|
-
// The result depends on whether other properties are equal
|
|
708
|
-
const result = fastDeepEqualUntyped(element1, element2);
|
|
709
|
-
|
|
710
|
-
// The important thing is that it doesn't throw or hang
|
|
711
|
-
assert.isBoolean(result);
|
|
777
|
+
assert.isTrue(fastDeepEqualUntyped(element1, element2));
|
|
712
778
|
});
|
|
713
779
|
|
|
780
|
+
test.each([
|
|
781
|
+
{
|
|
782
|
+
name: 'element-shaped objects with different _owner are equal',
|
|
783
|
+
x: {
|
|
784
|
+
$$typeof: Symbol.for('react.element'),
|
|
785
|
+
type: 'div',
|
|
786
|
+
key: null,
|
|
787
|
+
props: { className: 'x' },
|
|
788
|
+
_owner: { name: 'A' },
|
|
789
|
+
},
|
|
790
|
+
y: {
|
|
791
|
+
$$typeof: Symbol.for('react.element'),
|
|
792
|
+
type: 'div',
|
|
793
|
+
key: null,
|
|
794
|
+
props: { className: 'x' },
|
|
795
|
+
_owner: { name: 'B' },
|
|
796
|
+
},
|
|
797
|
+
expected: '=',
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: 'element-shaped objects with different props are not equal',
|
|
801
|
+
x: {
|
|
802
|
+
$$typeof: Symbol.for('react.element'),
|
|
803
|
+
type: 'div',
|
|
804
|
+
props: { className: 'x' },
|
|
805
|
+
_owner: null,
|
|
806
|
+
},
|
|
807
|
+
y: {
|
|
808
|
+
$$typeof: Symbol.for('react.element'),
|
|
809
|
+
type: 'div',
|
|
810
|
+
props: { className: 'y' },
|
|
811
|
+
_owner: null,
|
|
812
|
+
},
|
|
813
|
+
expected: '!=',
|
|
814
|
+
},
|
|
815
|
+
{
|
|
816
|
+
name: '_owner is compared on an object without $$typeof',
|
|
817
|
+
x: { _owner: { name: 'A' } },
|
|
818
|
+
y: { _owner: { name: 'B' } },
|
|
819
|
+
expected: '!=',
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
name: '_owner is compared when $$typeof is falsy',
|
|
823
|
+
x: { $$typeof: null, _owner: { name: 'A' } },
|
|
824
|
+
y: { $$typeof: null, _owner: { name: 'B' } },
|
|
825
|
+
expected: '!=',
|
|
826
|
+
},
|
|
827
|
+
] as const satisfies readonly TestCase[])('$name', testFn);
|
|
828
|
+
|
|
714
829
|
test('React elements with different props are not equal', () => {
|
|
715
830
|
const element1 = React.createElement('div', { className: 'test1' });
|
|
716
831
|
|
|
@@ -747,9 +862,7 @@ describe(fastDeepEqual, () => {
|
|
|
747
862
|
child.render();
|
|
748
863
|
}
|
|
749
864
|
|
|
750
|
-
|
|
751
|
-
// The important thing is it doesn't throw or hang
|
|
752
|
-
assert.isTrue(mut_renderCount >= 1);
|
|
865
|
+
assert.strictEqual(mut_renderCount, 1);
|
|
753
866
|
|
|
754
867
|
// Update with different props - should re-render
|
|
755
868
|
const differentProps = {
|
|
@@ -763,8 +876,7 @@ describe(fastDeepEqual, () => {
|
|
|
763
876
|
child.render();
|
|
764
877
|
}
|
|
765
878
|
|
|
766
|
-
|
|
767
|
-
assert.isTrue(mut_renderCount >= 2);
|
|
879
|
+
assert.strictEqual(mut_renderCount, 2);
|
|
768
880
|
});
|
|
769
881
|
});
|
|
770
882
|
});
|
package/src/others/index.mts
CHANGED