Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mdx-loader): wrap mdx content title (# Title) in <header> for concistency #10335

Merged
merged 5 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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