Skip to content

Commit

Permalink
Merge pull request #24 from nao1215/flowchart
Browse files Browse the repository at this point in the history
Introduce mermaid flowchart syntax
  • Loading branch information
nao1215 authored May 6, 2024
2 parents cbbac3b + 3f182a6 commit 4d412d0
Show file tree
Hide file tree
Showing 24 changed files with 796 additions and 57 deletions.
86 changes: 85 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# What is markdown package
The Package markdown is a simple markdown builder in golang. The markdown package assembles Markdown using method chaining, not uses a template engine like [html/template](https://pkg.go.dev/html/template). The syntax of Markdown follows **GitHub Markdown**.

The markdown package was initially developed to save test results in [nao1215/spectest](https://github.com/nao1215/spectest). Therefore, the markdown package implements the features required by spectest. For example, the markdown package supports **mermaid sequence diagrams (entity relationship diagram, sequence diagram, pie chart)**, which was a necessary feature in spectest.
The markdown package was initially developed to save test results in [nao1215/spectest](https://github.com/nao1215/spectest). Therefore, the markdown package implements the features required by spectest. For example, the markdown package supports **mermaid sequence diagrams (entity relationship diagram, sequence diagram, flowchart, pie chart)**, which was a necessary feature in spectest.

Additionally, complex code that increases the complexity of the library, such as generating nested lists, will not be added. I want to keep this library as simple as possible.

Expand All @@ -34,6 +34,7 @@ Additionally, complex code that increases the complexity of the library, such as
- [x] Alerts; NOTE, TIP, IMPORTANT, CAUTION, WARNING
- [x] mermaid sequence diagram
- [x] mermaid entity relationship diagram
- [x] mermaid flowchart
- [x] mermaid pie chart

### Features not in Markdown syntax
Expand Down Expand Up @@ -165,6 +166,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

md.NewMarkdown(f).
H1("go generate example").
Expand Down Expand Up @@ -366,6 +368,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

teachers := er.NewEntity(
"teachers",
Expand Down Expand Up @@ -523,6 +526,86 @@ erDiagram
}
```

### Flowchart syntax

```go
package main

import (
"io"
"os"

"github.com/nao1215/markdown"
"github.com/nao1215/markdown/mermaid/flowchart"
)

//go:generate go run main.go

func main() {
f, err := os.Create("generated.md")
if err != nil {
panic(err)
}
defer f.Close()

fc := flowchart.NewFlowchart(
io.Discard,
flowchart.WithTitle("mermaid flowchart builder"),
flowchart.WithOrientalTopToBottom(),
).
NodeWithText("A", "Node A").
StadiumNode("B", "Node B").
SubroutineNode("C", "Node C").
DatabaseNode("D", "Database").
LinkWithArrowHead("A", "B").
LinkWithArrowHeadAndText("B", "D", "send original data").
LinkWithArrowHead("B", "C").
DottedLinkWithText("C", "D", "send filtered data").
String()

err = markdown.NewMarkdown(f).
H2("Flowchart").
CodeBlocks(markdown.SyntaxHighlightMermaid, fc).
Build()

if err != nil {
panic(err)
}
}
```

Plain text output: [markdown is here](./doc/flowchart/generated.md)
````
## Flowchart
```mermaid
---
title: mermaid flowchart builder
---
flowchart TB
A["Node A"]
B(["Node B"])
C[["Node C"]]
D[("Database")]
A-->B
B-->|"send original data"|D
B-->C
C-. "send filtered data" .-> D
```
````

Mermaid output:
```mermaid
flowchart TB
A["Node A"]
B(["Node B"])
C[["Node C"]]
D[("Database")]
A-->B
B-->|"send original data"|D
B-->C
C-. "send filtered data" .-> D
```

### Pie chart syntax

```go
Expand All @@ -543,6 +626,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

chart := piechart.NewPieChart(
io.Discard,
Expand Down
1 change: 1 addition & 0 deletions doc/alert/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

if err := md.NewMarkdown(f).
H1("Alert example").
Expand Down
1 change: 1 addition & 0 deletions doc/badge/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

if err := md.NewMarkdown(f).
H1("badge example").
Expand Down
1 change: 1 addition & 0 deletions doc/er/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

teachers := er.NewEntity(
"teachers",
Expand Down
15 changes: 15 additions & 0 deletions doc/flowchart/generated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Flowchart
```mermaid
---
title: mermaid flowchart builder
---
flowchart TB
A["Node A"]
B(["Node B"])
C[["Node C"]]
D[("Database")]
A-->B
B-->|"send original data"|D
B-->C
C-. "send filtered data" .-> D
```
46 changes: 46 additions & 0 deletions doc/flowchart/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//go:build linux || darwin

// Package main is generating flowchart.
package main

import (
"io"
"os"

"github.com/nao1215/markdown"
"github.com/nao1215/markdown/mermaid/flowchart"
)

//go:generate go run main.go

func main() {
f, err := os.Create("generated.md")
if err != nil {
panic(err)
}
defer f.Close()

fc := flowchart.NewFlowchart(
io.Discard,
flowchart.WithTitle("mermaid flowchart builder"),
flowchart.WithOrientalTopToBottom(),
).
NodeWithText("A", "Node A").
StadiumNode("B", "Node B").
SubroutineNode("C", "Node C").
DatabaseNode("D", "Database").
LinkWithArrowHead("A", "B").
LinkWithArrowHeadAndText("B", "D", "send original data").
LinkWithArrowHead("B", "C").
DottedLinkWithText("C", "D", "send filtered data").
String()

err = markdown.NewMarkdown(f).
H2("Flowchart").
CodeBlocks(markdown.SyntaxHighlightMermaid, fc).
Build()

if err != nil {
panic(err)
}
}
1 change: 1 addition & 0 deletions doc/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

if err := md.NewMarkdown(f).
H1("go generate example").
Expand Down
1 change: 1 addition & 0 deletions doc/piechart/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

chart := piechart.NewPieChart(
io.Discard,
Expand Down
1 change: 1 addition & 0 deletions doc/sequence/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func main() {
if err != nil {
panic(err)
}
defer f.Close()

diagram := sequence.NewDiagram(io.Discard).
Participant("Sophia").
Expand Down
12 changes: 12 additions & 0 deletions internal/lf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Package internal package is used to store the internal implementation of the mermaid package.
package internal

import "runtime"

// LineFeed return line feed for current OS.
func LineFeed() string {
if runtime.GOOS == "windows" {
return "\r\n"
}
return "\n"
}
28 changes: 28 additions & 0 deletions internal/lf_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Package internal package is used to store the internal implementation of the mermaid package.
package internal

import (
"runtime"
"testing"
)

func TestLineFeed(t *testing.T) {
t.Parallel()

t.Run("should return line feed for current OS", func(t *testing.T) {
t.Parallel()

got := LineFeed()

switch runtime.GOOS {
case "windows":
if got != "\r\n" {
t.Errorf("expected \\r\\n, but got %s", got)
}
default:
if got != "\n" {
t.Errorf("expected \\n, but got %s", got)
}
}
})
}
23 changes: 8 additions & 15 deletions markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ package markdown
import (
"fmt"
"io"
"runtime"
"strings"

"github.com/nao1215/markdown/internal"
"github.com/olekukonko/tablewriter"
)

Expand Down Expand Up @@ -126,7 +126,7 @@ func NewMarkdown(w io.Writer) *Markdown {

// String returns markdown text.
func (m *Markdown) String() string {
return strings.Join(m.body, lineFeed())
return strings.Join(m.body, internal.LineFeed())
}

// Error returns error.
Expand Down Expand Up @@ -238,7 +238,8 @@ func (m *Markdown) H6f(format string, args ...interface{}) *Markdown {
func (m *Markdown) Details(summary, text string) *Markdown {
m.body = append(
m.body,
fmt.Sprintf("<details><summary>%s</summary>%s%s%s</details>", summary, lineFeed(), text, lineFeed()))
fmt.Sprintf("<details><summary>%s</summary>%s%s%s</details>",
summary, internal.LineFeed(), text, internal.LineFeed()))
return m
}

Expand Down Expand Up @@ -288,7 +289,7 @@ func (m *Markdown) CheckBox(set []CheckBoxSet) *Markdown {
// Blockquote is markdown blockquote.
// If you set text "Hello", it will be converted to "> Hello".
func (m *Markdown) Blockquote(text string) *Markdown {
lines := strings.Split(text, lineFeed())
lines := strings.Split(text, internal.LineFeed())
for _, line := range lines {
m.body = append(m.body, fmt.Sprintf("> %s", line))
}
Expand All @@ -302,7 +303,7 @@ func (m *Markdown) Blockquote(text string) *Markdown {
// ```".
func (m *Markdown) CodeBlocks(lang SyntaxHighlight, text string) *Markdown {
m.body = append(m.body,
fmt.Sprintf("```%s%s%s%s```", lang, lineFeed(), text, lineFeed()))
fmt.Sprintf("```%s%s%s%s```", lang, internal.LineFeed(), text, internal.LineFeed()))
return m
}

Expand Down Expand Up @@ -345,7 +346,7 @@ func (m *Markdown) Table(t TableSet) *Markdown {

buf := &strings.Builder{}
table := tablewriter.NewWriter(buf)
table.SetNewLine(lineFeed())
table.SetNewLine(internal.LineFeed())
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
table.SetCenterSeparator("|")
table.SetHeader(t.Header)
Expand Down Expand Up @@ -379,7 +380,7 @@ func (m *Markdown) CustomTable(t TableSet, options TableOptions) *Markdown {

buf := &strings.Builder{}
table := tablewriter.NewWriter(buf)
table.SetNewLine(lineFeed())
table.SetNewLine(internal.LineFeed())
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
table.SetCenterSeparator("|")
table.SetAutoWrapText(options.AutoWrapText)
Expand All @@ -401,11 +402,3 @@ func (m *Markdown) LF() *Markdown {
m.body = append(m.body, " ")
return m
}

// lineFeed return line feed for current OS.
func lineFeed() string {
if runtime.GOOS == "windows" {
return "\r\n"
}
return "\n"
}
Loading

0 comments on commit 4d412d0

Please sign in to comment.