@superhero/deep 4.4.0 → 4.5.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/README.md +111 -71
- package/equal.js +31 -0
- package/equal.test.js +62 -0
- package/index.js +3 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -134,7 +134,33 @@ console.log(result)
|
|
|
134
134
|
|
|
135
135
|
---
|
|
136
136
|
|
|
137
|
-
## 6. **
|
|
137
|
+
## 6. **DeepEqual**
|
|
138
|
+
|
|
139
|
+
### Purpose:
|
|
140
|
+
Performs a deep equal compare between two values. Supports objects, arrays, and nested structures, and handles circular references. Values are strictly compared by default.
|
|
141
|
+
|
|
142
|
+
### Features:
|
|
143
|
+
- Compares first and second argument - returns a boolean.
|
|
144
|
+
- Can perform a loose compare by passing a false third argument.
|
|
145
|
+
|
|
146
|
+
### Example:
|
|
147
|
+
```javascript
|
|
148
|
+
import deepequal from '@superhero/deep/equal'
|
|
149
|
+
|
|
150
|
+
const a = { foo: { bar: 1 }, arr: [1, 2, 3] }
|
|
151
|
+
const b = { foo: { bar: 1 }, arr: [1, 2, 3] }
|
|
152
|
+
const c = { foo: { bar: 1 }, arr: ['1', '2', '3'] }
|
|
153
|
+
|
|
154
|
+
deepequal(a, b) // true
|
|
155
|
+
deepequal(a, c) // false
|
|
156
|
+
deepequal(a, c, false) // true
|
|
157
|
+
deepequal(a, b, false) // true
|
|
158
|
+
deepequal(a, b, c) // throws AssertionError
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 7. **Deep**
|
|
138
164
|
|
|
139
165
|
### Purpose:
|
|
140
166
|
Makes the functions accessible through the imported default object.
|
|
@@ -149,6 +175,7 @@ import deep from '@superhero/deep'
|
|
|
149
175
|
|
|
150
176
|
deep.assign(/* ... */)
|
|
151
177
|
deep.clone(/* ... */)
|
|
178
|
+
deep.equal(/* ... */)
|
|
152
179
|
deep.freeze(/* ... */)
|
|
153
180
|
deep.intersect(/* ... */)
|
|
154
181
|
deep.merge(/* ... */)
|
|
@@ -156,10 +183,11 @@ deep.merge(/* ... */)
|
|
|
156
183
|
|
|
157
184
|
### Example:
|
|
158
185
|
```javascript
|
|
159
|
-
import { assign, clone, freeze, intersect, merge } from '@superhero/deep'
|
|
186
|
+
import { assign, clone, equal, freeze, intersect, merge } from '@superhero/deep'
|
|
160
187
|
|
|
161
188
|
assign(/* ... */)
|
|
162
189
|
clone(/* ... */)
|
|
190
|
+
equal(/* ... */)
|
|
163
191
|
freeze(/* ... */)
|
|
164
192
|
intersect(/* ... */)
|
|
165
193
|
merge(/* ... */)
|
|
@@ -180,103 +208,115 @@ npm test
|
|
|
180
208
|
|
|
181
209
|
```
|
|
182
210
|
▶ @superhero/deep/assign
|
|
183
|
-
✔ Assigns arrays correctly (
|
|
184
|
-
✔ Assigns objects correctly (0.
|
|
185
|
-
✔ Overwrites non-object properties correctly (
|
|
186
|
-
✔ Handles undefined values correctly (
|
|
187
|
-
|
|
211
|
+
✔ Assigns arrays correctly (2.973718ms)
|
|
212
|
+
✔ Assigns objects correctly (0.70144ms)
|
|
213
|
+
✔ Overwrites non-object properties correctly (0.318183ms)
|
|
214
|
+
✔ Handles undefined values correctly (1.009161ms)
|
|
188
215
|
▶ Descriptor properties
|
|
189
216
|
▶ Retains
|
|
190
|
-
✔ non-writable, non-configurable and non-enumarable (0.
|
|
191
|
-
✔ writable but non-configurable and non-enumarable (0.
|
|
192
|
-
✔ writable and configurable but non-enumarable (0.
|
|
193
|
-
✔ Retains (
|
|
194
|
-
|
|
217
|
+
✔ non-writable, non-configurable and non-enumarable (0.479579ms)
|
|
218
|
+
✔ writable but non-configurable and non-enumarable (0.466066ms)
|
|
219
|
+
✔ writable and configurable but non-enumarable (0.309409ms)
|
|
220
|
+
✔ Retains (1.735145ms)
|
|
221
|
+
|
|
195
222
|
▶ Assigns
|
|
196
|
-
✔ non-writable, non-configurable and non-enumarable (0.
|
|
197
|
-
✔ Assigns (0.
|
|
198
|
-
✔ Descriptor properties (3.
|
|
199
|
-
|
|
200
|
-
✔ Merges nested
|
|
201
|
-
✔
|
|
202
|
-
|
|
203
|
-
✔ @superhero/deep/assign (20.322649ms)
|
|
223
|
+
✔ non-writable, non-configurable and non-enumarable (0.384251ms)
|
|
224
|
+
✔ Assigns (0.73481ms)
|
|
225
|
+
✔ Descriptor properties (3.130721ms)
|
|
226
|
+
✔ Merges nested arrays correctly (2.917128ms)
|
|
227
|
+
✔ Merges nested objects correctly (0.937044ms)
|
|
228
|
+
✔ Does not alter objects with no conflicts (0.274969ms)
|
|
229
|
+
✔ @superhero/deep/assign (15.154613ms)
|
|
204
230
|
|
|
205
231
|
▶ @superhero/deep/clone
|
|
206
|
-
✔ Clones simple objects (
|
|
207
|
-
✔ Clones nested objects (0.
|
|
208
|
-
✔
|
|
209
|
-
✔
|
|
210
|
-
✔
|
|
211
|
-
✔ Clones
|
|
212
|
-
✔
|
|
232
|
+
✔ Clones simple objects (3.281531ms)
|
|
233
|
+
✔ Clones nested objects (0.470928ms)
|
|
234
|
+
✔ Do not preserves descriptors (0.56486ms)
|
|
235
|
+
✔ Preserves descriptors (0.547388ms)
|
|
236
|
+
✔ Does not preserve frozen object state (1.833744ms)
|
|
237
|
+
✔ Clones arrays (0.707413ms)
|
|
238
|
+
✔ Handles circular references (0.320116ms)
|
|
239
|
+
✔ Clones objects with null prototype (0.620148ms)
|
|
240
|
+
✔ @superhero/deep/clone (12.239426ms)
|
|
241
|
+
|
|
242
|
+
▶ @superhero/deep/equal
|
|
243
|
+
✔ Strict equality: same values, same types (5.24189ms)
|
|
244
|
+
✔ Strict equality: fails on type mismatch (0.422575ms)
|
|
245
|
+
✔ Loose equality: same values, different types (0.457711ms)
|
|
246
|
+
✔ Loose equality: different values (1.583009ms)
|
|
247
|
+
✔ Deep equality with nested structure (0.678751ms)
|
|
248
|
+
✔ Fails on missing property (0.721941ms)
|
|
249
|
+
✔ Validates third argument is boolean (2.323427ms)
|
|
250
|
+
✔ @superhero/deep/equal (13.789463ms)
|
|
213
251
|
|
|
214
252
|
▶ @superhero/deep/freeze
|
|
215
|
-
✔ Freezes a simple object (
|
|
216
|
-
✔ Freezes nested objects recursively (0.
|
|
217
|
-
✔ Handles circular references gracefully (
|
|
218
|
-
✔ Freezes objects with symbols (0.
|
|
219
|
-
✔ Handles already frozen objects without error (0.
|
|
220
|
-
✔ Freezes objects with non-enumerable properties (0.
|
|
221
|
-
✔ Freezes arrays (0.
|
|
222
|
-
✔ Handles objects with null prototype (0.
|
|
223
|
-
✔ Freezes objects with multiple property types (0.
|
|
224
|
-
✔ @superhero/deep/freeze (
|
|
253
|
+
✔ Freezes a simple object (3.92657ms)
|
|
254
|
+
✔ Freezes nested objects recursively (0.371321ms)
|
|
255
|
+
✔ Handles circular references gracefully (1.267506ms)
|
|
256
|
+
✔ Freezes objects with symbols (0.444381ms)
|
|
257
|
+
✔ Handles already frozen objects without error (0.930388ms)
|
|
258
|
+
✔ Freezes objects with non-enumerable properties (0.455779ms)
|
|
259
|
+
✔ Freezes arrays (0.477364ms)
|
|
260
|
+
✔ Handles objects with null prototype (0.536402ms)
|
|
261
|
+
✔ Freezes objects with multiple property types (0.776249ms)
|
|
262
|
+
✔ @superhero/deep/freeze (15.887295ms)
|
|
225
263
|
|
|
226
264
|
▶ @superhero/deep
|
|
227
|
-
✔ All functions are accessible as a member to the default import object (1.
|
|
228
|
-
✔ All functions are accessible to import from the default import object (0.
|
|
229
|
-
✔ @superhero/deep (
|
|
265
|
+
✔ All functions are accessible as a member to the default import object (1.711564ms)
|
|
266
|
+
✔ All functions are accessible to import from the default import object (0.375857ms)
|
|
267
|
+
✔ @superhero/deep (4.37013ms)
|
|
230
268
|
|
|
231
269
|
▶ @superhero/deep/intersect
|
|
232
|
-
✔ Intersects arrays by value and position (5.
|
|
233
|
-
✔ Intersects nested arrays (0.
|
|
234
|
-
✔ Handles empty array intersection (0.
|
|
235
|
-
✔ Intersects objects with matching keys and values (
|
|
236
|
-
✔ Deeply intersects nested objects (0.
|
|
237
|
-
✔ Intersection stops at type mismatch (0.
|
|
238
|
-
✔ Throws on circular references (1.
|
|
239
|
-
✔ Intersects arrays with undefined positions (0.
|
|
240
|
-
✔ Handles intersection of primitive types (0.
|
|
241
|
-
✔ Returns undefined for non-intersecting primitives (
|
|
242
|
-
✔ Handles multiple sequential intersections (0.
|
|
243
|
-
✔ @superhero/deep/intersect (
|
|
270
|
+
✔ Intersects arrays by value and position (5.404912ms)
|
|
271
|
+
✔ Intersects nested arrays (0.367099ms)
|
|
272
|
+
✔ Handles empty array intersection (0.687107ms)
|
|
273
|
+
✔ Intersects objects with matching keys and values (2.015991ms)
|
|
274
|
+
✔ Deeply intersects nested objects (0.501549ms)
|
|
275
|
+
✔ Intersection stops at type mismatch (0.423998ms)
|
|
276
|
+
✔ Throws on circular references (1.079638ms)
|
|
277
|
+
✔ Intersects arrays with undefined positions (0.399501ms)
|
|
278
|
+
✔ Handles intersection of primitive types (0.576801ms)
|
|
279
|
+
✔ Returns undefined for non-intersecting primitives (2.684012ms)
|
|
280
|
+
✔ Handles multiple sequential intersections (0.511929ms)
|
|
281
|
+
✔ @superhero/deep/intersect (19.049326ms)
|
|
244
282
|
|
|
245
283
|
▶ @superhero/deep/merge
|
|
246
|
-
✔ Merges arrays with unique values (4.
|
|
247
|
-
✔ Merges arrays with order preserved (0.
|
|
248
|
-
✔ Handles empty arrays correctly (0.
|
|
249
|
-
✔ Handles arrays with duplicate values (0.
|
|
250
|
-
✔ Merges objects and prioritizes restrictive descriptors (
|
|
251
|
-
✔ Merges objects with non-enumerable properties (0.
|
|
252
|
-
✔ Handles nested object merging (0.
|
|
253
|
-
✔ Stops at circular references (0.
|
|
254
|
-
✔ Stops when nested and with circular references (1.
|
|
255
|
-
✔ Returns second value for non-object types (
|
|
256
|
-
✔ Handles multiple merges sequentially (
|
|
257
|
-
✔ @superhero/deep/merge (
|
|
258
|
-
|
|
259
|
-
tests
|
|
260
|
-
suites
|
|
261
|
-
pass
|
|
284
|
+
✔ Merges arrays with unique values (4.448622ms)
|
|
285
|
+
✔ Merges arrays with order preserved (0.439982ms)
|
|
286
|
+
✔ Handles empty arrays correctly (0.291365ms)
|
|
287
|
+
✔ Handles arrays with duplicate values (0.497621ms)
|
|
288
|
+
✔ Merges objects and prioritizes restrictive descriptors (3.844952ms)
|
|
289
|
+
✔ Merges objects with non-enumerable properties (0.710082ms)
|
|
290
|
+
✔ Handles nested object merging (0.412465ms)
|
|
291
|
+
✔ Stops at circular references (0.446904ms)
|
|
292
|
+
✔ Stops when nested and with circular references (1.003584ms)
|
|
293
|
+
✔ Returns second value for non-object types (3.370647ms)
|
|
294
|
+
✔ Handles multiple merges sequentially (10.429993ms)
|
|
295
|
+
✔ @superhero/deep/merge (37.960347ms)
|
|
296
|
+
|
|
297
|
+
tests 59
|
|
298
|
+
suites 10
|
|
299
|
+
pass 59
|
|
262
300
|
|
|
263
301
|
------------------------------------------------------------------------
|
|
264
302
|
file | line % | branch % | funcs % | uncovered lines
|
|
265
303
|
------------------------------------------------------------------------
|
|
266
304
|
assign.js | 97.80 | 96.15 | 100.00 | 15-16
|
|
267
305
|
assign.test.js | 100.00 | 100.00 | 100.00 |
|
|
268
|
-
clone.js |
|
|
306
|
+
clone.js | 89.47 | 83.33 | 100.00 | 27-28 87-94
|
|
269
307
|
clone.test.js | 100.00 | 100.00 | 100.00 |
|
|
308
|
+
equal.js | 87.10 | 85.71 | 100.00 | 26-29
|
|
309
|
+
equal.test.js | 100.00 | 100.00 | 100.00 |
|
|
270
310
|
freeze.js | 100.00 | 100.00 | 100.00 |
|
|
271
311
|
freeze.test.js | 100.00 | 100.00 | 100.00 |
|
|
272
312
|
index.js | 100.00 | 100.00 | 100.00 |
|
|
273
313
|
index.test.js | 100.00 | 100.00 | 100.00 |
|
|
274
|
-
intersect.js |
|
|
314
|
+
intersect.js | 95.15 | 91.67 | 100.00 | 70-71 97-98 146-149
|
|
275
315
|
intersect.test.js | 100.00 | 100.00 | 100.00 |
|
|
276
316
|
merge.js | 98.72 | 96.30 | 100.00 | 81-82
|
|
277
317
|
merge.test.js | 100.00 | 100.00 | 100.00 |
|
|
278
318
|
------------------------------------------------------------------------
|
|
279
|
-
all files | 98.
|
|
319
|
+
all files | 98.15 | 95.43 | 100.00 |
|
|
280
320
|
------------------------------------------------------------------------
|
|
281
321
|
```
|
|
282
322
|
|
package/equal.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import assert from 'node:assert'
|
|
2
|
+
import util from 'node:util'
|
|
3
|
+
|
|
4
|
+
export default function equal(a, b, strict = true)
|
|
5
|
+
{
|
|
6
|
+
assert.strictEqual(typeof strict, 'boolean', 'Third argument "loose" must be a boolean')
|
|
7
|
+
|
|
8
|
+
return strict
|
|
9
|
+
? util.isDeepStrictEqual(a, b)
|
|
10
|
+
: isDeepLooseEqual(a, b)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isDeepLooseEqual(a, b)
|
|
14
|
+
{
|
|
15
|
+
try
|
|
16
|
+
{
|
|
17
|
+
assert.deepEqual(a, b)
|
|
18
|
+
return true
|
|
19
|
+
}
|
|
20
|
+
catch(error)
|
|
21
|
+
{
|
|
22
|
+
if(error instanceof assert.AssertionError)
|
|
23
|
+
{
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
else
|
|
27
|
+
{
|
|
28
|
+
throw error
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
package/equal.test.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import assert from 'assert'
|
|
2
|
+
import { suite, test } from 'node:test'
|
|
3
|
+
import deepequal from './equal.js'
|
|
4
|
+
|
|
5
|
+
suite('@superhero/deep/equal', () =>
|
|
6
|
+
{
|
|
7
|
+
test('Strict equality: same values, same types', () =>
|
|
8
|
+
{
|
|
9
|
+
const a = { foo: 'bar', baz: 42 }
|
|
10
|
+
const b = { foo: 'bar', baz: 42 }
|
|
11
|
+
|
|
12
|
+
assert.strictEqual(deepequal(a, b), true)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('Strict equality: fails on type mismatch', () =>
|
|
16
|
+
{
|
|
17
|
+
const a = { foo: 'bar', baz: 42 }
|
|
18
|
+
const b = { foo: 'bar', baz: '42' }
|
|
19
|
+
|
|
20
|
+
assert.strictEqual(deepequal(a, b, true), false)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('Loose equality: same values, different types', () =>
|
|
24
|
+
{
|
|
25
|
+
const a = { foo: 'bar', baz: 42 }
|
|
26
|
+
const b = { foo: 'bar', baz: '42' }
|
|
27
|
+
|
|
28
|
+
assert.strictEqual(deepequal(a, b, false), true)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('Loose equality: different values', () =>
|
|
32
|
+
{
|
|
33
|
+
const a = { foo: 'bar', baz: 42 }
|
|
34
|
+
const b = { foo: 'bar', baz: 99 }
|
|
35
|
+
|
|
36
|
+
assert.strictEqual(deepequal(a, b, false), false)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('Deep equality with nested structure', () =>
|
|
40
|
+
{
|
|
41
|
+
const a = { foo: { bar: [1, 2] } }
|
|
42
|
+
const b = { foo: { bar: [1, 2] } }
|
|
43
|
+
|
|
44
|
+
assert.strictEqual(deepequal(a, b), true)
|
|
45
|
+
assert.strictEqual(deepequal(a, b, false), true)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('Fails on missing property', () =>
|
|
49
|
+
{
|
|
50
|
+
const a = { foo: 'bar', baz: 42 }
|
|
51
|
+
const b = { foo: 'bar' }
|
|
52
|
+
|
|
53
|
+
assert.strictEqual(deepequal(a, b), false)
|
|
54
|
+
assert.strictEqual(deepequal(a, b, false), false)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('Validates third argument is boolean', () =>
|
|
58
|
+
{
|
|
59
|
+
assert.throws(() => deepequal({}, {}, 'loose'),
|
|
60
|
+
{ name : 'AssertionError' })
|
|
61
|
+
})
|
|
62
|
+
})
|
package/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import assign from '@superhero/deep/assign'
|
|
2
2
|
import clone from '@superhero/deep/clone'
|
|
3
|
+
import equal from '@superhero/deep/equal'
|
|
3
4
|
import freeze from '@superhero/deep/freeze'
|
|
4
5
|
import intersect from '@superhero/deep/intersect'
|
|
5
6
|
import merge from '@superhero/deep/merge'
|
|
6
7
|
|
|
7
|
-
export { assign, clone, freeze, intersect, merge }
|
|
8
|
-
export default { assign, clone, freeze, intersect, merge }
|
|
8
|
+
export { assign, clone, equal, freeze, intersect, merge }
|
|
9
|
+
export default { assign, clone, equal, freeze, intersect, merge }
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superhero/deep",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "A collection of deep structure operations",
|
|
5
|
-
"keywords": ["deep", "assign", "clone", "freeze", "intersect", "merge"],
|
|
5
|
+
"keywords": ["deep", "assign", "clone", "equal", "freeze", "intersect", "merge"],
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"type": "module",
|