markdown

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 13, 2026 License: MIT Imports: 13 Imported by: 41

README

All Contributors

Go Reference MultiPlatformUnitTest reviewdog Gosec Coverage

What is markdown package

The markdown package is a simple Markdown builder in Go. It assembles Markdown using method chaining, and does not use a template engine like html/template. The syntax follows GitHub Markdown.

It covers the GitHub Markdown syntax: headings, lists, checkbox lists, tables, code blocks, blockquotes, horizontal rules, text formatting, links, images, details, footnotes, math expressions, and alerts. It also builds 24 mermaid diagram types, from sequence and flowchart to Gantt, C4 context, and Wardley map; each one has an example below. Two helpers go beyond Markdown syntax: status badges and an index for a directory full of markdown files.

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.

Supported OS and go version

  • OS: Linux, macOS, Windows
  • Go: 1.23 or later

Example

Basic usage
package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	md.NewMarkdown(os.Stdout, md.WithBlockSpacing()).
		H1("This is H1").
		PlainText("This is plain text").
		H2f("This is %s with text format", "H2").
		PlainTextf("Text formatting, such as %s and %s, %s styles.",
			md.Bold("bold"), md.Italic("italic"), md.Code("code")).
		H2("Code Block").
		CodeBlocks(md.SyntaxHighlightGo,
			`package main
import "fmt"

func main() {
	fmt.Println("Hello, World!")
}`).
		H2("List").
		BulletList("Bullet Item 1", "Bullet Item 2", "Bullet Item 3").
		OrderedList("Ordered Item 1", "Ordered Item 2", "Ordered Item 3").
		H2("CheckBox").
		CheckBox([]md.CheckBoxSet{
			{Checked: false, Text: md.Code("sample code")},
			{Checked: true, Text: md.Link("Go", "https://golang.org")},
			{Checked: false, Text: md.Strikethrough("strikethrough")},
		}).
		H2("Blockquote").
		Blockquote("If you can dream it, you can do it.").
		H3("Horizontal Rule").
		HorizontalRule().
		H2("Table").
		Table(md.TableSet{
			Header: []string{"Name", "Age", "Country"},
			Rows: [][]string{
				{"David", "23", "USA"},
				{"John", "30", "UK"},
				{"Bob", "25", "Canada"},
			},
		}).
		H2("Image").
		PlainTextf(md.Image("sample_image", "./sample.png")).
		Build()
}

Output:

# This is H1

This is plain text

## This is H2 with text format

Text formatting, such as **bold** and *italic*, `code` styles.

## Code Block

```go
package main
import "fmt"

func main() {
	fmt.Println("Hello, World!")
}
```

## List

- Bullet Item 1
- Bullet Item 2
- Bullet Item 3

1. Ordered Item 1
2. Ordered Item 2
3. Ordered Item 3

## CheckBox

- [ ] `sample code`
- [x] [Go](https://golang.org)
- [ ] ~~strikethrough~~

## Blockquote

> If you can dream it, you can do it.

### Horizontal Rule

---

## Table

| Name | Age | Country |
|---------|---------|---------|
| David | 23 | USA |
| John | 30 | UK |
| Bob | 25 | Canada |

## Image

![sample_image](./sample.png)

If you want to see how it looks in Markdown, please refer to the following link.

Generate Markdown using "go generate ./..."

You can generate Markdown using go generate. Please define code to generate Markdown first. Then, run "go generate ./..." to generate Markdown.

Code example:

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

//go:generate go run main.go

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

	md.NewMarkdown(f).
		H1("go generate example").
		PlainText("This markdown is generated by `go generate`").
		Build()
}

Run below command:

go generate ./...

Output:

# go generate example
This markdown is generated by `go generate`
Alerts syntax

The markdown package can create alerts. Alerts are useful for displaying important information in Markdown. This syntax is supported by GitHub. Code example:

	md.NewMarkdown(f).
		H1("Alert example").
		Note("This is note").LF().
		Tip("This is tip").LF().
		Important("This is important").LF().
		Warning("This is warning").LF().
		Caution("This is caution").LF().
		Build()

Output:

# Alert example
> [!NOTE]  
> This is note
  
> [!TIP]  
> This is tip
  
> [!IMPORTANT]  
> This is important
  
> [!WARNING]  
> This is warning
  
> [!CAUTION]  
> This is caution

Your alert will look like this;

[!NOTE]
This is note

[!TIP]
This is tip

[!IMPORTANT]
This is important

[!WARNING]
This is warning

[!CAUTION]
This is caution

Status badge syntax

The markdown package can create red, yellow, and green status badges. Code example:

	md.NewMarkdown(os.Stdout).
		H1("badge example").
		RedBadge("red_badge").
		YellowBadge("yellow_badge").
		GreenBadge("green_badge").
		BlueBadge("blue_badge").
		Build()

Output:

# badge example
![Badge](https://img.shields.io/badge/red_badge-red)
![Badge](https://img.shields.io/badge/yellow_badge-yellow)
![Badge](https://img.shields.io/badge/green_badge-green)
![Badge](https://img.shields.io/badge/blue_badge-blue)

Your badge will look like this;
Badge Badge Badge Badge

Mermaid sequence diagram syntax
package main

import (
	"io"
	"os"

	"github.com/nao1215/markdown"
	"github.com/nao1215/markdown/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, markdown.WithBlockSpacing()).
		H2("Sequence Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()
}

Plain text output: markdown is here

## 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 output:

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 user journey diagram syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

func main() {
	diagram := userjourney.NewDiagram(
		io.Discard,
		userjourney.WithTitle("Checkout Journey"),
	).
		Section("Discover").
		Task("Browse products", userjourney.ScoreVerySatisfied, "Customer").
		Task("Add item to cart", userjourney.ScoreSatisfied, "Customer").
		LF().
		Section("Checkout").
		Task("Enter shipping details", userjourney.ScoreNeutral, "Customer").
		Task("Complete payment", userjourney.ScoreSatisfied, "Customer", "Payment Service").
		String()

	if err := markdown.NewMarkdown(os.Stdout, markdown.WithBlockSpacing()).
		H2("User Journey Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build(); err != nil {
		panic(err)
	}
}

Plain text output: markdown is here

## User Journey Diagram

```mermaid
journey
    title Checkout Journey
    section Discover
        Browse products: 5: Customer
        Add item to cart: 4: Customer

    section Checkout
        Enter shipping details: 3: Customer
        Complete payment: 4: Customer, Payment Service
```

Mermaid output:

journey
    title Checkout Journey
    section Discover
        Browse products: 5: Customer
        Add item to cart: 4: Customer

    section Checkout
        Enter shipping details: 3: Customer
        Complete payment: 4: Customer, Payment Service
Mermaid git graph syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

func main() {
	diagram := gitgraph.NewDiagram(
		io.Discard,
		gitgraph.WithTitle("Release Flow"),
	).
		Commit(gitgraph.WithCommitID("init"), gitgraph.WithCommitTag("v0.1.0")).
		Branch("develop", gitgraph.WithBranchOrder(2)).
		Checkout("develop").
		Commit(gitgraph.WithCommitType(gitgraph.CommitTypeHighlight)).
		Checkout("main").
		Merge("develop", gitgraph.WithCommitTag("v1.0.0")).
		String()

	if err := markdown.NewMarkdown(os.Stdout, markdown.WithBlockSpacing()).
		H2("Git Graph").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build(); err != nil {
		panic(err)
	}
}

Plain text output: markdown is here

## Git Graph

```mermaid
---
title: "Release Flow"
---
gitGraph
    commit id: "init" tag: "v0.1.0"
    branch develop order: 2
    checkout develop
    commit type: HIGHLIGHT
    checkout main
    merge develop tag: "v1.0.0"
```

Mermaid output:

---
title: "Release Flow"
---
gitGraph
    commit id: "init" tag: "v0.1.0"
    branch develop order: 2
    checkout develop
    commit type: HIGHLIGHT
    checkout main
    merge develop tag: "v1.0.0"
Mermaid mindmap syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

func main() {
	diagram := mindmap.NewDiagram(
		io.Discard,
		mindmap.WithTitle("Product Strategy Mindmap"),
	).
		Root("Product Strategy").
		Child("Market").
		Child("SMB").
		Sibling("Enterprise").
		Parent().
		Sibling("Execution").
		Child("Q1").
		Sibling("Q2").
		String()

	if err := markdown.NewMarkdown(os.Stdout, markdown.WithBlockSpacing()).
		H2("Mindmap").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build(); err != nil {
		panic(err)
	}
}

Plain text output: markdown is here

## Mindmap

```mermaid
---
title: "Product Strategy Mindmap"
---
mindmap
    Product Strategy
        Market
            SMB
            Enterprise
        Execution
            Q1
            Q2
```

Mermaid output:

---
title: "Product Strategy Mindmap"
---
mindmap
    Product Strategy
        Market
            SMB
            Enterprise
        Execution
            Q1
            Q2
Mermaid requirement diagram syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

func main() {
	diagram := requirement.NewDiagram(
		io.Discard,
		requirement.WithTitle("Checkout Requirements"),
	).
		SetDirection(requirement.DirectionTB).
		Requirement(
			"Login",
			requirement.WithID("REQ-1"),
			requirement.WithText("The system shall support login."),
			requirement.WithRisk(requirement.RiskHigh),
			requirement.WithVerifyMethod(requirement.VerifyMethodTest),
			requirement.WithRequirementClasses("critical"),
		).
		FunctionalRequirement(
			"RememberSession",
			requirement.WithID("REQ-2"),
			requirement.WithText("The system shall remember the user."),
			requirement.WithRisk(requirement.RiskMedium),
			requirement.WithVerifyMethod(requirement.VerifyMethodInspection),
		).
		Element(
			"AuthService",
			requirement.WithElementType("system"),
			requirement.WithDocRef("docs/auth.md"),
			requirement.WithElementClasses("service"),
		).
		From("AuthService").
		Satisfies("Login").
		From("RememberSession").
		Verifies("Login").
		ClassDefs(
			requirement.Def("critical", "fill:#f96,stroke:#333,stroke-width:2px"),
			requirement.Def("service", "fill:#9cf,stroke:#333,stroke-width:1px"),
		).
		String()

	if err := markdown.NewMarkdown(os.Stdout, markdown.WithBlockSpacing()).
		H2("Requirement Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build(); err != nil {
		panic(err)
	}
}

Plain text output: markdown is here

## Requirement Diagram

```mermaid
---
title: "Checkout Requirements"
---
requirementDiagram
    direction TB
    requirement Login:::critical {
        id: "REQ-1"
        text: "The system shall support login."
        risk: High
        verifymethod: Test
    }
    functionalRequirement RememberSession {
        id: "REQ-2"
        text: "The system shall remember the user."
        risk: Medium
        verifymethod: Inspection
    }
    element AuthService:::service {
        type: "system"
        docRef: "docs/auth.md"
    }
    AuthService - satisfies -> Login
    RememberSession - verifies -> Login
    classDef critical fill:#f96,stroke:#333,stroke-width:2px
    classDef service fill:#9cf,stroke:#333,stroke-width:1px
```

Mermaid output:

---
title: "Checkout Requirements"
---
requirementDiagram
    direction TB
    requirement Login:::critical {
        id: "REQ-1"
        text: "The system shall support login."
        risk: High
        verifymethod: Test
    }
    functionalRequirement RememberSession {
        id: "REQ-2"
        text: "The system shall remember the user."
        risk: Medium
        verifymethod: Inspection
    }
    element AuthService:::service {
        type: "system"
        docRef: "docs/auth.md"
    }
    AuthService - satisfies -> Login
    RememberSession - verifies -> Login
    classDef critical fill:#f96,stroke:#333,stroke-width:2px
    classDef service fill:#9cf,stroke:#333,stroke-width:1px
Mermaid XY chart syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

func main() {
	diagram := xychart.NewDiagram(
		io.Discard,
		xychart.WithTitle("Sales Revenue"),
	).
		XAxisLabels("Jan", "Feb", "Mar", "Apr", "May", "Jun").
		YAxisRangeWithTitle("Revenue (k$)", 0, 100).
		Bar(25, 40, 60, 80, 70, 90).
		Line(30, 50, 70, 85, 75, 95).
		String()

	if err := markdown.NewMarkdown(os.Stdout, markdown.WithBlockSpacing()).
		H2("XY Chart").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build(); err != nil {
		panic(err)
	}
}

Plain text output: markdown is here

## XY Chart

```mermaid
xychart
    title "Sales Revenue"
    x-axis [Jan, Feb, Mar, Apr, May, Jun]
    y-axis "Revenue (k$)" 0 --> 100
    bar [25, 40, 60, 80, 70, 90]
    line [30, 50, 70, 85, 75, 95]
```

Mermaid output:

xychart
    title "Sales Revenue"
    x-axis [Jan, Feb, Mar, Apr, May, Jun]
    y-axis "Revenue (k$)" 0 --> 100
    bar [25, 40, 60, 80, 70, 90]
    line [30, 50, 70, 85, 75, 95]
Mermaid packet syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

func main() {
	diagram := packet.NewDiagram(
		io.Discard,
		packet.WithTitle("UDP Packet"),
	).
		Next(16, "Source Port").
		Next(16, "Destination Port").
		Field(32, 47, "Length").
		Field(48, 63, "Checksum").
		Field(64, 95, "Data (variable length)").
		String()

	if err := markdown.NewMarkdown(os.Stdout, markdown.WithBlockSpacing()).
		H2("Packet").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build(); err != nil {
		panic(err)
	}
}

Plain text output: markdown is here

## Packet

```mermaid
packet
    title UDP Packet
    +16: "Source Port"
    +16: "Destination Port"
    32-47: "Length"
    48-63: "Checksum"
    64-95: "Data (variable length)"
```

Mermaid output:

packet
    title UDP Packet
    +16: "Source Port"
    +16: "Destination Port"
    32-47: "Length"
    48-63: "Checksum"
    64-95: "Data (variable length)"
Mermaid block syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

func main() {
	diagram := block.NewDiagram(
		io.Discard,
		block.WithTitle("Checkout Architecture"),
	).
		Columns(3).
		Row(
			block.Node("Frontend"),
			block.ArrowRight("toBackend", block.WithArrowLabel("calls")),
			block.Node("Backend"),
		).
		Row(
			block.Space(2),
			block.ArrowDown("toDB"),
		).
		Row(
			block.Node("Database", block.WithNodeLabel("Primary DB"), block.WithNodeShape(block.ShapeCylinder)),
			block.Space(),
			block.Node("Cache", block.WithNodeLabel("Cache"), block.WithNodeShape(block.ShapeRound)),
		).
		Link("Backend", "Database").
		LinkWithLabel("Backend", "reads from", "Cache").
		String()

	if err := markdown.NewMarkdown(os.Stdout, markdown.WithBlockSpacing()).
		H2("Block Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build(); err != nil {
		panic(err)
	}
}

Plain text output: markdown is here

## Block Diagram

```mermaid
---
title: "Checkout Architecture"
---
block
    columns 3
    Frontend toBackend<["calls"]>(right) Backend
    space:2 toDB<["&nbsp;"]>(down)
    Database[("Primary DB")] space Cache("Cache")
    Backend --> Database
    Backend -- "reads from" --> Cache
```

Mermaid output:

---
title: "Checkout Architecture"
---
block
    columns 3
    Frontend toBackend<["calls"]>(right) Backend
    space:2 toDB<["&nbsp;"]>(down)
    Database[("Primary DB")] space Cache("Cache")
    Backend --> Database
    Backend -- "reads from" --> Cache
Mermaid kanban syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

func main() {
	diagram := kanban.NewDiagram(
		io.Discard,
		kanban.WithTitle("Sprint Board"),
		kanban.WithTicketBaseURL("https://example.com/tickets/"),
	).
		Column("Todo").
		Task("Define scope").
		Task(
			"Create login page",
			kanban.WithTaskTicket("MB-101"),
			kanban.WithTaskAssigned("Alice"),
			kanban.WithTaskPriority(kanban.PriorityHigh),
		).
		Column("In Progress").
		Task("Review API", kanban.WithTaskPriority(kanban.PriorityVeryHigh)).
		String()

	if err := markdown.NewMarkdown(os.Stdout, markdown.WithBlockSpacing()).
		H2("Kanban Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build(); err != nil {
		panic(err)
	}
}

Plain text output: markdown is here

## Kanban Diagram

```mermaid
---
title: "Sprint Board"
config:
  kanban:
    ticketBaseUrl: 'https://example.com/tickets/'
---
kanban
    [Todo]
        [Define scope]
        [Create login page]@{ ticket: 'MB-101', assigned: 'Alice', priority: 'High' }
    [In Progress]
        [Review API]@{ priority: 'Very High' }
```

Mermaid output:

---
title: "Sprint Board"
config:
  kanban:
    ticketBaseUrl: 'https://example.com/tickets/'
---
kanban
    [Todo]
        [Define scope]
        [Create login page]@{ ticket: 'MB-101', assigned: 'Alice', priority: 'High' }
    [In Progress]
        [Review API]@{ priority: 'Very High' }
Entity Relationship Diagram syntax
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)
	}
	defer f.Close()

	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, markdown.WithBlockSpacing()).
		H2("Entity Relationship Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, erString).
		Build()

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

Plain text output: markdown is here

## 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 output:

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"
	}
Flowchart syntax
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(),
	).
		Subgraph("ingest", "Ingest").
		SubgraphDirection(flowchart.DirectionLR).
		NodeWithText("A", "Node A").
		StadiumNode("B", "Node B").
		LinkWithArrowHead("A", "B").
		SubgraphEnd().
		SubroutineNode("C", "Node C").
		DatabaseNode("D", "Database").
		LinkWithArrowHeadAndText("B", "D", "send original data").
		LinkWithArrowHead("B", "C").
		DottedLinkWithText("C", "D", "send filtered data").
		ClassDef("stored", "fill:#d4f7d4,stroke:#2b8a3e").
		Class("D", "stored").
		Style("C", "fill:#fff3bf,stroke:#e67700").
		ClickHref("D", "https://example.com/database", "The database").
		String()

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

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

Plain text output: markdown is here

## Flowchart

```mermaid
---
title: "mermaid flowchart builder"
---
flowchart TB
    subgraph ingest["Ingest"]
        direction LR
        A["Node A"]
        B(["Node B"])
        A-->B
    end
    C[["Node C"]]
    D[("Database")]
    B-->|"send original data"|D
    B-->C
    C-. "send filtered data" .-> D
    classDef stored fill:#d4f7d4,stroke:#2b8a3e
    class D stored
    style C fill:#fff3bf,stroke:#e67700
    click D "https://example.com/database" "The database"
```

Mermaid output:

---
title: "mermaid flowchart builder"
---
flowchart TB
    subgraph ingest["Ingest"]
        direction LR
        A["Node A"]
        B(["Node B"])
        A-->B
    end
    C[["Node C"]]
    D[("Database")]
    B-->|"send original data"|D
    B-->C
    C-. "send filtered data" .-> D
    classDef stored fill:#d4f7d4,stroke:#2b8a3e
    class D stored
    style C fill:#fff3bf,stroke:#e67700
    click D "https://example.com/database" "The database"
Pie chart syntax
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)
	}
	defer f.Close()

	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, markdown.WithBlockSpacing()).
		H2("Pie Chart").
		CodeBlocks(markdown.SyntaxHighlightMermaid, chart).
		Build()

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

