Core: Support remarkMdxMermaid - convert mermaid codeblocks into <Mermaid /> component

This commit is contained in:
Fuma Nama
2025-08-31 18:03:14 +08:00
parent 68c92f981a
commit 0b530568ce
6 changed files with 90 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-core': patch
---
Support `remarkMdxMermaid` - convert `mermaid` codeblocks into `<Mermaid />` component
+2
View File
@@ -12,3 +12,5 @@ export * from './remark-code-tab';
export * from './remark-steps';
export * from './remark-npm';
export * from './codeblock-utils';
export * from './remark-mdx-files';
export * from './remark-mdx-mermaid';
@@ -0,0 +1,43 @@
import { visit } from 'unist-util-visit';
import type { Transformer } from 'unified';
import type { Root } from 'mdast';
import type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
function toMDX(code: string): MdxJsxFlowElement {
return {
type: 'mdxJsxFlowElement',
name: 'Mermaid',
attributes: [
{
type: 'mdxJsxAttribute',
name: 'chart',
value: code.trim(),
},
],
children: [],
};
}
export interface RemarkMdxMermaidOptions {
/**
* @defaultValue mermaid
*/
lang?: string;
}
/**
* Convert `mermaid` codeblocks into `<Mermaid />` MDX component
*/
export function remarkMdxMermaid(
options: RemarkMdxMermaidOptions = {},
): Transformer<Root, Root> {
const { lang = 'mermaid' } = options;
return (tree) => {
visit(tree, 'code', (node) => {
if (node.lang !== lang || !node.value) return;
Object.assign(node, toMDX(node.value));
});
};
}
+5
View File
@@ -0,0 +1,5 @@
```mermaid
graph TD;
A-->B;
A-->C;
```
@@ -0,0 +1,5 @@
<Mermaid
chart="graph TD;
A-->B;
A-->C;"
/>
+30
View File
@@ -7,6 +7,8 @@ import {
remarkAdmonition,
remarkHeading,
remarkImage,
remarkMdxFiles,
remarkMdxMermaid,
remarkStructure,
} from '@/mdx-plugins';
import { fileURLToPath } from 'node:url';
@@ -117,6 +119,34 @@ test('Remark Image: `publicDir` with URL', async () => {
);
});
test('Remark MDX Files', async () => {
const content = readFileSync(
path.resolve(cwd, './fixtures/remark-mdx-files.md'),
);
const result = await remark()
.use(remarkMdxFiles)
.use(remarkMdx)
.process(content);
await expect(result.value).toMatchFileSnapshot(
path.resolve(cwd, './fixtures/remark-mdx-files.output.mdx'),
);
});
test('converts mermaid codeblock to MDX Mermaid component', async () => {
const content = readFileSync(
path.resolve(cwd, './fixtures/remark-mdx-mermaid.md'),
);
const result = await remark()
.use(remarkMdxMermaid)
.use(remarkMdx)
.process(content);
await expect(result.value).toMatchFileSnapshot(
path.resolve(cwd, './fixtures/remark-mdx-mermaid.output.mdx'),
);
});
test('Rehype Toc', async () => {
const content = readFileSync(path.resolve(cwd, './fixtures/rehype-toc.md'));