Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798const BLOCK = /<pre><code((?: [a-z-]+="[^"]*")*?) class="language-([^"]+)"((?: [a-z-]+="[^"]*")*)>([\s\S]*?)<\/code><\/pre>/g;
const MAX_BLOCK_CHARS = 200_000;
const ENTITIES: Record<string, string> = { amp: "&", lt: "<", gt: ">", quot: '"', "#39": "'", "#x27": "'", "#x2F": "/"};
const decodeEntities = (value: string): string => value.replace(/&(#x[0-9a-fA-F]+|#\d+|[a-zA-Z#0-9]+);/g, (match, body: string) => { if (body.startsWith("#x") || body.startsWith("#X")) try { return String.fromCodePoint(parseInt(body.slice(2), 16)); } catch { return match; } if (body.startsWith("#")) { const point = parseInt(body.slice(1), 10); return Number.isNaN(point) ? match : String.fromCodePoint(point); } return ENTITIES[body] ?? match; });
const INNER = /<code[^>]*>([\s\S]*)<\/code>\s*<\/pre>/;
type Highlighter = Awaited<ReturnType<typeof import("@pierre/diffs").getSharedHighlighter>>;
type Loaded = { highlighter: Highlighter; theme: string };
// importing this lazily keeps shiki out of markdown pages with no codeconst loadHighlighter = async (langs: string[]): Promise<Loaded | null> => { try { const { SYNTAX_THEME_NAME, getSharedHighlighter } = await import("$lib/syntax"); const highlighter = await getSharedHighlighter({ themes: [SYNTAX_THEME_NAME], langs }); return { highlighter, theme: SYNTAX_THEME_NAME }; } catch { return null; }};
const highlightInner = (loaded: Loaded, code: string, lang: string): string | null => { let full: string; try { full = loaded.highlighter.codeToHtml(code, { lang, theme: loaded.theme, defaultColor: false, cssVariablePrefix: "--diffs-token-" }); } catch { return null; } return INNER.exec(full)?.[1] ?? null;};
export const highlightCodeblocks = async (html: string): Promise<string> => { const found = [...html.matchAll(BLOCK)]; if (found.length === 0) return html;
const blocks = found.flatMap((match) => { const [raw, before, lang, after, escaped] = match as unknown as [ string, string, string, string, string ]; const code = decodeEntities(escaped); return code.length > 0 && code.length <= MAX_BLOCK_CHARS ? [{ raw, before, lang, after, code }] : []; }); if (blocks.length === 0) return html;
const loaded = await loadHighlighter([...new Set(blocks.map((block) => block.lang))]); if (!loaded) return html;
const swapped = new Map<string, string>(); for (const block of blocks) { if (swapped.has(block.raw)) continue; const inner = highlightInner(loaded, block.code, block.lang); if (inner !== null) swapped.set( block.raw, `<pre><code${block.before} class="language-${block.lang}"${block.after}>${inner}</code></pre>` ); } if (swapped.size === 0) return html; return html.replace(BLOCK, (raw) => swapped.get(raw) ?? raw);};