From dbca701008ecd60fd9355511db622ce737cf935a Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Thu, 23 Jul 2026 11:01:29 -0700 Subject: [PATCH] Revert "fix(import): fall back to body H1 for title when frontmatter lacks title: instead of slug-derived junk (#2446) (#2495)" This reverts commit 033fd24fe8b159b390b4e84e0c51417ea25875a1. --- src/core/markdown.ts | 36 +---------------------------------- test/markdown.test.ts | 44 ------------------------------------------- 2 files changed, 1 insertion(+), 79 deletions(-) diff --git a/src/core/markdown.ts b/src/core/markdown.ts index b48549993..d46775310 100644 --- a/src/core/markdown.ts +++ b/src/core/markdown.ts @@ -135,16 +135,7 @@ export function parseMarkdown( const type = coerceFrontmatterString(frontmatter.type) || ( opts?.activePack ? inferTypeFromPack(filePath, opts.activePack) : inferType(filePath) ); - // #2446: title precedence is frontmatter `title:` > the body's first H1 > - // the slug/filename-humanized fallback. Slug-based imports (contacts, - // calendar) write a correct `# Heading` but no frontmatter title; without - // the H1 fallback they get junk titles humanized from the slug - // (`Contact 20170928 5 John Defalco`), which also breaks anything keyed on - // the title (e.g. the by-mention gazetteer's first-token bucketing). - const title = - coerceFrontmatterString(frontmatter.title).trim() || - inferTitleFromBody(body) || - inferTitle(filePath); + const title = coerceFrontmatterString(frontmatter.title).trim() || inferTitle(filePath); const tags = extractTags(frontmatter); const slug = coerceFrontmatterString(frontmatter.slug) || inferSlug(filePath); @@ -611,31 +602,6 @@ function inferTypeWithPrefixes( return 'concept'; } -/** - * #2446: derive a title from the body's first ATX H1 (`# Heading`). - * - * Returns the trimmed heading text with the leading `# ` and any decorative - * trailing `#` run stripped, or '' if the body has no H1. Only a SINGLE leading - * `#` matches — `##`+ (h2 and deeper) are skipped — and lines inside a fenced - * code block (```/~~~) are ignored so a `# comment` in a shell snippet can't be - * mistaken for the page title. - */ -function inferTitleFromBody(body: string): string { - let inFence = false; - for (const raw of body.split('\n')) { - const fence = /^\s*(`{3,}|~{3,})/.exec(raw); - if (fence) { - inFence = !inFence; - continue; - } - if (inFence) continue; - // Exactly one leading `#`, then whitespace, then the heading text. - const m = /^#(?!#)\s+(.+?)\s*$/.exec(raw); - if (m) return m[1].replace(/\s+#+\s*$/, '').trim(); - } - return ''; -} - function inferTitle(filePath?: string): string { if (!filePath) return 'Untitled'; diff --git a/test/markdown.test.ts b/test/markdown.test.ts index 138c5d206..2e485f521 100644 --- a/test/markdown.test.ts +++ b/test/markdown.test.ts @@ -343,47 +343,3 @@ describe('issue #1939 — non-string frontmatter coercion', () => { expect(parsed.title).toBe('A Normal Title'); }); }); - -// issue #2446 — when frontmatter has no `title:`, prefer the body's first H1 -// over the slug/filename-humanized fallback. Slug-based imports (contacts, -// calendar) carry a correct `# Heading` but no frontmatter title; humanizing -// the slug leaks date/id tokens and loses casing (`Defalco` vs `DeFalco`). -describe('issue #2446 — body H1 fallback for missing frontmatter title', () => { - test('no frontmatter title uses the body H1, not the slug-humanized junk', () => { - const md = '---\ntype: person\n---\n\n# John DeFalco\n\nNotes about John.\n'; - const parsed = parseMarkdown(md, 'people/contact-20170928-5-john-defalco.md'); - expect(parsed.title).toBe('John DeFalco'); - // The slug-derived junk title must NOT win. - expect(parsed.title).not.toBe('Contact 20170928 5 John Defalco'); - }); - - test('no frontmatter title and no H1 falls back to the inferred slug title', () => { - const md = '---\ntype: note\n---\n\njust body prose, no heading\n'; - const parsed = parseMarkdown(md, 'people/alice-example.md'); - expect(parsed.title).toBe('Alice Example'); - }); - - test('frontmatter title wins over a body H1 (no regression)', () => { - const md = '---\ntitle: Frontmatter Wins\n---\n\n# Body Heading\n\nbody\n'; - const parsed = parseMarkdown(md, 'people/some-slug.md'); - expect(parsed.title).toBe('Frontmatter Wins'); - }); - - test('h2 is not treated as the title; first real H1 is used', () => { - const md = '---\ntype: note\n---\n\n## Subsection First\n\n# The Real Title\n\nbody\n'; - const parsed = parseMarkdown(md, 'notes/x.md'); - expect(parsed.title).toBe('The Real Title'); - }); - - test('a # inside a fenced code block is not mistaken for the title', () => { - const md = '---\ntype: note\n---\n\n```sh\n# this is a shell comment, not a heading\n```\n\n# Actual Heading\n'; - const parsed = parseMarkdown(md, 'notes/x.md'); - expect(parsed.title).toBe('Actual Heading'); - }); - - test('trailing closing hashes are stripped from the H1', () => { - const md = '---\ntype: note\n---\n\n# Closed ATX Heading #\n\nbody\n'; - const parsed = parseMarkdown(md, 'notes/x.md'); - expect(parsed.title).toBe('Closed ATX Heading'); - }); -});