Plain text output: markdown is here

## 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
```

Mermaid output:

%%{init: {"pie": {"textPosition": 0.75}, "themeVariables": {"pieOuterStrokeWidth": "5px"}} }%%
pie showData
    title mermaid pie chart builder
    "A" : 10
    "B" : 20.100000
    "C" : 30
Architecture Diagrams (beta feature)

The mermaid provides a feature to visualize infrastructure architecture as a beta version, and that feature has been introduced.

package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := arch.NewArchitecture(io.Discard).
		Service("left_disk", arch.IconDisk, "Disk").
		Service("top_disk", arch.IconDisk, "Disk").
		Service("bottom_disk", arch.IconDisk, "Disk").
		Service("top_gateway", arch.IconInternet, "Gateway").
		Service("bottom_gateway", arch.IconInternet, "Gateway").
		Junction("junctionCenter").
		Junction("junctionRight").
		LF().
		Edges(
			arch.Edge{
				ServiceID: "left_disk",
				Position:  arch.PositionRight,
				Arrow:     arch.ArrowNone,
			},
			arch.Edge{
				ServiceID: "junctionCenter",
				Position:  arch.PositionLeft,
				Arrow:     arch.ArrowNone,
			}).
		Edges(
			arch.Edge{
				ServiceID: "top_disk",
				Position:  arch.PositionBottom,
				Arrow:     arch.ArrowNone,
			},
			arch.Edge{
				ServiceID: "junctionCenter",
				Position:  arch.PositionTop,
				Arrow:     arch.ArrowNone,
			}).
		Edges(
			arch.Edge{
				ServiceID: "bottom_disk",
				Position:  arch.PositionTop,
				Arrow:     arch.ArrowNone,
			},
			arch.Edge{
				ServiceID: "junctionCenter",
				Position:  arch.PositionBottom,
				Arrow:     arch.ArrowNone,
			}).
		Edges(
			arch.Edge{
				ServiceID: "junctionCenter",
				Position:  arch.PositionRight,
				Arrow:     arch.ArrowNone,
			},
			arch.Edge{
				ServiceID: "junctionRight",
				Position:  arch.PositionLeft,
				Arrow:     arch.ArrowNone,
			}).
		Edges(
			arch.Edge{
				ServiceID: "top_gateway",
				Position:  arch.PositionBottom,
				Arrow:     arch.ArrowNone,
			},
			arch.Edge{
				ServiceID: "junctionRight",
				Position:  arch.PositionTop,
				Arrow:     arch.ArrowNone,
			}).
		Edges(
			arch.Edge{
				ServiceID: "bottom_gateway",
				Position:  arch.PositionTop,
				Arrow:     arch.ArrowNone,
			},
			arch.Edge{
				ServiceID: "junctionRight",
				Position:  arch.PositionBottom,
				Arrow:     arch.ArrowNone,
			}).String() //nolint

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Architecture Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()

	if err != nil {
		panic(err)
	}

Plain text output: markdown is here

## Architecture Diagram

```mermaid
architecture-beta
    service left_disk(disk)[Disk]
    service top_disk(disk)[Disk]
    service bottom_disk(disk)[Disk]
    service top_gateway(internet)[Gateway]
    service bottom_gateway(internet)[Gateway]
    junction junctionCenter
    junction junctionRight

    left_disk:R -- L:junctionCenter
    top_disk:B -- T:junctionCenter
    bottom_disk:T -- B:junctionCenter
    junctionCenter:R -- L:junctionRight
    top_gateway:B -- T:junctionRight
    bottom_gateway:T -- B:junctionRight
```

Architecture Diagram

State Diagram syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := state.NewDiagram(io.Discard, state.WithTitle("Order State Machine")).
		StartTransition("Pending").
		State("Pending", "Order received").
		State("Processing", "Preparing order").
		State("Shipped", "Order in transit").
		State("Delivered", "Order completed").
		LF().
		TransitionWithNote("Pending", "Processing", "payment confirmed").
		TransitionWithNote("Processing", "Shipped", "items packed").
		TransitionWithNote("Shipped", "Delivered", "customer received").
		LF().
		NoteRight("Pending", "Waiting for payment").
		NoteRight("Processing", "Preparing items").
		LF().
		EndTransition("Delivered").
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("State Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()

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

Plain text output: markdown is here

## State Diagram

```mermaid
---
title: "Order State Machine"
---
stateDiagram-v2
    [*] --> Pending
    Pending : Order received
    Processing : Preparing order
    Shipped : Order in transit
    Delivered : Order completed

    Pending --> Processing : payment confirmed
    Processing --> Shipped : items packed
    Shipped --> Delivered : customer received

    note right of Pending : Waiting for payment
    note right of Processing : Preparing items

    Delivered --> [*]
```

Mermaid output:

---
title: "Order State Machine"
---
stateDiagram-v2
    [*] --> Pending
    Pending : Order received
    Processing : Preparing order
    Shipped : Order in transit
    Delivered : Order completed

    Pending --> Processing : payment confirmed
    Processing --> Shipped : items packed
    Shipped --> Delivered : customer received

    note right of Pending : Waiting for payment
    note right of Processing : Preparing items

    Delivered --> [*]
Class Diagram syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := class.NewDiagram(
		io.Discard,
		class.WithTitle("Checkout Domain"),
	).
		SetDirection(class.DirectionLR).
		Class(
			"Order",
			class.WithPublicField("string", "id"),
			class.WithPublicMethod("Create", "error", "items []LineItem"),
			class.WithPublicMethod("Pay", "error"),
		).
		Class(
			"LineItem",
			class.WithPublicField("string", "sku"),
			class.WithPublicField("int", "quantity"),
			class.WithPublicMethod("Subtotal", "int"),
		).
		Interface("PaymentGateway")

	diagram.From("Order").
		Composition("LineItem", class.WithOneToMany(), class.WithRelationLabel("contains")).
		Association("PaymentGateway", class.WithRelationLabel("uses"))

	diagramString := diagram.
		NoteFor("Order", "Aggregate Root").
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Class Diagram").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagramString).
		Build()

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

Plain text output: markdown is here

## Class Diagram

```mermaid
---
title: "Checkout Domain"
---
classDiagram
    direction LR
    class Order {
        +string id
        +Create(items []LineItem) error
        +Pay() error
    }
    class LineItem {
        +string sku
        +int quantity
        +Subtotal() int
    }
    class PaymentGateway {
        <<Interface>>
    }
    Order "1" *-- "many" LineItem : contains
    Order --> PaymentGateway : uses
    note for Order "Aggregate Root"
