eng/tools/internal/markdown/markdown.go (159 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
package markdown
import (
"fmt"
"strings"
)
// RenderLink returns a rendered markdown link
func RenderLink(name, link string) string {
return fmt.Sprintf("[%s](%s)", name, link)
}
// Writer is a writer to write contents in markdown format
type Writer struct {
sb strings.Builder
nl bool
}
func (md *Writer) checkNL() {
if md.nl {
md.sb.WriteString("\n")
md.nl = false
}
}
// WriteTitle writes a title to the markdown document
func (md *Writer) WriteTitle(h string) {
md.checkNL()
md.sb.WriteString("# ")
md.sb.WriteString(h)
md.sb.WriteString("\n\n")
}
// WriteTopLevelHeader writes a header to the markdown document
func (md *Writer) WriteTopLevelHeader(h string) {
md.checkNL()
md.sb.WriteString("## ")
md.sb.WriteString(h)
md.sb.WriteString("\n\n")
}
// WriteHeader writes a header to the markdown document
func (md *Writer) WriteHeader(h string) {
md.checkNL()
md.sb.WriteString("### ")
md.sb.WriteString(h)
md.sb.WriteString("\n\n")
}
// WriteSubheader writes a sub-header to the markdown document
func (md *Writer) WriteSubheader(sh string) {
md.checkNL()
md.sb.WriteString("#### ")
md.sb.WriteString(sh)
md.sb.WriteString("\n\n")
}
// WriteLine writes a line to the markdown document
func (md *Writer) WriteLine(s string) {
md.nl = true
md.sb.WriteString(s)
md.sb.WriteString("\n")
}
// WriteListItem writes a line in a list
func (md *Writer) WriteListItem(item string) {
md.WriteLine(fmt.Sprintf("- %s", item))
}
// WriteTable writes a table to the markdown document
func (md *Writer) WriteTable(table Table) {
md.WriteLine(table.String())
}
// EmptyLine inserts an empty line to the markdown document
func (md *Writer) EmptyLine() {
md.WriteLine("")
}
// String outputs the markdown document as a string
func (md *Writer) String() string {
return md.sb.String()
}
// Table describes a table in a markdown document
type Table struct {
sb *strings.Builder
headers []string
alignment string
rows []markdownTableRow
}
const (
leftAlignment = ":---"
centerAlignment = ":---:"
rightAlignment = "---:"
)
// NewTable creates a new table with given alignments and headers
func NewTable(alignment string, headers ...string) *Table {
alignment, headers = checkAlignmentAndHeaders(alignment, headers)
t := Table{
sb: &strings.Builder{},
headers: headers,
alignment: alignment,
}
return &t
}
// Columns returns the number of columns in this table
func (t *Table) Columns() int {
return len(t.headers)
}
// Rows returns the number of rows in this table
func (t *Table) Rows() int {
return len(t.rows)
}
// AddRow adds a new row to the table
func (t *Table) AddRow(items ...string) {
t.rows = append(t.rows, markdownTableRow{
items: items,
})
}
func checkAlignmentAndHeaders(alignment string, headers []string) (string, []string) {
if len(alignment) == len(headers) {
return alignment, headers
}
if len(alignment) > len(headers) {
return alignment[:len(headers)], headers
}
// default alignment is l
return alignment + strings.Repeat("l", len(headers)-len(alignment)), headers
}
type markdownTableRow struct {
items []string
}
func (r *markdownTableRow) ensureItems(count int) []string {
if len(r.items) < count {
var items []string
for i := 0; i < count-len(r.items); i++ {
items = append(r.items, "")
}
return items
}
if len(r.items) > count {
return r.items[:count]
}
return r.items
}
func (t *Table) writeHeader() {
if len(t.headers) == 0 {
return
}
t.sb.WriteString("| ")
t.sb.WriteString(strings.Join(t.headers, " | "))
t.sb.WriteString(" |")
}
func (t *Table) writeAlignment() {
if len(t.alignment) == 0 {
return
}
var alignments []string
for _, a := range t.alignment {
switch a {
case 'c':
alignments = append(alignments, centerAlignment)
case 'r':
alignments = append(alignments, rightAlignment)
default:
alignments = append(alignments, leftAlignment)
}
}
t.sb.WriteString("\n| ")
t.sb.WriteString(strings.Join(alignments, " | "))
t.sb.WriteString(" |")
}
func (t *Table) writeRows() {
for _, r := range t.rows {
t.writeRow(r)
}
}
func (t *Table) writeRow(row markdownTableRow) {
items := row.ensureItems(t.Columns())
t.sb.WriteString("\n| ")
t.sb.WriteString(strings.Join(items, " | "))
t.sb.WriteString(" |")
}
// String outputs the markdown table to a string
func (t *Table) String() string {
t.writeHeader()
t.writeAlignment()
t.writeRows()
return t.sb.String()
}