simple mermaid builder in golang: support ER/sequence diagram, pie chart
nchika
Posted on May 5, 2024
Markdown with mermaid
I previously introduced the nao1215/markdown package as a markdown builder for the Go language (previously it was go-spectest/markdown, but the Owner has changed). What syntax do you want when writing markdown? I thought it was important to support mermaid. When we write design documents, we should be able to write not only text but also sequence diagrams and ER diagrams.
I decided to support some mermaid syntax in the markdown package. This article introduces that.
Mermaid sequence diagram syntax
Sample code
package main
import (
"os"
"github.com/nao1215/markdown"
"github.com/nao1215/mermaid/sequence"
)
//go:generate go run main.go
func main() {
diagram := sequence.NewDiagram(io.Discard).
Participant("Sophia").
Participant("David").
Participant("Subaru").
LF().
SyncRequest("Sophia", "David", "Please wake up Subaru").
SyncResponse("David", "Sophia", "OK").
LF().
LoopStart("until Subaru wake up").
SyncRequest("David", "Subaru", "Wake up!").
SyncResponse("Subaru", "David", "zzz").
SyncRequest("David", "Subaru", "Hey!!!").
BreakStart("if Subaru wake up").
SyncResponse("Subaru", "David", "......").
BreakEnd().
LoopEnd().
LF().
SyncResponse("David", "Sophia", "wake up, wake up").
String()
markdown.NewMarkdown(os.Stdout).
H2("Sequence Diagram").
CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
Build()
}
Generated markdown with sequence diagram
## Sequence Diagram ```mermaid sequenceDiagram participant Sophia participant David participant Subaru Sophia->>David: Please wake up Subaru David-->>Sophia: OK loop until Subaru wake up David->>Subaru: Wake up! Subaru-->>David: zzz David->>Subaru: Hey!!! break if Subaru wake up Subaru-->>David: ...... end end David-->>Sophia: wake up, wake up ```
Mermaid entity relationsip diagram syntax
Sample code
package main
import (
"os"
"github.com/nao1215/markdown"
"github.com/nao1215/markdown/mermaid/er"
)
//go:generate go run main.go
func main() {
f, err := os.Create("generated.md")
if err != nil {
panic(err)
}
teachers := er.NewEntity(
"teachers",
[]*er.Attribute{
{
Type: "int",
Name: "id",
IsPrimaryKey: true,
IsForeignKey: false,
IsUniqueKey: true,
Comment: "Teacher ID",
},
{
Type: "string",
Name: "name",
IsPrimaryKey: false,
IsForeignKey: false,
IsUniqueKey: false,
Comment: "Teacher Name",
},
},
)
students := er.NewEntity(
"students",
[]*er.Attribute{
{
Type: "int",
Name: "id",
IsPrimaryKey: true,
IsForeignKey: false,
IsUniqueKey: true,
Comment: "Student ID",
},
{
Type: "string",
Name: "name",
IsPrimaryKey: false,
IsForeignKey: false,
IsUniqueKey: false,
Comment: "Student Name",
},
{
Type: "int",
Name: "teacher_id",
IsPrimaryKey: false,
IsForeignKey: true,
IsUniqueKey: true,
Comment: "Teacher ID",
},
},
)
schools := er.NewEntity(
"schools",
[]*er.Attribute{
{
Type: "int",
Name: "id",
IsPrimaryKey: true,
IsForeignKey: false,
IsUniqueKey: true,
Comment: "School ID",
},
{
Type: "string",
Name: "name",
IsPrimaryKey: false,
IsForeignKey: false,
IsUniqueKey: false,
Comment: "School Name",
},
{
Type: "int",
Name: "teacher_id",
IsPrimaryKey: false,
IsForeignKey: true,
IsUniqueKey: true,
Comment: "Teacher ID",
},
},
)
erString := er.NewDiagram(f).
Relationship(
teachers,
students,
er.ExactlyOneRelationship, // "||"
er.ZeroToMoreRelationship, // "}o"
er.Identifying, // "--"
"Teacher has many students",
).
Relationship(
teachers,
schools,
er.OneToMoreRelationship, // "|}"
er.ExactlyOneRelationship, // "||"
er.NonIdentifying, // ".."
"School has many teachers",
).
String()
err = markdown.NewMarkdown(f).
H2("Entity Relationship Diagram").
CodeBlocks(markdown.SyntaxHighlightMermaid, erString).
Build()
if err != nil {
panic(err)
}
}
Generated markdown with entity relationship diagram
## Entity Relationship Diagram ```mermaid erDiagram teachers ||--o{ students : "Teacher has many students" teachers }|..|| schools : "School has many teachers" schools { int id PK,UK "School ID" string name "School Name" int teacher_id FK,UK "Teacher ID" } students { int id PK,UK "Student ID" string name "Student Name" int teacher_id FK,UK "Teacher ID" } teachers { int id PK,UK "Teacher ID" string name "Teacher Name" } ```
Mermaid pie chart syntax
Sample code
package main
import (
"io"
"os"
"github.com/nao1215/markdown"
"github.com/nao1215/markdown/mermaid/piechart"
)
//go:generate go run main.go
func main() {
f, err := os.Create("generated.md")
if err != nil {
panic(err)
}
chart := piechart.NewPieChart(
io.Discard,
piechart.WithTitle("mermaid pie chart builder"),
piechart.WithShowData(true),
).
LabelAndIntValue("A", 10).
LabelAndFloatValue("B", 20.1).
LabelAndIntValue("C", 30).
String()
err = markdown.NewMarkdown(f).
H2("Pie Chart").
CodeBlocks(markdown.SyntaxHighlightMermaid, chart).
Build()
if err != nil {
panic(err)
}
}
Generated markdown with pie chart diagram
## Pie Chart ```mermaid %%{init: {"pie": {"textPosition": 0.75}, "themeVariables": {"pieOuterStrokeWidth": "5px"}} }%% pie showData title mermaid pie chart builder "A" : 10 "B" : 20.100000 "C" : 30 ```
Next work
This new markdown package, which incorporates Mermaid support, enables a more diverse range of expressions when writing design documents, including sequence diagrams, ER diagrams, and more, alongside traditional text.
In the future, I will continue to develop to support more Mermaid syntax. If you're interested, please try using the nao1215/markdown package.
Thank you for reading this article.
Posted on May 5, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.