highlight.ts (1657B)
1 // Language-agnostic operator's-eye command highlighter, ported from 2 // daemon-sec's terminal-highlight. Emits an HTML string (escaped) so it can be 3 // used both server-side (Astro `set:html`) and in the client island — one 4 // implementation, no drift. 5 6 export const escapeHtml = (s: string) => 7 String(s) 8 .replace(/&/g, '&') 9 .replace(/</g, '<') 10 .replace(/>/g, '>') 11 .replace(/"/g, '"'); 12 13 const TOKENISER = /'[^']*'|"[^"]*"|\S+|\s+/g; 14 15 export function highlightCommand(source: string): string { 16 return String(source) 17 .split('\n') 18 .map((line) => { 19 if (/^\s*#/.test(line)) return `<span class="tk-muted">${escapeHtml(line)}</span>`; 20 let firstWord = true; 21 let out = ''; 22 const toks = line.match(TOKENISER) || []; 23 for (const tok of toks) { 24 if (/^\s+$/.test(tok)) { out += escapeHtml(tok); continue; } 25 let cls = 'tk-base'; 26 if (tok.startsWith('#')) cls = 'tk-muted'; 27 else if (/REDACTED|PLACEHOLDER/.test(tok)) cls = 'tk-warn'; 28 else if (/^(SQL>|PS>|>|\$|#)$/.test(tok)) cls = 'tk-kw'; 29 else if (tok.startsWith('-')) cls = 'tk-flag'; 30 else if (tok.startsWith("'") || tok.startsWith('"')) cls = 'tk-str'; 31 else if (/^[\d.]+$/.test(tok) || /^\d{1,3}(\.\d{1,3}){3}/.test(tok)) cls = 'tk-num'; 32 else if (/^(\||&&|>|>>|\\|;|\|\|)$/.test(tok)) cls = 'tk-op'; 33 else if (/^[a-z]+:\/\//i.test(tok)) cls = 'tk-num'; 34 else if (firstWord) cls = 'tk-cmd'; 35 out += `<span class="${cls}">${escapeHtml(tok)}</span>`; 36 if (!/^\s+$/.test(tok)) firstWord = false; 37 } 38 return out; 39 }) 40 .join('\n'); 41 }