Skip to content

Fix markdown twins and "Open Markdown" button on API reference pages#2644

Open
kaankacar wants to merge 2 commits into
mainfrom
2643-fix-api-reference-markdown
Open

Fix markdown twins and "Open Markdown" button on API reference pages#2644
kaankacar wants to merge 2 commits into
mainfrom
2643-fix-api-reference-markdown

Conversation

@kaankacar

Copy link
Copy Markdown
Contributor

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 .md twins 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 no article .markdown header element for the plugin to inject its button into.

Part 1: complete .md twins for API operation pages

New postbuild script scripts/generate_api_markdown.mjs, chained before rewrite_md_links.mjs:

  • Every docs/**/api-reference/**/*.api.mdx source file carries the complete, dereferenced operation object in its api: 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.
  • Output goes over the near-empty twin at the matching build/**/api-reference/**/<id>.md path. All 127 operation pages across the four bundled specs (Horizon, Anchor Platform platform + callbacks, SDP) are covered.
  • Same invariants as the shipped feature: output-only (writes only build/**/*.md), no HTML or repo-source changes, idempotent, scoped strictly to API reference operation pages — prose twins are untouched.

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 2: "Open Markdown" button on API operation pages

New client module src/clientModules/apiReferenceMarkdownButton.js:

  • On /api-reference/ routes it injects the plugin's own MarkdownActionsDropdown component (same markup, same behavior, same .markdown-actions-container styling) right after h1.openapi__heading — the element operation pages do have.
  • Guarded against double-injection: it only acts on operation pages (identified by that heading) and only when no .markdown-actions-container exists yet, so regular pages — including prose pages that live under /api-reference/ routes, where the plugin already injects — are left alone. A MutationObserver handles late hydration and client-side navigation, mirroring the plugin's own approach.

Verification

  • Full build passes; postbuild logs both scripts.
  • Spot-checked generated markdown for Horizon, Anchor Platform, and SDP operations.
  • build/**/*.html byte-identical before/after the postbuild scripts (hash check over all HTML files).
  • Scripts idempotent: re-running writes 0 files.
  • Prose twins byte-identical to production (spot-checked against developers.stellar.org).
  • Button verified via headless Chrome against a served build: exactly one .markdown-actions-container on 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 custom RpcMethod component) and are not covered here — their twins already carry the prose/SDK-guide content. Can be a follow-up if wanted.

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.
Copilot AI review requested due to automatic review settings July 20, 2026 14:10
lines.push('', `### ${location[0].toUpperCase()}${location.slice(1)} parameters`, '');
lines.push('| Name | Type | Required | Description |', '| --- | --- | --- | --- |');
for (const param of params) {
let desc = inlineText(param.description).replace(/\|/g, '\\|');

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +114 to +121
function detailLines(schema, pad, lines) {
if (schema.enum) {
lines.push(`${pad}Possible values: ${schema.enum.map((v) => `\`${v}\``).join(', ')}.`);
}
if (schema.default !== undefined) {
lines.push(`${pad}Default: \`${JSON.stringify(schema.default)}\`.`);
}
}
const parts = [`\`${name}\``, '—', typeLabel(schema)];
if (required) parts.push('(required)');
if (schema?.deprecated) parts.push('(deprecated)');
const desc = inlineText(schema?.description);
Comment on lines +248 to +252
for (const [status, response] of Object.entries(responses)) {
lines.push('', `### ${status}`, '');
const desc = inlineText(response.description);
if (desc) lines.push(desc, '');
for (const [contentType, media] of Object.entries(response.content ?? {})) {
@stellar-jenkins-ci

Copy link
Copy Markdown

@kaankacar kaankacar self-assigned this Jul 20, 2026
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.

API reference pages: empty .md twins + missing "Open Markdown" button

3 participants