From 86e720b7e933d88cb44e47b7816c292b6e404a56 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Tue, 13 Oct 2026 11:21:53 -0600 Subject: [PATCH 1/2] fix: preserve blog headings and fenced code comments --- src/routes/blog.$.tsx | 7 ++----- src/utils/blogMarkdown.ts | 20 ++++++++++++++++++ tests/blog-markdown.test.ts | 41 +++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 src/utils/blogMarkdown.ts create mode 100644 tests/blog-markdown.test.ts diff --git a/src/routes/blog.$.tsx b/src/routes/blog.$.tsx index 87608c97f..35aa0b64c 100644 --- a/src/routes/blog.$.tsx +++ b/src/routes/blog.$.tsx @@ -16,7 +16,7 @@ import { Breadcrumbs } from '~/components/Breadcrumbs' import { findMaintainerByAuthorName } from '~/utils/authors' import { CoverFallback } from '~/components/CoverFallback' import { fetchBlogPost } from '~/utils/blog.functions' -import { parseSiteMarkdown } from '~/utils/markdown' +import { parseBlogMarkdown } from '~/utils/blogMarkdown' import { getBlogPostHead, getBlogSocialImageUrl } from '~/utils/blog-post-seo' export const Route = createFileRoute('/blog/$')({ @@ -58,10 +58,7 @@ function BlogPost() { const videoRef = React.useRef(null) const [startedVideo, setStartedVideo] = React.useState() const hasStartedVideo = startedVideo === headerVideo - const markdown = React.useMemo( - () => parseSiteMarkdown(content.replace(/^# [^\n]+\n*/m, '')), - [content], - ) + const markdown = React.useMemo(() => parseBlogMarkdown(content), [content]) const headings = markdown.headings const isTocVisible = headings.length > 1 diff --git a/src/utils/blogMarkdown.ts b/src/utils/blogMarkdown.ts new file mode 100644 index 000000000..ca476becc --- /dev/null +++ b/src/utils/blogMarkdown.ts @@ -0,0 +1,20 @@ +import { parseSiteMarkdown } from './markdown' + +export function parseBlogMarkdown(content: string) { + const markdown = parseSiteMarkdown(content) + const titleIndex = markdown.children.findIndex( + (block) => + block.type !== 'html' || + !/^\s*(?:\s*)+$/.test(block.value), + ) + const title = markdown.children[titleIndex] + + if (title?.type === 'heading' && title.depth === 1) { + markdown.children.splice(titleIndex, 1) + markdown.headings = markdown.headings.filter( + (heading) => heading.id !== title.id, + ) + } + + return markdown +} diff --git a/tests/blog-markdown.test.ts b/tests/blog-markdown.test.ts new file mode 100644 index 000000000..5cfe33b3f --- /dev/null +++ b/tests/blog-markdown.test.ts @@ -0,0 +1,41 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { parseBlogMarkdown } from '../src/utils/blogMarkdown' +import { parseSiteMarkdown } from '../src/utils/markdown' + +test('blog title removal preserves code comments and later headings', () => { + for (const content of [ + '```bash\n# Install dependencies\npnpm install\n```', + 'Introduction\n\n# How to install\n\nInstructions', + ]) { + assert.deepEqual(parseBlogMarkdown(content), parseSiteMarkdown(content)) + } +}) + +test('removes a leading title and its TOC entry, including after a comment', () => { + for (const prefix of ['', '\n\n']) { + const markdown = parseBlogMarkdown( + prefix + '# Article\n\n## Details\n\nText', + ) + assert.deepEqual( + markdown.headings.map((heading) => heading.level), + [2], + ) + assert.equal( + markdown.children.some( + (block) => block.type === 'heading' && block.depth === 1, + ), + false, + ) + } +}) + +test('preserves a later heading with the same text and its existing anchor', () => { + const markdown = parseBlogMarkdown('# Title\n\n# Title\n\nText') + assert.deepEqual(markdown.headings.map((heading) => heading.id), ['title-2']) +}) + +test('does not skip visible HTML when looking for the article title', () => { + const content = '
Introduction
\n\n# Keep this heading' + assert.deepEqual(parseBlogMarkdown(content), parseSiteMarkdown(content)) +}) From 11466ece6aec173e0cb5ced587902b07feb625b8 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2026 17:22:57 +0000 Subject: [PATCH 2/2] ci: apply automated fixes --- tests/blog-markdown.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/blog-markdown.test.ts b/tests/blog-markdown.test.ts index 5cfe33b3f..cce9f82bf 100644 --- a/tests/blog-markdown.test.ts +++ b/tests/blog-markdown.test.ts @@ -32,7 +32,10 @@ test('removes a leading title and its TOC entry, including after a comment', () test('preserves a later heading with the same text and its existing anchor', () => { const markdown = parseBlogMarkdown('# Title\n\n# Title\n\nText') - assert.deepEqual(markdown.headings.map((heading) => heading.id), ['title-2']) + assert.deepEqual( + markdown.headings.map((heading) => heading.id), + ['title-2'], + ) }) test('does not skip visible HTML when looking for the article title', () => {