Skip to content

Commit

Permalink
feat(eslint-plugin): Catch unused React import with new JSX transform (
Browse files Browse the repository at this point in the history
  • Loading branch information
lexanth committed Aug 1, 2021
1 parent 3db6532 commit 02998ea
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 8 deletions.
Expand Up @@ -1576,6 +1576,33 @@ export const ComponentFoo = () => {
},
],
},
// https://github.com/typescript-eslint/typescript-eslint/issues/3303
{
code: `
import React from 'react';
export const ComponentFoo = () => {
return <div>Foo Foo</div>;
};
`,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
jsxPragma: null,
},
errors: [
{
messageId: 'unusedVar',
line: 2,
data: {
varName: 'React',
action: 'defined',
additional: '',
},
},
],
},
{
code: `
declare module 'foo' {
Expand Down
4 changes: 2 additions & 2 deletions packages/parser/README.md
Expand Up @@ -55,7 +55,7 @@ interface ParserOptions {
};
ecmaVersion?: number;

jsxPragma?: string;
jsxPragma?: string | null;
jsxFragmentName?: string | null;
lib?: string[];

Expand Down Expand Up @@ -111,7 +111,7 @@ Specifies the version of ECMAScript syntax you want to use. This is used by the
Default `'React'`

The identifier that's used for JSX Elements creation (after transpilation).
If you're using a library other than React (like `preact`), then you should change this value.
If you're using a library other than React (like `preact`), then you should change this value. If you are using the [new JSX transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) you can set this to `null`.

This should not be a member expression - just the root identifier (i.e. use `"React"` instead of `"React.createElement"`).

Expand Down
7 changes: 5 additions & 2 deletions packages/scope-manager/src/analyze.ts
Expand Up @@ -38,7 +38,7 @@ interface AnalyzeOptions {
* This should not be a member expression - just the root identifier (i.e. use "React" instead of "React.createElement").
* Defaults to `"React"`.
*/
jsxPragma?: string;
jsxPragma?: string | null;

/**
* The identifier that's used for JSX fragment elements (after transpilation).
Expand Down Expand Up @@ -108,7 +108,10 @@ function analyze(
globalReturn: providedOptions?.globalReturn ?? DEFAULT_OPTIONS.globalReturn,
impliedStrict:
providedOptions?.impliedStrict ?? DEFAULT_OPTIONS.impliedStrict,
jsxPragma: providedOptions?.jsxPragma ?? DEFAULT_OPTIONS.jsxPragma,
jsxPragma:
providedOptions?.jsxPragma === undefined
? DEFAULT_OPTIONS.jsxPragma
: providedOptions.jsxPragma,
jsxFragmentName:
providedOptions?.jsxFragmentName ?? DEFAULT_OPTIONS.jsxFragmentName,
sourceType: providedOptions?.sourceType ?? DEFAULT_OPTIONS.sourceType,
Expand Down
6 changes: 3 additions & 3 deletions packages/scope-manager/src/referencer/Referencer.ts
Expand Up @@ -22,15 +22,15 @@ import { lib as TSLibraries } from '../lib';
import { Scope, GlobalScope } from '../scope';

interface ReferencerOptions extends VisitorOptions {
jsxPragma: string;
jsxPragma: string | null;
jsxFragmentName: string | null;
lib: Lib[];
emitDecoratorMetadata: boolean;
}

// Referencing variables and creating bindings.
class Referencer extends Visitor {
#jsxPragma: string;
#jsxPragma: string | null;
#jsxFragmentName: string | null;
#hasReferencedJsxFactory = false;
#hasReferencedJsxFragmentFactory = false;
Expand Down Expand Up @@ -120,7 +120,7 @@ class Referencer extends Visitor {
}

private referenceJsxPragma(): void {
if (this.#hasReferencedJsxFactory) {
if (this.#jsxPragma === null || this.#hasReferencedJsxFactory) {
return;
}
this.#hasReferencedJsxFactory = this.referenceInSomeUpperScope(
Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/parser-options.ts
Expand Up @@ -29,7 +29,7 @@ interface ParserOptions {
ecmaVersion?: EcmaVersion;

// scope-manager specific
jsxPragma?: string;
jsxPragma?: string | null;
jsxFragmentName?: string | null;
lib?: Lib[];

Expand Down

0 comments on commit 02998ea

Please sign in to comment.