* 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)
| 125 | * JSON, or a typo'd value never throws. |
| 126 | */ |
| 127 | function parseConfig(file: string): ParsedConfig { |
| 128 | let raw: string; |
| 129 | try { |
| 130 | raw = fs.readFileSync(file, 'utf-8'); |
| 131 | } catch { |
| 132 | return EMPTY_CONFIG; |
| 133 | } |
| 134 | |
| 135 | let parsed: unknown; |
| 136 | try { |
| 137 | parsed = JSON.parse(raw); |
| 138 | } catch (err) { |
| 139 | logWarn(`Ignoring ${PROJECT_CONFIG_FILENAME}: not valid JSON`, { |
| 140 | file, |
| 141 | error: err instanceof Error ? err.message : String(err), |
| 142 | }); |
| 143 | return EMPTY_CONFIG; |
| 144 | } |
| 145 | |
| 146 | if (!parsed || typeof parsed !== 'object') return EMPTY_CONFIG; |
| 147 | |
| 148 | const extensions = extractExtensions(parsed, file); |
| 149 | const includeIgnored = extractIncludeIgnored(parsed, file); |
| 150 | const exclude = extractExclude(parsed, file); |
| 151 | const include = extractInclude(parsed, file); |
| 152 | if ( |
| 153 | extensions === EMPTY_EXTENSIONS && |
| 154 | includeIgnored.length === 0 && |
| 155 | exclude.length === 0 && |
| 156 | include.length === 0 |
| 157 | ) { |
| 158 | return EMPTY_CONFIG; |
| 159 | } |
| 160 | return { extensions, includeIgnored, exclude, include }; |
| 161 | } |
| 162 | |
| 163 | /** |
| 164 | * Validate the `extensions` map. Every failure mode degrades to "no overrides |
no test coverage detected