Skip to content

Commit 58639a0

Browse files
authored
fix: jsx name could be namespace or member expression (#460)
1 parent 296a319 commit 58639a0

File tree

5 files changed

+1894
-18
lines changed

5 files changed

+1894
-18
lines changed

.changeset/eight-emus-lay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-mdx": patch
3+
---
4+
5+
fix: jsx name could be namespace or member expression

packages/eslint-mdx/src/worker.ts

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ import type {
1515
Program,
1616
SpreadElement,
1717
} from 'estree'
18-
import type { JSXClosingElement, JSXElement, JSXFragment } from 'estree-jsx'
18+
import type {
19+
JSXClosingElement,
20+
JSXElement,
21+
JSXFragment,
22+
JSXIdentifier,
23+
JSXMemberExpression,
24+
JSXNamespacedName,
25+
} from 'estree-jsx'
1926
import type {
2027
BlockContent,
2128
PhrasingContent,
@@ -289,6 +296,58 @@ runAsWorker(
289296
raw: text.slice(start, end),
290297
})
291298

299+
const handleJsxName = (
300+
nodeName: string,
301+
start: number,
302+
): JSXIdentifier | JSXMemberExpression | JSXNamespacedName => {
303+
const name = nodeName.trim()
304+
const nameIndex = nodeName.indexOf(name)
305+
306+
const colonIndex = nodeName.indexOf(':')
307+
if (colonIndex !== -1) {
308+
const [fullNamespace, fullName] = nodeName.split(':')
309+
return {
310+
...normalizeNode(
311+
start + nameIndex,
312+
start + nameIndex + name.length,
313+
),
314+
type: 'JSXNamespacedName',
315+
namespace: handleJsxName(fullNamespace, start) as JSXIdentifier,
316+
name: handleJsxName(
317+
fullName,
318+
start + colonIndex + 1,
319+
) as JSXIdentifier,
320+
}
321+
}
322+
323+
const lastPointIndex = nodeName.lastIndexOf('.')
324+
if (lastPointIndex === -1) {
325+
return {
326+
...normalizeNode(
327+
start + nameIndex,
328+
start + nameIndex + name.length,
329+
),
330+
type: 'JSXIdentifier',
331+
name,
332+
}
333+
}
334+
335+
const objectName = nodeName.slice(0, lastPointIndex)
336+
const propertyName = nodeName.slice(lastPointIndex + 1)
337+
338+
return {
339+
...normalizeNode(start + nameIndex, start + nameIndex + name.length),
340+
type: 'JSXMemberExpression',
341+
object: handleJsxName(objectName, start) as
342+
| JSXIdentifier
343+
| JSXMemberExpression,
344+
property: handleJsxName(
345+
propertyName,
346+
start + lastPointIndex + 1,
347+
) as JSXIdentifier,
348+
}
349+
}
350+
292351
visit(root, node => {
293352
if (
294353
processed.has(node) ||
@@ -374,20 +433,16 @@ runAsWorker(
374433
if (!selfClosing) {
375434
const prevOffset = prevCharOffset(lastCharOffset)
376435
const slashOffset = prevCharOffset(prevOffset - nodeNameLength)
377-
assert(text[slashOffset] === '/')
436+
assert(
437+
text[slashOffset] === '/',
438+
`expect \`${text[slashOffset]}\` to be \`/\`, the node is ${node.name}`,
439+
)
378440
const tagStartOffset = prevCharOffset(slashOffset - 1)
379441
assert(text[tagStartOffset] === '<')
380442
closingElement = {
381443
...normalizeNode(tagStartOffset, nodeEnd),
382444
type: 'JSXClosingElement',
383-
name: {
384-
...normalizeNode(
385-
prevOffset + 1 - nodeNameLength,
386-
prevOffset + 1,
387-
),
388-
type: 'JSXIdentifier',
389-
name: node.name,
390-
},
445+
name: handleJsxName(node.name, prevOffset + 1 - nodeNameLength),
391446
}
392447
}
393448

@@ -396,14 +451,7 @@ runAsWorker(
396451
type: 'JSXElement',
397452
openingElement: {
398453
type: 'JSXOpeningElement',
399-
name: {
400-
...normalizeNode(
401-
nodeNameStart,
402-
nodeNameStart + nodeNameLength,
403-
),
404-
type: 'JSXIdentifier',
405-
name: node.name,
406-
},
454+
name: handleJsxName(node.name, nodeNameStart),
407455
attributes: node.attributes.map(attr => {
408456
if (attr.type === 'mdxJsxExpressionAttribute') {
409457
assert(attr.data)

test/__snapshots__/fixtures.test.ts.snap

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,22 @@ exports[`fixtures should match all snapshots: 429.mdx 1`] = `
430430
]
431431
`;
432432
433+
exports[`fixtures should match all snapshots: 445.mdx 1`] = `
434+
[
435+
{
436+
"column": 2,
437+
"endColumn": 3,
438+
"endLine": 9,
439+
"line": 9,
440+
"message": "'A' is not defined.",
441+
"messageId": "undefined",
442+
"nodeType": "JSXIdentifier",
443+
"ruleId": "react/jsx-no-undef",
444+
"severity": 2,
445+
},
446+
]
447+
`;
448+
433449
exports[`fixtures should match all snapshots: 450.mdx 1`] = `
434450
[
435451
{

0 commit comments

Comments
 (0)