From 8abde83d053c5875805c22465e5967c6d1b08e5b Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Mon, 2 Dec 2024 13:40:38 +0200 Subject: [PATCH 1/8] Also handle cloneProtoObject in mergeObject This fixes not being able to set an instantiated logger in `options.logger` using `fastify-cli`, as it would try to merge a prototype object, the `pino.Logger`. --- index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 50d1548..f8ae783 100644 --- a/index.js +++ b/index.js @@ -111,7 +111,9 @@ 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) || // eslint-disable-line no-mixed-operators + key in target && (targetKeys.indexOf(key) !== -1 && + (cloneProtoObject && Object.getPrototypeOf(source[key]) !== JSON_PROTO && (result[key] = cloneProtoObject(source[key]))) || + (result[key] = _deepmerge(target[key], source[key])), true) || // eslint-disable-line no-mixed-operators (result[key] = clone(source[key])) ) } From 2d4838cc1867d9a3dbbe9acd54c208c8ec1d5277 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Mon, 2 Dec 2024 16:49:29 +0200 Subject: [PATCH 2/8] Fix tests --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index f8ae783..2b8bad3 100644 --- a/index.js +++ b/index.js @@ -112,8 +112,8 @@ function deepmergeConstructor (options) { isNotPrototypeKey(key = sourceKeys[i]) && ( key in target && (targetKeys.indexOf(key) !== -1 && - (cloneProtoObject && Object.getPrototypeOf(source[key]) !== JSON_PROTO && (result[key] = cloneProtoObject(source[key]))) || - (result[key] = _deepmerge(target[key], source[key])), true) || // eslint-disable-line no-mixed-operators + ((isMergeableObject(key) && cloneProtoObject && Object.getPrototypeOf(source[key]) !== JSON_PROTO && (result[key] = cloneProtoObject(source[key]))) || + (result[key] = _deepmerge(target[key], source[key]))), true) || // eslint-disable-line no-mixed-operators (result[key] = clone(source[key])) ) } From c1c27920310cecc8a93113a44dee8c1523b0afdc Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Mon, 2 Dec 2024 17:41:45 +0200 Subject: [PATCH 3/8] Fix lint --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 2b8bad3..f00fac4 100644 --- a/index.js +++ b/index.js @@ -111,7 +111,7 @@ function deepmergeConstructor (options) { for (i = 0, il = sourceKeys.length; i < il; ++i) { isNotPrototypeKey(key = sourceKeys[i]) && ( - key in target && (targetKeys.indexOf(key) !== -1 && + key in target && (targetKeys.indexOf(key) !== -1 && // eslint-disable-line no-mixed-operators ((isMergeableObject(key) && cloneProtoObject && Object.getPrototypeOf(source[key]) !== JSON_PROTO && (result[key] = cloneProtoObject(source[key]))) || (result[key] = _deepmerge(target[key], source[key]))), true) || // eslint-disable-line no-mixed-operators (result[key] = clone(source[key])) From 6f092105104e393ab953342af786f26943d6bc86 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sat, 7 Dec 2024 22:59:35 +0200 Subject: [PATCH 4/8] Add a test --- index.js | 2 +- test/merge-proto-objects.test.js | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index f00fac4..15fe29f 100644 --- a/index.js +++ b/index.js @@ -112,7 +112,7 @@ function deepmergeConstructor (options) { isNotPrototypeKey(key = sourceKeys[i]) && ( key in target && (targetKeys.indexOf(key) !== -1 && // eslint-disable-line no-mixed-operators - ((isMergeableObject(key) && cloneProtoObject && Object.getPrototypeOf(source[key]) !== JSON_PROTO && (result[key] = cloneProtoObject(source[key]))) || + ((isMergeableObject(source[key]) && cloneProtoObject && Object.getPrototypeOf(source[key]) !== JSON_PROTO && (result[key] = cloneProtoObject(source[key]))) || (result[key] = _deepmerge(target[key], source[key]))), true) || // eslint-disable-line no-mixed-operators (result[key] = clone(source[key])) ) diff --git a/test/merge-proto-objects.test.js b/test/merge-proto-objects.test.js index 57e44b7..a636e21 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 refernce 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 From f327baa63da4dce833f0969fbdba23a8a3c6ccac Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sat, 7 Dec 2024 23:08:02 +0200 Subject: [PATCH 5/8] Fix formatting --- test/merge-proto-objects.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/merge-proto-objects.test.js b/test/merge-proto-objects.test.js index a636e21..b5fc489 100644 --- a/test/merge-proto-objects.test.js +++ b/test/merge-proto-objects.test.js @@ -7,8 +7,8 @@ const deepmerge = require('../index') const { test } = require('tape') class Foo { - constructor(foo) { - this.foo = foo; + constructor (foo) { + this.foo = foo } } @@ -94,7 +94,7 @@ test('should not merge the buffers when cloned by reference', async t => { test('should clone by refernce with proto object in both source and target', async t => { t.plan(4) - const foo2 = new Foo(2) + const foo2 = new Foo(2) const result = deepmerge({ cloneProtoObject (x) { t.ok(x instanceof Foo) From da2bca6dfdec9f9dbb49d3354b5dd36f86234b05 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sun, 8 Dec 2024 11:07:07 +0200 Subject: [PATCH 6/8] Update test/merge-proto-objects.test.js Co-authored-by: Matteo Collina Signed-off-by: Segev Finer --- test/merge-proto-objects.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/merge-proto-objects.test.js b/test/merge-proto-objects.test.js index b5fc489..611c54b 100644 --- a/test/merge-proto-objects.test.js +++ b/test/merge-proto-objects.test.js @@ -92,7 +92,7 @@ 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 refernce with proto object in both source and target', async t => { +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({ From 672ea38dc463aa78bae6546e1b9d9cfdecc5b502 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sun, 8 Dec 2024 19:41:22 +0200 Subject: [PATCH 7/8] Refactor the code to make it more readable, hopefully... --- index.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 15fe29f..22e4c2b 100644 --- a/index.js +++ b/index.js @@ -109,13 +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 && // eslint-disable-line no-mixed-operators - ((isMergeableObject(source[key]) && cloneProtoObject && Object.getPrototypeOf(source[key]) !== JSON_PROTO && (result[key] = cloneProtoObject(source[key]))) || - (result[key] = _deepmerge(target[key], source[key]))), true) || // eslint-disable-line no-mixed-operators - (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 } From 86879151f71a10f29b3ef53228a5be03b44af04a Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Mon, 9 Dec 2024 00:07:38 +0200 Subject: [PATCH 8/8] Fix lint, whoops --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 22e4c2b..99fd42e 100644 --- a/index.js +++ b/index.js @@ -122,7 +122,7 @@ function deepmergeConstructor (options) { } } } else { - result[key] = clone(source[key]); + result[key] = clone(source[key]) } } return result