Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ require (
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/yuin/goldmark v1.8.5 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/crypto v0.47.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.8.5 h1:r6N5afV5qj/5S4UTch8agZHJ8UxNCMwX7WjkkJam2NA=
github.com/yuin/goldmark v1.8.5/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
Expand Down
81 changes: 77 additions & 4 deletions renderer/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@
package renderer

import (
"bytes"
"fmt"
"io/fs"
"os"
"slices"
"strings"
"text/template"

"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer/html"

"github.com/Masterminds/sprig/v3"
"github.com/elastic/crd-ref-docs/config"
"github.com/elastic/crd-ref-docs/templates"
Expand Down Expand Up @@ -78,7 +84,9 @@ func (m *MarkdownRenderer) ToFuncMap() template.FuncMap {
"ShouldRenderType": m.ShouldRenderType,
"TypeID": m.TypeID,
"RenderFieldDoc": m.RenderFieldDoc,
"RenderFieldHTML": m.RenderFieldHTML,
"RenderDefault": m.RenderDefault,
"RenderValidation": m.RenderValidation,
"TemplateValue": m.TemplateValue,
}
}
Expand Down Expand Up @@ -186,9 +194,74 @@ func (m *MarkdownRenderer) RenderFieldDoc(text string) string {
return strings.ReplaceAll(out, "<br /><br />", "<br />")
}

// RenderFieldHTML renders a field whose docs are written in Markdown themselves
// as a single line of formatted HTML, that can be included in a Markdown table.
func (m *MarkdownRenderer) RenderFieldHTML(text string) string {
out := m.RewriteLinks(text)

md := goldmark.New(
goldmark.WithExtensions(extension.GFM),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
html.WithXHTML(),
),
)

var buf bytes.Buffer
docstringBytes := []byte(text)

if err := md.Convert(docstringBytes, &buf); err != nil {
panic(err)
}

out = buf.String()

// Escape the pipe character, which has special meaning for Markdown as a way to format tables
// so that including | in a comment does not result in wonky tables.
out = strings.ReplaceAll(out, "|", "\\|")

// Escape the curly bracket character.
out = strings.ReplaceAll(out, "{", "\\{")
out = strings.ReplaceAll(out, "}", "\\}")

// Replace any newlines that are left with spaces.
out = strings.ReplaceAll(out, "\n", " ")
// and remove double newline generated for empty lines
// empty line is still rendered in the table, without removing the duplicate
// newline it would be rendered as two empty lines
return strings.ReplaceAll(out, "<br /><br />", "<br />")
}

func (m *MarkdownRenderer) RenderDefault(text string) string {
return strings.NewReplacer(
"{", "\\{",
"}", "\\}",
).Replace(text)
out := text

if strings.Contains(out, "{") ||
strings.Contains(out, "[") {
out = fmt.Sprintf("`%s`", out)
}

return out
}

// RenderValidation renders validation with special handling
// for Required and Optional validations.
func (m *MarkdownRenderer) RenderValidation(text string) string {
out := text

if strings.HasPrefix(out, "Optional") {
return "_Optional_"
}

if strings.HasPrefix(out, "Required") {
return "_Required_"
}

out = strings.ReplaceAll(out, "|", "\\|")
// Escape the curly bracket character.
out = strings.ReplaceAll(out, "{", "\\{")
out = strings.ReplaceAll(out, "}", "\\}")

return out
}