diff --git a/core/util/merge.test.ts b/core/util/merge.test.ts index 7131ca0090b..840d2daad74 100644 --- a/core/util/merge.test.ts +++ b/core/util/merge.test.ts @@ -71,6 +71,27 @@ describe("mergeJson", () => { expect(result).toEqual({ a: 1, b: 2, c: undefined }); }); + it("should let null in the second object replace an object", () => { + const first = { a: { b: 1 } }; + const second = { a: null }; + const result = mergeJson(first, second); + expect(result).toEqual({ a: null }); + }); + + it("should let an object in the second object replace null", () => { + const first = { a: null }; + const second = { a: { b: 1 } }; + const result = mergeJson(first, second); + expect(result).toEqual({ a: { b: 1 } }); + }); + + it("should replace rather than merge when only one value is an array", () => { + expect(mergeJson({ a: [1, 2] }, { a: { b: 1 } })).toEqual({ + a: { b: 1 }, + }); + expect(mergeJson({ a: { b: 1 } }, { a: [1, 2] })).toEqual({ a: [1, 2] }); + }); + it("should handle empty objects", () => { const first = {}; const second = { a: 1 }; diff --git a/core/util/merge.ts b/core/util/merge.ts index d20ebcd1599..3fbe2933b62 100644 --- a/core/util/merge.ts +++ b/core/util/merge.ts @@ -2,6 +2,10 @@ import { ConfigMergeType } from "../index.js"; type JsonObject = { [key: string]: any }; +function isMergeableObject(value: any): boolean { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + export function mergeJson( first: JsonObject, second: JsonObject, @@ -38,13 +42,13 @@ export function mergeJson( copyOfFirst[key] = [...firstValue, ...secondValue]; } } else if ( - typeof secondValue === "object" && - typeof firstValue === "object" + isMergeableObject(secondValue) && + isMergeableObject(firstValue) ) { // Object copyOfFirst[key] = mergeJson(firstValue, secondValue, mergeBehavior); } else { - // Other (boolean, number, string) + // Other (boolean, number, string, null, or mismatched types) copyOfFirst[key] = secondValue; } }