Skip to content

Commit

Permalink
fix(scope-manager): don't create references for intrinsic JSX elements (
Browse files Browse the repository at this point in the history
  • Loading branch information
bradzacher committed Sep 6, 2020
1 parent 5afeeab commit cdb9807
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 10 deletions.
21 changes: 21 additions & 0 deletions packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts
Expand Up @@ -199,6 +199,27 @@ function Foo() {}
},
},
},
// intrinsic elements should not cause errors
{
code: `
<div />;
`,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
{
code: `
<span></span>;
`,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
// https://github.com/typescript-eslint/typescript-eslint/issues/2477
`
const x = 1 as const;
Expand Down
15 changes: 14 additions & 1 deletion packages/scope-manager/src/referencer/Referencer.ts
Expand Up @@ -558,6 +558,10 @@ class Referencer extends Visitor {
this.visit(node.value);
}

protected JSXClosingElement(): void {
// should not be counted as a reference
}

protected JSXFragment(node: TSESTree.JSXFragment): void {
this.referenceJsxPragma();
this.referenceJsxFragment();
Expand All @@ -575,7 +579,16 @@ class Referencer extends Visitor {

protected JSXOpeningElement(node: TSESTree.JSXOpeningElement): void {
this.referenceJsxPragma();
this.visit(node.name);
if (node.name.type === AST_NODE_TYPES.JSXIdentifier) {
if (node.name.name[0].toUpperCase() === node.name.name[0]) {
// lower cased component names are always treated as "intrinsic" names, and are converted to a string,
// not a variable by JSX transforms:
// <div /> => React.createElement("div", null)
this.visit(node.name);
}
} else {
this.visit(node.name);
}
this.visitType(node.typeParameters);
for (const attr of node.attributes) {
this.visit(attr);
Expand Down
8 changes: 0 additions & 8 deletions packages/scope-manager/tests/fixtures/jsx/children.tsx.shot
Expand Up @@ -51,14 +51,6 @@ ScopeManager {
resolved: null,
},
Reference$3,
Reference$4 {
identifier: JSXIdentifier$5,
isRead: true,
isTypeReference: false,
isValueReference: true,
isWrite: false,
resolved: null,
},
],
set: Map {
"const" => ImplicitGlobalConstTypeVariable,
Expand Down
@@ -0,0 +1,2 @@
function div() {} // should not be referenced
<div />;
@@ -0,0 +1,58 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`jsx component-intrinsic-name 1`] = `
ScopeManager {
variables: Array [
ImplicitGlobalConstTypeVariable,
Variable$2 {
defs: Array [
FunctionNameDefinition$1 {
name: Identifier<"div">,
node: FunctionDeclaration$1,
},
],
name: "div",
references: Array [],
isValueVariable: true,
isTypeVariable: false,
},
Variable$3 {
defs: Array [],
name: "arguments",
references: Array [],
isValueVariable: true,
isTypeVariable: true,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$2,
isStrict: false,
references: Array [],
set: Map {
"const" => ImplicitGlobalConstTypeVariable,
"div" => Variable$2,
},
type: "global",
upper: null,
variables: Array [
ImplicitGlobalConstTypeVariable,
Variable$2,
],
},
FunctionScope$2 {
block: FunctionDeclaration$1,
isStrict: false,
references: Array [],
set: Map {
"arguments" => Variable$3,
},
type: "function",
upper: GlobalScope$1,
variables: Array [
Variable$3,
],
},
],
}
`;
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`jsx component-namespaced 1`] = `
exports[`jsx component-namespaced1 1`] = `
ScopeManager {
variables: Array [
ImplicitGlobalConstTypeVariable,
Expand Down
@@ -0,0 +1,6 @@
const x = {
Foo() {},
};
const Foo = 1; // should be unreferenced

<x.Foo />; // lower cased namespaces should still create a reference
@@ -0,0 +1,106 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`jsx component-namespaced2 1`] = `
ScopeManager {
variables: Array [
ImplicitGlobalConstTypeVariable,
Variable$2 {
defs: Array [
VariableDefinition$1 {
name: Identifier<"x">,
node: VariableDeclarator$1,
},
],
name: "x",
references: Array [
Reference$1 {
identifier: Identifier<"x">,
init: true,
isRead: false,
isTypeReference: false,
isValueReference: true,
isWrite: true,
resolved: Variable$2,
writeExpr: ObjectExpression$2,
},
Reference$3 {
identifier: JSXIdentifier$3,
isRead: true,
isTypeReference: false,
isValueReference: true,
isWrite: false,
resolved: Variable$2,
},
],
isValueVariable: true,
isTypeVariable: false,
},
Variable$3 {
defs: Array [],
name: "arguments",
references: Array [],
isValueVariable: true,
isTypeVariable: true,
},
Variable$4 {
defs: Array [
VariableDefinition$2 {
name: Identifier<"Foo">,
node: VariableDeclarator$4,
},
],
name: "Foo",
references: Array [
Reference$2 {
identifier: Identifier<"Foo">,
init: true,
isRead: false,
isTypeReference: false,
isValueReference: true,
isWrite: true,
resolved: Variable$4,
writeExpr: Literal$5,
},
],
isValueVariable: true,
isTypeVariable: false,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$6,
isStrict: false,
references: Array [
Reference$1,
Reference$2,
Reference$3,
],
set: Map {
"const" => ImplicitGlobalConstTypeVariable,
"x" => Variable$2,
"Foo" => Variable$4,
},
type: "global",
upper: null,
variables: Array [
ImplicitGlobalConstTypeVariable,
Variable$2,
Variable$4,
],
},
FunctionScope$2 {
block: FunctionExpression$7,
isStrict: false,
references: Array [],
set: Map {
"arguments" => Variable$3,
},
type: "function",
upper: GlobalScope$1,
variables: Array [
Variable$3,
],
},
],
}
`;

0 comments on commit cdb9807

Please sign in to comment.