From 25dd0e61c32ea4b5f3d78d5ac2478270bf030d39 Mon Sep 17 00:00:00 2001 From: Parv Ahuja <17094219+parvahuja@users.noreply.github.com> Date: Fri, 24 Jul 2026 17:56:01 -0700 Subject: [PATCH] fix: expose the changelog fallback in Markdown --- scripts/check-markdown-components.mjs | 18 ++++++++++++++++ src/lib/markdown-output.test.ts | 31 +++++++++++++++++++++++++++ src/lib/markdown-output.ts | 9 ++++++++ 3 files changed, 58 insertions(+) diff --git a/scripts/check-markdown-components.mjs b/scripts/check-markdown-components.mjs index 9e10e7c6..c0316468 100644 --- a/scripts/check-markdown-components.mjs +++ b/scripts/check-markdown-components.mjs @@ -42,13 +42,21 @@ if (files.length === 0) const llmsFile = resolve('dist/public/llms-full.txt') const generatedFiles = [...files, llmsFile] +const hiddenChangelogFallbacks = [] const unresolvedIncludes = [] for (const file of generatedFiles) { const content = await readFile(file, 'utf8') + if (hasHiddenChangelogFallback(content)) hiddenChangelogFallbacks.push(file) const count = content.match(/\[!include /g)?.length ?? 0 if (count > 0) unresolvedIncludes.push({ count, file }) } +if (hiddenChangelogFallbacks.length > 0) { + console.error('Generated Markdown changelog fallback audit failed.') + for (const file of hiddenChangelogFallbacks) console.error(`- ${file}: hidden changelog fallback`) + process.exit(1) +} + if (unresolvedIncludes.length > 0) { console.error('Generated Markdown include audit failed.') for (const { count, file } of unresolvedIncludes) @@ -76,6 +84,16 @@ if (generatedComponents.size > 0) { console.log('Markdown output audit passed (no unresolved component types or includes).') +function hasHiddenChangelogFallback(content) { + let found = false + const tree = unified().use(remarkParse).parse(content) + visit(tree, (node) => { + if (node.type === 'html' && node.value?.trim() === '') + found = true + }) + return found +} + function maskHtmlComments(content) { const ranges = [] const tree = unified().use(remarkParse).parse(content) diff --git a/src/lib/markdown-output.test.ts b/src/lib/markdown-output.test.ts index a64daa27..d393f396 100644 --- a/src/lib/markdown-output.test.ts +++ b/src/lib/markdown-output.test.ts @@ -95,6 +95,27 @@ Status: Required expect(output).not.toMatch(/<\/?[A-Z]/) }) + test('turns an unavailable changelog into a visible release link', async () => { + const output = await renderMarkdown(` +# Changelog + + +`) + + expect(output).toContain('Release notes could not be loaded.') + expect(output).toContain( + '[View Tempo releases on GitHub.](https://github.com/tempoxyz/tempo/releases)', + ) + expect(output).not.toContain('') + + const example = await renderMarkdown(` +\`\`\`md + +\`\`\` +`) + expect(example).toContain('') + }) + test('expands code includes and removes region markers', async () => { const output = await render(` \`\`\`ts @@ -191,3 +212,13 @@ async function render(source: string) { .process(source), ) } + +async function renderMarkdown(source: string) { + return String( + await unified() + .use(remarkParse) + .use(plainMarkdownComponents) + .use(remarkStringify) + .process(source), + ) +} diff --git a/src/lib/markdown-output.ts b/src/lib/markdown-output.ts index 08c571dc..0d6ca940 100644 --- a/src/lib/markdown-output.ts +++ b/src/lib/markdown-output.ts @@ -41,6 +41,7 @@ type MarkdownNode = { } const openApiSpecUrl = 'https://api.tempo.xyz/openapi.json' +const tempoReleasesUrl = 'https://github.com/tempoxyz/tempo/releases' const interactiveDescriptions: Record = { ConnectWallet: 'Connect a wallet in the interactive web page.', @@ -131,6 +132,14 @@ function rewriteNode( headingDepth: number, getSnippet: (fileName: string) => string | undefined, ): MarkdownNode[] { + if (node.type === 'html' && node.value?.trim() === '') + return [ + paragraph([ + text('Release notes could not be loaded. '), + link('View Tempo releases on GitHub.', tempoReleasesUrl), + ]), + ] + if (node.type !== 'mdxJsxFlowElement' && node.type !== 'mdxJsxTextElement') { if (node.type === 'code' && node.value) node.value = inlineCodeSnippets(node.value, getSnippet) rewriteChildren(node, headingDepth, getSnippet)