/**
* TypeDoc plugin that properly decodes HTML entities in mermaid code blocks.
*
* This runs BEFORE the mermaid plugin and converts HTML entities back to raw
* characters, allowing mermaid to parse them correctly.
*
* The @boneskull/typedoc-plugin-mermaid converts < to #lt; and > to #gt;,
* but those aren't valid mermaid entities (mermaid uses numeric codes like #60;).
* This plugin sidesteps the issue by decoding entities before mermaid sees them.
*/
import { Renderer } from "typedoc";
/**
* Decode HTML entities back to raw characters.
* @param {string} html - HTML-encoded string
* @returns {string} Decoded string
*/
function decodeHtmlEntities(html) {
return html
.replace(/(\d+);/g, (_, num) => String.fromCharCode(parseInt(num, 10)))
.replace(/([0-9a-fA-F]+);/g, (_, hex) =>
String.fromCharCode(parseInt(hex, 16)),
)
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/&/g, "&"); // Must be last
}
/**
* TypeDoc plugin entry point.
* @param {import('typedoc').Application} app
*/
export function load(app) {
// Use high priority (200) to run before the mermaid plugin (default is 0)
app.renderer.on(
Renderer.EVENT_END_PAGE,
(page) => {
if (!page.contents) return;
// Find mermaid code blocks and decode HTML entities
page.contents = page.contents.replace(
/([\s\S]*?)<\/code>/g,
(match, code) => {
const decoded = decodeHtmlEntities(code);
return `${decoded}`;
},
);
},
200,
);
}