Skip to content

Commit cdb9807

Browse files
authored
fix(scope-manager): don't create references for intrinsic JSX elements (#2504)
1 parent 5afeeab commit cdb9807

9 files changed

+208
-10
lines changed

Diff for: packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts

+21
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,27 @@ function Foo() {}
199199
},
200200
},
201201
},
202+
// intrinsic elements should not cause errors
203+
{
204+
code: `
205+
<div />;
206+
`,
207+
parserOptions: {
208+
ecmaFeatures: {
209+
jsx: true,
210+
},
211+
},
212+
},
213+
{
214+
code: `
215+
<span></span>;
216+
`,
217+
parserOptions: {
218+
ecmaFeatures: {
219+
jsx: true,
220+
},
221+
},
222+
},
202223
// https://github.com/typescript-eslint/typescript-eslint/issues/2477
203224
`
204225
const x = 1 as const;

Diff for: packages/scope-manager/src/referencer/Referencer.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,10 @@ class Referencer extends Visitor {
558558
this.visit(node.value);
559559
}
560560

561+
protected JSXClosingElement(): void {
562+
// should not be counted as a reference
563+
}
564+
561565
protected JSXFragment(node: TSESTree.JSXFragment): void {
562566
this.referenceJsxPragma();
563567
this.referenceJsxFragment();
@@ -575,7 +579,16 @@ class Referencer extends Visitor {
575579

576580
protected JSXOpeningElement(node: TSESTree.JSXOpeningElement): void {
577581
this.referenceJsxPragma();
578-
this.visit(node.name);
582+
if (node.name.type === AST_NODE_TYPES.JSXIdentifier) {
583+
if (node.name.name[0].toUpperCase() === node.name.name[0]) {
584+
// lower cased component names are always treated as "intrinsic" names, and are converted to a string,
585+
// not a variable by JSX transforms:
586+
// <div /> => React.createElement("div", null)
587+
this.visit(node.name);
588+
}
589+
} else {
590+
this.visit(node.name);
591+
}
579592
this.visitType(node.typeParameters);
580593
for (const attr of node.attributes) {
581594
this.visit(attr);

Diff for: packages/scope-manager/tests/fixtures/jsx/children.tsx.shot

-8
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,6 @@ ScopeManager {
5151
resolved: null,
5252
},
5353
Reference$3,
54-
Reference$4 {
55-
identifier: JSXIdentifier$5,
56-
isRead: true,
57-
isTypeReference: false,
58-
isValueReference: true,
59-
isWrite: false,
60-
resolved: null,
61-
},
6254
],
6355
set: Map {
6456
"const" => ImplicitGlobalConstTypeVariable,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
function div() {} // should not be referenced
2+
<div />;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`jsx component-intrinsic-name 1`] = `
4+
ScopeManager {
5+
variables: Array [
6+
ImplicitGlobalConstTypeVariable,
7+
Variable$2 {
8+
defs: Array [
9+
FunctionNameDefinition$1 {
10+
name: Identifier<"div">,
11+
node: FunctionDeclaration$1,
12+
},
13+
],
14+
name: "div",
15+
references: Array [],
16+
isValueVariable: true,
17+
isTypeVariable: false,
18+
},
19+
Variable$3 {
20+
defs: Array [],
21+
name: "arguments",
22+
references: Array [],
23+
isValueVariable: true,
24+
isTypeVariable: true,
25+
},
26+
],
27+
scopes: Array [
28+
GlobalScope$1 {
29+
block: Program$2,
30+
isStrict: false,
31+
references: Array [],
32+
set: Map {
33+
"const" => ImplicitGlobalConstTypeVariable,
34+
"div" => Variable$2,
35+
},
36+
type: "global",
37+
upper: null,
38+
variables: Array [
39+
ImplicitGlobalConstTypeVariable,
40+
Variable$2,
41+
],
42+
},
43+
FunctionScope$2 {
44+
block: FunctionDeclaration$1,
45+
isStrict: false,
46+
references: Array [],
47+
set: Map {
48+
"arguments" => Variable$3,
49+
},
50+
type: "function",
51+
upper: GlobalScope$1,
52+
variables: Array [
53+
Variable$3,
54+
],
55+
},
56+
],
57+
}
58+
`;

Diff for: packages/scope-manager/tests/fixtures/jsx/component-namespaced.tsx.shot renamed to packages/scope-manager/tests/fixtures/jsx/component-namespaced1.tsx.shot

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`jsx component-namespaced 1`] = `
3+
exports[`jsx component-namespaced1 1`] = `
44
ScopeManager {
55
variables: Array [
66
ImplicitGlobalConstTypeVariable,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const x = {
2+
Foo() {},
3+
};
4+
const Foo = 1; // should be unreferenced
5+
6+
<x.Foo />; // lower cased namespaces should still create a reference
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`jsx component-namespaced2 1`] = `
4+
ScopeManager {
5+
variables: Array [
6+
ImplicitGlobalConstTypeVariable,
7+
Variable$2 {
8+
defs: Array [
9+
VariableDefinition$1 {
10+
name: Identifier<"x">,
11+
node: VariableDeclarator$1,
12+
},
13+
],
14+
name: "x",
15+
references: Array [
16+
Reference$1 {
17+
identifier: Identifier<"x">,
18+
init: true,
19+
isRead: false,
20+
isTypeReference: false,
21+
isValueReference: true,
22+
isWrite: true,
23+
resolved: Variable$2,
24+
writeExpr: ObjectExpression$2,
25+
},
26+
Reference$3 {
27+
identifier: JSXIdentifier$3,
28+
isRead: true,
29+
isTypeReference: false,
30+
isValueReference: true,
31+
isWrite: false,
32+
resolved: Variable$2,
33+
},
34+
],
35+
isValueVariable: true,
36+
isTypeVariable: false,
37+
},
38+
Variable$3 {
39+
defs: Array [],
40+
name: "arguments",
41+
references: Array [],
42+
isValueVariable: true,
43+
isTypeVariable: true,
44+
},
45+
Variable$4 {
46+
defs: Array [
47+
VariableDefinition$2 {
48+
name: Identifier<"Foo">,
49+
node: VariableDeclarator$4,
50+
},
51+
],
52+
name: "Foo",
53+
references: Array [
54+
Reference$2 {
55+
identifier: Identifier<"Foo">,
56+
init: true,
57+
isRead: false,
58+
isTypeReference: false,
59+
isValueReference: true,
60+
isWrite: true,
61+
resolved: Variable$4,
62+
writeExpr: Literal$5,
63+
},
64+
],
65+
isValueVariable: true,
66+
isTypeVariable: false,
67+
},
68+
],
69+
scopes: Array [
70+
GlobalScope$1 {
71+
block: Program$6,
72+
isStrict: false,
73+
references: Array [
74+
Reference$1,
75+
Reference$2,
76+
Reference$3,
77+
],
78+
set: Map {
79+
"const" => ImplicitGlobalConstTypeVariable,
80+
"x" => Variable$2,
81+
"Foo" => Variable$4,
82+
},
83+
type: "global",
84+
upper: null,
85+
variables: Array [
86+
ImplicitGlobalConstTypeVariable,
87+
Variable$2,
88+
Variable$4,
89+
],
90+
},
91+
FunctionScope$2 {
92+
block: FunctionExpression$7,
93+
isStrict: false,
94+
references: Array [],
95+
set: Map {
96+
"arguments" => Variable$3,
97+
},
98+
type: "function",
99+
upper: GlobalScope$1,
100+
variables: Array [
101+
Variable$3,
102+
],
103+
},
104+
],
105+
}
106+
`;

0 commit comments

Comments
 (0)