import { readFileSync, existsSync } from 'fs'; import { resolve, join } from 'path'; import type { CoverageConfig, CLIOptions } from './types'; const DEFAULT_CONFIG: CoverageConfig = { exclude: [ '**/node_modules/**', '**/dist/**', '**/build/**', '**/coverage/**', '**/*.test.ts', '**/*.test.js', '**/*.spec.ts', '**/*.spec.js', '**/test/**', '**/tests/**', '**/__tests__/**', '**/__mocks__/**', '**/setup.ts', '**/setup.js', ], reporters: ['terminal'], thresholds: { lines: 80, functions: 80, branches: 80, statements: 80, }, outputDir: 'coverage', }; export function loadConfig(options: CLIOptions): CoverageConfig { let config = { ...DEFAULT_CONFIG }; // Load from config file const configPath = options.config || findConfigFile(); if (configPath && existsSync(configPath)) { try { const fileConfig = JSON.parse(readFileSync(configPath, 'utf-8')); config = mergeConfig(config, fileConfig); } catch (error) { console.warn(`Warning: Failed to load config from ${configPath}:`, error); } } // Override with CLI options if (options.exclude && options.exclude.length > 0) { config.exclude = options.exclude; } if (options.include && options.include.length > 0) { config.include = options.include; } if (options.reporters && options.reporters.length > 0) { config.reporters = options.reporters as any[]; } if (options.outputDir) { config.outputDir = options.outputDir; } // Handle thresholds if (options.threshold !== undefined) { config.thresholds = { lines: options.threshold, functions: options.threshold, branches: options.threshold, statements: options.threshold, }; } if (options.thresholdLines !== undefined) { config.thresholds.lines = options.thresholdLines; } if (options.thresholdFunctions !== undefined) { config.thresholds.functions = options.thresholdFunctions; } if (options.thresholdBranches !== undefined) { config.thresholds.branches = options.thresholdBranches; } if (options.thresholdStatements !== undefined) { config.thresholds.statements = options.thresholdStatements; } if (options.packages) { config.packages = options.packages; } // Find workspace root config.workspaceRoot = findWorkspaceRoot(); return config; } function findConfigFile(): string | null { const configNames = ['.coveragerc.json', '.coveragerc', 'coverage.config.json']; const searchDirs = [process.cwd(), ...getParentDirs(process.cwd())]; for (const dir of searchDirs) { for (const name of configNames) { const path = join(dir, name); if (existsSync(path)) { return path; } } } return null; } function findWorkspaceRoot(): string { const searchDirs = [process.cwd(), ...getParentDirs(process.cwd())]; for (const dir of searchDirs) { // Check for common workspace indicators if ( existsSync(join(dir, 'package.json')) && (existsSync(join(dir, 'packages')) || existsSync(join(dir, 'apps')) || existsSync(join(dir, 'libs'))) ) { return dir; } } return process.cwd(); } function getParentDirs(dir: string): string[] { const parents: string[] = []; let current = resolve(dir); let parent = resolve(current, '..'); while (parent !== current) { parents.push(parent); current = parent; parent = resolve(current, '..'); } return parents; } function mergeConfig(base: CoverageConfig, override: Partial): CoverageConfig { return { ...base, ...override, thresholds: { ...base.thresholds, ...(override.thresholds || {}), }, }; }