feat(05-02): create highlightText utility function
- Wrap matching text in <mark> tags with bold styling - Escape HTML before highlighting to prevent XSS - 2-character minimum query requirement - Uses bg-transparent (no background per CONTEXT.md)
This commit is contained in:
36
src/lib/utils/highlightText.ts
Normal file
36
src/lib/utils/highlightText.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Wraps matching text in <mark> tags for highlighting.
|
||||||
|
* Returns HTML string to be used with {@html} in Svelte.
|
||||||
|
*
|
||||||
|
* @param text - The text to search within
|
||||||
|
* @param query - The search query to highlight
|
||||||
|
* @returns HTML string with matches wrapped in <mark> tags
|
||||||
|
*/
|
||||||
|
export function highlightText(text: string, query: string): string {
|
||||||
|
// Don't highlight if query is too short
|
||||||
|
if (!query || query.length < 2) return escapeHtml(text);
|
||||||
|
|
||||||
|
// Escape HTML in the original text first
|
||||||
|
const escaped = escapeHtml(text);
|
||||||
|
|
||||||
|
// Escape regex special characters in query
|
||||||
|
const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
const regex = new RegExp(`(${escapedQuery})`, 'gi');
|
||||||
|
|
||||||
|
// Wrap matches in <mark> with bold styling (no background per CONTEXT.md)
|
||||||
|
return escaped.replace(regex, '<mark class="font-bold bg-transparent">$1</mark>');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes HTML special characters to prevent XSS.
|
||||||
|
*/
|
||||||
|
function escapeHtml(text: string): string {
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
"'": '''
|
||||||
|
};
|
||||||
|
return text.replace(/[&<>"']/g, (char) => map[char]);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user