Skip to content

Commit

Permalink
feat(mdx-loader): wrap mdx content title (# Title) in <header> fo…
Browse files Browse the repository at this point in the history
…r concistency (#10335)

Co-authored-by: sebastien <lorber.sebastien@gmail.com>
  • Loading branch information
OzakIOne and slorber committed Jul 25, 2024
1 parent fb4e32f commit 23dbf9c
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 11 deletions.
2 changes: 2 additions & 0 deletions argos/tests/screenshot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,22 @@
* LICENSE file in the root directory of this source tree.
*/

import {escapeMarkdownHeadingIds} from '@docusaurus/utils';
import plugin from '../index';

async function process(
content: string,
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', () => {
Expand All @@ -33,7 +40,8 @@ some **markdown** *content*
});

it('extracts h1 heading alt syntax', async () => {
const result = await process(`
const result = await process(
`
contentTitle alt
===
Expand All @@ -44,7 +52,8 @@ contentTitle alt
# contentTitle 2
some **markdown** *content*
`);
`,
);

expect(result.data.contentTitle).toBe('contentTitle alt');
});
Expand Down Expand Up @@ -98,7 +107,9 @@ some **markdown** *content*
});

describe('returns appropriate content', () => {
it('returns content unmodified', async () => {
it('returns heading wrapped in <header>', async () => {
// Test case for https://github.com/facebook/docusaurus/issues/8476

const content = `
# contentTitle 1
Expand All @@ -111,7 +122,19 @@ some **markdown** *content*

const result = await process(content);

expect(result.toString().trim()).toEqual(content);
expect(result.toString().trim()).toEqual(
`
<header>
# contentTitle 1
</header>
## Heading Two \\{#custom-heading-two}
# contentTitle 2
some **markdown** *content*
`.trim(),
);
});

it('can strip contentTitle', async () => {
Expand All @@ -129,7 +152,7 @@ some **markdown** *content*

expect(result.toString().trim()).toEqual(
`
## Heading Two {#custom-heading-two}
## Heading Two \\{#custom-heading-two}
# contentTitle 2
Expand All @@ -154,7 +177,7 @@ some **markdown** *content*

expect(result.toString().trim()).toEqual(
`
## Heading Two {#custom-heading-two}
## Heading Two \\{#custom-heading-two}
# contentTitle 2
Expand Down
27 changes: 25 additions & 2 deletions packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

// @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} 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
Expand All @@ -19,6 +22,20 @@ interface PluginOptions {
removeContentTitle?: boolean;
}

function wrapHeadingInJsxHeader(
headingNode: Heading,
parent: Parent,
index: number,
) {
const header: MdxJsxFlowElement = {
type: 'mdxJsxFlowElement',
name: 'header',
attributes: [],
children: [headingNode],
};
parent.children[index] = header;
}

/**
* A remark plugin to extract the h1 heading found in Markdown files
* This is exposed as "data.contentTitle" to the processed vfile
Expand All @@ -33,15 +50,21 @@ 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;
// 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 {
// 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
}
Expand Down
2 changes: 1 addition & 1 deletion packages/docusaurus-mdx-loader/src/remark/head/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 <head> to <Head>
Expand Down

0 comments on commit 23dbf9c

Please sign in to comment.