diff --git a/gen-apidocs/generators/markdown.go b/gen-apidocs/generators/markdown.go
index 103f50ff8e..6fe8d978ed 100644
--- a/gen-apidocs/generators/markdown.go
+++ b/gen-apidocs/generators/markdown.go
@@ -19,6 +19,7 @@ package generators
import (
_ "embed"
"fmt"
+ "html"
"io"
"os"
"path/filepath"
@@ -460,7 +461,7 @@ func (m *MarkdownWriter) buildDefinitionPage(d *api.Definition, currentCategory
Title: d.Name,
Weight: m.nextResourceWeight(),
Anchor: anchor(d.Name),
- Description: d.DescriptionWithEntities,
+ Description: html.UnescapeString(d.DescriptionWithEntities),
}
// Inline closure rooted at d gates which types may flatten inline;
@@ -856,6 +857,7 @@ func anchor(s string) string {
// escape covers the only markdown-breaking character in OpenAPI descriptions:
// raw `<` that would otherwise be read as HTML.
func escape(s string) string {
+ s = html.UnescapeString(s)
s = strings.ReplaceAll(s, "<", `\<`)
s = enumHeaderRegex.ReplaceAllString(s, "
Possible enum values:")
s = enumBulletRegex.ReplaceAllString(s, "
- `")
diff --git a/gen-apidocs/generators/markdown_test.go b/gen-apidocs/generators/markdown_test.go
index 449fb9109b..366bbe2a59 100644
--- a/gen-apidocs/generators/markdown_test.go
+++ b/gen-apidocs/generators/markdown_test.go
@@ -62,6 +62,12 @@ func TestEscape(t *testing.T) {
if got := escape("no change"); got != "no change" {
t.Errorf("escape: got %q", got)
}
+ if got := escape(`Name: "mysvc"`); got != `Name: "mysvc"` {
+ t.Errorf("escape quotes: got %q", got)
+ }
+ if got := escape("https://git.k8s.io/community?foo=1&bar=2"); got != "https://git.k8s.io/community?foo=1&bar=2" {
+ t.Errorf("escape url amp: got %q", got)
+ }
if got := escape("Allowed values. Possible enum values: - `\"A\"` first. - `\"B\"` second."); got != "Allowed values.
Possible enum values:
- `\"A\"` first.
- `\"B\"` second." {
t.Errorf("escape enum list: got %q", got)
}
@@ -117,10 +123,10 @@ func TestWritePipeTable(t *testing.T) {
func TestOperationSlug(t *testing.T) {
cases := map[string]string{
- "listCoreV1Pod": "listcorev1pod",
- "readAppsV1NamespacedDeployment": "readappsv1namespaceddeployment",
- "watchCore.V1.Pod": "watchcore-v1-pod",
- "Some/Weird ID": "some-weird-id",
+ "listCoreV1Pod": "listcorev1pod",
+ "readAppsV1NamespacedDeployment": "readappsv1namespaceddeployment",
+ "watchCore.V1.Pod": "watchcore-v1-pod",
+ "Some/Weird ID": "some-weird-id",
}
for in, want := range cases {
if got := operationSlug(in); got != want {
@@ -405,8 +411,8 @@ func TestLinkDefinitionsSkipsInlined(t *testing.T) {
m := &MarkdownWriter{
linkMap: map[string]linkInfo{},
classifications: map[string]defClassification{
- azureDisk.Key(): {Mode: classifyInline}, // InlineInto irrelevant for this test
- objectMeta.Key(): {Mode: classifyStandalone},
+ azureDisk.Key(): {Mode: classifyInline}, // InlineInto irrelevant for this test
+ objectMeta.Key(): {Mode: classifyStandalone},
},
}