step/providers/markdown/markdown.go

81 lines
2.0 KiB
Go

package markdown
import "fmt"
import "bytes"
import "strings"
import "html/template"
import "github.com/yuin/goldmark"
import "github.com/yuin/goldmark/parser"
import "github.com/yuin/goldmark/renderer"
import "github.com/yuin/goldmark/extension"
import "git.tebibyte.media/sashakoshka/step"
import "github.com/yuin/goldmark/renderer/html"
var _ step.FuncProvider = new(Provider)
// Provider provides Markdown functions.
type Provider struct {
Extensions []goldmark.Extender
ParserOptions []parser.Option
RendererOptions []renderer.Option
}
// Package fulfills the step.Provider interface.
func (this *Provider) Package () string {
return "markdown"
}
// Default returns a provider with the default configuration.
func Default () *Provider {
return &Provider {
Extensions: []goldmark.Extender { extension.GFM },
ParserOptions: []parser.Option { parser.WithAutoHeadingID() },
RendererOptions: []renderer.Option {
html.WithXHTML(),
html.WithUnsafe(),
},
}
}
// FuncMap fulfills the step.FuncProvider interface.
func (this *Provider) FuncMap () template.FuncMap {
stat := &state {
md: goldmark.New (
goldmark.WithExtensions(this.Extensions...),
goldmark.WithParserOptions(this.ParserOptions...),
goldmark.WithRendererOptions(this.RendererOptions...)),
}
return template.FuncMap {
"markdown": stat.funcMarkdown,
"markdownHTML": stat.funcMarkdownHTML,
}
}
type state struct {
md goldmark.Markdown
}
func (this *state) funcMarkdown (input any) (string, error) {
builder := strings.Builder { }
err := this.md.Convert(toBytes(input), &builder)
if err != nil { return "", nil }
return builder.String(), nil
}
func (this *state) funcMarkdownHTML (input any) (template.HTML, error) {
str, err := this.funcMarkdown(input)
return template.HTML(str), err
}
func toBytes (data any) []byte {
switch data := data.(type) {
case []byte: return data
case string: return []byte(data)
case template.HTML: return []byte(data)
default:
buffer := bytes.Buffer { }
fmt.Fprint(&buffer, data)
return buffer.Bytes()
}
}