mirror of
https://github.com/apricote/releaser-pleaser.git
synced 2026-01-13 21:21:03 +00:00
122 lines
2.9 KiB
Go
122 lines
2.9 KiB
Go
package markdown
|
|
|
|
import (
|
|
"bytes"
|
|
"strings"
|
|
|
|
markdown "github.com/teekennedy/goldmark-markdown"
|
|
"github.com/yuin/goldmark"
|
|
gast "github.com/yuin/goldmark/ast"
|
|
"github.com/yuin/goldmark/parser"
|
|
"github.com/yuin/goldmark/text"
|
|
"github.com/yuin/goldmark/util"
|
|
|
|
"github.com/apricote/releaser-pleaser/internal/markdown/extensions"
|
|
"github.com/apricote/releaser-pleaser/internal/markdown/extensions/ast"
|
|
)
|
|
|
|
func New() goldmark.Markdown {
|
|
return goldmark.New(
|
|
goldmark.WithExtensions(extensions.Section),
|
|
goldmark.WithParserOptions(parser.WithASTTransformers(
|
|
util.Prioritized(&newLineTransformer{}, 1),
|
|
)),
|
|
goldmark.WithRenderer(markdown.NewRenderer()),
|
|
)
|
|
}
|
|
|
|
// Format the Markdown document in a style mimicking Prettier. This is done for compatibility with other tools
|
|
// users might have installed in their IDE. This does not guarantee that the output matches Prettier exactly.
|
|
func Format(input string) (string, error) {
|
|
var buf bytes.Buffer
|
|
buf.Grow(len(input))
|
|
|
|
err := New().Convert([]byte(input), &buf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return buf.String(), nil
|
|
}
|
|
|
|
func GetCodeBlockText(source []byte, language string, output *string, found *bool) gast.Walker {
|
|
return func(n gast.Node, entering bool) (gast.WalkStatus, error) {
|
|
if !entering {
|
|
return gast.WalkContinue, nil
|
|
}
|
|
|
|
if n.Kind() != gast.KindFencedCodeBlock {
|
|
return gast.WalkContinue, nil
|
|
}
|
|
|
|
codeBlock := n.(*gast.FencedCodeBlock)
|
|
|
|
if string(codeBlock.Language(source)) != language {
|
|
return gast.WalkContinue, nil
|
|
}
|
|
|
|
*output = textFromLines(source, codeBlock)
|
|
if found != nil {
|
|
*found = true
|
|
}
|
|
// Stop looking after we find the first result
|
|
return gast.WalkStop, nil
|
|
}
|
|
}
|
|
|
|
func GetSectionText(source []byte, name string, output *string) gast.Walker {
|
|
return func(n gast.Node, entering bool) (gast.WalkStatus, error) {
|
|
if !entering {
|
|
return gast.WalkContinue, nil
|
|
}
|
|
|
|
if n.Kind() != ast.KindSection {
|
|
return gast.WalkContinue, nil
|
|
}
|
|
|
|
section := n.(*ast.Section)
|
|
|
|
if section.Name != name {
|
|
return gast.WalkContinue, nil
|
|
}
|
|
|
|
// Do not show section markings in output, we only care about the content
|
|
section.HideInOutput()
|
|
|
|
// Found the right section
|
|
outputBuffer := new(bytes.Buffer)
|
|
err := New().Renderer().Render(outputBuffer, source, section)
|
|
if err != nil {
|
|
return gast.WalkStop, err
|
|
}
|
|
|
|
*output = outputBuffer.String()
|
|
// Stop looking after we find the first result
|
|
return gast.WalkStop, nil
|
|
}
|
|
}
|
|
|
|
func textFromLines(source []byte, n gast.Node) string {
|
|
content := make([]byte, 0)
|
|
|
|
l := n.Lines().Len()
|
|
for i := 0; i < l; i++ {
|
|
line := n.Lines().At(i)
|
|
content = append(content, line.Value(source)...)
|
|
}
|
|
|
|
return strings.TrimSpace(string(content))
|
|
}
|
|
|
|
func WalkAST(source []byte, walkers ...gast.Walker) (err error) {
|
|
doc := New().Parser().Parse(text.NewReader(source))
|
|
|
|
for _, walker := range walkers {
|
|
err = gast.Walk(doc, walker)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|