(rootDir: string)
| 178 | } |
| 179 | |
| 180 | async function buildIdentifierIndex(rootDir: string): Promise<IdentifierIndex> { |
| 181 | if (cachedIndex && cachedRootDir === rootDir && Date.now() - cachedAt < INDEX_TTL_MS) { |
| 182 | return cachedIndex; |
| 183 | } |
| 184 | |
| 185 | const entries = await walkDirectory({ rootDir, depthLimit: 0 }); |
| 186 | const files = entries.filter((entry) => !entry.isDirectory && isSupportedFile(entry.path)); |
| 187 | const docs: IdentifierDoc[] = []; |
| 188 | const fileLines = new Map<string, string[]>(); |
| 189 | |
| 190 | for (const file of files) { |
| 191 | try { |
| 192 | const content = await readFile(file.path, "utf-8"); |
| 193 | fileLines.set(file.relativePath, content.split("\n")); |
| 194 | const analysis = await analyzeFile(file.path); |
| 195 | const flat = flattenSymbols(analysis.symbols); |
| 196 | for (const symbol of flat) { |
| 197 | docs.push({ |
| 198 | id: `${file.relativePath}:${symbol.name}:${symbol.line}`, |
| 199 | path: file.relativePath, |
| 200 | header: analysis.header, |
| 201 | name: symbol.name, |
| 202 | kind: symbol.kind, |
| 203 | line: symbol.line, |
| 204 | endLine: symbol.endLine, |
| 205 | signature: symbol.signature, |
| 206 | parentName: symbol.parentName, |
| 207 | text: `${symbol.name} ${symbol.kind} ${symbol.signature} ${file.relativePath} ${analysis.header} ${symbol.parentName ?? ""}`, |
| 208 | }); |
| 209 | } |
| 210 | } catch { |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | if (docs.length === 0) { |
| 215 | const empty: IdentifierIndex = { docs: [], vectors: [], fileLines }; |
| 216 | cachedIndex = empty; |
| 217 | cachedRootDir = rootDir; |
| 218 | cachedAt = Date.now(); |
| 219 | return empty; |
| 220 | } |
| 221 | |
| 222 | const cache = await loadEmbeddingCache(rootDir, IDENTIFIER_CACHE_FILE); |
| 223 | const vectors: number[][] = new Array(docs.length); |
| 224 | const uncached: { idx: number; key: string; hash: string; text: string }[] = []; |
| 225 | |
| 226 | for (let i = 0; i < docs.length; i++) { |
| 227 | const text = docs[i].text; |
| 228 | const hash = hashContent(text); |
| 229 | const key = `id:${docs[i].id}`; |
| 230 | if (cache[key]?.hash === hash) { |
| 231 | vectors[i] = cache[key].vector; |
| 232 | } else { |
| 233 | uncached.push({ idx: i, key, hash, text }); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | if (uncached.length > 0) { |
no test coverage detected