diff --git a/package-lock.json b/package-lock.json index 06624d39f..675c45b5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5135,9 +5135,9 @@ } }, "node_modules/estree-util-build-jsx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.0.tgz", - "integrity": "sha512-mIxOqyNfkwCz7MU7d8Hd0meGj+Vnn2U06mGuUkPTPlNumBfM1gqL2OlC+rB+QgRAmodoUGaHK5GgqoKQ0T8QRw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", diff --git a/packages/mdx/lib/plugin/recma-jsx-build.js b/packages/mdx/lib/plugin/recma-jsx-build.js index 1bc81495c..58192166c 100644 --- a/packages/mdx/lib/plugin/recma-jsx-build.js +++ b/packages/mdx/lib/plugin/recma-jsx-build.js @@ -46,20 +46,37 @@ export function recmaJsxBuild(options) { // When compiling to a function body, replace the import that was just // generated, and get `jsx`, `jsxs`, and `Fragment` from `arguments[0]` // instead. - if ( - outputFormat === 'function-body' && - tree.body[0] && - tree.body[0].type === 'ImportDeclaration' && - typeof tree.body[0].source.value === 'string' && - /\/jsx-(dev-)?runtime$/.test(tree.body[0].source.value) - ) { - tree.body[0] = { - type: 'VariableDeclaration', - kind: 'const', - declarations: specifiersToDeclarations( - tree.body[0].specifiers, - toIdOrMemberExpression(['arguments', 0]) - ) + if (outputFormat === 'function-body') { + let index = 0 + + // Skip directives: JS currently only has `use strict`, but Acorn allows + // arbitrary ones. + // Practically things like `use client` could be used? + while (index < tree.body.length) { + const child = tree.body[index] + if ('directive' in child && child.directive) { + index++ + } else { + break + } + } + + const declaration = tree.body[index] + + if ( + declaration && + declaration.type === 'ImportDeclaration' && + typeof declaration.source.value === 'string' && + /\/jsx-(dev-)?runtime$/.test(declaration.source.value) + ) { + tree.body[index] = { + type: 'VariableDeclaration', + kind: 'const', + declarations: specifiersToDeclarations( + declaration.specifiers, + toIdOrMemberExpression(['arguments', 0]) + ) + } } } } diff --git a/packages/mdx/lib/plugin/recma-jsx-rewrite.js b/packages/mdx/lib/plugin/recma-jsx-rewrite.js index db93bf60e..818053d56 100644 --- a/packages/mdx/lib/plugin/recma-jsx-rewrite.js +++ b/packages/mdx/lib/plugin/recma-jsx-rewrite.js @@ -560,6 +560,14 @@ export function recmaJsxRewrite(options) { } }) } + + if (outputFormat === 'function-body') { + tree.body.unshift({ + type: 'ExpressionStatement', + expression: {type: 'Literal', value: 'use strict'}, + directive: 'use strict' + }) + } } } diff --git a/packages/mdx/test/syntax.js b/packages/mdx/test/syntax.js index 43996a768..5ae661ef1 100644 --- a/packages/mdx/test/syntax.js +++ b/packages/mdx/test/syntax.js @@ -899,4 +899,40 @@ test('@mdx-js/mdx: syntax: MDX (ESM)', async function (t) { ].join('\n') ) }) + + await t.test( + "should add a 'use strict' when generating a `function-body`", + async function () { + assert.equal( + String(await compile('# hi', {outputFormat: 'function-body'})), + [ + '/*@jsxRuntime automatic @jsxImportSource react*/', + '"use strict";', + 'const {jsx: _jsx} = arguments[0];', + 'function _createMdxContent(props) {', + ' const _components = {', + ' h1: "h1",', + ' ...props.components', + ' };', + ' return _jsx(_components.h1, {', + ' children: "hi"', + ' });', + '}', + 'function MDXContent(props = {}) {', + ' const {wrapper: MDXLayout} = props.components || ({});', + ' return MDXLayout ? _jsx(MDXLayout, {', + ' ...props,', + ' children: _jsx(_createMdxContent, {', + ' ...props', + ' })', + ' }) : _createMdxContent(props);', + '}', + 'return {', + ' default: MDXContent', + '};', + '' + ].join('\n') + ) + } + ) })