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}, }, }