From 16e6944b72ef94032ac91bdf4a9c3470e9f9ef94 Mon Sep 17 00:00:00 2001 From: ozakione <29860391+OzakIOne@users.noreply.github.com> Date: Tue, 23 Jul 2024 17:16:31 +0200 Subject: [PATCH 1/5] feat: wrap mdx title h1 in header --- .../contentTitle/__tests__/index.test.ts | 21 +++++++++++++------ .../src/remark/contentTitle/index.ts | 21 ++++++++++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/remark/contentTitle/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/contentTitle/__tests__/index.test.ts index 54d111754833..913b788ffc91 100644 --- a/packages/docusaurus-mdx-loader/src/remark/contentTitle/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/contentTitle/__tests__/index.test.ts @@ -19,7 +19,8 @@ async function process( describe('contentTitle remark plugin', () => { describe('extracts data.contentTitle', () => { it('extracts h1 heading', async () => { - const result = await process(` + const result = await process( + ` # contentTitle 1 ## Heading Two {#custom-heading-two} @@ -27,13 +28,16 @@ describe('contentTitle remark plugin', () => { # contentTitle 2 some **markdown** *content* - `); + `, + {removeContentTitle: true}, + ); expect(result.data.contentTitle).toBe('contentTitle 1'); }); it('extracts h1 heading alt syntax', async () => { - const result = await process(` + const result = await process( + ` contentTitle alt === @@ -44,7 +48,9 @@ contentTitle alt # contentTitle 2 some **markdown** *content* - `); + `, + {removeContentTitle: true}, + ); expect(result.data.contentTitle).toBe('contentTitle alt'); }); @@ -87,11 +93,14 @@ some **markdown** *content* }); it('is able to decently serialize Markdown syntax', async () => { - const result = await process(` + const result = await process( + ` # some **markdown** \`content\` _italic_ some **markdown** *content* - `); + `, + {removeContentTitle: true}, + ); expect(result.data.contentTitle).toBe('some markdown content italic'); }); diff --git a/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts b/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts index 65ad91f82528..ce085ac4911e 100644 --- a/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts @@ -7,7 +7,7 @@ // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; -import type {Heading} from 'mdast'; +import type {Heading, Parent, RootContent} from 'mdast'; // TODO as of April 2023, no way to import/re-export this ESM type easily :/ // TODO upgrade to TS 5.3 @@ -19,6 +19,21 @@ interface PluginOptions { removeContentTitle?: boolean; } +function wrapHeadingInJsxHeader( + headingNode: Heading, + parent: Parent, + index: number | undefined, +) { + const article: RootContent = { + type: 'mdxJsxFlowElement', + name: 'header', + attributes: [], + children: [headingNode], + }; + // @ts-expect-error: TODO how to fix? + parent.children[index] = article; +} + /** * A remark plugin to extract the h1 heading found in Markdown files * This is exposed as "data.contentTitle" to the processed vfile @@ -37,11 +52,15 @@ const plugin: Plugin = function plugin( visit(root, ['heading', 'thematicBreak'], (node, index, parent) => { if (node.type === 'heading') { const headingNode = node as Heading; + // console.log('headingNode:', headingNode); + if (headingNode.depth === 1) { vfile.data.contentTitle = toString(headingNode); if (removeContentTitle) { // @ts-expect-error: TODO how to fix? parent!.children.splice(index, 1); + } else { + wrapHeadingInJsxHeader(headingNode, parent, index); } return EXIT; // We only handle the very first heading } From 0dabd11ef5e2ce31d8d323a36f12985e2c33c5d7 Mon Sep 17 00:00:00 2001 From: sebastien Date: Thu, 25 Jul 2024 14:05:35 +0200 Subject: [PATCH 2/5] Fix tests --- .../contentTitle/__tests__/index.test.ts | 48 ++++++++++++------- .../src/remark/contentTitle/index.ts | 15 +++--- .../src/remark/head/index.ts | 2 +- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/remark/contentTitle/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/contentTitle/__tests__/index.test.ts index 913b788ffc91..995bd394088e 100644 --- a/packages/docusaurus-mdx-loader/src/remark/contentTitle/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/contentTitle/__tests__/index.test.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {escapeMarkdownHeadingIds} from '@docusaurus/utils'; import plugin from '../index'; async function process( @@ -12,15 +13,20 @@ async function process( options: {removeContentTitle?: boolean} = {}, ) { const {remark} = await import('remark'); - const processor = await remark().use({plugins: [[plugin, options]]}); - return processor.process(content); + const {default: mdx} = await import('remark-mdx'); + + const result = await remark() + .use(mdx) + .use(plugin, options) + .process(escapeMarkdownHeadingIds(content)); + + return result; } describe('contentTitle remark plugin', () => { describe('extracts data.contentTitle', () => { it('extracts h1 heading', async () => { - const result = await process( - ` + const result = await process(` # contentTitle 1 ## Heading Two {#custom-heading-two} @@ -28,9 +34,7 @@ describe('contentTitle remark plugin', () => { # contentTitle 2 some **markdown** *content* - `, - {removeContentTitle: true}, - ); + `); expect(result.data.contentTitle).toBe('contentTitle 1'); }); @@ -49,7 +53,6 @@ contentTitle alt some **markdown** *content* `, - {removeContentTitle: true}, ); expect(result.data.contentTitle).toBe('contentTitle alt'); @@ -93,21 +96,20 @@ some **markdown** *content* }); it('is able to decently serialize Markdown syntax', async () => { - const result = await process( - ` + const result = await process(` # some **markdown** \`content\` _italic_ some **markdown** *content* - `, - {removeContentTitle: true}, - ); + `); expect(result.data.contentTitle).toBe('some markdown content italic'); }); }); describe('returns appropriate content', () => { - it('returns content unmodified', async () => { + it('returns heading wrapped in
', async () => { + // Test case for https://github.com/facebook/docusaurus/issues/8476 + const content = ` # contentTitle 1 @@ -120,7 +122,19 @@ some **markdown** *content* const result = await process(content); - expect(result.toString().trim()).toEqual(content); + expect(result.toString().trim()).toEqual( + ` +
+ # contentTitle 1 +
+ +## Heading Two \\{#custom-heading-two} + +# contentTitle 2 + +some **markdown** *content* +`.trim(), + ); }); it('can strip contentTitle', async () => { @@ -138,7 +152,7 @@ some **markdown** *content* expect(result.toString().trim()).toEqual( ` -## Heading Two {#custom-heading-two} +## Heading Two \\{#custom-heading-two} # contentTitle 2 @@ -163,7 +177,7 @@ some **markdown** *content* expect(result.toString().trim()).toEqual( ` -## Heading Two {#custom-heading-two} +## Heading Two \\{#custom-heading-two} # contentTitle 2 diff --git a/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts b/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts index ce085ac4911e..7ba9296191c3 100644 --- a/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts @@ -7,7 +7,10 @@ // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; -import type {Heading, Parent, RootContent} from 'mdast'; +import type {Heading, Parent} from 'mdast'; + +// @ts-expect-error: ES support... +import type {MdxJsxFlowElement} from 'mdast-util-mdx'; // TODO as of April 2023, no way to import/re-export this ESM type easily :/ // TODO upgrade to TS 5.3 @@ -22,16 +25,15 @@ interface PluginOptions { function wrapHeadingInJsxHeader( headingNode: Heading, parent: Parent, - index: number | undefined, + index: number, ) { - const article: RootContent = { + const header: MdxJsxFlowElement = { type: 'mdxJsxFlowElement', name: 'header', attributes: [], children: [headingNode], }; - // @ts-expect-error: TODO how to fix? - parent.children[index] = article; + parent.children[index] = header; } /** @@ -48,7 +50,6 @@ const plugin: Plugin = function plugin( return async (root, vfile) => { const {toString} = await import('mdast-util-to-string'); const {visit, EXIT} = await import('unist-util-visit'); - visit(root, ['heading', 'thematicBreak'], (node, index, parent) => { if (node.type === 'heading') { const headingNode = node as Heading; @@ -60,7 +61,7 @@ const plugin: Plugin = function plugin( // @ts-expect-error: TODO how to fix? parent!.children.splice(index, 1); } else { - wrapHeadingInJsxHeader(headingNode, parent, index); + wrapHeadingInJsxHeader(headingNode, parent, index!); } return EXIT; // We only handle the very first heading } diff --git a/packages/docusaurus-mdx-loader/src/remark/head/index.ts b/packages/docusaurus-mdx-loader/src/remark/head/index.ts index 3063c93a8285..0bab7a76692d 100644 --- a/packages/docusaurus-mdx-loader/src/remark/head/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/head/index.ts @@ -8,7 +8,7 @@ // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {Transformer} from 'unified'; -// @ts-expect-error: ES support... +// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 import type {MdxJsxFlowElement} from 'mdast-util-mdx'; // Transform to From 76da744249946aa80edda32ccba326cee9e1584a Mon Sep 17 00:00:00 2001 From: sebastien Date: Thu, 25 Jul 2024 14:21:46 +0200 Subject: [PATCH 3/5] disable /showcase from argos --- argos/tests/screenshot.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/argos/tests/screenshot.spec.ts b/argos/tests/screenshot.spec.ts index b1f6824288f8..3fbb4b0d6308 100644 --- a/argos/tests/screenshot.spec.ts +++ b/argos/tests/screenshot.spec.ts @@ -41,6 +41,8 @@ function isBlacklisted(pathname: string) { '/feature-requests', // Flaky because of dynamic canary version fetched from npm '/community/canary', + // Flaky because of screenshots being taken dynamically + '/showcase', // Long blog post with many image carousels, often timeouts '/blog/2022/08/01/announcing-docusaurus-2.0', ]; From d891a87eb06872cee0f7d6c1f5593d8c1c8ffa14 Mon Sep 17 00:00:00 2001 From: sebastien Date: Thu, 25 Jul 2024 14:21:54 +0200 Subject: [PATCH 4/5] add useful comment --- .../docusaurus-mdx-loader/src/remark/contentTitle/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts b/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts index 7ba9296191c3..12aa5cdc7ba9 100644 --- a/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts @@ -61,6 +61,9 @@ const plugin: Plugin = function plugin( // @ts-expect-error: TODO how to fix? parent!.children.splice(index, 1); } else { + // TODO in the future it might be better to export contentTitle as + // as JSX node to keep this logic a theme concern? + // See https://github.com/facebook/docusaurus/pull/10335#issuecomment-2250187371 wrapHeadingInJsxHeader(headingNode, parent, index!); } return EXIT; // We only handle the very first heading From 8fae0180060171496f8eb02dca0c0a305ed658fc Mon Sep 17 00:00:00 2001 From: sebastien Date: Thu, 25 Jul 2024 14:53:37 +0200 Subject: [PATCH 5/5] empty