Skip to content

Commit

Permalink
fix: messages deepCopy mutates src arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
BobbieGoede committed Sep 15, 2024
1 parent 28a83ba commit df4b09f
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 4 deletions.
14 changes: 10 additions & 4 deletions packages/shared/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ export function deepCopy(src: any, des: any): void {
const { src, des } = stack.pop()!

Object.keys(src).forEach(key => {
if (isNotObjectOrIsArray(src[key]) || isNotObjectOrIsArray(des[key])) {
// if src[key] is an object/array, set des[key]
// to empty object/array to prevent setting by reference
if (isObject(src[key]) && !isObject(des[key])) {
des[key] = Array.isArray(src[key]) ? [] : {}
}

if (isObject(des[key]) && isObject(src[key])) {
// src[key] and des[key] are both objects, merge them
stack.push({ src: src[key], des: des[key] })
} else {
// replace with src[key] when:
// src[key] or des[key] is not an object, or
// src[key] or des[key] is an array
des[key] = src[key]
} else {
// src[key] and des[key] are both objects, merge them
stack.push({ src: src[key], des: des[key] })
}
})
}
Expand Down
50 changes: 50 additions & 0 deletions packages/shared/test/messages.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { deepCopy } from '../src/index'

test('deepCopy merges without mutating src argument', () => {
const msg1 = {
hello: 'Greetings',
about: {
title: 'About us'
},
overwritten: 'Original text',
fruit: [{ name: 'Apple' }]
}
const copy1 = structuredClone(msg1)

const msg2 = {
bye: 'Goodbye',
about: {
content: 'Some text'
},
overwritten: 'New text',
fruit: [{ name: 'Strawberry' }],
// @ts-ignore
car: ({ plural }) => plural(['car', 'cars'])
}

const merged = {}

deepCopy(msg1, merged)
deepCopy(msg2, merged)

expect(merged).toMatchInlineSnapshot(`
{
"about": {
"content": "Some text",
"title": "About us",
},
"bye": "Goodbye",
"car": [Function],
"fruit": [
{
"name": "Strawberry",
},
],
"hello": "Greetings",
"overwritten": "New text",
}
`)

// should not mutate source object
expect(msg1).toStrictEqual(copy1)
})

0 comments on commit df4b09f

Please sign in to comment.