Fix markdown twins and "Open Markdown" button on API reference pages - #2644
Fix markdown twins and "Open Markdown" button on API reference pages#2644kaankacar wants to merge 10 commits into
Conversation
The markdown-source plugin builds each page's .md twin from static page content, but API reference pages render their operation content (parameters, schemas, examples) client-side, so their twins came out as just the one-line description (~39 tokens vs ~14k tokens of rendered HTML). Rebuild those twins from the operation data itself: every *.api.mdx source carries the complete dereferenced operation object in its api: frontmatter field (zlib+base64, written by docusaurus-plugin-openapi-docs). Decode it and emit full markdown - method + path, base URLs, auth, parameter tables, request body, response schema trees, and JSON examples - over the near-empty twin under build/. Covers all 127 operation pages across the four bundled specs (Horizon, Anchor Platform platform + callbacks, SDP). Output-only like rewrite_md_links.mjs (which now runs after it in postbuild): writes only build/**/api-reference/**/*.md, leaves HTML and prose twins byte-identical, and is idempotent. Part 1 of #2643.
The markdown-source plugin injects its actions dropdown into 'article .markdown header', which regular doc pages have but OpenAPI operation pages don't (they render h1.openapi__heading and no header), so the button never appeared on them. Add a small client module that injects the plugin's own dropdown component right after that heading, on /api-reference/ routes only and only when no .markdown-actions-container exists yet - so regular pages (including prose pages under /api-reference/ routes, where the plugin already injects) are untouched and nothing is ever doubled. A MutationObserver handles late hydration and client-side navigation, mirroring the plugin's own approach. Part 2 of #2643.
There was a problem hiding this comment.
Pull request overview
Adds complete Markdown twins and the “Open Markdown” control for OpenAPI operation pages.
Changes:
- Generates Markdown from embedded OpenAPI operation data.
- Injects the Markdown dropdown on API operation pages.
- Adds generation to the postbuild pipeline.
Recommendation: NEEDS-CHANGES — generated output omits schema details, allOf descriptions, and response headers.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/clientModules/apiReferenceMarkdownButton.js |
Injects the Markdown dropdown. |
scripts/generate_api_markdown.mjs |
Generates OpenAPI Markdown twins. |
package.json |
Adds generation to postbuild. |
docusaurus.config.ts |
Registers the client module. |
|
Preview is available here: |
…caping or encoding' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
Preview is available here: |
2 similar comments
|
Preview is available here: |
|
Preview is available here: |
Same incomplete-sanitization pattern CodeQL flagged on the parameter table (alert 21): escaping pipes without escaping backslashes first.
Addresses the remaining Copilot review comment: the schema detail bullets now include the property's example value (inline, capped at 300 chars), its pattern regex, and minItems/maxItems constraints. Across the 127 operation blobs that is 758 examples, 191 patterns, and 3 array size bounds that previously did not reach the twins.
|
Preview is available here: |
|
Preview is available here: |
The markdown-source-plugin drops JSX blocks together with their markdown children when it builds a page's twin, so the 76 hand-written api-reference pages that keep their content inside AttributeTable, ExampleResponse, CodeExample, or MethodTable lost it: the Fee Stats object twin was 254 bytes with the whole attribute list missing. A second postbuild pass regenerates those twins from the .mdx source with the component tags unwrapped and their children kept. Fence-aware line walking keeps imports and tag-like lines inside code blocks untouched, and a twin is only overwritten when it provably matches the plugin's own lossy output for that source, so anything unrecognized is left alone. Comparison masks link targets because rewrite_md_links.mjs runs afterwards, which keeps the pass idempotent across rebuilds.
|
Preview is available here: |
|
Update for reviewers, three things landed since the initial review:
RPC method pages remain a known gap (their content is rendered by the custom RpcMethod component from the OpenRPC spec) and stay a follow-up, though their surrounding code examples now survive via the new pass. |
Closes #2643.
Follow-up to #2289: API reference pages (generated by
docusaurus-plugin-openapi-docs) were the one page type the markdown feature didn't handle — their.mdtwins were near-empty and the "Open Markdown" button never showed up on them. Both problems come from those pages using a different layout: the operation content (parameters, schemas, examples) is client-rendered, and there is noarticle .markdown headerelement for the plugin to inject its button into.Part 1: complete
.mdtwins for API operation pagesNew postbuild script
scripts/generate_api_markdown.mjs, chained beforerewrite_md_links.mjs:docs/**/api-reference/**/*.api.mdxsource file carries the complete, dereferenced operation object in itsapi:frontmatter field (zlib+base64, written by the openapi plugin — the exact data the page renders client-side). The script decodes that and emits clean markdown: method + path, base URLs, auth, parameter tables, request body, response schemas as an indented tree, and JSON examples.build/**/api-reference/**/<id>.mdpath. All 127 operation pages across the four bundled specs (Horizon, Anchor Platform platform + callbacks, SDP) are covered.build/**/*.md), no HTML or repo-source changes, idempotent, scoped strictly toapi-referencepages.Example (
platform/transactions/get-transaction.md): ~39 tokens before, now the full operation (~5k tokens) — still roughly a third of the rendered HTML's token count.Part 1b: hand-written api-reference pages (
<AttributeTable>and friends)The plugin drops JSX blocks including their markdown children when it builds a twin, so the 76 hand-written api-reference pages that keep their content inside
<AttributeTable>,<ExampleResponse>,<CodeExample>, or<MethodTable>lost it. Example: the Fee Stats object twin was 254 bytes, missing the entire attribute list that sits as plain markdown in the source.A second pass in the same script regenerates those twins from the
.mdxsource with the component tags unwrapped and children kept:rewrite_md_links.mjsruns after this script, which keeps the pass idempotent across rebuilds.RPC method pages still leak their
<RpcMethod />tag and get no operation content from the OpenRPC spec; that stays a follow-up. Their surrounding code examples do survive now via this pass.Part 2: "Open Markdown" button on API operation pages
New client module
src/clientModules/apiReferenceMarkdownButton.js:/api-reference/routes it injects the plugin's ownMarkdownActionsDropdowncomponent (same markup, same behavior, same.markdown-actions-containerstyling) right afterh1.openapi__heading— the element operation pages do have..markdown-actions-containerexists yet, so regular pages — including prose pages that live under/api-reference/routes, where the plugin already injects — are left alone. AMutationObserverhandles late hydration and client-side navigation, mirroring the plugin's own approach.Verification
build/**/*.htmlbyte-identical before/after the postbuild scripts (hash check over all HTML files)..markdown-actions-containeron operation pages, linking to the page's.md; normal pages still show exactly one (the plugin's).RPC method pages (
docs/data/apis/rpc/api-reference/methods/**) are a different mechanism (OpenRPC spec rendered by the customRpcMethodcomponent) and are not covered here — their twins already carry the prose/SDK-guide content. Can be a follow-up if wanted.