Enhance search result merging and Svelte component extraction

Changes search result deduplication to use max scores across channels instead of first-seen prioritization, adds template component usage extraction for Svelte files, exempts exact matches from single-term score dampening, prioritizes structural edges in graph traversal, and increases explore tool node budget while including edge source locations in file clustering.
This commit is contained in:
Colby McHenry
2026-04-08 17:27:35 -05:00
parent 88fa716418
commit 19532a81a5
4 changed files with 111 additions and 16 deletions
+47
View File
@@ -54,6 +54,9 @@ export class SvelteExtractor {
// Extract function calls from template expressions ({fn(...)})
this.extractTemplateCalls(componentNode.id, scriptBlocks);
// Extract component usages from template (<ComponentName>)
this.extractTemplateComponents(componentNode.id);
// Filter out Svelte rune calls ($state, $props, $derived, etc.)
this.unresolvedReferences = this.unresolvedReferences.filter(
ref => !SVELTE_RUNES.has(ref.referenceName)
@@ -273,4 +276,48 @@ export class SvelteExtractor {
}
}
}
/**
* Extract component usages from the Svelte template.
*
* PascalCase tags like <Modal>, <Button />, <DevServerPreview> represent
* component instantiations — analogous to function calls in imperative code.
* Capturing these creates graph edges from parent to child components and
* gives codegraph_explore anchor points in the template markup.
*/
private extractTemplateComponents(componentNodeId: string): void {
// Build ranges covered by <script> and <style> blocks to skip them
const coveredRanges: Array<[number, number]> = [];
const tagRegex = /<(script|style)(\s[^>]*)?>[\s\S]*?<\/\1>/g;
let tagMatch;
while ((tagMatch = tagRegex.exec(this.source)) !== null) {
const startLine = (this.source.substring(0, tagMatch.index).match(/\n/g) || []).length;
const endLine = startLine + (tagMatch[0].match(/\n/g) || []).length;
coveredRanges.push([startLine, endLine]);
}
const lines = this.source.split('\n');
// Match PascalCase opening/self-closing tags (closing tags </Foo> start with </ so won't match)
const componentTagRegex = /<([A-Z][a-zA-Z0-9_$]*)\b/g;
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
if (coveredRanges.some(([start, end]) => lineIdx >= start && lineIdx <= end)) continue;
const line = lines[lineIdx]!;
let match;
while ((match = componentTagRegex.exec(line)) !== null) {
const componentName = match[1]!;
this.unresolvedReferences.push({
fromNodeId: componentNodeId,
referenceName: componentName,
referenceKind: 'references',
line: lineIdx + 1, // 1-indexed
column: match.index + 1,
filePath: this.filePath,
language: 'svelte',
});
}
}
}
}