Skip to content

Commit

Permalink
chore: Refactor deepMerge function to improve readability and maintai…
Browse files Browse the repository at this point in the history
…nability (#1207)
  • Loading branch information
oekazuma authored Oct 24, 2024
1 parent 1881ca7 commit fd1837c
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 35 deletions.
5 changes: 5 additions & 0 deletions .changeset/mean-impalas-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte-meta-tags': patch
---

Refactor deepMerge function to improve readability and maintainability
61 changes: 26 additions & 35 deletions packages/svelte-meta-tags/src/lib/deepMerge.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,29 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function deepMerge(target: any, source: any) {
const sourceKeys = Object.keys(source);
export const deepMerge = <X extends Record<string | symbol | number, unknown>>(target: X, source: X): X => {
if (!target || !source) return target ?? source ?? ({} as X);

for (let i = 0; i < sourceKeys.length; i++) {
const key = sourceKeys[i];
return Object.entries({ ...target, ...source }).reduce((acc, [key, value]) => {
return {
...acc,
[key]: (() => {
if (target[key] instanceof Date || typeof target[key] === 'function') {
return target[key];
}
if (value instanceof Date || typeof value === 'function') {
return value;
}
if (isObject(target[key]) && isObject(value)) {
return deepMerge(target[key], value);
}
if (isArray(target[key]) && isArray(value)) {
return value;
}
return value !== undefined ? value : target[key];
})()
};
}, {} as X);
};

const sourceValue = source[key];
const targetValue = target[key];
const isObject = (obj: unknown): obj is Record<string | symbol | number, unknown> =>
obj !== null && typeof obj === 'object' && !Array.isArray(obj);

if (Array.isArray(sourceValue)) {
if (Array.isArray(targetValue)) {
target[key] = deepMerge(targetValue, sourceValue);
} else {
target[key] = deepMerge([], sourceValue);
}
} else if (isPlainObject(sourceValue)) {
if (isPlainObject(targetValue)) {
target[key] = deepMerge(targetValue, sourceValue);
} else {
target[key] = deepMerge({}, sourceValue);
}
} else if (targetValue === undefined || sourceValue !== undefined) {
target[key] = sourceValue;
}
}

return target;
}

function isPlainObject(object?: unknown): boolean {
if (typeof object !== 'object' || object === null) {
return false;
}

const proto = Object.getPrototypeOf(object);
return proto === Object.prototype || proto === null;
}
const isArray = (obj: unknown): obj is unknown[] => Array.isArray(obj);
36 changes: 36 additions & 0 deletions packages/svelte-meta-tags/tests/deepMerge/deepMerge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,40 @@ describe('deepMerge functionality', () => {
expect(result.a).toEqual(date);
expect(result.b).toEqual(func);
});

test('merging with scalar values (number, string, boolean)', () => {
const result = deepMerge({ a: 10, b: 'hello' }, { b: 'world', c: true });
expect(result).toEqual({ a: 10, b: 'world', c: true });
});

test('deep merge when overrides are missing keys present in initial', () => {
const result = deepMerge({ a: 1, b: { c: 2, d: 3 } }, { b: { d: 4 } });
expect(result).toEqual({ a: 1, b: { c: 2, d: 4 } });
});

test('merging deep structures with different types at the same key level', () => {
const result = deepMerge({ a: { b: [1, 2] } }, { a: { b: { c: 3 } } });
expect(result).toEqual({ a: { b: { c: 3 } } });
});

test('handling of nested arrays', () => {
const result = deepMerge({ a: [[1, 2]], b: 1 }, { a: [[3, 4]], c: 2 });
expect(result).toEqual({ a: [[3, 4]], b: 1, c: 2 });
});

test('merging objects with identical nested structure', () => {
const result = deepMerge({ a: { b: { c: 1 } } }, { a: { b: { c: 2 } } });
expect(result).toEqual({ a: { b: { c: 2 } } });
});

test('merging with undefined in both initial and override', () => {
const result = deepMerge({ a: undefined }, { a: undefined });
expect(result).toEqual({ a: undefined });
});

test('merging with functions in deep structures', () => {
const func = () => {};
const result = deepMerge({ a: { b: func } }, { a: { c: 1 } });
expect(result).toEqual({ a: { b: func, c: 1 } });
});
});

0 comments on commit fd1837c

Please sign in to comment.