interface TextPart { text: string hit: boolean } export function searchTerms(query: string): string[] { return query.trim().toLowerCase().split(/\s+/).filter(Boolean) } export function highlight(text: string, query: string): TextPart[] { const terms = searchTerms(query) if (!terms.length) return [{ text, hit: false }] const escaped = terms.map(term => term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) return text .split(new RegExp(`(${escaped.join('|')})`, 'gi')) .map((part, index) => ({ text: part, hit: index % 2 === 1 })) .filter(part => part.text) }