From 5ef0558690bf7bbc5c7f2c520af0cc9753df1269 Mon Sep 17 00:00:00 2001
From: 0phoff <0phoff@users.noreply.github.com>
Date: Mon, 13 Jun 2022 18:40:02 +0200
Subject: [PATCH 1/5] Create the _mdxMdxContent component outside of the
MDXContent component
---
packages/mdx/lib/plugin/recma-document.js | 94 +++++++++++---------
packages/mdx/lib/plugin/recma-jsx-rewrite.js | 32 +++----
2 files changed, 69 insertions(+), 57 deletions(-)
diff --git a/packages/mdx/lib/plugin/recma-document.js b/packages/mdx/lib/plugin/recma-document.js
index 5ffa5af7f..7fa75f808 100644
--- a/packages/mdx/lib/plugin/recma-document.js
+++ b/packages/mdx/lib/plugin/recma-document.js
@@ -231,7 +231,7 @@ export function recmaDocument(options = {}) {
child.expression.type === 'JSXElement')
) {
content = true
- replacement.push(createMdxContent(child.expression))
+ replacement.push(...createMdxContent(child.expression, Boolean(layout)))
// The following catch-all branch is because plugins might’ve added
// other things.
// Normally, we only have import/export/jsx, but just add whatever’s
@@ -244,7 +244,7 @@ export function recmaDocument(options = {}) {
// If there was no JSX content at all, add an empty function.
if (!content) {
- replacement.push(createMdxContent())
+ replacement.push(...createMdxContent(undefined, Boolean(layout)))
}
exportedIdentifiers.push(['MDXContent', 'default'])
@@ -481,9 +481,10 @@ export function recmaDocument(options = {}) {
/**
* @param {Expression} [content]
- * @returns {FunctionDeclaration}
+ * @param {boolean} [hasLayout]
+ * @returns {FunctionDeclaration[]}
*/
- function createMdxContent(content) {
+ function createMdxContent(content, hasLayout) {
/** @type {JSXElement} */
const element = {
type: 'JSXElement',
@@ -508,7 +509,12 @@ export function recmaDocument(options = {}) {
openingElement: {
type: 'JSXOpeningElement',
name: {type: 'JSXIdentifier', name: '_createMdxContent'},
- attributes: [],
+ attributes: [
+ {
+ type: 'JSXSpreadAttribute',
+ argument: {type: 'Identifier', name: 'props'}
+ }
+ ],
selfClosing: true
},
closingElement: null,
@@ -518,7 +524,21 @@ export function recmaDocument(options = {}) {
}
// @ts-expect-error: JSXElements are expressions.
- const consequent = /** @type {Expression} */ (element)
+ let consequent = /** @type {Expression} */ (element)
+
+ if (!hasLayout) {
+ consequent = {
+ type: 'ConditionalExpression',
+ test: {type: 'Identifier', name: 'MDXLayout'},
+ consequent,
+ alternate: {
+ type: 'CallExpression',
+ callee: {type: 'Identifier', name: '_createMdxContent'},
+ arguments: [{type: 'Identifier', name: 'props'}],
+ optional: false
+ }
+ }
+ }
let argument = content || {type: 'Literal', value: null}
@@ -535,44 +555,36 @@ export function recmaDocument(options = {}) {
argument = argument.children[0]
}
- return {
- type: 'FunctionDeclaration',
- id: {type: 'Identifier', name: 'MDXContent'},
- params: [
- {
- type: 'AssignmentPattern',
- left: {type: 'Identifier', name: 'props'},
- right: {type: 'ObjectExpression', properties: []}
+ return [
+ {
+ type: 'FunctionDeclaration',
+ id: {type: 'Identifier', name: '_createMdxContent'},
+ params: [{type: 'Identifier', name: 'props'}],
+ body: {
+ type: 'BlockStatement',
+ body: [{type: 'ReturnStatement', argument}]
}
- ],
- body: {
- type: 'BlockStatement',
- body: [
- {
- type: 'ReturnStatement',
- argument: {
- type: 'ConditionalExpression',
- test: {type: 'Identifier', name: 'MDXLayout'},
- consequent,
- alternate: {
- type: 'CallExpression',
- callee: {type: 'Identifier', name: '_createMdxContent'},
- arguments: [],
- optional: false
- }
- }
- },
+ },
+ {
+ type: 'FunctionDeclaration',
+ id: {type: 'Identifier', name: 'MDXContent'},
+ params: [
{
- type: 'FunctionDeclaration',
- id: {type: 'Identifier', name: '_createMdxContent'},
- params: [],
- body: {
- type: 'BlockStatement',
- body: [{type: 'ReturnStatement', argument}]
- }
+ type: 'AssignmentPattern',
+ left: {type: 'Identifier', name: 'props'},
+ right: {type: 'ObjectExpression', properties: []}
}
- ]
+ ],
+ body: {
+ type: 'BlockStatement',
+ body: [
+ {
+ type: 'ReturnStatement',
+ argument: consequent
+ }
+ ]
+ }
}
- }
+ ]
}
}
diff --git a/packages/mdx/lib/plugin/recma-jsx-rewrite.js b/packages/mdx/lib/plugin/recma-jsx-rewrite.js
index e1d8dbf50..4539e3fd4 100644
--- a/packages/mdx/lib/plugin/recma-jsx-rewrite.js
+++ b/packages/mdx/lib/plugin/recma-jsx-rewrite.js
@@ -76,43 +76,43 @@ export function recmaJsxRewrite(options = {}) {
walk(tree, {
enter(_node) {
const node = /** @type {Node} */ (_node)
+ const newScope = /** @type {Scope|undefined} */ (
+ // @ts-expect-error: periscopic doesn’t support JSX.
+ scopeInfo.map.get(node)
+ )
if (
node.type === 'FunctionDeclaration' ||
node.type === 'FunctionExpression' ||
node.type === 'ArrowFunctionExpression'
) {
- fnStack.push({
+ const stackLength = fnStack.push({
objects: [],
components: [],
tags: [],
references: {},
node
})
- }
- let fnScope = fnStack[0]
+ // MDXContent only ever contains MDXLayout
+ if (
+ isNamedFunction(node, 'MDXContent') &&
+ newScope &&
+ !inScope(newScope, 'MDXLayout')
+ ) {
+ fnStack[stackLength - 1].components.push('MDXLayout')
+ }
+ }
+ const fnScope = fnStack[0]
if (
!fnScope ||
- (!isNamedFunction(fnScope.node, 'MDXContent') &&
+ (!isNamedFunction(fnScope.node, '_createMdxContent') &&
!providerImportSource)
) {
return
}
- if (
- fnStack[1] &&
- isNamedFunction(fnStack[1].node, '_createMdxContent')
- ) {
- fnScope = fnStack[1]
- }
-
- const newScope = /** @type {Scope|undefined} */ (
- // @ts-expect-error: periscopic doesn’t support JSX.
- scopeInfo.map.get(node)
- )
-
if (newScope) {
newScope.node = node
currentScope = newScope
From a5cf6a0c14df779f691cce8fcec1e615db44ca4c Mon Sep 17 00:00:00 2001
From: 0phoff <0phoff@users.noreply.github.com>
Date: Mon, 13 Jun 2022 21:12:17 +0200
Subject: [PATCH 2/5] Fixed wrong tests
---
packages/mdx/test/compile.js | 74 +++++++++++++++---------------
packages/rollup/test/index.test.js | 2 +-
2 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/packages/mdx/test/compile.js b/packages/mdx/test/compile.js
index 4385ec205..c09165c82 100644
--- a/packages/mdx/test/compile.js
+++ b/packages/mdx/test/compile.js
@@ -778,16 +778,16 @@ test('jsx', async () => {
String(compileSync('*a*', {jsx: true})),
[
'/*@jsxRuntime automatic @jsxImportSource react*/',
+ 'function _createMdxContent(props) {',
+ ' const _components = Object.assign({',
+ ' p: "p",',
+ ' em: "em"',
+ ' }, props.components);',
+ ' return <_components.p><_components.em>{"a"};',
+ '}',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
- ' return MDXLayout ? <_createMdxContent /> : _createMdxContent();',
- ' function _createMdxContent() {',
- ' const _components = Object.assign({',
- ' p: "p",',
- ' em: "em"',
- ' }, props.components);',
- ' return <_components.p><_components.em>{"a"};',
- ' }',
+ ' return MDXLayout ? <_createMdxContent {...props} /> : _createMdxContent(props);',
'}',
'export default MDXContent;',
''
@@ -799,12 +799,12 @@ test('jsx', async () => {
String(compileSync('', {jsx: true})),
[
'/*@jsxRuntime automatic @jsxImportSource react*/',
+ 'function _createMdxContent(props) {',
+ ' return ;',
+ '}',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
- ' return MDXLayout ? <_createMdxContent /> : _createMdxContent();',
- ' function _createMdxContent() {',
- ' return ;',
- ' }',
+ ' return MDXLayout ? <_createMdxContent {...props} /> : _createMdxContent(props);',
'}',
'export default MDXContent;',
''
@@ -816,15 +816,15 @@ test('jsx', async () => {
String(compileSync('<>>', {jsx: true})),
[
'/*@jsxRuntime automatic @jsxImportSource react*/',
+ 'function _createMdxContent(props) {',
+ ' const {c} = props.components || ({});',
+ ' if (!c) _missingMdxReference("c", false);',
+ ' if (!c.d) _missingMdxReference("c.d", true);',
+ ' return <><>>>;',
+ '}',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
- ' return MDXLayout ? <_createMdxContent /> : _createMdxContent();',
- ' function _createMdxContent() {',
- ' const {c} = props.components || ({});',
- ' if (!c) _missingMdxReference("c", false);',
- ' if (!c.d) _missingMdxReference("c.d", true);',
- ' return <><>>>;',
- ' }',
+ ' return MDXLayout ? <_createMdxContent {...props} /> : _createMdxContent(props);',
'}',
'export default MDXContent;',
'function _missingMdxReference(id, component) {',
@@ -840,12 +840,12 @@ test('jsx', async () => {
[
'/*@jsxRuntime automatic @jsxImportSource react*/',
'/*1*/',
+ 'function _createMdxContent(props) {',
+ ' return <><>{"a "}{}{" b"}>>;',
+ '}',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
- ' return MDXLayout ? <_createMdxContent /> : _createMdxContent();',
- ' function _createMdxContent() {',
- ' return <><>{"a "}{}{" b"}>>;',
- ' }',
+ ' return MDXLayout ? <_createMdxContent {...props} /> : _createMdxContent(props);',
'}',
'export default MDXContent;',
''
@@ -857,15 +857,15 @@ test('jsx', async () => {
String(compileSync('{}', {jsx: true})),
[
'/*@jsxRuntime automatic @jsxImportSource react*/',
+ 'function _createMdxContent(props) {',
+ ' const _components = Object.assign({',
+ ' "a-b": "a-b"',
+ ' }, props.components);',
+ ' return <>{<_components.a-b>}>;',
+ '}',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
- ' return MDXLayout ? <_createMdxContent /> : _createMdxContent();',
- ' function _createMdxContent() {',
- ' const _components = Object.assign({',
- ' "a-b": "a-b"',
- ' }, props.components);',
- ' return <>{<_components.a-b>}>;',
- ' }',
+ ' return MDXLayout ? <_createMdxContent {...props} /> : _createMdxContent(props);',
'}',
'export default MDXContent;',
''
@@ -877,15 +877,15 @@ test('jsx', async () => {
String(compileSync('Hello {props.name}', {jsx: true})),
[
'/*@jsxRuntime automatic @jsxImportSource react*/',
+ 'function _createMdxContent(props) {',
+ ' const _components = Object.assign({',
+ ' p: "p"',
+ ' }, props.components);',
+ ' return <_components.p>{"Hello "}{props.name};',
+ '}',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
- ' return MDXLayout ? <_createMdxContent /> : _createMdxContent();',
- ' function _createMdxContent() {',
- ' const _components = Object.assign({',
- ' p: "p"',
- ' }, props.components);',
- ' return <_components.p>{"Hello "}{props.name};',
- ' }',
+ ' return MDXLayout ? <_createMdxContent {...props} /> : _createMdxContent(props);',
'}',
'export default MDXContent;',
''
diff --git a/packages/rollup/test/index.test.js b/packages/rollup/test/index.test.js
index 0f6168215..ae0b0781b 100644
--- a/packages/rollup/test/index.test.js
+++ b/packages/rollup/test/index.test.js
@@ -34,7 +34,7 @@ test('@mdx-js/rollup', async () => {
assert.equal(
output[0].map ? output[0].map.mappings : undefined,
- ';;;MAAaA,OAAU,GAAA,MAAAC,GAAA,CAAAC,QAAA,EAAA;AAAQ,EAAA,QAAA,EAAA,QAAA;;;;;;;;;;;;AAE7B,MAAA,QAAA,EAAA,CAAA,SAAA,EAAAD,GAAA,CAAA,OAAA,EAAA,EAAA,CAAA,CAAA;;;;;;;',
+ ';;;MAAaA,OAAU,GAAA,MAAAC,GAAA,CAAAC,QAAA,EAAA;AAAQ,EAAA,QAAA,EAAA,QAAA;;;;;;;AAE7B,IAAA,QAAA,EAAA,CAAA,SAAA,EAAAD,GAAA,CAAA,OAAA,EAAA,EAAA,CAAA,CAAA;;;;;;;;;;;;',
'should add a source map'
)
From 2e7267c67409ae4a5fedf6fbfc0f2c6033408683 Mon Sep 17 00:00:00 2001
From: 0phoff <0phoff@users.noreply.github.com>
Date: Tue, 14 Jun 2022 18:04:41 +0200
Subject: [PATCH 3/5] Renamed variables after PR Review
- `hasLayout` -> `hasInternalLayout`
- `consequent` -> `result`
---
packages/mdx/lib/plugin/recma-document.js | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/packages/mdx/lib/plugin/recma-document.js b/packages/mdx/lib/plugin/recma-document.js
index 7fa75f808..2b07a2866 100644
--- a/packages/mdx/lib/plugin/recma-document.js
+++ b/packages/mdx/lib/plugin/recma-document.js
@@ -481,10 +481,10 @@ export function recmaDocument(options = {}) {
/**
* @param {Expression} [content]
- * @param {boolean} [hasLayout]
+ * @param {boolean} [hasInternalLayout]
* @returns {FunctionDeclaration[]}
*/
- function createMdxContent(content, hasLayout) {
+ function createMdxContent(content, hasInternalLayout) {
/** @type {JSXElement} */
const element = {
type: 'JSXElement',
@@ -524,13 +524,13 @@ export function recmaDocument(options = {}) {
}
// @ts-expect-error: JSXElements are expressions.
- let consequent = /** @type {Expression} */ (element)
+ let result = /** @type {Expression} */ (element)
- if (!hasLayout) {
- consequent = {
+ if (!hasInternalLayout) {
+ result = {
type: 'ConditionalExpression',
test: {type: 'Identifier', name: 'MDXLayout'},
- consequent,
+ consequent: result,
alternate: {
type: 'CallExpression',
callee: {type: 'Identifier', name: '_createMdxContent'},
@@ -580,7 +580,7 @@ export function recmaDocument(options = {}) {
body: [
{
type: 'ReturnStatement',
- argument: consequent
+ argument: result
}
]
}
From 174ee1f0718537199c97db686a3202c7b5a32016 Mon Sep 17 00:00:00 2001
From: 0phoff <0phoff@users.noreply.github.com>
Date: Thu, 16 Jun 2022 16:06:40 +0200
Subject: [PATCH 4/5] Assume MDXContent is always the 0th function in the stack
---
packages/mdx/lib/plugin/recma-jsx-rewrite.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/mdx/lib/plugin/recma-jsx-rewrite.js b/packages/mdx/lib/plugin/recma-jsx-rewrite.js
index 4539e3fd4..4934eb7f8 100644
--- a/packages/mdx/lib/plugin/recma-jsx-rewrite.js
+++ b/packages/mdx/lib/plugin/recma-jsx-rewrite.js
@@ -86,7 +86,7 @@ export function recmaJsxRewrite(options = {}) {
node.type === 'FunctionExpression' ||
node.type === 'ArrowFunctionExpression'
) {
- const stackLength = fnStack.push({
+ fnStack.push({
objects: [],
components: [],
tags: [],
@@ -100,7 +100,7 @@ export function recmaJsxRewrite(options = {}) {
newScope &&
!inScope(newScope, 'MDXLayout')
) {
- fnStack[stackLength - 1].components.push('MDXLayout')
+ fnStack[0].components.push('MDXLayout')
}
}
From cc100be2c55d48b813b6fd5cde7d142136ec2b79 Mon Sep 17 00:00:00 2001
From: 0phoff <0phoff@users.noreply.github.com>
Date: Thu, 16 Jun 2022 16:07:03 +0200
Subject: [PATCH 5/5] Add jsx specific test for internal layouts
---
packages/mdx/test/compile.js | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/packages/mdx/test/compile.js b/packages/mdx/test/compile.js
index c09165c82..8b6d457a3 100644
--- a/packages/mdx/test/compile.js
+++ b/packages/mdx/test/compile.js
@@ -893,6 +893,33 @@ test('jsx', async () => {
'should allow using props'
)
+ assert.equal(
+ String(
+ compileSync(
+ 'export default function Layout({components, ...props}) { return }\n\na',
+ {jsx: true}
+ )
+ ),
+ [
+ '/*@jsxRuntime automatic @jsxImportSource react*/',
+ 'const MDXLayout = function Layout({components, ...props}) {',
+ ' return ;',
+ '};',
+ 'function _createMdxContent(props) {',
+ ' const _components = Object.assign({',
+ ' p: "p"',
+ ' }, props.components);',
+ ' return <_components.p>{"a"};',
+ '}',
+ 'function MDXContent(props = {}) {',
+ ' return <_createMdxContent {...props} />;',
+ '}',
+ 'export default MDXContent;',
+ ''
+ ].join('\n'),
+ 'should not have a conditional expression for MDXLayout when there is an internal layout'
+ )
+
assert.match(
String(compileSync("{}", {jsx: true})),
/x="y " z"/,