Skip to content

Commit

Permalink
Fix to add _missingMdxReference in some more cases
Browse files Browse the repository at this point in the history
Related-to GH-1986.
Closes GH-1988.

Reviewed-by: Titus Wormer <tituswormer@gmail.com>
  • Loading branch information
vlad-zhukov committed Mar 29, 2022
1 parent 427bcad commit 0df684b
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 67 deletions.
136 changes: 69 additions & 67 deletions packages/mdx/lib/plugin/recma-jsx-rewrite.js
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
34 changes: 34 additions & 0 deletions packages/mdx/test/compile.js
Expand Up @@ -504,6 +504,40 @@ test('compile', async () => {
)
}

// TODO: this is incorrect behavior, will be fixed in GH-1986
try {
renderToStaticMarkup(
React.createElement(
await run(compileSync('export const a = {}\n\n<a.b />'))
)
)
assert.unreachable()
} catch (/** @type {unknown} */ error) {
const exception = /** @type {Error} */ (error)
assert.match(
exception.message,
/Expected component `a.b` to be defined/,
'should throw if a used member is not defined locally'
)
}

// TODO: this is incorrect behavior, will be fixed in GH-1986
try {
renderToStaticMarkup(
React.createElement(
await run(compileSync('<a render={(x) => <x.y />} />'))
)
)
assert.unreachable()
} catch (/** @type {unknown} */ error) {
const exception = /** @type {Error} */ (error)
assert.match(
exception.message,
/x is not defined/,
'should throw if a used member is not defined locally (JSX in a function)'
)
}

try {
renderToStaticMarkup(
React.createElement(await run(compileSync('<X />', {development: true})))
Expand Down

1 comment on commit 0df684b

@vercel
Copy link

@vercel vercel bot commented on 0df684b Mar 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

Please sign in to comment.