(shiki: HighlighterCore, code: string, language: string)
| 102 | * @returns HTML string with syntax highlighting |
| 103 | */ |
| 104 | export function highlightCodeSync(shiki: HighlighterCore, code: string, language: string): string { |
| 105 | const loadedLangs = shiki.getLoadedLanguages() |
| 106 | |
| 107 | if (loadedLangs.includes(language as never)) { |
| 108 | try { |
| 109 | let html = shiki.codeToHtml(code, { |
| 110 | lang: language, |
| 111 | themes: { light: 'github-light', dark: 'github-dark' }, |
| 112 | defaultColor: 'dark', |
| 113 | }) |
| 114 | // Remove inline style from <pre> tag so CSS can control appearance |
| 115 | html = html.replace(/<pre([^>]*) style="[^"]*"/, '<pre$1') |
| 116 | // Shiki doesn't encode > in text content (e.g., arrow functions =>) |
| 117 | // We need to encode them for HTML validation |
| 118 | return escapeRawGt(html) |
| 119 | } catch { |
| 120 | // Fall back to plain |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | // Plain code block for unknown languages |
| 125 | const escaped = code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') |
| 126 | return `<pre><code class="language-${language}">${escaped}</code></pre>\n` |
| 127 | } |
| 128 | |
| 129 | /** |
| 130 | * Highlight a code block with syntax highlighting (async convenience wrapper). |
no test coverage detected