35 lines
1.4 KiB
Go
35 lines
1.4 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
||
|
|
|
||
|
|
package markdown
|
||
|
|
|
||
|
|
import (
|
||
|
|
stdhtml "html"
|
||
|
|
"regexp"
|
||
|
|
|
||
|
|
"sourcedock.dev/petrbalvin/scriptorium"
|
||
|
|
)
|
||
|
|
|
||
|
|
// mermaidBlockRe matches the fenced mermaid blocks the renderer writes.
|
||
|
|
// The diagram source arrives HTML-escaped, as code content always does.
|
||
|
|
var mermaidBlockRe = regexp.MustCompile(`(?s)<pre><code class="language-mermaid">(.*?)</code></pre>`)
|
||
|
|
|
||
|
|
// renderDiagrams replaces every fenced mermaid block with the SVG
|
||
|
|
// scriptorium draws from it, wrapped so a style sheet can tell diagrams
|
||
|
|
// from prose. It runs on sanitised HTML: the SVG is machine-drawn output
|
||
|
|
// whose vocabulary the library itself bounds, and the sanitiser's
|
||
|
|
// HTML-only parser would corrupt its case-sensitive attributes. A
|
||
|
|
// diagram the library does not carry, or a line it cannot parse, keeps
|
||
|
|
// its code block: the author sees the source that was not understood,
|
||
|
|
// and the reader never a half-drawn figure.
|
||
|
|
func renderDiagrams(html string) string {
|
||
|
|
return mermaidBlockRe.ReplaceAllStringFunc(html, func(block string) string {
|
||
|
|
src := stdhtml.UnescapeString(mermaidBlockRe.FindStringSubmatch(block)[1])
|
||
|
|
svg, err := scriptorium.RenderDiagram([]byte(src))
|
||
|
|
if err != nil {
|
||
|
|
return block
|
||
|
|
}
|
||
|
|
return `<div class="diagram">` + "\n" + string(svg) + "\n</div>"
|
||
|
|
})
|
||
|
|
}
|