@tim-code/my-util 0.4.9 → 0.4.10
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/package.json +1 -1
- package/src/object.js +34 -0
- package/src/object.test.js +111 -1
package/package.json
CHANGED
package/src/object.js
CHANGED
|
@@ -89,3 +89,37 @@ export function deepMerge(target, ...sources) {
|
|
|
89
89
|
}
|
|
90
90
|
return target
|
|
91
91
|
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Deeply compares two values to determine if they are equal.
|
|
95
|
+
* Objects and arrays are compared recursively by their properties and elements.
|
|
96
|
+
* Primitives are compared with strict equality.
|
|
97
|
+
* Caveats:
|
|
98
|
+
* Does not check class: [1] is considered equal to {0: 1}.
|
|
99
|
+
* Any Symbol keys in the arguments are ignored (Object.keys only returns string keys).
|
|
100
|
+
* @param {any} a The first value to compare.
|
|
101
|
+
* @param {any} b The second value to compare.
|
|
102
|
+
* @returns {boolean} True if the values are deeply equal, false otherwise.
|
|
103
|
+
*/
|
|
104
|
+
export function deepEqual(a, b) {
|
|
105
|
+
if (a === b) {
|
|
106
|
+
return true
|
|
107
|
+
}
|
|
108
|
+
if (typeof a !== "object" || typeof b !== "object" || !a || !b) {
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
const keysA = Object.keys(a)
|
|
112
|
+
const keysB = Object.keys(b)
|
|
113
|
+
if (keysA.length !== keysB.length) {
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
for (const key of keysA) {
|
|
117
|
+
if (!Object.hasOwn(b, key)) {
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
if (!deepEqual(a[key], b[key])) {
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return true
|
|
125
|
+
}
|
package/src/object.test.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/* eslint-disable no-restricted-syntax */
|
|
2
2
|
import { jest } from "@jest/globals"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
deepEqual,
|
|
5
|
+
deepMerge,
|
|
6
|
+
deleteUndefinedValues,
|
|
7
|
+
like,
|
|
8
|
+
mutateValues,
|
|
9
|
+
via,
|
|
10
|
+
} from "./object.js"
|
|
4
11
|
|
|
5
12
|
describe("mutateValues", () => {
|
|
6
13
|
it("mutates values in the object using the callback", () => {
|
|
@@ -257,3 +264,106 @@ describe("deepMerge", () => {
|
|
|
257
264
|
expect(result).toBe(target)
|
|
258
265
|
})
|
|
259
266
|
})
|
|
267
|
+
|
|
268
|
+
describe("deepEqual", () => {
|
|
269
|
+
it("returns true for strictly equal primitives", () => {
|
|
270
|
+
expect(deepEqual(1, 1)).toBe(true)
|
|
271
|
+
expect(deepEqual("foo", "foo")).toBe(true)
|
|
272
|
+
expect(deepEqual(true, true)).toBe(true)
|
|
273
|
+
expect(deepEqual(null, null)).toBe(true)
|
|
274
|
+
expect(deepEqual(undefined, undefined)).toBe(true)
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it("returns false for different primitives", () => {
|
|
278
|
+
expect(deepEqual(1, 2)).toBe(false)
|
|
279
|
+
expect(deepEqual("foo", "bar")).toBe(false)
|
|
280
|
+
expect(deepEqual(true, false)).toBe(false)
|
|
281
|
+
expect(deepEqual(null, undefined)).toBe(false)
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it("returns true for deeply equal objects", () => {
|
|
285
|
+
expect(deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true)
|
|
286
|
+
expect(deepEqual({ a: { b: 2 } }, { a: { b: 2 } })).toBe(true)
|
|
287
|
+
expect(deepEqual({}, {})).toBe(true)
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
it("returns false for objects with different keys or values", () => {
|
|
291
|
+
expect(deepEqual({ a: 1 }, { a: 2 })).toBe(false)
|
|
292
|
+
expect(deepEqual({ a: 1 }, { b: 1 })).toBe(false)
|
|
293
|
+
expect(deepEqual({ a: 1 }, {})).toBe(false)
|
|
294
|
+
expect(deepEqual({}, { a: 1 })).toBe(false)
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it("returns true for deeply equal arrays", () => {
|
|
298
|
+
expect(deepEqual([1, 2, 3], [1, 2, 3])).toBe(true)
|
|
299
|
+
expect(deepEqual([], [])).toBe(true)
|
|
300
|
+
expect(deepEqual([[1], [2]], [[1], [2]])).toBe(true)
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
it("returns false for arrays with different elements or lengths", () => {
|
|
304
|
+
expect(deepEqual([1, 2], [1, 2, 3])).toBe(false)
|
|
305
|
+
expect(deepEqual([1, 2, 3], [1, 2])).toBe(false)
|
|
306
|
+
expect(deepEqual([1, 2, 3], [3, 2, 1])).toBe(false)
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
it("returns true if one is array and one is object", () => {
|
|
310
|
+
expect(deepEqual([1, 2], { 0: 1, 1: 2 })).toBe(true)
|
|
311
|
+
expect(deepEqual({ 0: 1, 1: 2 }, [1, 2])).toBe(true)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
it("returns true for objects with same keys in different order", () => {
|
|
315
|
+
expect(deepEqual({ a: 1, b: 2 }, { b: 2, a: 1 })).toBe(true)
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it("returns true for nested objects and arrays", () => {
|
|
319
|
+
const a = { foo: [1, { bar: 2 }], baz: { qux: [3] } }
|
|
320
|
+
const b = { foo: [1, { bar: 2 }], baz: { qux: [3] } }
|
|
321
|
+
expect(deepEqual(a, b)).toBe(true)
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
it("returns false for nested difference", () => {
|
|
325
|
+
const a = { foo: [1, { bar: 2 }], baz: { qux: [3] } }
|
|
326
|
+
const b = { foo: [1, { bar: 3 }], baz: { qux: [3] } }
|
|
327
|
+
expect(deepEqual(a, b)).toBe(false)
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it("returns false if keys differ in nested objects", () => {
|
|
331
|
+
expect(deepEqual({ a: { b: 1 } }, { a: { c: 1 } })).toBe(false)
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
it("returns false if one is null or undefined and the other is object", () => {
|
|
335
|
+
expect(deepEqual(null, {})).toBe(false)
|
|
336
|
+
expect(deepEqual({}, null)).toBe(false)
|
|
337
|
+
expect(deepEqual(undefined, {})).toBe(false)
|
|
338
|
+
expect(deepEqual({}, undefined)).toBe(false)
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
it("returns true for self-references (same object)", () => {
|
|
342
|
+
const obj = { a: 1 }
|
|
343
|
+
expect(deepEqual(obj, obj)).toBe(true)
|
|
344
|
+
const arr = [1, 2]
|
|
345
|
+
expect(deepEqual(arr, arr)).toBe(true)
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
it("returns false for objects with different number of keys", () => {
|
|
349
|
+
expect(deepEqual({ a: 1, b: 2 }, { a: 1 })).toBe(false)
|
|
350
|
+
expect(deepEqual({ a: 1 }, { a: 1, b: 2 })).toBe(false)
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it("returns true if object keys match but values are objects of different types", () => {
|
|
354
|
+
expect(deepEqual({ a: [1, 2] }, { a: { 0: 1, 1: 2 } })).toBe(true)
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it("returns false for objects with missing keys", () => {
|
|
358
|
+
expect(deepEqual({ a: 1, b: 2 }, { a: 1 })).toBe(false)
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
it("returns true for objects with undefined values if both have them", () => {
|
|
362
|
+
expect(deepEqual({ a: undefined }, { a: undefined })).toBe(true)
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
it("returns false if one object has undefined key and the other doesn't", () => {
|
|
366
|
+
expect(deepEqual({ a: undefined }, {})).toBe(false)
|
|
367
|
+
expect(deepEqual({}, { a: undefined })).toBe(false)
|
|
368
|
+
})
|
|
369
|
+
})
|