```

Mermaid output:

---
title: "Checkout Domain"
---
classDiagram
    direction LR
    class Order {
        +string id
        +Create(items []LineItem) error
        +Pay() error
    }
    class LineItem {
        +string sku
        +int quantity
        +Subtotal() int
    }
    class PaymentGateway {
        <<Interface>>
    }
    Order "1" *-- "many" LineItem : contains
    Order --> PaymentGateway : uses
    note for Order "Aggregate Root"
Quadrant Chart syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	chart := quadrant.NewChart(io.Discard, quadrant.WithTitle("Product Prioritization")).
		XAxis("Low Effort", "High Effort").
		YAxis("Low Value", "High Value").
		LF().
		Quadrant1("Quick Wins").
		Quadrant2("Major Projects").
		Quadrant3("Fill Ins").
		Quadrant4("Thankless Tasks").
		LF().
		Point("Feature A", 0.9, 0.85).
		Point("Feature B", 0.25, 0.75).
		Point("Feature C", 0.15, 0.20).
		Point("Feature D", 0.80, 0.15).
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Quadrant Chart").
		CodeBlocks(markdown.SyntaxHighlightMermaid, chart).
		Build()

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

Plain text output: markdown is here

## Quadrant Chart

```mermaid
quadrantChart
    title Product Prioritization
    x-axis Low Effort --> High Effort
    y-axis Low Value --> High Value

    quadrant-1 Quick Wins
    quadrant-2 Major Projects
    quadrant-3 Fill Ins
    quadrant-4 Thankless Tasks

    Feature A: [0.90, 0.85]
    Feature B: [0.25, 0.75]
    Feature C: [0.15, 0.20]
    Feature D: [0.80, 0.15]
```

Mermaid output:

quadrantChart
    title Product Prioritization
    x-axis Low Effort --> High Effort
    y-axis Low Value --> High Value

    quadrant-1 Quick Wins
    quadrant-2 Major Projects
    quadrant-3 Fill Ins
    quadrant-4 Thankless Tasks

    Feature A: [0.90, 0.85]
    Feature B: [0.25, 0.75]
    Feature C: [0.15, 0.20]
    Feature D: [0.80, 0.15]
Gantt Chart syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	chart := gantt.NewChart(
		io.Discard,
		gantt.WithTitle("Project Schedule"),
		gantt.WithDateFormat("YYYY-MM-DD"),
	).
		Section("Planning").
		DoneTaskWithID("Requirements", "req", "2024-01-01", "5d").
		DoneTaskWithID("Design", "design", "2024-01-08", "3d").
		Section("Development").
		CriticalActiveTaskWithID("Coding", "code", "2024-01-12", "10d").
		TaskAfterWithID("Review", "review", "code", "2d").
		Section("Release").
		MilestoneWithID("Launch", "launch", "2024-01-26").
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Gantt Chart").
		CodeBlocks(markdown.SyntaxHighlightMermaid, chart).
		Build()

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

Plain text output: markdown is here

## Gantt Chart

```mermaid
gantt
    title Software Development Schedule
    dateFormat YYYY-MM-DD
    section Planning
    Requirements Analysis :done, req, 2024-01-01, 7d
    System Design :done, design, 2024-01-08, 5d

    section Development
    Backend Development :crit, active, backend, 2024-01-15, 14d
    Frontend Development :active, frontend, 2024-01-15, 14d
    Integration :integrate, after backend, 5d

    section Testing
    Unit Testing :unit, after integrate, 3d
    Integration Testing :inttest, after unit, 4d
    UAT :uat, after inttest, 5d

    section Deployment
    Staging Deploy :after uat, 2d
    Production Release :crit, milestone, 2024-03-01, 0d
```

Mermaid output:

gantt
    title Project Schedule
    dateFormat YYYY-MM-DD
    section Planning
    Requirements :done, req, 2024-01-01, 5d
    Design :done, design, 2024-01-08, 3d
    section Development
    Coding :crit, active, code, 2024-01-12, 10d
    Review :review, after code, 2d
    section Release
    Launch :milestone, launch, 2024-01-26, 0d
Timeline syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := timeline.NewDiagram(
		io.Discard,
		timeline.WithTitle("History of Social Media"),
	).
		Period("2002", "LinkedIn").
		Section("Second wave").
		Period("2004", "Facebook", "Google").
		Period("2005", "YouTube").
		Section("Third wave").
		Period("2006", "Twitter").
		Event("Reddit").
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Timeline").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()

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

A period holds as many events as you give it, and Event adds one more to the period written last. A colon in a section name, a period or an event is emitted as #58;, because a colon is what separates a period from its events; it reaches the reader as a colon either way, so Period("09:00", "Stand up") says what it looks like. The title keeps its colons: mermaid reads it as the rest of the line.

Plain text output: markdown is here

## Timeline

```mermaid
timeline
    title History of Social Media
    2002 : LinkedIn
    section Second wave
        2004 : Facebook : Google
        2005 : YouTube
    section Third wave
        2006 : Twitter : Reddit
```

Mermaid output:

timeline
    title History of Social Media
    2002 : LinkedIn
    section Second wave
        2004 : Facebook : Google
        2005 : YouTube
    section Third wave
        2006 : Twitter : Reddit
Sankey syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := sankey.NewDiagram(io.Discard).
		Link("Agricultural 'waste'", "Bio-conversion", 124.729).
		Link("Bio-conversion", "Liquid", 0.597).
		Link("Bio-conversion", "Losses, and more", 26.862).
		Link("Bio-conversion", "Solid", 280.322).
		Link("Bio-conversion", "Gas", 81.144).
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Sankey").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()

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

Nodes are never declared: a node exists because a flow names it, and two flows naming the same node are two flows through one node. The diagram body is CSV, so a node name holding a comma or a double quote is quoted for you, as Losses, and more is above.

Plain text output: markdown is here

## Sankey

```mermaid
sankey-beta

Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,"Losses, and more",26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
```

Mermaid output:

sankey-beta

Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,"Losses, and more",26.862
Bio-conversion,Solid,280.322
Bio-conversion,Gas,81.144
Radar syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	chart := radar.NewDiagram(io.Discard, radar.WithTitle("Grades")).
		Axis("Math", "Science", "English").
		Axis("History", "Art").
		Curve("Alice", 85, 90, 80, 70, 75).
		Curve("Bob", 70, 75, 85, 80, 90).
		Max(100).
		Min(0).
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Radar").
		CodeBlocks(markdown.SyntaxHighlightMermaid, chart).
		Build()

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

Axes are declared once, in order, and every curve gives its values in that same order. mermaid wants an identifier in front of each label; nothing in a radar chart refers to one, so the package numbers them and you pass only the labels.

Plain text output: markdown is here

## Radar

```mermaid
---
title: "Grades"
---
radar-beta
  axis a1["Math"], a2["Science"], a3["English"]
  axis a4["History"], a5["Art"]
  curve c1["Alice"]{85, 90, 80, 70, 75}
  curve c2["Bob"]{70, 75, 85, 80, 90}
  max 100
  min 0
```

Mermaid output:

---
title: "Grades"
---
radar-beta
  axis a1["Math"], a2["Science"], a3["English"]
  axis a4["History"], a5["Art"]
  curve c1["Alice"]{85, 90, 80, 70, 75}
  curve c2["Bob"]{70, 75, 85, 80, 90}
  max 100
  min 0
Treemap syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := treemap.NewDiagram(io.Discard, treemap.WithTitle("Budget")).
		Section("Ops").
		Leaf("Salaries", 1200).
		Section("Cloud").
		Leaf("Compute", 400).
		Parent().
		Leaf("Travel", 300).
		Parent().
		Section("Marketing").
		Leaf("Ads", 800).
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Treemap").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()

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

mermaid expresses the hierarchy with indentation, and the builder walks it rather than asking for a tree of objects: Section opens a level, Leaf puts a value in the current one, and Parent goes back up. A section carries no value of its own; mermaid gives it the sum of what it holds.

Plain text output: markdown is here

## Treemap

```mermaid
---
title: "Budget"
---
treemap-beta
"Ops"
    "Salaries": 1200
    "Cloud"
        "Compute": 400
    "Travel": 300
"Marketing"
    "Ads": 800
```

Mermaid output:

---
title: "Budget"
---
treemap-beta
"Ops"
    "Salaries": 1200
    "Cloud"
        "Compute": 400
    "Travel": 300
"Marketing"
    "Ads": 800
C4 context syntax

mermaid marks its C4 support experimental and says the syntax may change, so this package stays on the C4Context diagram: the people and the software systems around the one being described.

package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := c4.NewDiagram(io.Discard, c4.WithTitle("System Context: Internet Banking")).
		EnterpriseBoundary("bank", "Big Bank plc").
		Person("customer", "Personal Banking Customer", c4.WithDescription("A customer of the bank.")).
		SystemBoundary("banking", "Internet Banking").
		System("web", "Internet Banking System", c4.WithDescription("Shows account information.")).
		SystemDb("accounts", "Accounts Database").
		BoundaryEnd().
		BoundaryEnd().
		SystemExt("mail", "E-mail System", c4.WithDescription("The internal Microsoft Exchange system.")).
		Rel("customer", "web", "Views balances", c4.WithTechnology("HTTPS")).
		BiRel("web", "accounts", "Reads from and writes to", c4.WithTechnology("SQL/TCP")).
		Rel("web", "mail", "Sends e-mail using", c4.WithTechnology("SMTP")).
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("C4 Context").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()

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

A boundary is a pair of calls rather than a nested builder: Boundary, EnterpriseBoundary and SystemBoundary open one, everything after belongs to it, and BoundaryEnd closes it. Leaving one open is reported from Build, because mermaid refuses a diagram whose brace never closes.

Labels are escaped with the entity form mermaid decodes, so a quotation mark or a # in one cannot break the macro syntax. The title is the exception: mermaid reads the rest of the line, quotes and all, so the package does not quote it.

Plain text output: markdown is here

## C4 Context

```mermaid
C4Context
    title System Context: Internet Banking
    Enterprise_Boundary(bank, "Big Bank plc") {
        Person(customer, "Personal Banking Customer", "A customer of the bank.")
        System_Boundary(banking, "Internet Banking") {
            System(web, "Internet Banking System", "Shows account information.")
            SystemDb(accounts, "Accounts Database")
        }
    }
    System_Ext(mail, "E-mail System", "The internal Microsoft Exchange system.")
    Rel(customer, web, "Views balances", "HTTPS")
    BiRel(web, accounts, "Reads from and writes to", "SQL/TCP")
    Rel(web, mail, "Sends e-mail using", "SMTP")
```

Mermaid output:

C4Context
    title System Context: Internet Banking
    Enterprise_Boundary(bank, "Big Bank plc") {
        Person(customer, "Personal Banking Customer", "A customer of the bank.")
        System_Boundary(banking, "Internet Banking") {
            System(web, "Internet Banking System", "Shows account information.")
            SystemDb(accounts, "Accounts Database")
        }
    }
    System_Ext(mail, "E-mail System", "The internal Microsoft Exchange system.")
    Rel(customer, web, "Views balances", "HTTPS")
    BiRel(web, accounts, "Reads from and writes to", "SQL/TCP")
    Rel(web, mail, "Sends e-mail using", "SMTP")
Venn syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := venn.NewDiagram(io.Discard, venn.WithTitle("What the languages share")).
		SetWithLabel("go", "Go").
		SetWithLabel("rust", "Rust").
		SetWithLabel("compiled", "Compiled and statically typed").
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Venn").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()

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

A Venn diagram is the sets and nothing else: where they overlap is worked out by mermaid rather than declared, so there is no call for an intersection. A set name is written unquoted and mermaid reads only letters, digits, underscores and hyphens there, so Set reports a name outside that rather than mangling it; a label has no such limit, which is what SetWithLabel is for.

Plain text output: markdown is here

## Venn

```mermaid
venn-beta
    title What the languages share
    set go["Go"]
    set rust["Rust"]
    set compiled["Compiled and statically typed"]
