perf: Cache import mappings and index fuzzy matches for resolution

Two major optimizations for the ref resolution phase:

1. Cache extractImportMappings() results per file path — previously
   re-read and re-parsed the source file for every single ref from
   that file (e.g. 100 refs from one file = 100 identical file reads)

2. Replace linear scan in matchFuzzy() with a lazily-built
   case-insensitive Map index — O(1) lookup instead of iterating
   all function/method/class nodes for every unresolved ref.
   Also drop low-value prefix matching (confidence 0.3).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Olaf Monien
2026-02-12 19:29:18 +01:00
co-authored by Claude Opus 4.6
parent 44ea6af043
commit ab9d7188c1
3 changed files with 53 additions and 33 deletions
+19 -6
View File
@@ -425,6 +425,16 @@ function extractPHPImports(content: string): ImportMapping[] {
return mappings;
}
// Cache import mappings per file to avoid re-reading and re-parsing
const importMappingCache = new Map<string, ImportMapping[]>();
/**
* Clear the import mapping cache (call between indexing runs)
*/
export function clearImportMappingCache(): void {
importMappingCache.clear();
}
/**
* Resolve a reference using import mappings
*/
@@ -432,14 +442,17 @@ export function resolveViaImport(
ref: UnresolvedRef,
context: ResolutionContext
): ResolvedRef | null {
// Read the source file to extract imports
const content = context.readFile(ref.filePath);
if (!content) {
return null;
// Use cached import mappings or extract and cache them
let imports = importMappingCache.get(ref.filePath);
if (!imports) {
const content = context.readFile(ref.filePath);
if (!content) {
return null;
}
imports = extractImportMappings(ref.filePath, content, ref.language);
importMappingCache.set(ref.filePath, imports);
}
const imports = extractImportMappings(ref.filePath, content, ref.language);
// Check if the reference name matches any import
for (const imp of imports) {
if (imp.localName === ref.referenceName || ref.referenceName.startsWith(imp.localName + '.')) {