* 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
)
| 1747 | * Used by the parallel batch reader to avoid redundant file I/O. |
| 1748 | */ |
| 1749 | async indexFileWithContent( |
| 1750 | relativePath: string, |
| 1751 | content: string, |
| 1752 | stats: fs.Stats |
| 1753 | ): Promise<ExtractionResult> { |
| 1754 | // Prevent `../` traversal; follow in-root symlinks like the directory walk (#935). |
| 1755 | const fullPath = validatePathWithinRoot(this.rootDir, relativePath, { allowSymlinkEscape: true }); |
| 1756 | if (!fullPath) { |
| 1757 | logWarn('Path traversal blocked in indexFileWithContent', { relativePath }); |
| 1758 | return { |
| 1759 | nodes: [], |
| 1760 | edges: [], |
| 1761 | unresolvedReferences: [], |
| 1762 | errors: [{ message: 'Path traversal blocked', filePath: relativePath, severity: 'error', code: 'path_traversal' }], |
| 1763 | durationMs: 0, |
| 1764 | }; |
| 1765 | } |
| 1766 | |
| 1767 | // Check file size |
| 1768 | if (stats.size > MAX_FILE_SIZE) { |
| 1769 | return { |
| 1770 | nodes: [], |
| 1771 | edges: [], |
| 1772 | unresolvedReferences: [], |
| 1773 | errors: [ |
| 1774 | { |
| 1775 | message: `File exceeds max size (${stats.size} > ${MAX_FILE_SIZE})`, |
| 1776 | filePath: relativePath, |
| 1777 | severity: 'warning', |
| 1778 | code: 'size_exceeded', |
| 1779 | }, |
| 1780 | ], |
| 1781 | durationMs: 0, |
| 1782 | }; |
| 1783 | } |
| 1784 | |
| 1785 | // Detect language (honoring the project's codegraph.json extension overrides) |
| 1786 | const language = detectLanguage(relativePath, content, loadExtensionOverrides(this.rootDir)); |
| 1787 | if (!isLanguageSupported(language)) { |
| 1788 | return { |
| 1789 | nodes: [], |
| 1790 | edges: [], |
| 1791 | unresolvedReferences: [], |
| 1792 | errors: [], |
| 1793 | durationMs: 0, |
| 1794 | }; |
| 1795 | } |
| 1796 | |
| 1797 | // Extract from source. Use cached framework names if indexAll has run, |
| 1798 | // otherwise detect on the spot so single-file re-index paths still emit |
| 1799 | // route nodes / middleware / etc. |
| 1800 | const frameworkNames = this.ensureDetectedFrameworks(); |
| 1801 | const result = extractFromSource(relativePath, content, language, frameworkNames); |
| 1802 | |
| 1803 | // Store in database |
| 1804 | if (result.nodes.length > 0 || result.errors.length === 0) { |
| 1805 | this.storeExtractionResult(relativePath, content, language, stats, result); |
| 1806 | } |
no test coverage detected