From e504c73555c770a898c8df3f7be88548ee948c87 Mon Sep 17 00:00:00 2001 From: Oleg S <97077423+RobotSail@users.noreply.github.com> Date: Wed, 1 Mar 2023 14:02:17 -0500 Subject: [PATCH] test merging json objects Signed-off-by: Oleg S <97077423+RobotSail@users.noreply.github.com> --- .changeset/spotty-cougars-wink.md | 7 ++ packages/backend-app-api/api-report.md | 1 + packages/types/api-report.md | 3 + packages/types/src/json.test.ts | 94 +++++++++++++++++++++++++- packages/types/src/json.ts | 5 +- 5 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 .changeset/spotty-cougars-wink.md diff --git a/.changeset/spotty-cougars-wink.md b/.changeset/spotty-cougars-wink.md new file mode 100644 index 0000000000..4e8b97a164 --- /dev/null +++ b/.changeset/spotty-cougars-wink.md @@ -0,0 +1,7 @@ +--- +'@backstage/backend-app-api': minor +'@backstage/config-loader': minor +'@backstage/types': minor +--- + +Introduces the ability to merge configs and JsonObjects diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index e99135b3ec..ed84730fc0 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -178,6 +178,7 @@ export const lifecycleServiceFactory: () => ServiceFactory< export function loadBackendConfig(options: { remote?: LoadConfigOptionsRemote; argv: string[]; + config?: JsonObject; }): Promise<{ config: Config; }>; diff --git a/packages/types/api-report.md b/packages/types/api-report.md index 4b43f5daa6..e0b34203cf 100644 --- a/packages/types/api-report.md +++ b/packages/types/api-report.md @@ -29,6 +29,9 @@ export type JsonPrimitive = number | string | boolean | null; // @public export type JsonValue = JsonObject | JsonArray | JsonPrimitive; +// @public +export const mergeJson: (a: JsonObject, b: JsonObject) => JsonObject; + // @public export type Observable = { [Symbol.observable](): Observable; diff --git a/packages/types/src/json.test.ts b/packages/types/src/json.test.ts index 7da0ef8a3e..277992f00f 100644 --- a/packages/types/src/json.test.ts +++ b/packages/types/src/json.test.ts @@ -14,7 +14,13 @@ * limitations under the License. */ -import { JsonPrimitive, JsonArray, JsonObject, JsonValue } from './json'; +import { + JsonPrimitive, + JsonArray, + JsonObject, + JsonValue, + mergeJson, +} from './json'; describe('json', () => { it('JsonPrimitive', () => { @@ -79,3 +85,89 @@ describe('json', () => { expect(true).toBe(true); }); }); + +describe('jsonMerge', () => { + it('should merge two objects', () => { + const obj1 = { a: 1, b: 2, c: 3 }; + const obj2 = { b: 4, c: 5, d: 6 }; + const merged = mergeJson(obj1, obj2); + expect(merged).toEqual({ a: 1, b: 4, c: 5, d: 6 }); + }); + + it('should always prefer to merge the values of the second parameter', () => { + const obj1 = { + a: 1, + b: [1, 2, 3], + c: { + z: 1, + y: 2, + x: 3, + }, + }; + const obj2 = { + a: 2, + b: [2, 4, 6], + c: { + z: 2, + y: 4, + x: 6, + }, + }; + const merged = mergeJson(obj1, obj2); + expect(merged).toEqual(obj2); + }); + + it('should prefer the second argument whenever keys collide', () => { + const obj1 = { + a: 1, + b: [1, 2, 3], + c: { + z: 1, + y: 2, + x: 3, + }, + }; + const obj2 = { + a: 2, + c: { + y: 4, + }, + }; + const merged = mergeJson(obj1, obj2); + expect(merged).toEqual({ + a: 2, + b: [1, 2, 3], + c: { + z: 1, + y: 4, + x: 3, + }, + }); + }); + + it('should merge recursively', () => { + const obj1 = { + backend: { + database: { + provider: 'sqlite3', + }, + }, + }; + const obj2 = { + backend: { + database: { + password: 'password123', + }, + }, + }; + const merged = mergeJson(obj1, obj2); + expect(merged).toEqual({ + backend: { + database: { + provider: 'sqlite3', + password: 'password123', + }, + }, + }); + }); +}); diff --git a/packages/types/src/json.ts b/packages/types/src/json.ts index 1bfe0c543f..4b0bb958ef 100644 --- a/packages/types/src/json.ts +++ b/packages/types/src/json.ts @@ -47,9 +47,10 @@ export type JsonValue = JsonObject | JsonArray | JsonPrimitive; * prefers values from b, unless the value is an object, in which case it recursively * merges the values. * - * @param a The base object - * @param b The object to merge into a + * @param a - The base object + * @param b - The object to merge into a * @returns The merged object + * @public */ export const mergeJson = (a: JsonObject, b: JsonObject): JsonObject => { const final: JsonObject = {};