From 56dd53a29dedef5ccbb1d8b8a267d2d7bb90f6bf Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 18 Nov 2024 10:52:14 +0100 Subject: [PATCH] feat: properly handle arrays --- src/index.ts | 14 +++++++++----- src/utils.ts | 28 ++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/index.ts b/src/index.ts index 050b3b2..c0cf313 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,14 +8,18 @@ import { deepMerge } from './utils' * * @param {object} options - The configuration options. * @param {string} options.name - The name of the configuration file. - * @param {string} [options.cwd] - The current working directory. If not provided, defaults to the current process's working directory. + * @param {string} [options.cwd] - The current working directory. * @param {T} options.defaultConfig - The default configuration. - * @returns {Promise} The merged configuration object. + * @returns {Promise} The merged configuration. * @example ```ts - * // imports from example.config.{ts,js} and merges with default config - * await loadConfig({ name: 'example', defaultConfig: { foo: 'bar' } }) + * // Merges arrays if both configs are arrays, otherwise does object deep merge + * await loadConfig({ + * name: 'example', + * defaultConfig: [{ foo: 'bar' }] + * }) + * ``` */ -export async function loadConfig>({ name, cwd, defaultConfig }: Config): Promise { +export async function loadConfig({ name, cwd, defaultConfig }: Config): Promise { const configPath = resolve(cwd || process.cwd(), `${name}.config`) try { diff --git a/src/utils.ts b/src/utils.ts index 566216f..e82e88f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,25 +1,37 @@ /** - * Deep merge objects + * Deep merge objects or arrays * - * @param target - The target object - * @param sources - The source objects - * @returns The merged object - * @example deepMerge({ foo: 'bar' }, { bar: 'baz' }) // { foo: 'bar', bar: 'baz' } + * @param target - The target object or array + * @param sources - The source objects or arrays + * @returns The merged result */ -export function deepMerge(target: T, ...sources: Array>): T { +export function deepMerge(target: T, ...sources: Partial[]): T { if (!sources.length) return target const source = sources.shift() + if (!source) + return target + + if (Array.isArray(target) && Array.isArray(source)) { + // If both are arrays, concatenate them + return [...target, ...source] as T + } if (isObject(target) && isObject(source)) { for (const key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { const sourceValue = source[key] - if (isObject(sourceValue) && isObject(target[key])) { - target[key] = deepMerge(target[key] as any, sourceValue as any) + if (Array.isArray(sourceValue) && Array.isArray((target as any)[key])) { + // Merge arrays within objects + (target as any)[key] = [...(target as any)[key], ...sourceValue] + } + else if (isObject(sourceValue) && isObject((target as any)[key])) { + // Deep merge nested objects + (target as any)[key] = deepMerge((target as any)[key], sourceValue) } else { + // Replace primitive values and objects/arrays that don't match in type (target as any)[key] = sourceValue } }