* 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
)
| 2188 | * Used by the parallel batch reader to avoid redundant file I/O. |
| 2189 | */ |
| 2190 | async indexFileWithContent( |
| 2191 | relativePath: string, |
| 2192 | content: string, |
| 2193 | stats: fs.Stats |
| 2194 | ): Promise<ExtractionResult> { |
| 2195 | // Prevent `../` traversal; follow in-root symlinks like the directory walk (#935). |
| 2196 | const fullPath = validatePathWithinRoot(this.rootDir, relativePath, { allowSymlinkEscape: true }); |
| 2197 | if (!fullPath) { |
| 2198 | logWarn('Path traversal blocked in indexFileWithContent', { relativePath }); |
| 2199 | return { |
| 2200 | nodes: [], |
| 2201 | edges: [], |
| 2202 | unresolvedReferences: [], |
| 2203 | errors: [{ message: 'Path traversal blocked', filePath: relativePath, severity: 'error', code: 'path_traversal' }], |
| 2204 | durationMs: 0, |
| 2205 | }; |
| 2206 | } |
| 2207 | |
| 2208 | // Check file size |
| 2209 | if (stats.size > MAX_FILE_SIZE) { |
| 2210 | return { |
| 2211 | nodes: [], |
| 2212 | edges: [], |
| 2213 | unresolvedReferences: [], |
| 2214 | errors: [ |
| 2215 | { |
| 2216 | message: `File exceeds max size (${stats.size} > ${MAX_FILE_SIZE})`, |
| 2217 | filePath: relativePath, |
| 2218 | severity: 'warning', |
| 2219 | code: 'size_exceeded', |
| 2220 | }, |
| 2221 | ], |
| 2222 | durationMs: 0, |
| 2223 | }; |
| 2224 | } |
| 2225 | |
| 2226 | // Detect language (honoring the project's codegraph.json extension overrides) |
| 2227 | const language = detectLanguage(relativePath, content, loadExtensionOverrides(this.rootDir)); |
| 2228 | if (!isLanguageSupported(language)) { |
| 2229 | return { |
| 2230 | nodes: [], |
| 2231 | edges: [], |
| 2232 | unresolvedReferences: [], |
| 2233 | errors: [], |
| 2234 | durationMs: 0, |
| 2235 | }; |
| 2236 | } |
| 2237 | |
| 2238 | // Extract from source. Use cached framework names if indexAll has run, |
| 2239 | // otherwise detect on the spot so single-file re-index paths still emit |
| 2240 | // route nodes / middleware / etc. |
| 2241 | const frameworkNames = this.ensureDetectedFrameworks(); |
| 2242 | const result = extractFromSource(relativePath, content, language, frameworkNames); |
| 2243 | |
| 2244 | // Store in database |
| 2245 | if (result.nodes.length > 0 || result.errors.length === 0) { |
| 2246 | await this.storeExtractionResult(relativePath, content, language, stats, result, createYielder()); |
| 2247 | } |
no test coverage detected