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(``)
	_, _ = w.Write(nodeToHTMLText(n, source))
	_ = w.WriteByte('") 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() }