Skip to content

Commit

Permalink
Make sure _missingMdxReference checks are always added
Browse files Browse the repository at this point in the history
  • Loading branch information
vlad-zhukov committed Mar 26, 2022
1 parent b8a76c9 commit 280124f
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 67 deletions.
136 changes: 69 additions & 67 deletions packages/mdx/lib/plugin/recma-jsx-rewrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,25 +243,8 @@ export function recmaJsxRewrite(options = {}) {
}
}

/** @type {string} */
let key

// Add partials (so for `x.y.z` it’d generate `x` and `x.y` too).
for (key in scope.references) {
if (own.call(scope.references, key)) {
const parts = key.split('.')
let index = 0
while (++index < parts.length) {
const partial = parts.slice(0, index).join('.')
if (!own.call(scope.references, partial)) {
scope.references[partial] = {
node: scope.references[key].node,
component: false
}
}
}
}
}
/** @type {Array<Statement>} */
const statements = []

if (defaults.length > 0 || actual.length > 0) {
if (providerImportSource) {
Expand Down Expand Up @@ -356,60 +339,79 @@ export function recmaJsxRewrite(options = {}) {
})
}

// Arrow functions with an implied return:
if (fn.body.type !== 'BlockStatement') {
fn.body = {
type: 'BlockStatement',
body: [{type: 'ReturnStatement', argument: fn.body}]
statements.push({
type: 'VariableDeclaration',
kind: 'const',
declarations
})
}

/** @type {string} */
let key

// Add partials (so for `x.y.z` it’d generate `x` and `x.y` too).
for (key in scope.references) {
if (own.call(scope.references, key)) {
const parts = key.split('.')
let index = 0
while (++index < parts.length) {
const partial = parts.slice(0, index).join('.')
if (!own.call(scope.references, partial)) {
scope.references[partial] = {
node: scope.references[key].node,
component: false
}
}
}
}
}

/** @type {Array<Statement>} */
const statements = [
{
type: 'VariableDeclaration',
kind: 'const',
declarations
}
const references = Object.keys(scope.references).sort()
let index = -1
while (++index < references.length) {
const id = references[index]
const info = scope.references[id]
const place = stringifyPosition(positionFromEstree(info.node))
/** @type {Array<Expression>} */
const parameters = [
{type: 'Literal', value: id},
{type: 'Literal', value: info.component}
]

const references = Object.keys(scope.references).sort()
let index = -1
while (++index < references.length) {
const id = references[index]
const info = scope.references[id]
const place = stringifyPosition(positionFromEstree(info.node))
/** @type {Array<Expression>} */
const parameters = [
{type: 'Literal', value: id},
{type: 'Literal', value: info.component}
]

createErrorHelper = true

if (development && place !== '1:1-1:1') {
parameters.push({type: 'Literal', value: place})
}
createErrorHelper = true

statements.push({
type: 'IfStatement',
test: {
type: 'UnaryExpression',
operator: '!',
prefix: true,
argument: toIdOrMemberExpression(id.split('.'))
},
consequent: {
type: 'ExpressionStatement',
expression: {
type: 'CallExpression',
callee: {type: 'Identifier', name: '_missingMdxReference'},
arguments: parameters,
optional: false
}
},
alternate: null
})
if (development && place !== '1:1-1:1') {
parameters.push({type: 'Literal', value: place})
}

statements.push({
type: 'IfStatement',
test: {
type: 'UnaryExpression',
operator: '!',
prefix: true,
argument: toIdOrMemberExpression(id.split('.'))
},
consequent: {
type: 'ExpressionStatement',
expression: {
type: 'CallExpression',
callee: {type: 'Identifier', name: '_missingMdxReference'},
arguments: parameters,
optional: false
}
},
alternate: null
})
}

if (statements.length > 0) {
// Arrow functions with an implied return:
if (fn.body.type !== 'BlockStatement') {
fn.body = {
type: 'BlockStatement',
body: [{type: 'ReturnStatement', argument: fn.body}]
}
}

fn.body.body.unshift(...statements)
Expand Down
27 changes: 27 additions & 0 deletions packages/mdx/test/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,33 @@ test('jsx', async () => {
'should serialize fragments, namespaces, members'
)

assert.equal(
String(
compileSync('export const a = {}\n\n<a.b />', {
jsx: true
})
),
[
'/*@jsxRuntime automatic @jsxImportSource react*/',
'export const a = {};',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
' return MDXLayout ? <MDXLayout {...props}><_createMdxContent /></MDXLayout> : _createMdxContent();',
' function _createMdxContent() {',
' if (!a) _missingMdxReference("a", false);',
' if (!a.b) _missingMdxReference("a.b", true);',
' return <a.b />;',
' }',
'}',
'export default MDXContent;',
'function _missingMdxReference(id, component) {',
' throw new Error("Expected " + (component ? "component" : "object") + " `" + id + "` to be defined: you likely forgot to import, pass, or provide it.");',
'}',
''
].join('\n'),
'should serialize members inside expressions'
)

assert.equal(
String(compileSync('<>a {/* 1 */} b</>', {jsx: true})),
[
Expand Down

0 comments on commit 280124f

Please sign in to comment.