-
Notifications
You must be signed in to change notification settings - Fork 4
/
extend.go
148 lines (128 loc) · 3.72 KB
/
extend.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package mermaid
import (
"fmt"
"os/exec"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/util"
)
// Extender adds support for Mermaid diagrams to a Goldmark Markdown parser.
//
// Use it by installing it to the goldmark.Markdown object upon creation.
type Extender struct {
// RenderMode specifies which renderer the Extender should install.
//
// Defaults to AutoRenderMode, picking renderers
// based on the availability of the Mermaid CLI.
RenderMode RenderMode
// Compiler specifies how to compile Mermaid diagrams server-side.
//
// If specified, and render mode is not set to client-side,
// this will be used to render diagrams.
Compiler Compiler
// CLI specifies how to invoke the Mermaid CLI
// to compile Mermaid diagrams server-side.
//
// If specified, and render mode is not set to client-side,
// this will be used to render diagrams.
//
// If both CLI and Compiler are specified, Compiler takes precedence.
CLI CLI
// URL of Mermaid Javascript to be included in the page
// for client-side rendering.
//
// Ignored if NoScript is true or if we're rendering diagrams server-side.
//
// Defaults to the latest version available on cdn.jsdelivr.net.
MermaidURL string
// HTML tag to use for the container element for diagrams.
//
// Defaults to "pre" for client-side rendering,
// and "div" for server-side rendering.
ContainerTag string
// If true, don't add a <script> including Mermaid to the end of the
// page even if rendering diagrams client-side.
//
// Use this if the page you're including goldmark-mermaid in
// already has a MermaidJS script included elsewhere.
NoScript bool
// Theme for mermaid diagrams.
//
// Ignored if we're rendering diagrams client-side.
//
// Values include "dark", "default", "forest", and "neutral".
// See MermaidJS documentation for a full list.
Theme string
execLookPath func(string) (string, error) // == exec.LookPath
}
// Extend extends the provided Goldmark parser with support for Mermaid
// diagrams.
func (e *Extender) Extend(md goldmark.Markdown) {
mode, r := e.renderer()
md.Parser().AddOptions(
parser.WithASTTransformers(
util.Prioritized(&Transformer{
// If rendering server-side,
// don't generate <script> tags.
NoScript: e.NoScript || mode == RenderModeServer,
}, 100),
),
)
md.Renderer().AddOptions(
renderer.WithNodeRenderers(
util.Prioritized(r, 100),
),
)
}
func (e *Extender) renderer() (RenderMode, renderer.NodeRenderer) {
mode := e.RenderMode
compiler, ok := e.compiler()
if mode == RenderModeAuto {
if ok {
mode = RenderModeServer
} else {
mode = RenderModeClient
}
}
switch mode {
case RenderModeClient:
return RenderModeClient, &ClientRenderer{
MermaidURL: e.MermaidURL,
ContainerTag: e.ContainerTag,
}
case RenderModeServer:
return RenderModeServer, &ServerRenderer{
Compiler: compiler,
ContainerTag: e.ContainerTag,
}
default:
panic(fmt.Sprintf("unrecognized render mode: %v", mode))
}
}
// compiler returns the Compiler to use for server-side rendering
// only if server-side rendering should be used.
//
// The following conditions will cause server-side rendering:
//
// - Compiler is set
// - CLI is set (will use CLICompiler)
// - mmdc is available on $PATH
func (e *Extender) compiler() (c Compiler, ok bool) {
if e.Compiler != nil {
return e.Compiler, true
}
if e.CLI != nil {
return &CLICompiler{CLI: e.CLI, Theme: e.Theme}, true
}
lookPath := exec.LookPath
if e.execLookPath != nil {
lookPath = e.execLookPath
}
mmdcPath, err := lookPath("mmdc")
if err != nil {
return nil, false
}
cli := &mmdcCLI{Path: mmdcPath}
return &CLICompiler{CLI: cli, Theme: e.Theme}, true
}