diff --git a/index.js b/index.js index 04a5b14..99fd42e 100644 --- a/index.js +++ b/index.js @@ -109,11 +109,21 @@ function deepmergeConstructor (options) { } for (i = 0, il = sourceKeys.length; i < il; ++i) { - isNotPrototypeKey(key = sourceKeys[i]) && - ( - (key in target && (targetKeys.indexOf(key) !== -1 && (result[key] = _deepmerge(target[key], source[key])), true)) || - (result[key] = clone(source[key])) - ) + if (!isNotPrototypeKey(key = sourceKeys[i])) { + continue + } + + if (key in target) { + if (targetKeys.indexOf(key) !== -1) { + if (cloneProtoObject && isMergeableObject(source[key]) && Object.getPrototypeOf(source[key]) !== JSON_PROTO) { + result[key] = cloneProtoObject(source[key]) + } else { + result[key] = _deepmerge(target[key], source[key]) + } + } + } else { + result[key] = clone(source[key]) + } } return result } diff --git a/test/merge-proto-objects.test.js b/test/merge-proto-objects.test.js index 57e44b7..611c54b 100644 --- a/test/merge-proto-objects.test.js +++ b/test/merge-proto-objects.test.js @@ -6,6 +6,12 @@ const { Readable } = require('node:stream') const deepmerge = require('../index') const { test } = require('tape') +class Foo { + constructor (foo) { + this.foo = foo + } +} + test('merge nested objects should be immutable', function (t) { t.plan(3) const src = { @@ -86,6 +92,23 @@ test('should not merge the buffers when cloned by reference', async t => { t.same(result.logger.buffer, Buffer.of(1, 2, 3)) }) +test('should clone by reference with proto object in both source and target', async t => { + t.plan(4) + const foo2 = new Foo(2) + const result = deepmerge({ + cloneProtoObject (x) { + t.ok(x instanceof Foo) + return x + } + })( + { foo: new Foo(1) }, + { foo: foo2 } + ) + t.equal(typeof result.foo, 'object') + t.ok(result.foo instanceof Foo) + t.same(result.foo, foo2) +}) + test('doc example', async t => { const stream = process.stdout