MDX: Add useContent API to client loader for avoiding Lint errors

This commit is contained in:
Fuma Nama
2025-10-12 17:18:04 +08:00
parent 1f1c7877e7
commit 575cfb89bb
3 changed files with 76 additions and 1 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-mdx': patch
---
Include unravel plugin into `remark-include` parsing step, this ensures the parsed results are consistent with normal MDX.js processor output.
@@ -8,6 +8,7 @@ import type { MdxJsxFlowElement, MdxJsxTextElement } from 'mdast-util-mdx-jsx';
import { remarkHeading } from 'fumadocs-core/mdx-plugins';
import type { DataMap } from 'vfile';
import type { Directives } from 'mdast-util-directive';
import { remarkMarkAndUnravel } from '@/loaders/mdx/remark-unravel';
export interface Params {
lang?: string;
@@ -154,11 +155,12 @@ export function remarkInclude(this: Processor): Transformer<Root, Root> {
value: parsed.content,
data: { frontmatter: parsed.data as Record<string, unknown> },
}) as Root;
const baseProcessor = unified().use(remarkMarkAndUnravel);
if (heading) {
// parse headings before extraction
const extracted = extractSection(
await unified().use(remarkHeading).run(mdast),
await baseProcessor.use(remarkHeading).run(mdast),
heading,
);
if (!extracted)
@@ -167,6 +169,8 @@ export function remarkInclude(this: Processor): Transformer<Root, Root> {
);
mdast = extracted;
} else {
mdast = await baseProcessor.run(mdast);
}
await update(mdast, path.dirname(file), data);
@@ -0,0 +1,66 @@
// from internal remark plugins in https://github.com/mdx-js/mdx/blob/main/packages/mdx/lib/plugin/remark-mark-and-unravel.js
// we need to ensure consistency with MDX.js when parsing embed content in `remark-include`
import { visit } from 'unist-util-visit';
import type { Transformer } from 'unified';
import type { Root, RootContent } from 'mdast';
export function remarkMarkAndUnravel(): Transformer<Root, Root> {
return (tree) => {
visit(tree, function (node, index, parent) {
let offset = -1;
let all = true;
let oneOrMore = false;
if (parent && typeof index === 'number' && node.type === 'paragraph') {
const children = node.children;
while (++offset < children.length) {
const child = children[offset];
if (
child.type === 'mdxJsxTextElement' ||
child.type === 'mdxTextExpression'
) {
oneOrMore = true;
} else if (child.type === 'text' && child.value.trim().length === 0) {
// Empty.
} else {
all = false;
break;
}
}
if (all && oneOrMore) {
offset = -1;
const newChildren: RootContent[] = [];
while (++offset < children.length) {
const child = children[offset];
if (child.type === 'mdxJsxTextElement') {
// @ts-expect-error: mutate because it is faster; content model is fine.
child.type = 'mdxJsxFlowElement';
}
if (child.type === 'mdxTextExpression') {
// @ts-expect-error: mutate because it is faster; content model is fine.
child.type = 'mdxFlowExpression';
}
if (
child.type === 'text' &&
/^[\t\r\n ]+$/.test(String(child.value))
) {
// Empty.
} else {
newChildren.push(child);
}
}
parent.children.splice(index, 1, ...newChildren);
return index;
}
}
});
};
}