diff --git a/packages/mdx/lib/plugin/recma-jsx-rewrite.js b/packages/mdx/lib/plugin/recma-jsx-rewrite.js index d50b550a7..1e82a1e41 100644 --- a/packages/mdx/lib/plugin/recma-jsx-rewrite.js +++ b/packages/mdx/lib/plugin/recma-jsx-rewrite.js @@ -72,6 +72,8 @@ export function recmaJsxRewrite(options = {}) { let createErrorHelper /** @type {Scope|null} */ let currentScope + /** @type {Map} */ + const idToInvalidComponentName = new Map() walk(tree, { enter(_node) { @@ -193,16 +195,24 @@ export function recmaJsxRewrite(options = {}) { fnScope.tags.push(id) } - node.openingElement.name = toJsxIdOrMemberExpression([ - '_components', - id - ]) + /** @type {Array} */ + let jsxIdExpression = ['_components', id] + if (isIdentifierName(id) === false) { + let invalidComponentName = idToInvalidComponentName.get(id) + if (invalidComponentName === undefined) { + invalidComponentName = `_component${idToInvalidComponentName.size}` + idToInvalidComponentName.set(id, invalidComponentName) + } + + jsxIdExpression = [invalidComponentName] + } + + node.openingElement.name = + toJsxIdOrMemberExpression(jsxIdExpression) if (node.closingElement) { - node.closingElement.name = toJsxIdOrMemberExpression([ - '_components', - id - ]) + node.closingElement.name = + toJsxIdOrMemberExpression(jsxIdExpression) } } } @@ -259,7 +269,11 @@ export function recmaJsxRewrite(options = {}) { /** @type {Array} */ const statements = [] - if (defaults.length > 0 || actual.length > 0) { + if ( + defaults.length > 0 || + actual.length > 0 || + idToInvalidComponentName.size > 0 + ) { if (providerImportSource) { importProvider = true parameters.push({ @@ -344,6 +358,27 @@ export function recmaJsxRewrite(options = {}) { componentsInit = {type: 'Identifier', name: '_components'} } + if (isNamedFunction(scope.node, '_createMdxContent')) { + for (const [id, componentName] of idToInvalidComponentName) { + // For JSX IDs that can’t be represented as JavaScript IDs (as in, + // those with dashes, such as `custom-element`), generate a + // separate variable that is a valid JS ID (such as `_component0`), + // and takes it from components: + // `const _component0 = _components['custom-element']` + declarations.push({ + type: 'VariableDeclarator', + id: {type: 'Identifier', name: componentName}, + init: { + type: 'MemberExpression', + object: {type: 'Identifier', name: '_components'}, + property: {type: 'Literal', value: id}, + computed: true, + optional: false + } + }) + } + } + if (componentsPattern) { declarations.push({ type: 'VariableDeclarator', diff --git a/packages/mdx/test/compile.js b/packages/mdx/test/compile.js index 8b6d457a3..d00059758 100644 --- a/packages/mdx/test/compile.js +++ b/packages/mdx/test/compile.js @@ -860,8 +860,8 @@ test('jsx', async () => { 'function _createMdxContent(props) {', ' const _components = Object.assign({', ' "a-b": "a-b"', - ' }, props.components);', - ' return <>{<_components.a-b>};', + ' }, props.components), _component0 = _components["a-b"];', + ' return <>{<_component0>};', '}', 'function MDXContent(props = {}) {', ' const {wrapper: MDXLayout} = props.components || ({});',