@domql/utils 3.1.2 → 3.2.7
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/array.js +11 -5
- package/cache.js +3 -0
- package/component.js +3 -4
- package/dist/cjs/array.js +11 -5
- package/dist/cjs/component.js +4 -6
- package/dist/cjs/element.js +6 -6
- package/dist/cjs/env.js +1 -1
- package/dist/cjs/events.js +3 -3
- package/dist/cjs/extends.js +44 -28
- package/dist/cjs/function.js +3 -3
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/key.js +2 -2
- package/dist/cjs/keys.js +29 -15
- package/dist/cjs/methods.js +88 -33
- package/dist/cjs/object.js +154 -141
- package/dist/cjs/props.js +43 -34
- package/dist/cjs/scope.js +1 -2
- package/dist/cjs/state.js +12 -11
- package/dist/cjs/string.js +15 -20
- package/dist/cjs/tags.js +71 -16
- package/dist/cjs/triggerEvent.js +90 -0
- package/dist/cjs/types.js +4 -12
- package/dist/esm/array.js +11 -5
- package/dist/esm/component.js +4 -6
- package/dist/esm/element.js +9 -27
- package/dist/esm/env.js +1 -1
- package/dist/esm/events.js +3 -3
- package/dist/esm/extends.js +48 -50
- package/dist/esm/function.js +3 -3
- package/dist/esm/index.js +1 -0
- package/dist/esm/key.js +2 -2
- package/dist/esm/keys.js +29 -15
- package/dist/esm/methods.js +86 -31
- package/dist/esm/object.js +158 -165
- package/dist/esm/props.js +43 -50
- package/dist/esm/scope.js +1 -2
- package/dist/esm/state.js +21 -38
- package/dist/esm/string.js +15 -20
- package/dist/esm/tags.js +71 -16
- package/dist/esm/triggerEvent.js +70 -0
- package/dist/esm/types.js +4 -12
- package/dist/iife/index.js +2779 -0
- package/element.js +2 -2
- package/events.js +3 -3
- package/extends.js +28 -17
- package/function.js +10 -9
- package/index.js +1 -0
- package/keys.js +25 -15
- package/log.js +0 -1
- package/methods.js +99 -24
- package/object.js +155 -215
- package/package.json +34 -13
- package/props.js +44 -27
- package/state.js +12 -12
- package/string.js +20 -38
- package/tags.js +45 -16
- package/triggerEvent.js +76 -0
- package/types.js +8 -25
- package/dist/cjs/package.json +0 -4
package/object.js
CHANGED
|
@@ -7,9 +7,7 @@ import {
|
|
|
7
7
|
isObject,
|
|
8
8
|
isArray,
|
|
9
9
|
isString,
|
|
10
|
-
is
|
|
11
|
-
isUndefined,
|
|
12
|
-
isNull
|
|
10
|
+
is
|
|
13
11
|
} from './types.js'
|
|
14
12
|
import { unstackArrayOfObjects } from './array.js'
|
|
15
13
|
import { stringIncludesAny } from './string.js'
|
|
@@ -18,26 +16,25 @@ import { METHODS_EXL } from './keys.js'
|
|
|
18
16
|
|
|
19
17
|
const ENV = process.env.NODE_ENV
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
if (isFunction(param)) {
|
|
23
|
-
return param.call(
|
|
24
|
-
element,
|
|
25
|
-
element,
|
|
26
|
-
state || element.state,
|
|
27
|
-
context || element.context
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
return param
|
|
31
|
-
}
|
|
19
|
+
const _startsWithDunder = e => e.charCodeAt(0) === 95 && e.charCodeAt(1) === 95
|
|
32
20
|
|
|
33
|
-
export const
|
|
21
|
+
export const exec = (param, element, state, context) => {
|
|
34
22
|
if (isFunction(param)) {
|
|
35
|
-
|
|
23
|
+
if (!element) return
|
|
24
|
+
const result = param.call(
|
|
36
25
|
element,
|
|
37
26
|
element,
|
|
38
27
|
state || element.state,
|
|
39
28
|
context || element.context
|
|
40
29
|
)
|
|
30
|
+
if (result && typeof result.then === 'function') {
|
|
31
|
+
let resolved
|
|
32
|
+
result.then(value => {
|
|
33
|
+
resolved = value
|
|
34
|
+
})
|
|
35
|
+
return resolved
|
|
36
|
+
}
|
|
37
|
+
return result
|
|
41
38
|
}
|
|
42
39
|
return param
|
|
43
40
|
}
|
|
@@ -49,26 +46,24 @@ export const map = (obj, extention, element) => {
|
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
export const merge = (element, obj, excludeFrom = []) => {
|
|
49
|
+
const useSet = excludeFrom instanceof Set
|
|
52
50
|
for (const e in obj) {
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const objProp = obj[e]
|
|
59
|
-
if (elementProp === undefined) {
|
|
60
|
-
element[e] = objProp
|
|
51
|
+
if (!Object.prototype.hasOwnProperty.call(obj, e)) continue
|
|
52
|
+
if (_startsWithDunder(e)) continue
|
|
53
|
+
if (useSet ? excludeFrom.has(e) : excludeFrom.includes(e)) continue
|
|
54
|
+
if (element[e] === undefined) {
|
|
55
|
+
element[e] = obj[e]
|
|
61
56
|
}
|
|
62
57
|
}
|
|
63
58
|
return element
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
export const deepMerge = (element, extend, excludeFrom = METHODS_EXL) => {
|
|
62
|
+
const useSet = excludeFrom instanceof Set
|
|
67
63
|
for (const e in extend) {
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
}
|
|
64
|
+
if (!Object.prototype.hasOwnProperty.call(extend, e)) continue
|
|
65
|
+
if (_startsWithDunder(e)) continue
|
|
66
|
+
if (useSet ? excludeFrom.has(e) : excludeFrom.includes(e)) continue
|
|
72
67
|
const elementProp = element[e]
|
|
73
68
|
const extendProp = extend[e]
|
|
74
69
|
if (isObjectLike(elementProp) && isObjectLike(extendProp)) {
|
|
@@ -81,16 +76,12 @@ export const deepMerge = (element, extend, excludeFrom = METHODS_EXL) => {
|
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
export const clone = (obj, excludeFrom = []) => {
|
|
79
|
+
const useSet = excludeFrom instanceof Set
|
|
84
80
|
const o = {}
|
|
85
81
|
for (const prop in obj) {
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
excludeFrom.includes(prop) ||
|
|
90
|
-
prop.startsWith('__')
|
|
91
|
-
) {
|
|
92
|
-
continue
|
|
93
|
-
}
|
|
82
|
+
if (!Object.prototype.hasOwnProperty.call(obj, prop)) continue
|
|
83
|
+
if (_startsWithDunder(prop)) continue
|
|
84
|
+
if (useSet ? excludeFrom.has(prop) : excludeFrom.includes(prop)) continue
|
|
94
85
|
o[prop] = obj[prop]
|
|
95
86
|
}
|
|
96
87
|
return o
|
|
@@ -118,6 +109,8 @@ export const deepClone = (obj, options = {}) => {
|
|
|
118
109
|
handleExtends = false
|
|
119
110
|
} = options
|
|
120
111
|
|
|
112
|
+
const contentWindow = targetWindow || window || globalThis
|
|
113
|
+
|
|
121
114
|
// Handle non-object types and special cases
|
|
122
115
|
if (!isObjectLike(obj) || isDOMNode(obj)) {
|
|
123
116
|
return obj
|
|
@@ -129,35 +122,28 @@ export const deepClone = (obj, options = {}) => {
|
|
|
129
122
|
}
|
|
130
123
|
|
|
131
124
|
// Create appropriate container based on type and window context
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
? new targetWindow.Array()
|
|
135
|
-
: new targetWindow.Object()
|
|
136
|
-
: isArray(obj)
|
|
137
|
-
? []
|
|
138
|
-
: {}
|
|
125
|
+
const isArr = isArray(obj)
|
|
126
|
+
const clone = isArr ? [] : {}
|
|
139
127
|
|
|
140
128
|
// Store the clone to handle circular references
|
|
141
129
|
visited.set(obj, clone)
|
|
142
130
|
|
|
131
|
+
// Convert exclude to Set for O(1) lookups when list is non-trivial
|
|
132
|
+
const excludeSet = exclude instanceof Set ? exclude : (exclude.length > 3 ? new Set(exclude) : null)
|
|
133
|
+
|
|
143
134
|
// Clone properties
|
|
144
135
|
for (const key in obj) {
|
|
145
136
|
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue
|
|
146
137
|
|
|
147
138
|
// Skip excluded properties
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
}
|
|
139
|
+
if (_startsWithDunder(key) || key === '__proto__') continue
|
|
140
|
+
if (excludeSet ? excludeSet.has(key) : exclude.includes(key)) continue
|
|
151
141
|
|
|
152
142
|
const value = obj[key]
|
|
153
143
|
|
|
154
144
|
// Skip based on cleanup options
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
(cleanNull && isNull(value))
|
|
158
|
-
) {
|
|
159
|
-
continue
|
|
160
|
-
}
|
|
145
|
+
if (cleanUndefined && value === undefined) continue
|
|
146
|
+
if (cleanNull && value === null) continue
|
|
161
147
|
|
|
162
148
|
// Handle special cases
|
|
163
149
|
if (isDOMNode(value)) {
|
|
@@ -172,8 +158,8 @@ export const deepClone = (obj, options = {}) => {
|
|
|
172
158
|
}
|
|
173
159
|
|
|
174
160
|
// Handle functions in cross-frame scenario
|
|
175
|
-
if (isFunction(value) &&
|
|
176
|
-
clone[key] =
|
|
161
|
+
if (isFunction(value) && options.window) {
|
|
162
|
+
clone[key] = contentWindow.eval('(' + value.toString() + ')')
|
|
177
163
|
continue
|
|
178
164
|
}
|
|
179
165
|
|
|
@@ -211,17 +197,18 @@ export const deepStringify = (obj, stringified = {}) => {
|
|
|
211
197
|
stringified[prop] = {}
|
|
212
198
|
deepStringify(objProp, stringified[prop])
|
|
213
199
|
} else if (isArray(objProp)) {
|
|
214
|
-
stringified[prop] = []
|
|
215
|
-
objProp.
|
|
200
|
+
const arr = stringified[prop] = []
|
|
201
|
+
for (let i = 0; i < objProp.length; i++) {
|
|
202
|
+
const v = objProp[i]
|
|
216
203
|
if (isObject(v)) {
|
|
217
|
-
|
|
218
|
-
deepStringify(v,
|
|
204
|
+
arr[i] = {}
|
|
205
|
+
deepStringify(v, arr[i])
|
|
219
206
|
} else if (isFunction(v)) {
|
|
220
|
-
|
|
207
|
+
arr[i] = v.toString()
|
|
221
208
|
} else {
|
|
222
|
-
|
|
209
|
+
arr[i] = v
|
|
223
210
|
}
|
|
224
|
-
}
|
|
211
|
+
}
|
|
225
212
|
} else {
|
|
226
213
|
stringified[prop] = objProp
|
|
227
214
|
}
|
|
@@ -229,38 +216,32 @@ export const deepStringify = (obj, stringified = {}) => {
|
|
|
229
216
|
return stringified
|
|
230
217
|
}
|
|
231
218
|
|
|
219
|
+
const OBJ_TO_STR_SPECIAL_CHARS = new Set([
|
|
220
|
+
'&', '*', '-', ':', '%', '{', '}', '>', '<', '@', '.', '/', '!', ' '
|
|
221
|
+
])
|
|
222
|
+
|
|
232
223
|
export const objectToString = (obj = {}, indent = 0) => {
|
|
233
224
|
// Handle empty object case
|
|
234
225
|
if (obj === null || typeof obj !== 'object') {
|
|
235
226
|
return String(obj)
|
|
236
227
|
}
|
|
237
228
|
|
|
238
|
-
// Handle empty object case
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
229
|
+
// Handle empty object case - avoid Object.keys allocation
|
|
230
|
+
let hasKeys = false
|
|
231
|
+
for (const _k in obj) { hasKeys = true; break } // eslint-disable-line
|
|
232
|
+
if (!hasKeys) return '{}'
|
|
242
233
|
|
|
243
234
|
const spaces = ' '.repeat(indent)
|
|
244
235
|
let str = '{\n'
|
|
245
236
|
|
|
246
|
-
for (const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
'}',
|
|
255
|
-
'>',
|
|
256
|
-
'<',
|
|
257
|
-
'@',
|
|
258
|
-
'.',
|
|
259
|
-
'/',
|
|
260
|
-
'!',
|
|
261
|
-
' '
|
|
262
|
-
])
|
|
263
|
-
const stringedKey = keyNotAllowdChars ? `'${key}'` : key
|
|
237
|
+
for (const key in obj) {
|
|
238
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue
|
|
239
|
+
const value = obj[key]
|
|
240
|
+
let keyNeedsQuotes = false
|
|
241
|
+
for (let i = 0; i < key.length; i++) {
|
|
242
|
+
if (OBJ_TO_STR_SPECIAL_CHARS.has(key[i])) { keyNeedsQuotes = true; break }
|
|
243
|
+
}
|
|
244
|
+
const stringedKey = keyNeedsQuotes ? `'${key}'` : key
|
|
264
245
|
str += `${spaces} ${stringedKey}: `
|
|
265
246
|
|
|
266
247
|
if (isArray(value)) {
|
|
@@ -292,44 +273,46 @@ export const objectToString = (obj = {}, indent = 0) => {
|
|
|
292
273
|
return str
|
|
293
274
|
}
|
|
294
275
|
|
|
276
|
+
const FN_PATTERNS = [
|
|
277
|
+
/^\(\s*\{[^}]*\}\s*\)\s*=>/,
|
|
278
|
+
/^(\([^)]*\)|[^=]*)\s*=>/,
|
|
279
|
+
/^function[\s(]/,
|
|
280
|
+
/^async\s+/,
|
|
281
|
+
/^\(\s*function/,
|
|
282
|
+
/^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=>/
|
|
283
|
+
]
|
|
284
|
+
const RE_JSON_LIKE = /^["[{]/
|
|
285
|
+
|
|
295
286
|
export const hasFunction = str => {
|
|
296
287
|
if (!str) return false
|
|
297
288
|
|
|
298
289
|
const trimmed = str.trim().replace(/\n\s*/g, ' ').trim()
|
|
299
290
|
|
|
300
|
-
if (trimmed === '') return false
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const isFunction = patterns.some(pattern => pattern.test(trimmed))
|
|
314
|
-
const isObjectLiteral = trimmed.startsWith('{') && !trimmed.includes('=>')
|
|
315
|
-
const isArrayLiteral = trimmed.startsWith('[')
|
|
316
|
-
const isJSONLike = /^["[{]/.test(trimmed) && !trimmed.includes('=>')
|
|
317
|
-
|
|
318
|
-
return isFunction && !isObjectLiteral && !isArrayLiteral && !isJSONLike
|
|
291
|
+
if (trimmed === '' || trimmed === '{}' || trimmed === '[]') return false
|
|
292
|
+
|
|
293
|
+
const isFn = FN_PATTERNS.some(pattern => pattern.test(trimmed))
|
|
294
|
+
if (!isFn) return false
|
|
295
|
+
|
|
296
|
+
const firstChar = trimmed.charCodeAt(0)
|
|
297
|
+
const hasArrow = trimmed.includes('=>')
|
|
298
|
+
// '{' = 123, '[' = 91
|
|
299
|
+
if (firstChar === 123 && !hasArrow) return false // object literal
|
|
300
|
+
if (firstChar === 91) return false // array literal
|
|
301
|
+
if (RE_JSON_LIKE.test(trimmed) && !hasArrow) return false
|
|
302
|
+
|
|
303
|
+
return true
|
|
319
304
|
}
|
|
320
305
|
|
|
321
306
|
export const deepDestringify = (obj, destringified = {}) => {
|
|
322
307
|
for (const prop in obj) {
|
|
323
|
-
|
|
324
|
-
if (!hasOwnProperty) continue
|
|
308
|
+
if (!Object.prototype.hasOwnProperty.call(obj, prop)) continue
|
|
325
309
|
|
|
326
310
|
const objProp = obj[prop]
|
|
327
311
|
|
|
328
312
|
if (isString(objProp)) {
|
|
329
313
|
if (hasFunction(objProp)) {
|
|
330
314
|
try {
|
|
331
|
-
|
|
332
|
-
destringified[prop] = evalProp
|
|
315
|
+
destringified[prop] = window.eval(`(${objProp})`)
|
|
333
316
|
} catch (e) {
|
|
334
317
|
if (e) destringified[prop] = objProp
|
|
335
318
|
}
|
|
@@ -337,25 +320,25 @@ export const deepDestringify = (obj, destringified = {}) => {
|
|
|
337
320
|
destringified[prop] = objProp
|
|
338
321
|
}
|
|
339
322
|
} else if (isArray(objProp)) {
|
|
340
|
-
destringified[prop] = []
|
|
341
|
-
objProp.
|
|
323
|
+
const arr = destringified[prop] = []
|
|
324
|
+
for (let i = 0; i < objProp.length; i++) {
|
|
325
|
+
const arrProp = objProp[i]
|
|
342
326
|
if (isString(arrProp)) {
|
|
343
327
|
if (hasFunction(arrProp)) {
|
|
344
328
|
try {
|
|
345
|
-
|
|
346
|
-
destringified[prop].push(evalProp)
|
|
329
|
+
arr.push(window.eval(`(${arrProp})`))
|
|
347
330
|
} catch (e) {
|
|
348
|
-
if (e)
|
|
331
|
+
if (e) arr.push(arrProp)
|
|
349
332
|
}
|
|
350
333
|
} else {
|
|
351
|
-
|
|
334
|
+
arr.push(arrProp)
|
|
352
335
|
}
|
|
353
336
|
} else if (isObject(arrProp)) {
|
|
354
|
-
|
|
337
|
+
arr.push(deepDestringify(arrProp))
|
|
355
338
|
} else {
|
|
356
|
-
|
|
339
|
+
arr.push(arrProp)
|
|
357
340
|
}
|
|
358
|
-
}
|
|
341
|
+
}
|
|
359
342
|
} else if (isObject(objProp)) {
|
|
360
343
|
destringified[prop] = deepDestringify(objProp, destringified[prop])
|
|
361
344
|
} else {
|
|
@@ -376,7 +359,10 @@ export const stringToObject = (str, opts = { verbose: true }) => {
|
|
|
376
359
|
export const hasOwnProperty = (o, ...args) =>
|
|
377
360
|
Object.prototype.hasOwnProperty.call(o, ...args)
|
|
378
361
|
|
|
379
|
-
export const isEmpty = o =>
|
|
362
|
+
export const isEmpty = o => {
|
|
363
|
+
for (const _ in o) return false // eslint-disable-line
|
|
364
|
+
return true
|
|
365
|
+
}
|
|
380
366
|
|
|
381
367
|
export const isEmptyObject = o => isObject(o) && isEmpty(o)
|
|
382
368
|
|
|
@@ -390,12 +376,9 @@ export const overwrite = (element, params, opts = {}) => {
|
|
|
390
376
|
const allowUnderscore = opts.preventUnderscore
|
|
391
377
|
|
|
392
378
|
for (const e in params) {
|
|
393
|
-
if (excl.includes(e) || (!allowUnderscore && e
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (paramsProp !== undefined) {
|
|
398
|
-
element[e] = paramsProp
|
|
379
|
+
if (excl.includes(e) || (!allowUnderscore && _startsWithDunder(e))) continue
|
|
380
|
+
if (params[e] !== undefined) {
|
|
381
|
+
element[e] = params[e]
|
|
399
382
|
}
|
|
400
383
|
}
|
|
401
384
|
|
|
@@ -403,8 +386,10 @@ export const overwrite = (element, params, opts = {}) => {
|
|
|
403
386
|
}
|
|
404
387
|
|
|
405
388
|
export const overwriteShallow = (obj, params, excludeFrom = []) => {
|
|
389
|
+
const useSet = excludeFrom instanceof Set
|
|
406
390
|
for (const e in params) {
|
|
407
|
-
if (
|
|
391
|
+
if (_startsWithDunder(e)) continue
|
|
392
|
+
if (useSet ? excludeFrom.has(e) : excludeFrom.includes(e)) continue
|
|
408
393
|
obj[e] = params[e]
|
|
409
394
|
}
|
|
410
395
|
return obj
|
|
@@ -419,9 +404,6 @@ export const overwriteDeep = (
|
|
|
419
404
|
opts = {},
|
|
420
405
|
visited = new WeakMap()
|
|
421
406
|
) => {
|
|
422
|
-
const excl = opts.exclude || []
|
|
423
|
-
const forcedExclude = opts.preventForce ? [] : ['node', 'window']
|
|
424
|
-
|
|
425
407
|
if (
|
|
426
408
|
!isObjectLike(obj) ||
|
|
427
409
|
!isObjectLike(params) ||
|
|
@@ -434,9 +416,13 @@ export const overwriteDeep = (
|
|
|
434
416
|
if (visited.has(obj)) return visited.get(obj)
|
|
435
417
|
visited.set(obj, obj)
|
|
436
418
|
|
|
419
|
+
const excl = opts.exclude
|
|
420
|
+
const exclSet = excl ? (excl instanceof Set ? excl : new Set(excl)) : null
|
|
421
|
+
const forcedExclude = !opts.preventForce
|
|
422
|
+
|
|
437
423
|
for (const e in params) {
|
|
438
|
-
if (!Object.hasOwnProperty.call(params, e)) continue
|
|
439
|
-
if (
|
|
424
|
+
if (!Object.prototype.hasOwnProperty.call(params, e)) continue
|
|
425
|
+
if ((exclSet && exclSet.has(e)) || (forcedExclude && _startsWithDunder(e))) continue
|
|
440
426
|
|
|
441
427
|
const objProp = obj[e]
|
|
442
428
|
const paramsProp = params[e]
|
|
@@ -455,52 +441,19 @@ export const overwriteDeep = (
|
|
|
455
441
|
|
|
456
442
|
/**
|
|
457
443
|
* Recursively compares two values to determine if they are deeply equal.
|
|
458
|
-
*
|
|
459
|
-
* This function checks for deep equality between two values, including
|
|
460
|
-
* objects, arrays, and nested structures. It handles circular references to
|
|
461
|
-
* prevent infinite loops.
|
|
462
|
-
*
|
|
463
|
-
* @param {*} param - The first value to compare.
|
|
464
|
-
* @param {*} element - The second value to compare.
|
|
465
|
-
* @param {Set} [visited] - (Optional) A set to track visited objects during recursion
|
|
466
|
-
* to handle circular references. You can omit this parameter when calling
|
|
467
|
-
* the function; it is used internally for tracking visited objects.
|
|
468
|
-
*
|
|
469
|
-
* @returns {boolean} Returns `true` if the values are deeply equal, `false` otherwise.
|
|
470
|
-
*
|
|
471
|
-
* @example
|
|
472
|
-
* // Comparing primitive values
|
|
473
|
-
* isEqualDeep(42, 42); // true
|
|
474
|
-
* isEqualDeep('hello', 'hello'); // true
|
|
475
|
-
* isEqualDeep(true, true); // true
|
|
476
|
-
* isEqualDeep(42, '42'); // false
|
|
477
|
-
*
|
|
478
|
-
* // Comparing simple objects
|
|
479
|
-
* const obj1 = { a: 1, b: { c: 2 } };
|
|
480
|
-
* const obj2 = { a: 1, b: { c: 2 } };
|
|
481
|
-
* isEqualDeep(obj1, obj2); // true
|
|
482
|
-
*
|
|
483
|
-
* // Handling circular references
|
|
484
|
-
* const circularObj = { prop: null };
|
|
485
|
-
* circularObj.prop = circularObj;
|
|
486
|
-
* const anotherObj = { prop: null };
|
|
487
|
-
* anotherObj.prop = anotherObj;
|
|
488
|
-
* isEqualDeep(circularObj, anotherObj); // true
|
|
489
444
|
*/
|
|
490
445
|
export const isEqualDeep = (param, element, visited = new Set()) => {
|
|
491
|
-
// Check if both values are non-null objects
|
|
492
446
|
if (
|
|
493
447
|
typeof param !== 'object' ||
|
|
494
448
|
typeof element !== 'object' ||
|
|
495
449
|
param === null ||
|
|
496
450
|
element === null
|
|
497
451
|
) {
|
|
498
|
-
return param === element
|
|
452
|
+
return param === element
|
|
499
453
|
}
|
|
500
454
|
|
|
501
|
-
// Check for circular references
|
|
502
455
|
if (visited.has(param) || visited.has(element)) {
|
|
503
|
-
return true
|
|
456
|
+
return true
|
|
504
457
|
}
|
|
505
458
|
|
|
506
459
|
visited.add(param)
|
|
@@ -509,22 +462,16 @@ export const isEqualDeep = (param, element, visited = new Set()) => {
|
|
|
509
462
|
const keysParam = Object.keys(param)
|
|
510
463
|
const keysElement = Object.keys(element)
|
|
511
464
|
|
|
512
|
-
// Check if both objects have the same number of properties
|
|
513
465
|
if (keysParam.length !== keysElement.length) {
|
|
514
466
|
return false
|
|
515
467
|
}
|
|
516
468
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (!
|
|
469
|
+
for (let i = 0; i < keysParam.length; i++) {
|
|
470
|
+
const key = keysParam[i]
|
|
471
|
+
if (!Object.prototype.hasOwnProperty.call(element, key)) {
|
|
520
472
|
return false
|
|
521
473
|
}
|
|
522
|
-
|
|
523
|
-
const paramProp = param[key]
|
|
524
|
-
const elementProp = element[key]
|
|
525
|
-
|
|
526
|
-
// Recursively check property values
|
|
527
|
-
if (!isEqualDeep(paramProp, elementProp, visited)) {
|
|
474
|
+
if (!isEqualDeep(param[key], element[key], visited)) {
|
|
528
475
|
return false
|
|
529
476
|
}
|
|
530
477
|
}
|
|
@@ -532,23 +479,23 @@ export const isEqualDeep = (param, element, visited = new Set()) => {
|
|
|
532
479
|
return true
|
|
533
480
|
}
|
|
534
481
|
|
|
535
|
-
|
|
482
|
+
const DEEP_CONTAINS_IGNORED = new Set(['node', '__ref'])
|
|
483
|
+
|
|
484
|
+
export const deepContains = (obj1, obj2, ignoredKeys = DEEP_CONTAINS_IGNORED) => {
|
|
536
485
|
if (obj1 === obj2) return true
|
|
537
486
|
if (!isObjectLike(obj1) || !isObjectLike(obj2)) return obj1 === obj2
|
|
538
487
|
if (isDOMNode(obj1) || isDOMNode(obj2)) return obj1 === obj2
|
|
539
488
|
|
|
489
|
+
const ignored = ignoredKeys instanceof Set ? ignoredKeys : new Set(ignoredKeys)
|
|
540
490
|
const visited = new WeakSet()
|
|
541
491
|
|
|
542
492
|
function checkContains (target, source) {
|
|
543
493
|
if (visited.has(source)) return true
|
|
544
494
|
visited.add(source)
|
|
545
495
|
|
|
546
|
-
// Check each property in source
|
|
547
496
|
for (const key in source) {
|
|
548
497
|
if (!Object.prototype.hasOwnProperty.call(source, key)) continue
|
|
549
|
-
if (
|
|
550
|
-
|
|
551
|
-
// If key doesn't exist in target, return false
|
|
498
|
+
if (ignored.has(key)) continue
|
|
552
499
|
if (!Object.prototype.hasOwnProperty.call(target, key)) return false
|
|
553
500
|
|
|
554
501
|
const sourceValue = source[key]
|
|
@@ -574,7 +521,7 @@ export const removeFromObject = (obj, props) => {
|
|
|
574
521
|
if (is(props)('string', 'number')) {
|
|
575
522
|
delete obj[props]
|
|
576
523
|
} else if (isArray(props)) {
|
|
577
|
-
props.
|
|
524
|
+
for (let i = 0; i < props.length; i++) delete obj[props[i]]
|
|
578
525
|
} else {
|
|
579
526
|
throw new Error(
|
|
580
527
|
'Invalid input: props must be a string or an array of strings'
|
|
@@ -585,14 +532,14 @@ export const removeFromObject = (obj, props) => {
|
|
|
585
532
|
|
|
586
533
|
export const createObjectWithoutPrototype = obj => {
|
|
587
534
|
if (obj === null || typeof obj !== 'object') {
|
|
588
|
-
return obj
|
|
535
|
+
return obj
|
|
589
536
|
}
|
|
590
537
|
|
|
591
|
-
const newObj = Object.create(null)
|
|
538
|
+
const newObj = Object.create(null)
|
|
592
539
|
|
|
593
540
|
for (const key in obj) {
|
|
594
541
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
595
|
-
newObj[key] = createObjectWithoutPrototype(obj[key])
|
|
542
|
+
newObj[key] = createObjectWithoutPrototype(obj[key])
|
|
596
543
|
}
|
|
597
544
|
}
|
|
598
545
|
|
|
@@ -600,21 +547,19 @@ export const createObjectWithoutPrototype = obj => {
|
|
|
600
547
|
}
|
|
601
548
|
|
|
602
549
|
export const createNestedObject = (arr, lastValue) => {
|
|
603
|
-
|
|
550
|
+
if (arr.length === 0) return lastValue
|
|
604
551
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
}
|
|
552
|
+
const nestedObject = {}
|
|
553
|
+
let current = nestedObject
|
|
608
554
|
|
|
609
|
-
arr.
|
|
610
|
-
if (
|
|
611
|
-
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
|
|
555
|
+
for (let i = 0; i < arr.length; i++) {
|
|
556
|
+
if (i === arr.length - 1 && lastValue) {
|
|
557
|
+
current[arr[i]] = lastValue
|
|
558
|
+
} else {
|
|
559
|
+
current[arr[i]] = {}
|
|
560
|
+
current = current[arr[i]]
|
|
615
561
|
}
|
|
616
|
-
|
|
617
|
-
}, nestedObject)
|
|
562
|
+
}
|
|
618
563
|
|
|
619
564
|
return nestedObject
|
|
620
565
|
}
|
|
@@ -627,14 +572,12 @@ export const removeNestedKeyByPath = (obj, path) => {
|
|
|
627
572
|
let current = obj
|
|
628
573
|
|
|
629
574
|
for (let i = 0; i < path.length - 1; i++) {
|
|
630
|
-
if (current[path[i]] === undefined)
|
|
631
|
-
return // Path does not exist, so nothing to remove.
|
|
632
|
-
}
|
|
575
|
+
if (current[path[i]] === undefined) return
|
|
633
576
|
current = current[path[i]]
|
|
634
577
|
}
|
|
635
578
|
|
|
636
579
|
const lastKey = path[path.length - 1]
|
|
637
|
-
if (current && Object.hasOwnProperty.call(current, lastKey)) {
|
|
580
|
+
if (current && Object.prototype.hasOwnProperty.call(current, lastKey)) {
|
|
638
581
|
delete current[lastKey]
|
|
639
582
|
}
|
|
640
583
|
}
|
|
@@ -647,15 +590,13 @@ export const setInObjectByPath = (obj, path, value) => {
|
|
|
647
590
|
let current = obj
|
|
648
591
|
|
|
649
592
|
for (let i = 0; i < path.length - 1; i++) {
|
|
650
|
-
// If the current path segment doesn't exist or isn't an object, create it
|
|
651
593
|
if (!current[path[i]] || typeof current[path[i]] !== 'object') {
|
|
652
594
|
current[path[i]] = {}
|
|
653
595
|
}
|
|
654
596
|
current = current[path[i]]
|
|
655
597
|
}
|
|
656
598
|
|
|
657
|
-
|
|
658
|
-
current[lastKey] = value
|
|
599
|
+
current[path[path.length - 1]] = value
|
|
659
600
|
|
|
660
601
|
return obj
|
|
661
602
|
}
|
|
@@ -678,25 +619,21 @@ export const getInObjectByPath = (obj, path) => {
|
|
|
678
619
|
}
|
|
679
620
|
|
|
680
621
|
export const detectInfiniteLoop = arr => {
|
|
681
|
-
const maxRepeats = 10
|
|
622
|
+
const maxRepeats = 10
|
|
682
623
|
let pattern = []
|
|
683
624
|
let repeatCount = 0
|
|
684
625
|
|
|
685
626
|
for (let i = 0; i < arr.length; i++) {
|
|
686
627
|
if (pattern.length < 2) {
|
|
687
|
-
// Build the initial pattern with two consecutive elements
|
|
688
628
|
pattern.push(arr[i])
|
|
689
629
|
} else {
|
|
690
|
-
// Check if the current element follows the repeating pattern
|
|
691
630
|
if (arr[i] === pattern[i % 2]) {
|
|
692
631
|
repeatCount++
|
|
693
632
|
} else {
|
|
694
|
-
// If there's a mismatch, reset the pattern and repeat counter
|
|
695
633
|
pattern = [arr[i - 1], arr[i]]
|
|
696
|
-
repeatCount = 1
|
|
634
|
+
repeatCount = 1
|
|
697
635
|
}
|
|
698
636
|
|
|
699
|
-
// If the pattern repeats more than `maxRepeats`, throw a warning
|
|
700
637
|
if (repeatCount >= maxRepeats * 2) {
|
|
701
638
|
if (ENV === 'test' || ENV === 'development') {
|
|
702
639
|
console.warn(
|
|
@@ -711,16 +648,14 @@ export const detectInfiniteLoop = arr => {
|
|
|
711
648
|
}
|
|
712
649
|
|
|
713
650
|
export const isCyclic = obj => {
|
|
714
|
-
const
|
|
651
|
+
const seen = new WeakSet()
|
|
715
652
|
|
|
716
653
|
function detect (obj) {
|
|
717
654
|
if (obj && typeof obj === 'object') {
|
|
718
|
-
if (
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
seenObjects.push(obj)
|
|
655
|
+
if (seen.has(obj)) return true
|
|
656
|
+
seen.add(obj)
|
|
722
657
|
for (const key in obj) {
|
|
723
|
-
if (Object.hasOwnProperty.call(obj, key) && detect(obj[key])) {
|
|
658
|
+
if (Object.prototype.hasOwnProperty.call(obj, key) && detect(obj[key])) {
|
|
724
659
|
console.log(obj, 'cycle at ' + key)
|
|
725
660
|
return true
|
|
726
661
|
}
|
|
@@ -733,7 +668,12 @@ export const isCyclic = obj => {
|
|
|
733
668
|
}
|
|
734
669
|
|
|
735
670
|
export const excludeKeysFromObject = (obj, excludedKeys) => {
|
|
736
|
-
const
|
|
737
|
-
|
|
671
|
+
const excluded = excludedKeys instanceof Set ? excludedKeys : new Set(excludedKeys)
|
|
672
|
+
const result = {}
|
|
673
|
+
for (const key in obj) {
|
|
674
|
+
if (Object.prototype.hasOwnProperty.call(obj, key) && !excluded.has(key)) {
|
|
675
|
+
result[key] = obj[key]
|
|
676
|
+
}
|
|
677
|
+
}
|
|
738
678
|
return result
|
|
739
679
|
}
|