From 285b2f67e967286019f0f29d1f0921134347a586 Mon Sep 17 00:00:00 2001 From: Nantha Sorubakanthan Date: Mon, 3 Nov 2025 19:58:32 +0100 Subject: Syntax highlighting from javascript script --- scripts/highlight.mjs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 scripts/highlight.mjs (limited to 'scripts/highlight.mjs') diff --git a/scripts/highlight.mjs b/scripts/highlight.mjs new file mode 100644 index 0000000..2870866 --- /dev/null +++ b/scripts/highlight.mjs @@ -0,0 +1,57 @@ +import { createHighlighter, bundledLanguages } from 'shiki'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { readFile, writeFile } from 'node:fs/promises'; +import { glob } from 'glob'; +import { parseDocument } from 'htmlparser2'; +import { findAll, findOne, textContent, replaceElement } from 'domutils'; +import render from 'dom-serializer'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +main(); + +async function main() { + const LIGHT_THEME = 'github-dark'; + const DARK_THEME = LIGHT_THEME; + + const start = Date.now(); + + const highlighter = await createHighlighter({ + themes: [LIGHT_THEME, DARK_THEME], + langs: Object.keys(bundledLanguages), + }); + + const files = await glob(join(__dirname, '../public/**/**/index.html')); + await Promise.all( + files.map((filepath) => highlightFile(highlighter, filepath, { lightTheme: LIGHT_THEME, darkTheme: DARK_THEME })) + ); + + console.log(`Highlighted ${files.length} files in ${Math.round(Date.now() - start)} ms`); +} + +async function highlightFile(highlighter, filepath, { lightTheme, darkTheme }) { + const contents = await readFile(filepath, { encoding: 'utf-8' }); + await writeFile(filepath, highlightHtmlContent(highlighter, contents, { lightTheme, darkTheme })); +} + +function highlightHtmlContent(highlighter, htmlContent, { lightTheme, darkTheme }) { + const doc = parseDocument(htmlContent); + for (const preNode of findAll((e) => e.name === 'pre', doc.children)) { + const codeNode = findOne((e) => e.name === 'code', preNode.children); + if (!codeNode) continue; + + const lang = codeNode.attribs['class']?.replace(/^language-/, '') ?? 'text'; + const code = textContent(codeNode); + const highlighted = highlighter.codeToHtml(code, { + lang, + themes: { light: lightTheme, dark: darkTheme }, + }); + + const highlightedPreNode = parseDocument(highlighted).children[0]; + replaceElement(preNode, highlightedPreNode); + } + + return render(doc); +} + -- cgit v1.2.3