/
defu.ts
67 lines (53 loc) 路 1.82 KB
/
defu.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import type { Merger, DefuFn, DefuInstance } from './types'
function isObject (val: any) {
return val !== null && typeof val === 'object'
}
// Base function to apply defaults
function _defu<T> (baseObj: T, defaults: any, namespace: string = '.', merger?: Merger): T {
if (!isObject(defaults)) {
return _defu(baseObj, {}, namespace, merger)
}
const obj = Object.assign({}, defaults)
for (const key in baseObj) {
if (key === '__proto__' || key === 'constructor') {
continue
}
const val = baseObj[key]
if (val === null || val === undefined) {
continue
}
if (merger && merger(obj, key, val, namespace)) {
continue
}
if (Array.isArray(val) && Array.isArray(obj[key])) {
obj[key] = val.concat(obj[key])
} else if (isObject(val) && isObject(obj[key])) {
obj[key] = _defu(val, obj[key], (namespace ? `${namespace}.` : '') + key.toString(), merger)
} else {
obj[key] = val
}
}
return obj
}
// Create defu wrapper with optional merger and multi arg support
export function createDefu (merger?: Merger): DefuFn {
return (...args) => args.reduce((p, c) => _defu(p, c, '', merger), {} as any)
}
// Standard version
export const defu = createDefu() as DefuInstance
export default defu
// Custom version with function merge support
export const defuFn = createDefu((obj, key, currentValue, _namespace) => {
if (typeof obj[key] !== 'undefined' && typeof currentValue === 'function') {
obj[key] = currentValue(obj[key])
return true
}
})
// Custom version with function merge support only for defined arrays
export const defuArrayFn = createDefu((obj, key, currentValue, _namespace) => {
if (Array.isArray(obj[key]) && typeof currentValue === 'function') {
obj[key] = currentValue(obj[key])
return true
}
})
export type { Defu } from './types'