From 9868babf7576adc00d168bb241563205b00cbf03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Fri, 25 Aug 2023 19:05:16 +0200 Subject: [PATCH] fix(mdx-loader): improve mdxJsxTextElementToHtml (#9262) --- .../__fixtures__/non-text-content.md | 2 + .../__snapshots__/index.test.ts.snap | 7 ++++ .../src/remark/utils/index.ts | 41 ++++++++++++++++--- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__fixtures__/non-text-content.md b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__fixtures__/non-text-content.md index 2ea62a2bbaf6..94814d8d9be8 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__fixtures__/non-text-content.md +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__fixtures__/non-text-content.md @@ -7,3 +7,5 @@ ## HTML ## `inline.code()` + +## some styled heading test diff --git a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap index 8af155e2c96d..5cad7ef21337 100644 --- a/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.ts.snap @@ -171,6 +171,11 @@ exports[`toc remark plugin works on non text phrasing content 1`] = ` value: 'inline.code()', id: 'inlinecode', level: 2 + }, + { + value: 'some styled heading test', + id: 'some-styled-heading--test', + level: 2 } ] @@ -183,6 +188,8 @@ exports[`toc remark plugin works on non text phrasing content 1`] = ` ## HTML ## \`inline.code()\` + +## some styled heading test " `; diff --git a/packages/docusaurus-mdx-loader/src/remark/utils/index.ts b/packages/docusaurus-mdx-loader/src/remark/utils/index.ts index da3c40209997..46e959176239 100644 --- a/packages/docusaurus-mdx-loader/src/remark/utils/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/utils/index.ts @@ -8,26 +8,57 @@ import escapeHtml from 'escape-html'; import type {Parent} from 'unist'; import type {PhrasingContent, Heading} from 'mdast'; -// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 -import type {MdxJsxAttributeValueExpression} from 'mdast-util-mdx'; +import type { + MdxJsxAttribute, + MdxJsxAttributeValueExpression, + MdxJsxTextElement, + // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 +} from 'mdast-util-mdx'; export function stringifyContent( node: Parent, - toString: (param: unknown) => string, // TODO weird but works): string { + toString: (param: unknown) => string, // TODO weird but works ): string { return (node.children as PhrasingContent[]) .map((item) => toValue(item, toString)) .join(''); } +// TODO This is really a workaround, and not super reliable +// For now we only support serializing tagName, className and content +// Can we implement the TOC with real JSX nodes instead of html strings later? +function mdxJsxTextElementToHtml( + element: MdxJsxTextElement, + toString: (param: unknown) => string, // TODO weird but works +): string { + const tag = element.name; + + const attributes = element.attributes.filter( + (child): child is MdxJsxAttribute => child.type === 'mdxJsxAttribute', + ); + + const classAttribute = + attributes.find((attr) => attr.name === 'className') ?? + attributes.find((attr) => attr.name === 'class'); + + const classAttributeString = classAttribute + ? `class="${escapeHtml(String(classAttribute.value))}"` + : ``; + + const allAttributes = classAttributeString ? ` ${classAttributeString}` : ''; + + const content = stringifyContent(element, toString); + + return `<${tag}${allAttributes}>${content}`; +} + export function toValue( node: PhrasingContent | Heading, toString: (param: unknown) => string, // TODO weird but works ): string { switch (node.type) { case 'mdxJsxTextElement': { - const tag = node.name; - return `<${tag}>${stringifyContent(node, toString)}`; + return mdxJsxTextElementToHtml(node as MdxJsxTextElement, toString); } case 'text': return escapeHtml(node.value);