mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
34 lines
1.2 KiB
TypeScript
34 lines
1.2 KiB
TypeScript
/**
|
|||
|
|
* Case-insensitive fuzzy match: a query matches a target when every query
|
||
|
|
* character appears in the target in order (not necessarily contiguous).
|
||
|
|
* Lower scores rank first. An exact substring hit ranks by how early it
|
||
|
|
* starts; a non-contiguous subsequence hit is penalized by the total gap
|
||
|
|
* between matched characters so tighter matches still outrank loose ones.
|
||
|
|
* Returns null when the query isn't a subsequence of the target at all.
|
||
|
|
*/
|
||
|
|
export function fuzzyScore(query: string, target: string): number | null {
|
||
|
|
const q = query.trim().toLowerCase();
|
||
|
|
if (!q) return 0;
|
||
|
|
const t = target.toLowerCase();
|
||
|
|
|
||
|
|
const substringIndex = t.indexOf(q);
|
||
|
|
if (substringIndex !== -1) return substringIndex;
|
||
|
|
|
||
|
|
let searchFrom = 0;
|
||
|
|
let gap = 0;
|
||
|
|
let lastMatch = -1;
|
||
|
|
for (const ch of q) {
|
||
|
|
const found = t.indexOf(ch, searchFrom);
|
||
|
|
if (found === -1) return null;
|
||
|
|
if (lastMatch !== -1) gap += found - lastMatch - 1;
|
||
|
|
lastMatch = found;
|
||
|
|
searchFrom = found + 1;
|
||
|
|
}
|
||
|
|
return t.length + gap;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** True when `query` fuzzy-matches `target` (see `fuzzyScore`). */
|
||
|
|
export function fuzzyMatch(query: string, target: string): boolean {
|
||
|
|
return fuzzyScore(query, target) !== null;
|
||
|
|
}
|