package md
import (
"bytes"
"strings"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/util"
)
type UrlTransformer = func(string) (string, error)
type urlTransformerExtension struct {
transformer UrlTransformer
}
func (e *urlTransformerExtension) Extend(m goldmark.Markdown) {
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(&urlRenderer{e.transformer}, 500),
))
}
type urlRenderer struct {
transformer UrlTransformer
}
func (r *urlRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(ast.KindImage, r.renderImage)
reg.Register(ast.KindLink, r.renderLink)
}
func (r *urlRenderer) renderImage(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
n := node.(*ast.Image)
url, err := r.resolveUrl(string(n.Destination))
if err != nil {
return ast.WalkStop, err
}
_, _ = w.WriteString(`
")
return ast.WalkSkipChildren, nil
}
func (r *urlRenderer) renderLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
n := node.(*ast.Link)
url, err := r.resolveUrl(string(n.Destination))
if err != nil {
return ast.WalkStop, err
}
_, _ = w.WriteString(``)
if n.Title != nil {
_, _ = w.Write(n.Title)
}
_, _ = w.WriteString("")
return ast.WalkSkipChildren, nil
}
func (r *urlRenderer) resolveUrl(url string) (string, error) {
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
return r.transformer(url)
}
return url, nil
}
func nodeToHTMLText(n ast.Node, source []byte) []byte {
var buf bytes.Buffer
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
if s, ok := c.(*ast.String); ok && s.IsCode() {
buf.Write(s.Text(source))
} else if !c.HasChildren() {
buf.Write(util.EscapeHTML(c.Text(source)))
} else {
buf.Write(nodeToHTMLText(c, source))
}
}
return buf.Bytes()
}