* Index a single file with pre-read content and stats. * Used by the parallel batch reader to avoid redundant file I/O.
(
relativePath: string,
content: string,
stats: fs.Stats
)
| 2669 | * Used by the parallel batch reader to avoid redundant file I/O. |
| 2670 | */ |
| 2671 | async indexFileWithContent( |
| 2672 | relativePath: string, |
| 2673 | content: string, |
| 2674 | stats: fs.Stats |
| 2675 | ): Promise<ExtractionResult> { |
| 2676 | // Prevent `../` traversal; follow in-root symlinks like the directory walk (#935). |
| 2677 | const fullPath = validatePathWithinRoot(this.rootDir, relativePath, { allowSymlinkEscape: true }); |
| 2678 | if (!fullPath) { |
| 2679 | logWarn('Path traversal blocked in indexFileWithContent', { relativePath }); |
| 2680 | return { |
| 2681 | nodes: [], |
| 2682 | edges: [], |
| 2683 | unresolvedReferences: [], |
| 2684 | errors: [{ message: 'Path traversal blocked', filePath: relativePath, severity: 'error', code: 'path_traversal' }], |
| 2685 | durationMs: 0, |
| 2686 | }; |
| 2687 | } |
| 2688 | |
| 2689 | const language = detectLanguage(relativePath, content, loadExtensionOverrides(this.rootDir)); |
| 2690 | |
| 2691 | // Check file size |
| 2692 | if (stats.size > MAX_SOURCE_FILE_SIZE_BYTES) { |
| 2693 | const result: ExtractionResult = { |
| 2694 | nodes: [], |
| 2695 | edges: [], |
| 2696 | unresolvedReferences: [], |
| 2697 | errors: [ |
| 2698 | { |
| 2699 | message: `File exceeds max size (${stats.size} > ${MAX_SOURCE_FILE_SIZE_BYTES})`, |
| 2700 | filePath: relativePath, |
| 2701 | severity: 'warning', |
| 2702 | code: 'size_exceeded', |
| 2703 | }, |
| 2704 | ], |
| 2705 | durationMs: 0, |
| 2706 | }; |
| 2707 | await this.storeExtractionResult(relativePath, content, language, stats, result, createYielder()); |
| 2708 | return result; |
| 2709 | } |
| 2710 | |
| 2711 | // Detect language (honoring the project's codegraph.json extension overrides) |
| 2712 | if (!isLanguageSupported(language)) { |
| 2713 | return { |
| 2714 | nodes: [], |
| 2715 | edges: [], |
| 2716 | unresolvedReferences: [], |
| 2717 | errors: [], |
| 2718 | durationMs: 0, |
| 2719 | }; |
| 2720 | } |
| 2721 | |
| 2722 | // Extract from source. Use cached framework names if indexAll has run, |
| 2723 | // otherwise detect on the spot so single-file re-index paths still emit |
| 2724 | // route nodes / middleware / etc. |
| 2725 | const frameworkNames = this.ensureDetectedFrameworks(); |
| 2726 | const result = extractFromSource(relativePath, content, language, frameworkNames); |
| 2727 | |
| 2728 | // Store in database |
no test coverage detected