-
Notifications
You must be signed in to change notification settings - Fork 19
/
mermaid.go
100 lines (91 loc) · 2.43 KB
/
mermaid.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
package dot
import (
"fmt"
"html"
"strings"
)
const (
MermaidTopToBottom = iota
MermaidTopDown
MermaidBottomToTop
MermaidRightToLeft
MermaidLeftToRight
)
var (
MermaidShapeRound = shape{"(", ")"}
MermaidShapeStadium = shape{"([", "])"}
MermaidShapeSubroutine = shape{"[[", "]]"}
MermaidShapeCylinder = shape{"[(", ")]"}
MermaidShapeCirle = shape{"((", "))"} // Deprecated: use MermaidShapeCircle instead
MermaidShapeCircle = shape{"((", "))"}
MermaidShapeAsymmetric = shape{">", "]"}
MermaidShapeRhombus = shape{"{", "}"}
MermaidShapeTrapezoid = shape{"[/", "\\]"}
MermaidShapeTrapezoidAlt = shape{"[\\", "/]"}
)
type shape struct {
open, close string
}
func MermaidGraph(g *Graph, orientation int) string {
return diagram(g, "graph", orientation)
}
func MermaidFlowchart(g *Graph, orientation int) string {
return diagram(g, "flowchart", orientation)
}
func escape(value string) string {
return fmt.Sprintf(`"%s"`, html.EscapeString(value))
}
func diagram(g *Graph, diagramType string, orientation int) string {
sb := new(strings.Builder)
sb.WriteString(diagramType)
sb.WriteRune(' ')
switch orientation {
case MermaidTopDown, MermaidTopToBottom:
sb.WriteString("TD")
case MermaidBottomToTop:
sb.WriteString("BT")
case MermaidRightToLeft:
sb.WriteString("RL")
case MermaidLeftToRight:
sb.WriteString("LR")
default:
sb.WriteString("TD")
}
writeEnd(sb)
// graph nodes
for _, key := range g.sortedNodesKeys() {
nodeShape := MermaidShapeRound
each := g.nodes[key]
if s := each.GetAttr("shape"); s != nil {
nodeShape = s.(shape)
}
txt := "?"
if label := each.GetAttr("label"); label != nil {
txt = label.(string)
}
fmt.Fprintf(sb, "\tn%d%s%s%s;\n", each.seq, nodeShape.open, escape(txt), nodeShape.close)
if style := each.GetAttr("style"); style != nil {
fmt.Fprintf(sb, "\tstyle n%d %s\n", each.seq, style.(string))
}
}
// all edges
// graph edges
denoteEdge := "-->"
if g.graphType == "graph" {
denoteEdge = "---"
}
for _, each := range g.sortedEdgesFromKeys() {
all := g.edgesFrom[each]
for _, each := range all {
if label := each.GetAttr("label"); label != nil {
fmt.Fprintf(sb, "\tn%d%s|%s|n%d;\n", each.from.seq, denoteEdge, escape(label.(string)), each.to.seq)
} else {
fmt.Fprintf(sb, "\tn%d%sn%d;\n", each.from.seq, denoteEdge, each.to.seq)
}
}
}
return sb.String()
}
func writeEnd(sb *strings.Builder) {
sb.WriteString(";\n")
}