import type { OxlintConfig } from './types'; /** * Deep merge two objects. Arrays are concatenated, objects are recursively merged. */ function deepMerge(target: Record, source: Record): Record { const result = { ...target }; for (const key of Object.keys(source)) { const targetValue = target[key]; const sourceValue = source[key]; if ( typeof targetValue === 'object' && targetValue !== null && !Array.isArray(targetValue) && typeof sourceValue === 'object' && sourceValue !== null && !Array.isArray(sourceValue) ) { result[key] = deepMerge( targetValue as Record, sourceValue as Record, ); } else { result[key] = sourceValue; } } return result; } /** * Compose multiple oxlint configurations into a single config. * * - `plugins` — union (deduplicated) * - `categories` — later configs override earlier * - `rules` — later configs override earlier * - `overrides` — concatenated * - `env` — merged (later overrides earlier) * - `globals` — merged (later overrides earlier) * - `settings` — deep-merged * - `ignorePatterns` — concatenated * * @example * ```ts * import { compose, base, typescript, vue } from '@robonen/oxlint'; * import { defineConfig } from 'oxlint'; * * export default defineConfig( * compose(base, typescript, vue, { * rules: { 'eslint/no-console': 'off' }, * }), * ); * ``` */ export function compose(...configs: OxlintConfig[]): OxlintConfig { const result: OxlintConfig = {}; for (const config of configs) { // Plugins — union with dedup if (config.plugins?.length) { result.plugins = Array.from(new Set([...(result.plugins ?? []), ...config.plugins])); } // Categories — shallow merge if (config.categories) { result.categories = { ...result.categories, ...config.categories }; } // Rules — shallow merge (later overrides earlier) if (config.rules) { result.rules = { ...result.rules, ...config.rules }; } // Overrides — concatenate if (config.overrides?.length) { result.overrides = [...(result.overrides ?? []), ...config.overrides]; } // Env — shallow merge if (config.env) { result.env = { ...result.env, ...config.env }; } // Globals — shallow merge if (config.globals) { result.globals = { ...result.globals, ...config.globals }; } // Settings — deep merge if (config.settings) { result.settings = deepMerge( (result.settings ?? {}) as Record, config.settings as Record, ); } // Ignore patterns — concatenate if (config.ignorePatterns?.length) { result.ignorePatterns = [...(result.ignorePatterns ?? []), ...config.ignorePatterns]; } } return result; }