```

Mermaid output:

venn-beta
    title What the languages share
    set go["Go"]
    set rust["Rust"]
    set compiled["Compiled and statically typed"]
Wardley map syntax
package main

import (
	"io"
	"os"

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

//go:generate go run main.go

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

	diagram := wardley.NewMap(io.Discard, wardley.WithTitle("Checkout, as it stands")).
		Anchor("Customer", 0.95, 0.95).
		Component("Checkout (web)", 0.6, 0.8).
		Component("Payment service", 0.75, 0.5).
		Component("Card network", 0.95, 0.2).
		Link("Customer", "Checkout (web)").
		Link("Checkout (web)", "Payment service").
		Link("Payment service", "Card network").
		Evolve("Payment service", 0.9).
		String()

	err = markdown.NewMarkdown(f, markdown.WithBlockSpacing()).
		H2("Wardley map").
		CodeBlocks(markdown.SyntaxHighlightMermaid, diagram).
		Build()

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

The two coordinates are evolution and visibility, each from 0.0 to 1.0: evolution runs left to right, from something built for the first time to something bought as a commodity, and visibility runs bottom to top, from the plumbing to what the user actually touches. Evolve is what turns a map of today into an argument about tomorrow.

A name is written unquoted and mermaid reads only letters, digits, spaces, underscores, hyphens and parentheses there, refusing its own escape form as well, so a name outside that set is reported from Build rather than mangled into one that draws something else.

Plain text output: markdown is here

## Wardley map

```mermaid
wardley-beta
    title Checkout, as it stands
    anchor Customer [0.95, 0.95]
    component Checkout (web) [0.6, 0.8]
    component Payment service [0.75, 0.5]
    component Card network [0.95, 0.2]
    Customer -> Checkout (web)
    Checkout (web) -> Payment service
    Payment service -> Card network
    evolve Payment service 0.9
```

Mermaid output:

wardley-beta
    title Checkout, as it stands
    anchor Customer [0.95, 0.95]
    component Checkout (web) [0.6, 0.8]
    component Payment service [0.75, 0.5]
    component Card network [0.95, 0.2]
    Customer -> Checkout (web)
    Checkout (web) -> Payment service
    Payment service -> Card network
    evolve Payment service 0.9

Creating an index for a directory full of markdown files

The markdown package can create an index for Markdown files within the specified directory. This feature was added to generate indexes for Markdown documents produced by nao1215/spectest.

For example, consider the following directory structure:

testdata
├── abc
│   ├── dummy.txt
│   ├── jkl
│   │   └── text.md
│   └── test.md
├── def
│   ├── test.md
│   └── test2.md
├── expected
│   └── index.md
├── ghi
└── test.md

In the following implementation, it creates an index markdown file containing links to all markdown files located within the testdata directory.

		if err := GenerateIndex(
			"testdata", // target directory that contains markdown files
			WithTitle("Test Title"), // title of index markdown
			WithDescription([]string{"Test Description", "Next Description"}), // description of index markdown
		); err != nil {
			panic(err)
		}

The index Markdown file is created under "target directory/index.md" by default. If you want to change this path, please use the WithWriter() option. The link names in the file will be the first occurrence of H1 or H2 in the target Markdown. If neither H1 nor H2 is present, the link name will be the file name of the destination.

Output:

## Test Title
Test Description
  
Next Description
  
### testdata
- [test.md](test.md)
  
### abc
- [h2 is here](abc/test.md)
  
### jkl
- [text.md](abc/jkl/text.md)
  
### def
- [h2 is first, not h1](def/test.md)
- [h1 is here](def/test2.md)
  
### expected
- [Test Title](expected/index.md)

License

MIT License

Contribution

First off, thanks for taking the time to contribute! See CONTRIBUTING.md for more information. Contributions are not only related to development. For example, GitHub Star motivates me to develop! Please feel free to contribute to this project.

Contributors ✨

Thanks goes to these wonderful people (emoji key):

CHIKAMATSU Naohiro
CHIKAMATSU Naohiro

💻
Karthik Sundari
Karthik Sundari

💻 🤔
Avihuc
Avihuc

💻
Clarance Liberiste Ntwari
Clarance Liberiste Ntwari

💻
Amitai Frey
Amitai Frey

💻
William Poussier
William Poussier

🤔
Shubham Hibare
Shubham Hibare

🐛
Barry Morrison
Barry Morrison

🤔
chaunsin
chaunsin

🤔
Add your contributions

This project follows the all-contributors specification. Contributions of any kind are welcome, and that includes bug reports and feature requests: several of the features above exist because someone opened an issue asking for them.

Documentation

Overview

Package markdown is a simple markdown builder.

A document is one method chain: call NewMarkdown with a writer, add blocks in the order they should appear, and finish with Markdown.Build. The output follows GitHub Flavored Markdown.

Nested structures, such as a list inside a list item, are out of scope. They would turn the chain into a tree.

The builder records errors instead of returning them from every call. Nothing panics on bad input, and a rejected call does not stop the document: the chain runs to the end, and Markdown.Error and Markdown.Build both report the first error it recorded.

Markdown.String returns the document without needing a writer. That is how the mermaid subpackages hand a diagram to Markdown.CodeBlocks.

A builder is not safe for concurrent use. Build one document per goroutine.

Index

Examples

Constants

View Source
const (
	// TableOfContentsMarkerBegin is the marker for the beginning of the table of contents.
	TableOfContentsMarkerBegin = "<!-- BEGIN_TOC -->"
	// TableOfContentsMarkerEnd is the marker for the end of the table of contents.
	TableOfContentsMarkerEnd = "<!-- END_TOC -->"
)

Variables

View Source
var (
	// ErrMismatchColumn is returned when the number of columns in the record doesn't match the header.
	ErrMismatchColumn = errors.New("number of columns in the record doesn't match the header")
	// ErrInitMarkdownIndex is returned when the index can't be initialized.
	ErrInitMarkdownIndex = errors.New("markdown index can't be initialized")
	// ErrCreateMarkdownIndex is returned when the index can't be created.
	ErrCreateMarkdownIndex = errors.New("markdown index can't be created")
	// ErrWriteMarkdownIndex is returned when the index can't be written.
	ErrWriteMarkdownIndex = errors.New("markdown index can't be written")
)

Functions

func BlockMath added in v0.11.0

func BlockMath(expression string) string

BlockMath returns text with block mathematical expression format. BlockMath does not escape expression; it writes the raw expression between '$$' delimiters. If you set expression "x^2 + y^2 = z^2", it will be converted to:

$$
x^2 + y^2 = z^2
$$
Example

ExampleBlockMath returns a mathematical expression that stands on its own.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainText(md.BlockMath("\\int_0^1 x^2 dx = \\frac{1}{3}")).
		Build()

}
Output:
$$
\int_0^1 x^2 dx = \frac{1}{3}
$$

func Bold

func Bold(text string) string

Bold return text with bold format. If you set text "Hello", it will be converted to "**Hello**".

Example

ExampleBold returns the inline markup rather than writing it, so it can be put inside any text a builder takes.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainTextf("This word is %s.", md.Bold("important")).
		Build()

}
Output:
This word is **important**.

func BoldItalic

func BoldItalic(text string) string

BoldItalic return text with bold and italic format. If you set text "Hello", it will be converted to "***Hello***".

Example

ExampleBoldItalic returns the inline markup rather than writing it, so it can be put inside any text a builder takes.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainTextf("This word is %s.", md.BoldItalic("both")).
		Build()

}
Output:
This word is ***both***.

func Code

func Code(text string) string

Code return text with code format. If you set text "Hello", it will be converted to "`Hello`".

Example

ExampleCode returns the inline markup rather than writing it, so it can be put inside any text a builder takes.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainTextf("This word is %s.", md.Code("go test ./...")).
		Build()

}
Output:
This word is `go test ./...`.

func EscapeTableCell added in v1.0.0

func EscapeTableCell(s string) string

EscapeTableCell makes text safe to place in a table cell.

A pipe ends the cell, so a pipe in the data silently splits it in two and drops the last column of the row; a newline ends the row outright. Neither produces an error, and ValidateColumns cannot see either, because the row still has the right length before it is serialized.

The function is idempotent: a pipe that the caller already escaped is left alone, so passing text through it twice is harmless.

Example

ExampleEscapeTableCell escapes the characters that would end a table cell early. A pipe closes the cell it is written in, so text arriving from a database or a command's output needs this before it reaches a row.

package main

import (
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	fmt.Println(md.EscapeTableCell("a|b"))
	fmt.Println(md.EscapeTableCell("multi\nline"))

}
Output:
a\|b
multi<br>line

func FootnoteDefinition added in v0.11.0

func FootnoteDefinition(id, text string) string

FootnoteDefinition returns text with footnote definition format. If you set id "1" and text "Hello", it will be converted to "[^1]: Hello".

Example

ExampleFootnoteDefinition writes the text a footnote reference points at.

package main

import (
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	fmt.Println(md.FootnoteDefinition("1", "github.com/nao1215/markdown"))

}
Output:
[^1]: github.com/nao1215/markdown

func FootnoteReference added in v0.11.0

func FootnoteReference(id string) string

FootnoteReference returns text with footnote reference format. If you set id "1", it will be converted to "[^1]".

Example

ExampleFootnoteReference returns the marker that points at a footnote.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainTextf("Generated by this library%s.", md.FootnoteReference("1")).
		PlainText(md.FootnoteDefinition("1", "github.com/nao1215/markdown")).
		Build()

}
Output:
Generated by this library[^1].
[^1]: github.com/nao1215/markdown

func GenerateIndex

func GenerateIndex(targetDir string, opts ...IndexOption) error

GenerateIndex generates an index of all markdown files in the target directory. The index is written to the provided io.Writer.

Example

ExampleGenerateIndex writes an index of the markdown files under a directory. WithWriter sends it somewhere other than the index.md the function would otherwise create, which is what makes the output here worth showing.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	md "github.com/nao1215/markdown"
)

func main() {
	parent, err := os.MkdirTemp("", "markdown-index")
	if err != nil {
		fmt.Println("temp dir:", err)
		return
	}
	defer func() { _ = os.RemoveAll(parent) }()

	// The index is headed with the name of the directory it describes, so the
	// directory is named here rather than left as the random one MkdirTemp
	// makes, which would put a different heading in the output on every run.
	dir := filepath.Join(parent, "guide")
	if err := os.Mkdir(dir, 0o750); err != nil {
		fmt.Println("mkdir:", err)
		return
	}
	if err := os.WriteFile(filepath.Join(dir, "install.md"), []byte("# Install\n"), 0o600); err != nil {
		fmt.Println("write:", err)
		return
	}

	if err := md.GenerateIndex(dir, md.WithWriter(os.Stdout)); err != nil {
		fmt.Println("generate:", err)
	}

}
Output:
### guide
- [Install](install.md)

func Highlight added in v0.6.0

func Highlight(text string) string

Highlight return text with highlight format. If you set text "Hello", it will be converted to "==Hello==".

Example

ExampleHighlight returns the inline markup rather than writing it, so it can be put inside any text a builder takes.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainTextf("This word is %s.", md.Highlight("marked")).
		Build()

}
Output:
This word is ==marked==.

func Image

func Image(text, url string) string

Image return text with image format. If you set text "Hello" and url "https://example.com/image.png", it will be converted to "![Hello](https://example.com/image.png)".

Example

ExampleImage returns an inline image.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainText(md.Image("The Go gopher", "./gopher.png")).
		Build()

}
Output:
![The Go gopher](./gopher.png)

func InlineMath added in v0.11.0

func InlineMath(expression string) string

InlineMath returns text with inline mathematical expression format. It calls escapeMathExpression, so '$' in expression is escaped as '\$'. If you set expression "E=mc^2", it will be converted to "$E=mc^2$".

Example

ExampleInlineMath returns a mathematical expression that sits inside a sentence. GitHub renders it with KaTeX.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainTextf("The area is %s.", md.InlineMath("\\pi r^2")).
		Build()

}
Output:
The area is $\pi r^2$.

func Italic

func Italic(text string) string

Italic return text with italic format. If you set text "Hello", it will be converted to "*Hello*".

Example

ExampleItalic returns the inline markup rather than writing it, so it can be put inside any text a builder takes.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainTextf("This word is %s.", md.Italic("emphasis")).
		Build()

}
Output:
This word is *emphasis*.
func Link(text, url string) string

Link return text with link format. If you set text "Hello" and url "https://example.com", it will be converted to "[Hello](https://example.com)".

func ReferenceLink(text, id string) string

ReferenceLink returns text with reference link format. If you set text "Go" and id "go-site", it will be converted to "[Go][go-site]".

func ReferenceLinkDefinition added in v0.11.0

func ReferenceLinkDefinition(id, url string, title ...string) string

ReferenceLinkDefinition returns text with reference link definition format. If you set id "go-site" and url "https://golang.org", it will be converted to "[go-site]: https://golang.org". If title is set, it will be converted to "[go-site]: https://golang.org \"The Go Programming Language\"".

Example

ExampleReferenceLinkDefinition writes the definition a reference link points at. The optional third argument is the title a browser shows on hover.

package main

import (
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	fmt.Println(md.ReferenceLinkDefinition("go", "https://go.dev"))
	fmt.Println(md.ReferenceLinkDefinition("go", "https://go.dev", "The Go website"))

}
Output:
[go]: https://go.dev
[go]: https://go.dev "The Go website"

func Strikethrough

func Strikethrough(text string) string

Strikethrough return text with strikethrough format. If you set text "Hello", it will be converted to "~~Hello~~".

Example

ExampleStrikethrough returns the inline markup rather than writing it, so it can be put inside any text a builder takes.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainTextf("This word is %s.", md.Strikethrough("removed")).
		Build()

}
Output:
This word is ~~removed~~.

Types

type CheckBoxSet

type CheckBoxSet struct {
	// Checked is whether checked or not.
	Checked bool
	// Text is checkbox text.
	Text string
}

CheckBoxSet is markdown checkbox list.

Example

ExampleCheckBoxSet shows the shape one item of a task list is described with.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		CheckBox([]md.CheckBoxSet{
			{Checked: true, Text: "Write the proposal"},
			{Checked: false, Text: "Get it reviewed"},
		}).
		Build()

}
Output:
- [x] Write the proposal
- [ ] Get it reviewed

type Index

type Index struct {
	// contains filtered or unexported fields
}

Index represents an Index of all markdown files in a directory.

Example

ExampleIndex shows where an Index comes from. The type carries what GenerateIndex collected, and nothing exported reaches inside it: the index is written rather than inspected.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	md "github.com/nao1215/markdown"
)

func main() {
	parent, err := os.MkdirTemp("", "markdown-index")
	if err != nil {
		fmt.Println("temp dir:", err)
		return
	}
	defer func() { _ = os.RemoveAll(parent) }()

	dir := filepath.Join(parent, "guide")
	if err := os.Mkdir(dir, 0o750); err != nil {
		fmt.Println("mkdir:", err)
		return
	}
	if err := os.WriteFile(filepath.Join(dir, "usage.md"), []byte("# Usage\n"), 0o600); err != nil {
		fmt.Println("write:", err)
		return
	}

	if err := md.GenerateIndex(dir, md.WithWriter(os.Stdout)); err != nil {
		fmt.Println("generate:", err)
	}

}
Output:
### guide
- [Usage](usage.md)

type IndexOption

type IndexOption func(*Index) error

IndexOption are options for generating an index.

Example

ExampleIndexOption shows what an IndexOption is: a function that changes what GenerateIndex writes, passed to it after the directory.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	md "github.com/nao1215/markdown"
)

func main() {
	parent, err := os.MkdirTemp("", "markdown-index")
	if err != nil {
		fmt.Println("temp dir:", err)
		return
	}
	defer func() { _ = os.RemoveAll(parent) }()

	dir := filepath.Join(parent, "guide")
	if err := os.Mkdir(dir, 0o750); err != nil {
		fmt.Println("mkdir:", err)
		return
	}
	if err := os.WriteFile(filepath.Join(dir, "install.md"), []byte("# Install\n"), 0o600); err != nil {
		fmt.Println("write:", err)
		return
	}

	options := []md.IndexOption{md.WithTitle("Documentation"), md.WithWriter(os.Stdout)}
	if err := md.GenerateIndex(dir, options...); err != nil {
		fmt.Println("generate:", err)
	}

}
Output:
## Documentation
### guide
- [Install](install.md)

func WithDescription

func WithDescription(description []string) IndexOption

WithDescription sets the description of the index.

Example

ExampleWithDescription sets the paragraphs written under the index heading.

package main

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"

	md "github.com/nao1215/markdown"
)

func main() {
	parent, err := os.MkdirTemp("", "markdown-index")
	if err != nil {
		fmt.Println("temp dir:", err)
		return
	}
	defer func() { _ = os.RemoveAll(parent) }()

	// The index is headed with the name of the directory it describes, so the
	// directory is named here rather than left as the random one MkdirTemp
	// makes, which would put a different heading in the output on every run.
	dir := filepath.Join(parent, "guide")
	if err := os.Mkdir(dir, 0o750); err != nil {
		fmt.Println("mkdir:", err)
		return
	}
	if err := os.WriteFile(filepath.Join(dir, "install.md"), []byte("# Install\n"), 0o600); err != nil {
		fmt.Println("write:", err)
		return
	}

	buf := &bytes.Buffer{}
	err = md.GenerateIndex(dir,
		md.WithDescription([]string{"Every page in this directory.", "Regenerated on each release."}),
		md.WithWriter(buf),
	)
	if err != nil {
		fmt.Println("generate:", err)
		return
	}
	// Printed quoted because each description line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot hold
	// trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"Every page in this directory.\n  \nRegenerated on each release.\n  \n### guide\n- [Install](install.md)\n  \n"

func WithTitle

func WithTitle(title string) IndexOption

WithTitle sets the title of the index.

Example

ExampleWithTitle sets the heading the generated index opens with.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	md "github.com/nao1215/markdown"
)

func main() {
	parent, err := os.MkdirTemp("", "markdown-index")
	if err != nil {
		fmt.Println("temp dir:", err)
		return
	}
	defer func() { _ = os.RemoveAll(parent) }()

	// The index is headed with the name of the directory it describes, so the
	// directory is named here rather than left as the random one MkdirTemp
	// makes, which would put a different heading in the output on every run.
	dir := filepath.Join(parent, "guide")
	if err := os.Mkdir(dir, 0o750); err != nil {
		fmt.Println("mkdir:", err)
		return
	}
	if err := os.WriteFile(filepath.Join(dir, "install.md"), []byte("# Install\n"), 0o600); err != nil {
		fmt.Println("write:", err)
		return
	}

	if err := md.GenerateIndex(dir, md.WithTitle("Documentation"), md.WithWriter(os.Stdout)); err != nil {
		fmt.Println("generate:", err)
	}

}
Output:
## Documentation
### guide
- [Install](install.md)

func WithWriter

func WithWriter(w io.Writer) IndexOption

WithWriter sets the writer to write the index to.

Example

ExampleWithWriter sends the index somewhere other than the index.md the function creates by default, so it can be inspected or embedded rather than written to disk.

package main

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"

	md "github.com/nao1215/markdown"
)

func main() {
	parent, err := os.MkdirTemp("", "markdown-index")
	if err != nil {
		fmt.Println("temp dir:", err)
		return
	}
	defer func() { _ = os.RemoveAll(parent) }()

	// The index is headed with the name of the directory it describes, so the
	// directory is named here rather than left as the random one MkdirTemp
	// makes, which would put a different heading in the output on every run.
	dir := filepath.Join(parent, "guide")
	if err := os.Mkdir(dir, 0o750); err != nil {
		fmt.Println("mkdir:", err)
		return
	}
	if err := os.WriteFile(filepath.Join(dir, "install.md"), []byte("# Install\n"), 0o600); err != nil {
		fmt.Println("write:", err)
		return
	}

	buf := &bytes.Buffer{}
	if err := md.GenerateIndex(dir, md.WithWriter(buf)); err != nil {
		fmt.Println("generate:", err)
		return
	}
	fmt.Print(buf.String())

}
Output:
### guide
- [Install](install.md)

type Markdown

type Markdown struct {
	// contains filtered or unexported fields
}

Markdown is markdown text.

Example

ExampleMarkdown skips this test on Windows. The newline codes in the comment section where the expected values are written are represented as '\n', causing failures when testing on Windows.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		H1("This is H1").
		PlainText("This is plain text").
		H2f("This is %s with text format", "H2").
		PlainTextf("Text formatting, such as %s and %s, %s styles.",
			md.Bold("bold"), md.Italic("italic"), md.Code("code")).
		H2("Code Block").
		CodeBlocks(md.SyntaxHighlightGo,
			`package main
