-
Notifications
You must be signed in to change notification settings - Fork 23
/
defu.ts
76 lines (63 loc) · 2 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
68
69
70
71
72
73
74
75
76
import { isPlainObject } from "./_utils";
import type { Merger, DefuFn as DefuFunction, DefuInstance } from "./types";
// Base function to apply defaults
function _defu<T>(
baseObject: T,
defaults: any,
namespace = ".",
merger?: Merger,
): T {
if (!isPlainObject(defaults)) {
return _defu(baseObject, {}, namespace, merger);
}
const object = Object.assign({}, defaults);
for (const key in baseObject) {
if (key === "__proto__" || key === "constructor") {
continue;
}
const value = baseObject[key];
if (value === null || value === undefined) {
continue;
}
if (merger && merger(object, key, value, namespace)) {
continue;
}
if (Array.isArray(value) && Array.isArray(object[key])) {
object[key] = [...value, ...object[key]];
} else if (isPlainObject(value) && isPlainObject(object[key])) {
object[key] = _defu(
value,
object[key],
(namespace ? `${namespace}.` : "") + key.toString(),
merger,
);
} else {
object[key] = value;
}
}
return object;
}
// Create defu wrapper with optional merger and multi arg support
export function createDefu(merger?: Merger): DefuFunction {
return (...arguments_) =>
// eslint-disable-next-line unicorn/no-array-reduce
arguments_.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((object, key, currentValue) => {
if (object[key] !== undefined && typeof currentValue === "function") {
object[key] = currentValue(object[key]);
return true;
}
});
// Custom version with function merge support only for defined arrays
export const defuArrayFn = createDefu((object, key, currentValue) => {
if (Array.isArray(object[key]) && typeof currentValue === "function") {
object[key] = currentValue(object[key]);
return true;
}
});
export type { Defu } from "./types";