import type { Root, Element } from 'hast' import type { Plugin } from 'unified' import { visit } from 'unist-util-visit' import { fromHtmlIsomorphic } from 'hast-util-from-html-isomorphic' import { renderMermaidToSvg } from './mermaid-render' /** * A rehype plugin that processes
elements with a data-mermaid attribute and renders the Mermaid chart to SVG. * It replaces the
with the rendered SVG or displays an error message if rendering fails. */ export const rehypeMermaidSsg: Plugin<[], Root> = () => async (tree: Root) => { const targets: { node: Element; parent: Element | Root; index: number }[] = [] visit(tree, 'element', (node: Element, index, parent) => { if ( node.tagName === 'div' && node.properties?.['data-mermaid'] && parent && typeof index === 'number' ) { targets.push({ node, parent: parent as Element | Root, index }) } }) await Promise.all( targets.map(async ({ node, parent, index }) => { const chart = String(node.properties!['data-mermaid']) try { const svg = await renderMermaidToSvg(chart) const svgTree = fromHtmlIsomorphic(svg, { fragment: true }) const svgNode = svgTree.children.find((c) => c.type === 'element') as Element | undefined if (svgNode) { ;(parent.children as Element[])[index] = svgNode } } catch (err) { node.tagName = 'pre' node.properties = { className: ['text-red-500', 'text-sm'] } node.children = [{ type: 'text', value: `Mermaid render error: ${(err as Error).message}` }] } }), ) }