* Read + JSON-parse a `codegraph.json` once and return its validated view. * Every failure mode degrades to the zero-config default — a missing file, bad * JSON, or a typo'd value never throws.
(file: string)
| 109 | * JSON, or a typo'd value never throws. |
| 110 | */ |
| 111 | function parseConfig(file: string): ParsedConfig { |
| 112 | let raw: string; |
| 113 | try { |
| 114 | raw = fs.readFileSync(file, 'utf-8'); |
| 115 | } catch { |
| 116 | return EMPTY_CONFIG; |
| 117 | } |
| 118 | |
| 119 | let parsed: unknown; |
| 120 | try { |
| 121 | parsed = JSON.parse(raw); |
| 122 | } catch (err) { |
| 123 | logWarn(`Ignoring ${PROJECT_CONFIG_FILENAME}: not valid JSON`, { |
| 124 | file, |
| 125 | error: err instanceof Error ? err.message : String(err), |
| 126 | }); |
| 127 | return EMPTY_CONFIG; |
| 128 | } |
| 129 | |
| 130 | if (!parsed || typeof parsed !== 'object') return EMPTY_CONFIG; |
| 131 | |
| 132 | const extensions = extractExtensions(parsed, file); |
| 133 | const includeIgnored = extractIncludeIgnored(parsed, file); |
| 134 | const exclude = extractExclude(parsed, file); |
| 135 | if (extensions === EMPTY_EXTENSIONS && includeIgnored.length === 0 && exclude.length === 0) { |
| 136 | return EMPTY_CONFIG; |
| 137 | } |
| 138 | return { extensions, includeIgnored, exclude }; |
| 139 | } |
| 140 | |
| 141 | /** |
| 142 | * Validate the `extensions` map. Every failure mode degrades to "no overrides |
no test coverage detected