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)