import "fmt"

func main() {
	fmt.Println("Hello, World!")
}`).
		H2("List").
		BulletList("Bullet Item 1", "Bullet Item 2", "Bullet Item 3").
		OrderedList("Ordered Item 1", "Ordered Item 2", "Ordered Item 3").
		H2("CheckBox").
		CheckBox([]md.CheckBoxSet{
			{Checked: false, Text: md.Code("sample code")},
			{Checked: true, Text: md.Link("Go", "https://golang.org")},
			{Checked: false, Text: md.Strikethrough("strikethrough")},
		}).
		H2("Blockquote").
		Blockquote("If you can dream it, you can do it.").
		H3("Horizontal Rule").
		HorizontalRule().
		H2("Table").
		Table(md.TableSet{
			Header: []string{"Name", "Age", "Country"},
			Rows: [][]string{
				{"David", "23", "USA"},
				{"John", "30", "UK"},
				{"Bob", "25", "Canada"},
			},
		}).
		H2("Image").
		PlainTextf(md.Image("sample_image", "./sample.png")).
		Build()

}
Output:
# This is H1
This is plain text
## This is H2 with text format
Text formatting, such as **bold** and *italic*, `code` styles.
## Code Block
```go
package main
import "fmt"

func main() {
	fmt.Println("Hello, World!")
}
```
## List
- Bullet Item 1
- Bullet Item 2
- Bullet Item 3

1. Ordered Item 1
2. Ordered Item 2
3. Ordered Item 3

## CheckBox
- [ ] `sample code`
- [x] [Go](https://golang.org)
- [ ] ~~strikethrough~~

## Blockquote
> If you can dream it, you can do it.

### Horizontal Rule
---
## Table
| Name | Age | Country |
|---------|---------|---------|
| David | 23 | USA |
| John | 30 | UK |
| Bob | 25 | Canada |

## Image
![sample_image](./sample.png)

func NewMarkdown

func NewMarkdown(w io.Writer, opts ...Option) *Markdown

NewMarkdown returns new Markdown.

Example

ExampleNewMarkdown shows the shape every document has: a writer, a chain of calls, and Build.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		H1("Release Notes").
		PlainText("Everything that changed in this release.").
		Build()

}
Output:
# Release Notes
Everything that changed in this release.
Example (WriterIsAnyWriter)

ExampleNewMarkdown_writerIsAnyWriter shows that the destination is an io.Writer, so a document can be built into memory and used as a string.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).H2("Summary").Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	fmt.Printf("%q\n", buf.String())

}
Output:
"## Summary\n"

func (*Markdown) BlankLine added in v1.0.0

func (m *Markdown) BlankLine() *Markdown

BlankLine writes an empty line between two blocks.

Example

ExampleMarkdown_BlankLine writes an empty line, for the places a document needs one that the block spacing does not give it.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).PlainText("Above").BlankLine().PlainText("Below").Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the empty line carries the two spaces markdown
	// reads as a hard line break, and a godoc Output block cannot hold
	// trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"Above\n\nBelow\n"

func (*Markdown) Blockquote

func (m *Markdown) Blockquote(text string) *Markdown

Blockquote is markdown blockquote. If you set text "Hello", it will be converted to "> Hello".

Example

ExampleMarkdown_Blockquote writes a quotation. Each line of the text is prefixed, so a quotation spanning lines stays one block.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		Blockquote("If you can dream it, you can do it.").
		Build()

}
Output:
> If you can dream it, you can do it.

func (*Markdown) BlueBadge added in v0.5.0

func (m *Markdown) BlueBadge(text string) *Markdown

BlueBadge set text with blue badge format.

Example

ExampleMarkdown_BlueBadge writes a blue badge, which is an image served by shields.io rather than markdown of its own.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).BlueBadge("build").Build()

}
Output:
![Badge](https://img.shields.io/badge/build-blue)

func (*Markdown) BlueBadgef added in v0.5.0

func (m *Markdown) BlueBadgef(format string, args ...interface{}) *Markdown

BlueBadgef set text with blue badge format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_BlueBadgef writes a blue badge from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).BlueBadgef("coverage %d%%", 96).Build()

}
Output:
![Badge](https://img.shields.io/badge/coverage 96%-blue)

func (*Markdown) Build

func (m *Markdown) Build() error

Build writes markdown text to output destination.

It returns the error the chain recorded, or nil. A nil destination and a destination that refuses the document are both reported rather than causing a panic, and either message carries the earlier error too when there is one.

The document is written with a trailing line ending, so appending a second document to the same writer starts it on its own line.

Build may be called more than once; each call writes the document again.

Example

ExampleMarkdown_Build writes the document and reports the first error the chain recorded. Nothing in the chain panics on bad input, so one check at the end is enough.

package main

import (
	"fmt"
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	err := md.NewMarkdown(os.Stdout).
		H1("Report").
		Table(md.TableSet{
			Header: []string{"Name", "Age"},
			Rows:   [][]string{{"only one cell"}},
		}).
		Build()
	fmt.Println("error:", err)

}
Output:
# Report
error: failed to validate columns: number of columns in the record doesn't match the header

func (*Markdown) BulletList

func (m *Markdown) BulletList(text ...string) *Markdown

BulletList is markdown bullet list. If you set text "Hello", it will be converted to "- Hello".

Example

ExampleMarkdown_BulletList writes an unordered list.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		BulletList("Read the spec", "Write the test", "Write the code").
		Build()

}
Output:
- Read the spec
- Write the test
- Write the code

func (*Markdown) Caution

func (m *Markdown) Caution(text string) *Markdown

Caution set text with caution format.

Example

ExampleMarkdown_Caution writes a GitHub CAUTION alert.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Caution("Advises about the risks of an action.").Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!CAUTION]  \n> Advises about the risks of an action.\n"

func (*Markdown) Cautionf

func (m *Markdown) Cautionf(format string, args ...interface{}) *Markdown

Cautionf set text with caution format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_Cautionf writes a GitHub CAUTION alert from a format string.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Cautionf("Caution takes %d minutes.", 5).Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!CAUTION]  \n> Caution takes 5 minutes.\n"

func (*Markdown) CheckBox

func (m *Markdown) CheckBox(set []CheckBoxSet) *Markdown

CheckBox is markdown CheckBox.

Example

ExampleMarkdown_CheckBox writes a task list. GitHub renders each item as a checkbox, and the text of an item may hold any inline markup.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		CheckBox([]md.CheckBoxSet{
			{Checked: true, Text: "Write the proposal"},
			{Checked: false, Text: md.Code("go test ./...")},
		}).
		Build()

}
Output:
- [x] Write the proposal
- [ ] `go test ./...`

func (*Markdown) CodeBlocks

func (m *Markdown) CodeBlocks(lang SyntaxHighlight, text string) *Markdown

CodeBlocks is code blocks. If you set text "Hello" and lang "go", it will be converted to "```go Hello ```".

The block is fenced with three backticks, so content holding a line that starts with three backticks closes it early and everything after that line renders as prose. Markdown's answer is a longer fence, which this method does not write: a caller whose content can hold a fence has to build the block itself with PlainText.

Example

ExampleMarkdown_CodeBlocks writes a fenced code block tagged with its language.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		CodeBlocks(md.SyntaxHighlightGo, `fmt.Println("hello")`).
		Build()

}
Output:
```go
fmt.Println("hello")
```

func (*Markdown) CustomTable

func (m *Markdown) CustomTable(t TableSet, options TableOptions) *Markdown

CustomTable is markdown table. This is so not break the original Table function. with Possible breaking changes.

Example

ExampleMarkdown_CustomTable writes a table with the alignment row spelled out. Without the options every column is left aligned.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		CustomTable(md.TableSet{
			Header: []string{"Name", "Age"},
			Rows: [][]string{
				{"David", "23"},
				{"John", "30"},
			},
		}, md.TableOptions{
			AutoFormatHeaders: false,
			AutoWrapText:      false,
		}).
		Build()

}
Output:
| Name  | Age |
|-------|-----|
| David | 23  |
| John  | 30  |

func (*Markdown) Details

func (m *Markdown) Details(summary, text string) *Markdown

Details is markdown details.

The body is surrounded by blank lines because an HTML block swallows everything up to the next blank line: without them the markdown inside <details> renders as literal text, and the block that follows </details> disappears into the same HTML block.

Example

ExampleMarkdown_Details writes a collapsible section. Markdown has no syntax of its own for one, so this is the single place the library emits HTML.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		Details("Show the stack trace", "goroutine 1 [running]").
		Build()

}
Output:
<details>
<summary>Show the stack trace</summary>

goroutine 1 [running]

</details>

func (*Markdown) Detailsf

func (m *Markdown) Detailsf(summary, format string, args ...interface{}) *Markdown

Detailsf is markdown details with format.

Example

ExampleMarkdown_Detailsf writes a collapsible section from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		Detailsf("Show the log", "exited with status %d", 2).
		Build()

}
Output:
<details>
<summary>Show the log</summary>

exited with status 2

</details>

func (*Markdown) Error

func (m *Markdown) Error() error

Error returns the error the chain recorded, or nil.

It is the same error Markdown.Build returns, for callers who would rather check before writing than after.

Example

ExampleMarkdown_Error reports the same error Build does, for code that wants to look before writing anything.

package main

import (
	"fmt"
	"io"

	md "github.com/nao1215/markdown"
)

func main() {
	m := md.NewMarkdown(io.Discard).
		TableOfContents(md.TableOfContentsDepthH3).
		TableOfContents(md.TableOfContentsDepthH3)
	fmt.Println("error:", m.Error())

}
Output:
error: table of contents has already been generated

func (*Markdown) GreenBadge

func (m *Markdown) GreenBadge(text string) *Markdown

GreenBadge set text with green badge format.

Example

ExampleMarkdown_GreenBadge writes a green badge, which is an image served by shields.io rather than markdown of its own.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).GreenBadge("build").Build()

}
Output:
![Badge](https://img.shields.io/badge/build-green)

func (*Markdown) GreenBadgef

func (m *Markdown) GreenBadgef(format string, args ...interface{}) *Markdown

GreenBadgef set text with green badge format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_GreenBadgef writes a green badge from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).GreenBadgef("coverage %d%%", 96).Build()

}
Output:
![Badge](https://img.shields.io/badge/coverage 96%-green)

func (*Markdown) H1

func (m *Markdown) H1(text string) *Markdown

H1 is markdown header. If you set text "Hello", it will be converted to "# Hello".

Example

ExampleMarkdown_H1 writes a level 1 heading.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H1("Heading").Build()

}
Output:
# Heading

func (*Markdown) H1f

func (m *Markdown) H1f(format string, args ...interface{}) *Markdown

H1f is markdown header with format. If you set format "%s", text "Hello", it will be converted to "# Hello".

Example

ExampleMarkdown_H1f writes a level 1 heading from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H1f("Heading %d", 1).Build()

}
Output:
# Heading 1

func (*Markdown) H2

func (m *Markdown) H2(text string) *Markdown

H2 is markdown header. If you set text "Hello", it will be converted to "## Hello".

Example

ExampleMarkdown_H2 writes a level 2 heading.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H2("Heading").Build()

}
Output:
## Heading

func (*Markdown) H2f

func (m *Markdown) H2f(format string, args ...interface{}) *Markdown

H2f is markdown header with format. If you set format "%s", text "Hello", it will be converted to "## Hello".

Example

ExampleMarkdown_H2f writes a level 2 heading from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H2f("Heading %d", 2).Build()

}
Output:
## Heading 2

func (*Markdown) H3

func (m *Markdown) H3(text string) *Markdown

H3 is markdown header. If you set text "Hello", it will be converted to "### Hello".

Example

ExampleMarkdown_H3 writes a level 3 heading.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H3("Heading").Build()

}
Output:
### Heading

func (*Markdown) H3f

func (m *Markdown) H3f(format string, args ...interface{}) *Markdown

H3f is markdown header with format. If you set format "%s", text "Hello", it will be converted to "### Hello".

Example

ExampleMarkdown_H3f writes a level 3 heading from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H3f("Heading %d", 3).Build()

}
Output:
### Heading 3

func (*Markdown) H4

func (m *Markdown) H4(text string) *Markdown

H4 is markdown header. If you set text "Hello", it will be converted to "#### Hello".

Example

ExampleMarkdown_H4 writes a level 4 heading.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H4("Heading").Build()

}
Output:
#### Heading

func (*Markdown) H4f

func (m *Markdown) H4f(format string, args ...interface{}) *Markdown

H4f is markdown header with format. If you set format "%s", text "Hello", it will be converted to "#### Hello".

Example

ExampleMarkdown_H4f writes a level 4 heading from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H4f("Heading %d", 4).Build()

}
Output:
#### Heading 4

func (*Markdown) H5

func (m *Markdown) H5(text string) *Markdown

H5 is markdown header. If you set text "Hello", it will be converted to "##### Hello".

Example

ExampleMarkdown_H5 writes a level 5 heading.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H5("Heading").Build()

}
Output:
##### Heading

func (*Markdown) H5f

func (m *Markdown) H5f(format string, args ...interface{}) *Markdown

H5f is markdown header with format. If you set format "%s", text "Hello", it will be converted to "##### Hello".

Example

ExampleMarkdown_H5f writes a level 5 heading from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H5f("Heading %d", 5).Build()

}
Output:
##### Heading 5

func (*Markdown) H6

func (m *Markdown) H6(text string) *Markdown

H6 is markdown header. If you set text "Hello", it will be converted to "###### Hello".

Example

ExampleMarkdown_H6 writes a level 6 heading.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H6("Heading").Build()

}
Output:
###### Heading

func (*Markdown) H6f

func (m *Markdown) H6f(format string, args ...interface{}) *Markdown

H6f is markdown header with format. If you set format "%s", text "Hello", it will be converted to "###### Hello".

Example

ExampleMarkdown_H6f writes a level 6 heading from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).H6f("Heading %d", 6).Build()

}
Output:
###### Heading 6

func (*Markdown) HorizontalRule

func (m *Markdown) HorizontalRule() *Markdown

HorizontalRule is markdown horizontal rule. It will be converted to "---".

Example

ExampleMarkdown_HorizontalRule writes a thematic break.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		PlainText("Above").
		HorizontalRule().
		PlainText("Below").
		Build()

}
Output:
Above
---
Below

func (*Markdown) Important

func (m *Markdown) Important(text string) *Markdown

Important set text with important format.

Example

ExampleMarkdown_Important writes a GitHub IMPORTANT alert.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Important("Key information a reader needs to succeed.").Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!IMPORTANT]  \n> Key information a reader needs to succeed.\n"

func (*Markdown) Importantf

func (m *Markdown) Importantf(format string, args ...interface{}) *Markdown

Importantf set text with important format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_Importantf writes a GitHub IMPORTANT alert from a format string.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Importantf("Important takes %d minutes.", 5).Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!IMPORTANT]  \n> Important takes 5 minutes.\n"

func (*Markdown) LF

func (m *Markdown) LF() *Markdown

LF is line feed.

It writes a line holding two spaces, which is a hard line break marker. It also happens to separate blocks, which is how most callers use it. Use BlankLine when a blank line is what you mean.

Example

ExampleMarkdown_LF is the older name for BlankLine and does the same thing.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).PlainText("Above").LF().PlainText("Below").Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the empty line carries the two spaces markdown
	// reads as a hard line break, and a godoc Output block cannot hold
	// trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"Above\n  \nBelow\n"

func (*Markdown) Note

func (m *Markdown) Note(text string) *Markdown

Note set text with note format.

Example

ExampleMarkdown_Note writes a GitHub NOTE alert.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Note("Useful information a reader should know even when skimming.").Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!NOTE]  \n> Useful information a reader should know even when skimming.\n"

func (*Markdown) Notef

func (m *Markdown) Notef(format string, args ...interface{}) *Markdown

Notef set text with note format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_Notef writes a GitHub NOTE alert from a format string.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Notef("Note takes %d minutes.", 5).Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!NOTE]  \n> Note takes 5 minutes.\n"

func (*Markdown) OrderedList

func (m *Markdown) OrderedList(text ...string) *Markdown

OrderedList is markdown number list. If you set text "Hello", it will be converted to "1. Hello".

Example

ExampleMarkdown_OrderedList writes a numbered list. The numbers are written out, so the document reads the same as a plain file.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		OrderedList("Clone the repository", "Run the tests", "Open a pull request").
		Build()

}
Output:
1. Clone the repository
2. Run the tests
3. Open a pull request

func (*Markdown) PlainText

func (m *Markdown) PlainText(text string) *Markdown

PlainText set plain text

Example

ExampleMarkdown_PlainText writes a paragraph.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).PlainText("A paragraph of text.").Build()

}
Output:
A paragraph of text.

func (*Markdown) PlainTextf

func (m *Markdown) PlainTextf(format string, args ...interface{}) *Markdown

PlainTextf set plain text with format

Example

ExampleMarkdown_PlainTextf writes a paragraph from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).PlainTextf("Built %d documents in %s.", 3, "2s").Build()

}
Output:
Built 3 documents in 2s.

func (*Markdown) RedBadge

func (m *Markdown) RedBadge(text string) *Markdown

RedBadge set text with red badge format.

Example

ExampleMarkdown_RedBadge writes a red badge, which is an image served by shields.io rather than markdown of its own.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).RedBadge("build").Build()

}
Output:
![Badge](https://img.shields.io/badge/build-red)

func (*Markdown) RedBadgef

func (m *Markdown) RedBadgef(format string, args ...interface{}) *Markdown

RedBadgef set text with red badge format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_RedBadgef writes a red badge from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).RedBadgef("coverage %d%%", 96).Build()

}
Output:
![Badge](https://img.shields.io/badge/coverage 96%-red)

func (*Markdown) String

func (m *Markdown) String() string

String returns markdown text.

It returns the document built so far whether or not an error was recorded, and it does not need a writer, so it works on a builder constructed with nil.

Example

ExampleMarkdown_String returns the document built so far without needing a writer, which is how the mermaid subpackages hand a diagram to CodeBlocks.

package main

import (
	"fmt"
	"io"

	md "github.com/nao1215/markdown"
)

func main() {
	document := md.NewMarkdown(io.Discard).H2("Summary").PlainText("All green.").String()
	fmt.Printf("%q\n", document)

}
Output:
"## Summary\nAll green."

func (*Markdown) Table

func (m *Markdown) Table(t TableSet) *Markdown

Table is markdown table with alignment support.

Example

ExampleMarkdown_Table writes a table. Every row must have as many cells as the header, and a row that does not records an error rather than writing a broken table.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		Table(md.TableSet{
			Header: []string{"Name", "Age"},
			Rows: [][]string{
				{"David", "23"},
				{"John", "30"},
			},
		}).
		Build()

}
Output:
| Name | Age |
|---------|---------|
| David | 23 |
| John | 30 |

func (*Markdown) TableOfContents added in v0.8.2

func (m *Markdown) TableOfContents(maxDepth TableOfContentsDepth) *Markdown

TableOfContents generates a table of contents placeholder that will be replaced when Build() is called. The table of contents will include all headers from H1 to the specified maxDepth. Only one table of contents can be generated per document.

Example:

markdown.NewMarkdown(os.Stdout).
   H1("Title").
   TableOfContents(markdown.TableOfContentsDepthH3).  // Table of contents will be placed here
   H2("Section 1").
   H3("Subsection 1.1").
   Build()
Example

ExampleMarkdown_TableOfContents writes a table of contents built from the headings of the document. It may be called before the headings it lists: the list is filled in at Build.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		H1("Guide").
		TableOfContents(md.TableOfContentsDepthH3).
		H2("Install").
		H3("From source").
		H2("Usage").
		Build()

}
Output:
# Guide
<!-- BEGIN_TOC -->
- [Guide](#guide)
  - [Install](#install)
    - [From source](#from-source)
  - [Usage](#usage)
<!-- END_TOC -->

## Install
### From source
## Usage

func (*Markdown) TableOfContentsWithRange added in v0.8.3

func (m *Markdown) TableOfContentsWithRange(minDepth, maxDepth TableOfContentsDepth) *Markdown

TableOfContentsWithRange generates a table of contents placeholder with custom depth range. The table of contents will include headers from minDepth to maxDepth inclusive. Only one table of contents can be generated per document.

Example:

markdown.NewMarkdown(os.Stdout).
   H1("Title").  // This H1 will not appear in table of contents
   H2("Table of Contents").
   TableOfContentsWithRange(markdown.TableOfContentsDepthH2, markdown.TableOfContentsDepthH4).  // Only include H2-H4 in table of contents
   H2("Section 1").
   H3("Subsection 1.1").
   H4("Detail").
   H5("Deep Detail").  // This H5 will not appear in table of contents
   Build()
Example

ExampleMarkdown_TableOfContentsWithRange writes a table of contents holding only the heading levels between the two given, which is how a document leaves its own title out of its contents.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		H1("Guide").
		TableOfContentsWithRange(md.TableOfContentsDepthH2, md.TableOfContentsDepthH2).
		H2("Install").
		H3("From source").
		H2("Usage").
		Build()

}
Output:
# Guide
<!-- BEGIN_TOC -->
- [Install](#install)
- [Usage](#usage)
<!-- END_TOC -->

## Install
### From source
## Usage

func (*Markdown) Tip

func (m *Markdown) Tip(text string) *Markdown

Tip set text with tip format.

Example

ExampleMarkdown_Tip writes a GitHub TIP alert.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Tip("Helpful advice for doing things better.").Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!TIP]  \n> Helpful advice for doing things better.\n"

func (*Markdown) Tipf

func (m *Markdown) Tipf(format string, args ...interface{}) *Markdown

Tipf set text with tip format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_Tipf writes a GitHub TIP alert from a format string.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Tipf("Tip takes %d minutes.", 5).Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!TIP]  \n> Tip takes 5 minutes.\n"

func (*Markdown) Warning

func (m *Markdown) Warning(text string) *Markdown

Warning set text with warning format.

Example

ExampleMarkdown_Warning writes a GitHub WARNING alert.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Warning("Urgent information needing immediate attention.").Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!WARNING]  \n> Urgent information needing immediate attention.\n"

func (*Markdown) Warningf

func (m *Markdown) Warningf(format string, args ...interface{}) *Markdown

Warningf set text with warning format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_Warningf writes a GitHub WARNING alert from a format string.

package main

import (
	"bytes"
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	buf := &bytes.Buffer{}
	if err := md.NewMarkdown(buf).Warningf("Warning takes %d minutes.", 5).Build(); err != nil {
		fmt.Println("build:", err)
		return
	}
	// Printed quoted because the keyword line ends with the two spaces
	// markdown reads as a hard line break, and a godoc Output block cannot
	// hold trailing whitespace.
	fmt.Printf("%q\n", buf.String())

}
Output:
"> [!WARNING]  \n> Warning takes 5 minutes.\n"

func (*Markdown) YellowBadge

func (m *Markdown) YellowBadge(text string) *Markdown

YellowBadge set text with yellow badge format.

Example

ExampleMarkdown_YellowBadge writes a yellow badge, which is an image served by shields.io rather than markdown of its own.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).YellowBadge("build").Build()

}
Output:
![Badge](https://img.shields.io/badge/build-yellow)

func (*Markdown) YellowBadgef

func (m *Markdown) YellowBadgef(format string, args ...interface{}) *Markdown

YellowBadgef set text with yellow badge format. It is similar to fmt.Sprintf.

Example

ExampleMarkdown_YellowBadgef writes a yellow badge from a format string.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).YellowBadgef("coverage %d%%", 96).Build()

}
Output:
![Badge](https://img.shields.io/badge/coverage 96%-yellow)

type Option added in v1.0.0

type Option func(*Markdown)

Option configures a Markdown at construction time.

Example

ExampleOption shows what an Option is: a function that changes how a document is written, passed to NewMarkdown.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	options := []md.Option{md.WithBlockSpacing()}

	_ = md.NewMarkdown(os.Stdout, options...).
		H2("Deploy").
		PlainText("Runs on every merge to main.").
		Build()

}
Output:
## Deploy

Runs on every merge to main.

func WithBlockSpacing added in v1.0.0

func WithBlockSpacing() Option

WithBlockSpacing separates every block with a blank line.

The default output only inserts the blank lines markdown cannot do without, which keeps documents compact but leaves markdownlint complaining about headings, fenced blocks, and tables that touch their neighbors. Tools such as mkdocs are stricter than GitHub about this. Turn the option on when the document is going to be linted or rendered by something other than GitHub.

Example

ExampleWithBlockSpacing shows the option that puts a blank line between blocks. Without it the blocks are written one after another.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout, md.WithBlockSpacing()).
		H2("Deploy").
		PlainText("Runs on every merge to main.").
		H2("Rollback").
		PlainText("Re-run the previous release job.").
		Build()

}
Output:
## Deploy

Runs on every merge to main.

## Rollback

Re-run the previous release job.

type SyntaxHighlight

type SyntaxHighlight string

SyntaxHighlight is syntax highlight language.

Example

ExampleSyntaxHighlight shows the language a code block is tagged with. The constants cover the languages GitHub highlights; any other string works too.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		CodeBlocks(md.SyntaxHighlightGo, `fmt.Println("hello")`).
		CodeBlocks(md.SyntaxHighlightNone, "no highlighting here").
		Build()

}
Output:
```go
fmt.Println("hello")
```
```
no highlighting here
```
const (
	// SyntaxHighlightNone is no syntax highlight.
	SyntaxHighlightNone SyntaxHighlight = ""
	// SyntaxHighlightText is syntax highlight for text.
	SyntaxHighlightText SyntaxHighlight = "text"
	// SyntaxHighlightAPIBlueprint is syntax highlight for API Blueprint.
	SyntaxHighlightAPIBlueprint SyntaxHighlight = "markdown"
	// SyntaxHighlightShell is syntax highlight for Shell.
	SyntaxHighlightShell SyntaxHighlight = "shell"
	// SyntaxHighlightGo is syntax highlight for Go.
	SyntaxHighlightGo SyntaxHighlight = "go"
	// SyntaxHighlightJSON is syntax highlight for JSON.
	SyntaxHighlightJSON SyntaxHighlight = "json"
	// SyntaxHighlightYAML is syntax highlight for YAML.
	SyntaxHighlightYAML SyntaxHighlight = "yaml"
	// SyntaxHighlightXML is syntax highlight for XML.
	SyntaxHighlightXML SyntaxHighlight = "xml"
	// SyntaxHighlightHTML is syntax highlight for HTML.
	SyntaxHighlightHTML SyntaxHighlight = "html"
	// SyntaxHighlightCSS is syntax highlight for CSS.
	SyntaxHighlightCSS SyntaxHighlight = "css"
	// SyntaxHighlightJavaScript is syntax highlight for JavaScript.
	SyntaxHighlightJavaScript SyntaxHighlight = "javascript"
	// SyntaxHighlightTypeScript is syntax highlight for TypeScript.
	SyntaxHighlightTypeScript SyntaxHighlight = "typescript"
	// SyntaxHighlightSQL is syntax highlight for SQL.
	SyntaxHighlightSQL SyntaxHighlight = "sql"
	// SyntaxHighlightC is syntax highlight for C.
	SyntaxHighlightC SyntaxHighlight = "c"
	// SyntaxHighlightCSharp is syntax highlight for C#.
	SyntaxHighlightCSharp SyntaxHighlight = "csharp"
	// SyntaxHighlightCPlusPlus is syntax highlight for C++.
	SyntaxHighlightCPlusPlus SyntaxHighlight = "cpp"
	// SyntaxHighlightJava is syntax highlight for Java.
	SyntaxHighlightJava SyntaxHighlight = "java"
	// SyntaxHighlightKotlin is syntax highlight for Kotlin.
	SyntaxHighlightKotlin SyntaxHighlight = "kotlin"
	// SyntaxHighlightPHP is syntax highlight for PHP.
	SyntaxHighlightPHP SyntaxHighlight = "php"
	// SyntaxHighlightPython is syntax highlight for Python.
	SyntaxHighlightPython SyntaxHighlight = "python"
	// SyntaxHighlightRuby is syntax highlight for Ruby.
	SyntaxHighlightRuby SyntaxHighlight = "ruby"
	// SyntaxHighlightSwift is syntax highlight for Swift.
	SyntaxHighlightSwift SyntaxHighlight = "swift"
	// SyntaxHighlightScala is syntax highlight for Scala.
	SyntaxHighlightScala SyntaxHighlight = "scala"
	// SyntaxHighlightRust is syntax highlight for Rust.
	SyntaxHighlightRust SyntaxHighlight = "rust"
	// SyntaxHighlightObjectiveC is syntax highlight for Objective-C.
	SyntaxHighlightObjectiveC SyntaxHighlight = "objectivec"
	// SyntaxHighlightPerl is syntax highlight for Perl.
	SyntaxHighlightPerl SyntaxHighlight = "perl"
	// SyntaxHighlightLua is syntax highlight for Lua.
	SyntaxHighlightLua SyntaxHighlight = "lua"
	// SyntaxHighlightDart is syntax highlight for Dart.
	SyntaxHighlightDart SyntaxHighlight = "dart"
	// SyntaxHighlightClojure is syntax highlight for Clojure.
	SyntaxHighlightClojure SyntaxHighlight = "clojure"
	// SyntaxHighlightGroovy is syntax highlight for Groovy.
	SyntaxHighlightGroovy SyntaxHighlight = "groovy"
	// SyntaxHighlightR is syntax highlight for R.
	SyntaxHighlightR SyntaxHighlight = "r"
	// SyntaxHighlightHaskell is syntax highlight for Haskell.
	SyntaxHighlightHaskell SyntaxHighlight = "haskell"
	// SyntaxHighlightErlang is syntax highlight for Erlang.
	SyntaxHighlightErlang SyntaxHighlight = "erlang"
	// SyntaxHighlightElixir is syntax highlight for Elixir.
	SyntaxHighlightElixir SyntaxHighlight = "elixir"
	// SyntaxHighlightOCaml is syntax highlight for OCaml.
	SyntaxHighlightOCaml SyntaxHighlight = "ocaml"
	// SyntaxHighlightJulia is syntax highlight for Julia.
	SyntaxHighlightJulia SyntaxHighlight = "julia"
	// SyntaxHighlightScheme is syntax highlight for Scheme.
	SyntaxHighlightScheme SyntaxHighlight = "scheme"
	// SyntaxHighlightFSharp is syntax highlight for F#.
	SyntaxHighlightFSharp SyntaxHighlight = "fsharp"
	// SyntaxHighlightCoffeeScript is syntax highlight for CoffeeScript.
	SyntaxHighlightCoffeeScript SyntaxHighlight = "coffeescript"
	// SyntaxHighlightVBNet is syntax highlight for VB.NET.
	SyntaxHighlightVBNet SyntaxHighlight = "vbnet"
	// SyntaxHighlightTeX is syntax highlight for TeX.
	SyntaxHighlightTeX SyntaxHighlight = "tex"
	// SyntaxHighlightDiff is syntax highlight for Diff.
	SyntaxHighlightDiff SyntaxHighlight = "diff"
	// SyntaxHighlightApache is syntax highlight for Apache.
	SyntaxHighlightApache SyntaxHighlight = "apache"
	// SyntaxHighlightDockerfile is syntax highlight for Dockerfile.
	SyntaxHighlightDockerfile SyntaxHighlight = "dockerfile"
	// SyntaxHighlightMermaid is syntax highlight for Mermaid.
	SyntaxHighlightMermaid SyntaxHighlight = "mermaid"
)

type TableAlignment added in v0.8.1

type TableAlignment int

TableAlignment represents column alignment in markdown tables.

Example

ExampleTableAlignment demonstrates table alignment features.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		H2("Table with Alignments").
		Table(md.TableSet{
			Header: []string{"Left Align", "Center Align", "Right Align"},
			Rows: [][]string{
				{"Content1", "Content2", "Content3"},
				{"Content4", "Content5", "Content6"},
			},
			Alignment: []md.TableAlignment{md.AlignLeft, md.AlignCenter, md.AlignRight},
		}).
		Build()

}
Output:
## Table with Alignments
| Left Align | Center Align | Right Align |
|:--------|:-------:|--------:|
| Content1 | Content2 | Content3 |
| Content4 | Content5 | Content6 |
const (
	// AlignDefault represents no specific alignment (left by default).
	AlignDefault TableAlignment = iota
	// AlignLeft represents left alignment (:------).
	AlignLeft
	// AlignCenter represents center alignment (:-----:).
	AlignCenter
	// AlignRight represents right alignment (------:).
	AlignRight
)

type TableOfContentsDepth added in v0.8.2

type TableOfContentsDepth int

TableOfContentsDepth represents the depth level for table of contents.

Example

ExampleTableOfContentsDepth shows the heading level a table of contents stops at.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		TableOfContents(md.TableOfContentsDepthH2).
		H2("Install").
		H3("From source").
		Build()

}
Output:
<!-- BEGIN_TOC -->
- [Install](#install)
<!-- END_TOC -->

## Install
### From source
const (
	// TableOfContentsDepthH1 includes only H1 headers in the table of contents.
	TableOfContentsDepthH1 TableOfContentsDepth = 1
	// TableOfContentsDepthH2 includes H1 and H2 headers in the table of contents.
	TableOfContentsDepthH2 TableOfContentsDepth = 2
	// TableOfContentsDepthH3 includes H1, H2, and H3 headers in the table of contents.
	TableOfContentsDepthH3 TableOfContentsDepth = 3
	// TableOfContentsDepthH4 includes H1, H2, H3, and H4 headers in the table of contents.
	TableOfContentsDepthH4 TableOfContentsDepth = 4
	// TableOfContentsDepthH5 includes H1, H2, H3, H4, and H5 headers in the table of contents.
	TableOfContentsDepthH5 TableOfContentsDepth = 5
	// TableOfContentsDepthH6 includes all headers (H1 through H6) in the table of contents.
	TableOfContentsDepthH6 TableOfContentsDepth = 6
)

type TableOfContentsOptions added in v0.8.3

type TableOfContentsOptions struct {
	// MinDepth is the minimum header level to include (e.g., 2 for H2 and deeper).
	MinDepth TableOfContentsDepth
	// MaxDepth is the maximum header level to include (e.g., 4 for H4 and shallower).
	MaxDepth TableOfContentsDepth
}

TableOfContentsOptions contains options for generating the table of contents.

Example

ExampleTableOfContentsOptions shows the range a table of contents covers. Naming both ends is how a document leaves its own title out of its contents.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	options := md.TableOfContentsOptions{
		MinDepth: md.TableOfContentsDepthH2,
		MaxDepth: md.TableOfContentsDepthH2,
	}

	_ = md.NewMarkdown(os.Stdout).
		H1("Guide").
		TableOfContentsWithRange(options.MinDepth, options.MaxDepth).
		H2("Install").
		H3("From source").
		Build()

}
Output:
# Guide
<!-- BEGIN_TOC -->
- [Install](#install)
<!-- END_TOC -->

## Install
### From source

type TableOptions

type TableOptions struct {
	// AutoWrapText is whether to wrap the text automatically.
	AutoWrapText bool
	// AutoFormatHeaders is whether to format the header automatically.
	AutoFormatHeaders bool
}

TableOptions is markdown table options.

Example

ExampleTableOptions shows the options CustomTable takes. They control the header casing and the wrapping, not the alignment, which is a field of the table itself.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	_ = md.NewMarkdown(os.Stdout).
		CustomTable(md.TableSet{
			Header: []string{"package", "coverage"},
			Rows:   [][]string{{"markdown", "96%"}},
		}, md.TableOptions{
			AutoFormatHeaders: true,
			AutoWrapText:      false,
		}).
		Build()

}
Output:
| PACKAGE  | COVERAGE |
|----------|----------|
| MARKDOWN | 96 %     |

type TableSet

type TableSet struct {
	// Header is table header.
	Header []string
	// Rows is table record.
	Rows [][]string
	// Alignment is column alignment for each column.
	// If nil or shorter than header length, remaining columns use AlignDefault.
	Alignment []TableAlignment
	// EscapeCells runs every header and row cell through EscapeTableCell.
	//
	// It is off by default because cells often hold markup the caller built on
	// purpose, with Link or Bold, and because callers who already escape their
	// own data would end up escaping it twice. Turn it on when the cells carry
	// arbitrary text that may contain a pipe or a newline.
	EscapeCells bool
}

TableSet is markdown table.

Example

ExampleTableSet shows the shape a table is described with. Every row must have as many cells as the header.

package main

import (
	"os"

	md "github.com/nao1215/markdown"
)

func main() {
	set := md.TableSet{
		Header: []string{"Package", "Coverage"},
		Rows: [][]string{
			{"markdown", "96%"},
			{"internal", "100%"},
		},
	}

	_ = md.NewMarkdown(os.Stdout).Table(set).Build()

}
Output:
| Package | Coverage |
|---------|---------|
| markdown | 96% |
| internal | 100% |

func (*TableSet) ValidateColumns

func (t *TableSet) ValidateColumns() error

ValidateColumns checks if the number of columns in the header and records match.

Example

ExampleTableSet_ValidateColumns reports a row whose cell count does not match the header. Table calls it, so this is only worth calling directly when the table is assembled before the document is.

package main

import (
	"fmt"

	md "github.com/nao1215/markdown"
)

func main() {
	set := md.TableSet{
		Header: []string{"Name", "Age"},
		Rows:   [][]string{{"only one cell"}},
	}
	fmt.Println(set.ValidateColumns())

}
Output:
number of columns in the record doesn't match the header

Directories

Path Synopsis
doc
alert command
Package main is generating markdown.
Package main is generating markdown.
apiaudit command
Package main generates doc/v1-api-audit.md, the inventory of everything this library exports and the verdict on each of it for v1.0.0.
Package main generates doc/v1-api-audit.md, the inventory of everything this library exports and the verdict on each of it for v1.0.0.
architecture command
Package main is generating mermaid sequence diagram.
Package main is generating mermaid sequence diagram.
badge command
Package main is generating markdown.
Package main is generating markdown.
block command
Package main is generating mermaid block diagram.
Package main is generating mermaid block diagram.
c4 command
Package main is generating mermaid C4 context diagram.
Package main is generating mermaid C4 context diagram.
class command
Package main is generating mermaid class diagram.
Package main is generating mermaid class diagram.
edgecase command
Package main generates one document per mermaid subpackage, every label of which holds the punctuation that means something to mermaid.
Package main generates one document per mermaid subpackage, every label of which holds the punctuation that means something to mermaid.
er command
Package main is generating entity relationship diagram.
Package main is generating entity relationship diagram.
example command
Package main writes doc/generated_example.md, the sample document README links to.
Package main writes doc/generated_example.md, the sample document README links to.
flowchart command
Package main is generating flowchart.
Package main is generating flowchart.
gantt command
Package main is generating mermaid Gantt chart.
Package main is generating mermaid Gantt chart.
generate command
Package main is generating markdown.
Package main is generating markdown.
gitgraph command
Package main is generating mermaid git graph diagram.
Package main is generating mermaid git graph diagram.
kanban command
Package main is generating mermaid kanban diagram.
Package main is generating mermaid kanban diagram.
mindmap command
Package main is generating mermaid mindmap diagram.
Package main is generating mermaid mindmap diagram.
packet command
Package main is generating mermaid packet diagram.
Package main is generating mermaid packet diagram.
piechart command
Package main is generating pie chart.
Package main is generating pie chart.
quadrant command
Package main is generating mermaid quadrant chart.
Package main is generating mermaid quadrant chart.
radar command
Package main is generating mermaid radar chart.
Package main is generating mermaid radar chart.
requirement command
Package main is generating mermaid requirement diagram.
Package main is generating mermaid requirement diagram.
sankey command
Package main is generating mermaid sankey diagram.
Package main is generating mermaid sankey diagram.
sequence command
Package main is generating mermaid sequence diagram.
Package main is generating mermaid sequence diagram.
state command
Package main is generating mermaid state diagram.
Package main is generating mermaid state diagram.
timeline command
Package main is generating mermaid timeline diagram.
Package main is generating mermaid timeline diagram.
toc command
Package main is generating markdown with table of contents.
Package main is generating markdown with table of contents.
treemap command
Package main is generating mermaid treemap diagram.
Package main is generating mermaid treemap diagram.
userjourney command
Package main is generating mermaid user journey diagram.
Package main is generating mermaid user journey diagram.
venn command
Package main is generating mermaid Venn diagram.
Package main is generating mermaid Venn diagram.
wardley command
Package main is generating mermaid Wardley map.
Package main is generating mermaid Wardley map.
xychart command
Package main is generating mermaid XY chart.
Package main is generating mermaid XY chart.
Package internal package is used to store the internal implementation of the mermaid package.
Package internal package is used to store the internal implementation of the mermaid package.
buildertest
Package buildertest exercises the error handling that every builder in this module shares.
Package buildertest exercises the error handling that every builder in this module shares.
golden
Package golden compares generated markdown against committed golden files.
Package golden compares generated markdown against committed golden files.
mermaid
arch
Package arch is mermaid architecture diagram builder.
Package arch is mermaid architecture diagram builder.
block
Package block is mermaid block diagram builder.
Package block is mermaid block diagram builder.
c4
Package c4 is mermaid C4 context diagram builder.
Package c4 is mermaid C4 context diagram builder.
class
Package class is mermaid class diagram builder.
Package class is mermaid class diagram builder.
er
Package er is mermaid entity relationship diagram builder.
Package er is mermaid entity relationship diagram builder.
flowchart
Package flowchart provides a simple way to create flowcharts in mermaid syntax.
Package flowchart provides a simple way to create flowcharts in mermaid syntax.
gantt
Package gantt is a mermaid Gantt chart builder.
Package gantt is a mermaid Gantt chart builder.
gitgraph
Package gitgraph is mermaid git graph diagram builder.
Package gitgraph is mermaid git graph diagram builder.
kanban
Package kanban is mermaid kanban diagram builder.
Package kanban is mermaid kanban diagram builder.
mindmap
Package mindmap is mermaid mindmap diagram builder.
Package mindmap is mermaid mindmap diagram builder.
packet
Package packet is mermaid packet diagram builder.
Package packet is mermaid packet diagram builder.
piechart
Package piechart is mermaid pie chart builder.
Package piechart is mermaid pie chart builder.
quadrant
Package quadrant is mermaid quadrant chart builder.
Package quadrant is mermaid quadrant chart builder.
radar
Package radar is mermaid radar chart builder.
Package radar is mermaid radar chart builder.
requirement
Package requirement is mermaid requirement diagram builder.
Package requirement is mermaid requirement diagram builder.
sankey
Package sankey is mermaid sankey diagram builder.
Package sankey is mermaid sankey diagram builder.
sequence
Package sequence is mermaid sequence diagram builder.
Package sequence is mermaid sequence diagram builder.
state
Package state is mermaid state diagram builder.
Package state is mermaid state diagram builder.
timeline
Package timeline is mermaid timeline diagram builder.
Package timeline is mermaid timeline diagram builder.
treemap
Package treemap is mermaid treemap diagram builder.
Package treemap is mermaid treemap diagram builder.
userjourney
Package userjourney is mermaid user journey diagram builder.
Package userjourney is mermaid user journey diagram builder.
venn
Package venn is mermaid Venn diagram builder.
Package venn is mermaid Venn diagram builder.
wardley
Package wardley is mermaid Wardley map builder.
Package wardley is mermaid Wardley map builder.
xychart
Package xychart is mermaid XY chart builder.
Package xychart is mermaid XY chart builder.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL