(query: string, queryTerms: Set<string>, doc: SearchDocument, matchedSymbols: string[])
| 384 | } |
| 385 | |
| 386 | function computeKeywordScore(query: string, queryTerms: Set<string>, doc: SearchDocument, matchedSymbols: string[]): number { |
| 387 | if (queryTerms.size === 0) return 0; |
| 388 | const docText = `${doc.path} ${doc.header} ${doc.symbols.join(" ")} ${doc.content}`; |
| 389 | const docTerms = new Set(splitCamelCase(docText)); |
| 390 | const queryLower = query.trim().toLowerCase(); |
| 391 | const phraseBoost = queryLower.length > 0 && docText.toLowerCase().includes(queryLower) ? 0.15 : 0; |
| 392 | const symbolTerms = new Set(splitCamelCase(matchedSymbols.join(" "))); |
| 393 | const termCoverage = getTermCoverage(queryTerms, docTerms); |
| 394 | const symbolCoverage = getTermCoverage(queryTerms, symbolTerms); |
| 395 | return clamp01(termCoverage * 0.65 + symbolCoverage * 0.2 + phraseBoost); |
| 396 | } |
| 397 | |
| 398 | function computeCombinedScore(semanticScore: number, keywordScore: number, options: ResolvedSearchQueryOptions): number { |
| 399 | const semanticComponent = Math.max(semanticScore, 0); |
no test coverage detected