(filePath: string, source: string)
| 57 | }; |
| 58 | |
| 59 | export async function extractSymbols(filePath: string, source: string): Promise<ExtractedSymbol[]> { |
| 60 | const lang = detectLanguage(filePath); |
| 61 | if (!lang) return []; |
| 62 | |
| 63 | // Try Tree-sitter first |
| 64 | const parserResult = await getParser(lang).catch(() => null); |
| 65 | if (parserResult) { |
| 66 | try { |
| 67 | return extractWithTreeSitter(parserResult, lang, source); |
| 68 | } catch (e: any) { |
| 69 | logger.warn('Tree-sitter extraction failed, falling back to regex', { file: filePath, err: e.message }); |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | // Fallback: regex heuristics per language |
| 74 | return extractWithRegex(lang, source); |
| 75 | } |
| 76 | |
| 77 | function extractWithTreeSitter( |
| 78 | parserResult: { parser: any; language: any }, |
no test coverage detected