-
Notifications
You must be signed in to change notification settings - Fork 4
/
server_render.go
111 lines (95 loc) · 2.88 KB
/
server_render.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package mermaid
import (
"bytes"
"context"
"fmt"
"html/template"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/util"
)
// Compiler compiles Mermaid diagrams into images.
// It is used with [ServerRenderer] to render Mermaid diagrams server-side.
type Compiler interface {
Compile(context.Context, *CompileRequest) (*CompileResponse, error)
}
// CompileRequest is a request to compile a Mermaid diagram.
type CompileRequest struct {
// Source is the raw Mermaid diagram source.
Source string
}
// CompileResponse is a response from compiling a Mermaid diagram.
type CompileResponse struct {
// SVG holds the SVG diagram text
// including the <svg>...</svg> tags.
SVG string
}
// ServerRenderer renders Mermaid diagrams into images server-side.
//
// By default, it uses [CLICompiler] to compile Mermaid diagrams.
// You can specify a different compiler with [Compiler].
// For long-running processes, you should use the compiler
// provided by the mermaidcdp package.
type ServerRenderer struct {
// Compiler specifies how to compile Mermaid diagrams into images.
//
// If unspecified, this uses CLICompiler.
Compiler Compiler
// ContainerTag is the name of the HTML tag to use for the container
// that holds the Mermaid diagram.
// The name must be without the angle brackets.
//
// Defaults to "div".
ContainerTag string
}
// RegisterFuncs registers the renderer for Mermaid blocks with the provided
// Goldmark Registerer.
func (r *ServerRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(Kind, r.Render)
// Normally, we won't hit this
// because Transformer won't add ScriptBlocks for ServerRenderer.
//
// Guard against the possibility that the document used a different
// transformer.
reg.Register(ScriptKind, func(util.BufWriter, []byte, ast.Node, bool) (ast.WalkStatus, error) {
return ast.WalkContinue, nil // no-op
})
}
// Render renders [Block] nodes.
func (r *ServerRenderer) Render(w util.BufWriter, src []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
compiler := r.Compiler
if compiler == nil {
compiler = new(CLICompiler)
}
tag := r.ContainerTag
if len(tag) == 0 {
tag = "div"
}
n := node.(*Block)
if !entering {
_, _ = w.WriteString("</")
template.HTMLEscape(w, []byte(tag))
_, _ = w.WriteString(">")
return ast.WalkContinue, nil
}
_, _ = w.WriteString("<")
template.HTMLEscape(w, []byte(tag))
_, _ = w.WriteString(` class="mermaid">`)
var buff bytes.Buffer
lines := n.Lines()
for i := 0; i < lines.Len(); i++ {
line := lines.At(i)
buff.Write(line.Value(src))
}
if buff.Len() == 0 {
return ast.WalkContinue, nil
}
res, err := compiler.Compile(context.Background(), &CompileRequest{
Source: buff.String(),
})
if err != nil {
return ast.WalkContinue, fmt.Errorf("generate svg: %w", err)
}
_, err = w.WriteString(res.SVG)
return ast.WalkContinue, err
}