Repository navigation
fix(mdx-loader): support <head> metadata in CommonMark files (AI-assisted)
#12736
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,18 +6,53 @@ | |
| */ | ||
|
|
||
| import {visit} from 'unist-util-visit'; | ||
| import {transformNode} from '../utils'; | ||
| import type {Transformer} from 'unified'; | ||
|
|
||
| import type {Root} from 'mdast'; | ||
| import type {MdxJsxFlowElement} from 'mdast-util-mdx'; | ||
|
|
||
| // Transform <head> to <Head> | ||
| // MDX 2 doesn't allow to substitute html elements with the provider anymore | ||
| export default function plugin(): Transformer<Root> { | ||
| return (root) => { | ||
| visit(root, 'mdxJsxFlowElement', (node) => { | ||
| if (node.name === 'head') { | ||
| node.name = 'Head'; | ||
| } | ||
| }); | ||
| transformJsxHead(root); | ||
| transformHtmlHead(root); | ||
| }; | ||
| } | ||
|
|
||
| // With the MDX format, <head> is a JSX element | ||
| function transformJsxHead(root: Root) { | ||
| visit(root, 'mdxJsxFlowElement', (node) => { | ||
| if (node.name === 'head') { | ||
| node.name = 'Head'; | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| // With the CommonMark format, <head> is a raw HTML block | ||
| // rehype-raw parses raw HTML in body context, where the <head> tag is dropped | ||
| // We wrap its content in a <Head> JSX element, that rehype-raw passes through | ||
| // The content remains raw HTML that rehype-raw parses inside <Head> | ||
| function transformHtmlHead(root: Root) { | ||
| visit(root, 'html', (node) => { | ||
| const headContent = getHeadContent(node.value); | ||
| if (headContent === undefined) { | ||
| return; | ||
| } | ||
| const headElement: MdxJsxFlowElement = { | ||
| type: 'mdxJsxFlowElement', | ||
| name: 'Head', | ||
| attributes: [], | ||
| children: [{type: 'html', value: headContent}], | ||
| position: node.position, | ||
| }; | ||
| transformNode(node, headElement); | ||
| }); | ||
| } | ||
|
|
||
| const HeadHtmlRegExp = /^<head>(?<content>.*)<\/head>$/s; | ||
|
|
||
| function getHeadContent(html: string): string | undefined { | ||
| return HeadHtmlRegExp.exec(html.trim())?.groups?.content; | ||
|
Comment on lines
+54
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: meta/docusaurus
Length of output: 4226
Script executed:
Repository: meta/docusaurus
Length of output: 30388
Web query:
CommonMark specification HTML block head tag blank line type 6 end condition official specResult:
Script executed:
Repository: meta/docusaurus
Length of output: 16517
Web query:
CommonMark spec HTML block type 6 head tag list ends blank line 0.31.2Result:
Web query:
WHATWG HTML fragment parsing in body head start tag ignored script token in body parsing rulesResult:
Script executed:
Repository: meta/docusaurus
Length of output: 5487
Web query:
React DOM script component inline script no async rendered placed where rendered document head React 19 official documentationResult:
Web query:
rehype raw 7 hast util raw parse5 raw nodes parse fragment unified official readmeResult:
Preserve
<head>blocks across blank lines.When a CommonMark
<head>contains a blank line, CommonMark ends the HTML block before</head>.transformHtmlHeadthen matches neither fragment, so metadata remains in body content. Accumulate the complete head block before applying theHeadconversion.