this repo has no description
1// Package markup is an umbrella package for all markups and their renderers. 2package markup 3 4import ( 5 "bytes" 6 "path" 7 8 "github.com/yuin/goldmark" 9 "github.com/yuin/goldmark/ast" 10 "github.com/yuin/goldmark/extension" 11 "github.com/yuin/goldmark/parser" 12 "github.com/yuin/goldmark/text" 13 "github.com/yuin/goldmark/util" 14) 15 16// RendererType defines the type of renderer to use based on context 17type RendererType int 18 19const ( 20 // RendererTypeRepoMarkdown is for repository documentation markdown files 21 RendererTypeRepoMarkdown RendererType = iota 22) 23 24// RenderContext holds the contextual data for rendering markdown. 25// It can be initialized empty, and that'll skip any transformations. 26type RenderContext struct { 27 Ref string 28 FullRepoName string 29 RendererType RendererType 30} 31 32func (rctx *RenderContext) RenderMarkdown(source string) string { 33 md := goldmark.New( 34 goldmark.WithExtensions(extension.GFM), 35 goldmark.WithParserOptions( 36 parser.WithAutoHeadingID(), 37 ), 38 ) 39 40 if rctx != nil { 41 var transformers []util.PrioritizedValue 42 43 transformers = append(transformers, util.Prioritized(&MarkdownTransformer{rctx: rctx}, 10000)) 44 45 md.Parser().AddOptions( 46 parser.WithASTTransformers(transformers...), 47 ) 48 } 49 50 var buf bytes.Buffer 51 if err := md.Convert([]byte(source), &buf); err != nil { 52 return source 53 } 54 return buf.String() 55} 56 57type MarkdownTransformer struct { 58 rctx *RenderContext 59} 60 61func (a *MarkdownTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) { 62 _ = ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) { 63 if !entering { 64 return ast.WalkContinue, nil 65 } 66 67 switch a.rctx.RendererType { 68 case RendererTypeRepoMarkdown: 69 if v, ok := n.(*ast.Link); ok { 70 a.rctx.relativeLinkTransformer(v) 71 } 72 // more types here like RendererTypeIssue/Pull etc. 73 } 74 75 return ast.WalkContinue, nil 76 }) 77} 78 79func (rctx *RenderContext) relativeLinkTransformer(link *ast.Link) { 80 dst := string(link.Destination) 81 82 if len(dst) == 0 || dst[0] == '#' || 83 bytes.Contains(link.Destination, []byte("://")) || 84 bytes.HasPrefix(link.Destination, []byte("mailto:")) { 85 return 86 } 87 88 newPath := path.Join("/", rctx.FullRepoName, "tree", rctx.Ref, dst) 89 link.Destination = []byte(newPath) 90}