}
}
+async function detectAndHighlight(rawCode: string): Promise<string> {
+ const code = decodeEntities(rawCode).trimEnd();
+ const detected = hljs.highlightAuto(code);
+ let lang = 'text';
+ if (detected.language && detected.relevance >= MIN_RELEVANCE && detected.language in bundledLanguages) {
+ lang = detected.language;
+ } else if (code.trimStart().startsWith('<')) {
+ lang = 'xml';
+ }
+ return toShiki(code, lang);
+}
+
async function highlightBody(html: string): Promise<string> {
- // Pass 1: labeled Markdown blocks — <pre><code class="language-LANG">...</code></pre>
+ // Pass 1: labeled blocks — <pre><code class="language-LANG">...</code></pre>
html = await replaceAsync(
html,
/<pre><code class="language-([^"]+)">([\s\S]*?)<\/code><\/pre>/g,
}
);
- // Pass 2: unlabeled APT blocks — <pre>...</pre> (no attributes)
+ // Pass 2: unlabeled blocks with code wrapper — <pre><code>...</code></pre>
+ html = await replaceAsync(
+ html,
+ /<pre><code>([\s\S]*?)<\/code><\/pre>/g,
+ async (_, rawCode) => detectAndHighlight(rawCode)
+ );
+
+ // Pass 3: plain APT blocks — <pre>...</pre> (no attributes, no code wrapper)
html = await replaceAsync(
html,
/<pre>([\s\S]*?)<\/pre>/g,
- async (_, rawCode) => {
- const code = decodeEntities(rawCode).trimEnd();
- const detected = hljs.highlightAuto(code);
- let lang = 'text';
- if (detected.language && detected.relevance >= MIN_RELEVANCE && detected.language in bundledLanguages) {
- lang = detected.language;
- } else if (code.trimStart().startsWith('<')) {
- lang = 'xml';
- }
- return toShiki(code, lang);
- }
+ async (_, rawCode) => detectAndHighlight(rawCode)
);
return html;