diff --git a/src/defu.ts b/src/defu.ts index 61c8264..6a832aa 100644 --- a/src/defu.ts +++ b/src/defu.ts @@ -9,10 +9,11 @@ function _defu( baseObject: T, defaults: any, namespace = ".", - merger?: Merger + merger?: Merger, + clone?: boolean ): T { if (!isObject(defaults)) { - return _defu(baseObject, {}, namespace, merger); + return _defu(baseObject, {}, namespace, merger, clone); } const object = Object.assign({}, defaults); @@ -22,7 +23,7 @@ function _defu( continue; } - const value = baseObject[key]; + let value = baseObject[key]; if (value === null || value === undefined) { continue; @@ -39,9 +40,17 @@ function _defu( value, object[key], (namespace ? `${namespace}.` : "") + key.toString(), - merger + merger, + clone ); } else { + if (clone) { + // eslint-disable-next-line no-var + var structuredClone: (x: any) => any; + value = structuredClone + ? structuredClone(value) + : JSON.parse(JSON.stringify(value)); + } object[key] = value; } } @@ -50,10 +59,14 @@ function _defu( } // Create defu wrapper with optional merger and multi arg support -export function createDefu(merger?: Merger): DefuFunction { +export function createDefu( + merger?: Merger, + options?: { clone?: boolean } +): DefuFunction { + const clone = options?.clone || false; return (...arguments_) => // eslint-disable-next-line unicorn/no-array-reduce - arguments_.reduce((p, c) => _defu(p, c, "", merger), {} as any); + arguments_.reduce((p, c) => _defu(p, c, "", merger, clone), {} as any); } // Standard version diff --git a/test/defu.test.ts b/test/defu.test.ts index de980ba..f1897a1 100644 --- a/test/defu.test.ts +++ b/test/defu.test.ts @@ -213,4 +213,12 @@ describe("defu", () => { foo: { bar: { modules: "foo.bar:X,Y" } }, }); }); + + it("should clone the defaults object's values", () => { + const ext = createDefu(undefined, { clone: true }); + const source = { a: [1, 2] }; + const defaults = { a: { b: 1 } }; + const result = ext(source, defaults); + expect(result.a).not.toBe(source.a); + }); });