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() } }