| 280 | * only that file's speedup. |
| 281 | */ |
| 282 | export function tryKernelExtract( |
| 283 | filePath: string, |
| 284 | source: string, |
| 285 | language: Language |
| 286 | ): ExtractionResult | null { |
| 287 | if (!kernelRoutes(language)) return null; |
| 288 | const kernel = getKernel(); |
| 289 | if (!kernel) return null; |
| 290 | if (takeDeferredPreParse(filePath, source, language) !== null) return null; // already deferred |
| 291 | const t0 = Date.now(); |
| 292 | const pre = preParsedSource(filePath, source, language); |
| 293 | try { |
| 294 | const buffers = kernel.extractFile(filePath, pre, language); |
| 295 | const result = decodeExtractBuffers(buffers, filePath, language); |
| 296 | POST_PASSES[language]?.(result, source); |
| 297 | result.durationMs = Date.now() - t0; |
| 298 | return result; |
| 299 | } catch (err) { |
| 300 | const message = err instanceof Error ? err.message : String(err); |
| 301 | // `defer:` is the kernel's expected-routing signal (files with parse |
| 302 | // errors take the wasm path — its error RECOVERY is the canonical one; |
| 303 | // recovery differs between UTF-8 and UTF-16 parsing). Silent by design. |
| 304 | if (message.includes('defer:')) { |
| 305 | deferSlot = { filePath, source, language, pre }; |
| 306 | return null; |
| 307 | } |
| 308 | if (!warned.has(language)) { |
| 309 | warned.add(language); |
| 310 | process.stderr.write( |
| 311 | `[codegraph-kernel] ${language} extraction failed (${message}) — falling back to the wasm path\n` |
| 312 | ); |
| 313 | } |
| 314 | return null; |
| 315 | } |
| 316 | } |