Files
homepage/src/lib/js/fuzzy.ts
T
Alexander 2deb2c6c09 add fzf-style fuzzy search to exercises, recipes, and prayers
Replace substring matching with a shared fuzzy scorer that matches
characters in order (non-contiguous) with bonuses for consecutive
and word-boundary hits. Results are ranked by match quality.
2026-03-19 10:10:38 +01:00

43 lines
1.0 KiB
TypeScript

/**
* fzf-style fuzzy match: characters must appear in order (non-contiguous).
* Returns 0 for no match, higher scores for better matches.
*/
export function fuzzyScore(query: string, text: string): number {
if (query.length === 0) return 1;
let qi = 0;
let score = 0;
let consecutive = 0;
let prevMatchIdx = -2;
for (let ti = 0; ti < text.length && qi < query.length; ti++) {
if (text[ti] === query[qi]) {
qi++;
score += 1;
// Bonus for consecutive matches
if (ti === prevMatchIdx + 1) {
consecutive++;
score += consecutive * 2;
} else {
consecutive = 0;
}
// Bonus for matching at word boundary (start, after space/punctuation)
if (ti === 0 || /[\s()\-_/]/.test(text[ti - 1])) {
score += 5;
}
prevMatchIdx = ti;
}
}
// All query chars must be found
if (qi < query.length) return 0;
// Bonus for closer match length to query length (tighter matches)
const span = prevMatchIdx - (text.indexOf(query[0]) ?? 0) + 1;
score += Math.max(0, query.length * 2 - span);
return score;
}