diff --git a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts index a81e8cfff103..ba03831c7575 100644 --- a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts +++ b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts @@ -47,6 +47,38 @@ describe('createExcerpt', () => { ); }); + it('skips H1 heading whose text contains a hash character (e.g. "C#", "F#")', () => { + expect( + createExcerpt(dedent` + + # C# Programming Guide + + This paragraph should become the description. + `), + ).toBe('This paragraph should become the description.'); + }); + + it('skips H1 heading with trailing closing hashes and interior hash', () => { + expect( + createExcerpt(dedent` + + # F# Programming Guide # + + This paragraph should become the description. + `), + ).toBe('This paragraph should become the description.'); + }); + + it('keeps hash characters inside non-heading text', () => { + expect( + createExcerpt(dedent` + The language C# is used with .NET, and F# is a functional alternative. + + Nunc porttitor libero nec vulputate venenatis. + `), + ).toBe('The language C# is used with .NET, and F# is a functional alternative.'); + }); + it('creates excerpt for regular content with alternate title', () => { expect( createExcerpt(dedent` diff --git a/packages/docusaurus-utils/src/markdownUtils.ts b/packages/docusaurus-utils/src/markdownUtils.ts index 216d0122e7ad..700ee9c7fb1c 100644 --- a/packages/docusaurus-utils/src/markdownUtils.ts +++ b/packages/docusaurus-utils/src/markdownUtils.ts @@ -145,10 +145,15 @@ export function createExcerpt(fileString: string): string | undefined { const cleanedLine = fileLine // Remove HTML tags. .replace(/<[^>]*>/g, '') - // Remove Title headers - .replace(/^#[^#]+#?/gm, '') + // Remove Title headers (single-# ATX headings are skipped entirely) + // Note: the heading text may legitimately contain "#" (e.g. "C#", "F#"), + // so we must match the whole line instead of using a negated class + .replace(/^#.*$/gm, '') // Remove Markdown + ATX-style headers - .replace(/^#{1,6}\s*(?[^#]*?)\s*#{0,6}/gm, '$1') + // Note: we must not forbid "#" inside the heading text (e.g. "C#", "F#") + // Only the leading marker and an optional trailing closing sequence are + // stripped, anchored to the end of the line to avoid eating interior "#" + .replace(/^#{1,6}\s*(?.*?)\s*#*$/gm, '$1') // Remove emphasis. .replace(/(?[*_]{1,3})(?.*?)\1/g, '$2') // Remove strikethroughs.