Skip to content

Add URL rewrite for markdown docs#199

Merged
thbkrkr merged 7 commits into
elastic:masterfrom
shainaraskas:add-link-mappings
Jun 11, 2026
Merged

Add URL rewrite for markdown docs#199
thbkrkr merged 7 commits into
elastic:masterfrom
shainaraskas:add-link-mappings

Conversation

@shainaraskas

@shainaraskas shainaraskas commented May 22, 2026

Copy link
Copy Markdown
Member

Overview

Adds optional URL rewriting in the markdown renderer.

Consumers can declare (url, link, text) triples under render.linkMappings in the config file. The markdown renderer rewrites occurrences of the url in field and type doc comments to [text](link) at render time. Lets us produce docs-builder cross-repo links from plain URLs in godoc instead of post-processing the rendered markdown in a downstream script.

Replaces elastic/cloud-on-k8s#9454 - will follow up with mappings in cloud-on-k8s after this change is released

Changes

  • new render.linkMappings config field
  • RewriteLinks method on the markdown renderer
  • called automatically inside RenderFieldDoc; bundled markdown templates also call it on $type.Doc (which doesn't go through RenderFieldDoc)
  • empty/unset linkMappings is a no-op, so existing consumers see no behavior change

I've left the asciidoc renderer alone:

  • it would require a different set of mappings
  • the asciidoc build has less strict link validation
  • we are no longer actively contributing to those docs at Elastic (they're stable/don't require generation)

Questions

  • Should this be altered to consume a mapping file external to the config.yml?

thbkrkr and others added 6 commits June 11, 2026 07:54
Reject any render.linkMappings entry with an empty url, link, or text.
An empty url is especially dangerous: strings.ReplaceAll(text, "", repl)
inserts the replacement between every character, silently corrupting all
rendered output. Failing fast at config load surfaces the misconfiguration
clearly instead of producing garbage docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RewriteLinks used strings.ReplaceAll, so when one mapped URL was a prefix
of another (".../old" vs ".../old-page"), correctness depended on the order
mappings happened to be declared in the config. Sort a copy of the mappings
by descending URL length before applying them, so the more specific URL
always wins regardless of config order. Update the prefix test to declare
the shorter URL first, proving order-independence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Field docs and $type.Doc were rewritten, but group/version package doc
comments rendered raw via {{ $gv.Doc }}, so a mapped URL in a GV doc was
silently missed. Wrap $gv.Doc with markdownRewriteLinks in the bundled and
test markdown templates. Add a mapped URL to the test package comment to
exercise this end-to-end and regenerate the golden files (markdown rewrites
it, asciidoc leaves it raw as expected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A mapped URL that already appears inside a Markdown link gets rewritten too,
producing nested invalid Markdown. This is acceptable for the plain-URL godoc
use case. Relabel the test to mark it a known limitation rather than desired
behavior, and add a README caveat telling users not to map already-linked URLs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RenderFieldDoc rewrites links before escaping the pipe character. Add a test
exercising a field doc that both contains a mappable URL and a literal pipe,
asserting the URL becomes a link and the pipe is still escaped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
linkMappings are inline in the config file, which is fine for small per-repo
sets but can become unwieldy at scale. Document the trade-off rather than
building external mapping-file support now.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@thbkrkr

thbkrkr commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Hi @shainaraskas, thanks for this! 🙏 Really clean addition, and the no-op-when-unconfigured design means existing consumers see zero behavior change.

I pushed a few small follow-up commits on top of your branch:

  1. Validate linkMappings fields at config load — reject empty url/link/text, since an empty url would otherwise hit strings.ReplaceAll(text, "", …) and corrupt all output
  2. Make rewriting order-independent — sort mappings by descending URL length so a more specific URL (.../old-page) always wins over a prefix (.../old), regardless of config order
  3. Also rewrite group/version doc comments ($gv.Doc) — they went through a different template path and were being missed; added a mapped URL to the test fixture to cover it end-to-end
  4. Flagged the nested-link case (a URL already inside a Markdown link) as a known limitation in the test + a README caveat
  5. Added a test for the pipe-escape + link-rewrite interaction in RenderFieldDoc
  6. README note on the inline-vs-external mapping-file trade-off (your open question) — leaned toward documenting it rather than building external-file support now

Kept as separate commits for easy review, I would appreciate you taking a look and letting me know if anything doesn't sit right with you. Thanks again!

@shainaraskas

Copy link
Copy Markdown
Member Author

@thbkrkr thanks for all of these updates. looked over all of the commits / reran the tests locally and it all lgtm.

I have limited access to this repo, so please merge this when you think it's good to go. Would also love a preview of the release process: at what point would the maintainers consider cutting a new release?

@thbkrkr thbkrkr merged commit dac27ef into elastic:master Jun 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants