| type Mergeable = |
| | Record<string, unknown> |
| | unknown[] |
| | string |
| | number |
| | boolean |
| | null |
| | undefined; |
|
|
| function isPlainObject(value: unknown): value is Record<string, unknown> { |
| return typeof value === "object" && value !== null && !Array.isArray(value); |
| } |
|
|
| export function mergeConfig<T extends Mergeable>(base: T, override: unknown): T { |
| if (override === undefined || override === null) { |
| return base; |
| } |
|
|
| if (Array.isArray(base)) { |
| return (Array.isArray(override) ? [...override] : [...base]) as T; |
| } |
|
|
| if (isPlainObject(base)) { |
| if (!isPlainObject(override)) { |
| return { ...base } as T; |
| } |
|
|
| const result: Record<string, unknown> = { ...base }; |
| for (const [key, value] of Object.entries(override)) { |
| const baseValue = result[key]; |
| if (Array.isArray(value)) { |
| result[key] = [...value]; |
| continue; |
| } |
| if (isPlainObject(baseValue) && isPlainObject(value)) { |
| result[key] = mergeConfig(baseValue, value); |
| continue; |
| } |
| result[key] = value; |
| } |
| return result as T; |
| } |
|
|
| return override as T; |
| } |
|
|