Skip to content

Commit

Permalink
eslint-plugin-react-hooks: Add support for ESLint v9 (#28773)
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon committed Apr 23, 2024
1 parent a94838d commit 6f18664
Show file tree
Hide file tree
Showing 6 changed files with 618 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @jest-environment node
*/

'use strict';

const ESLintTester = require('eslint').RuleTester;
const ESLintTesterV7 = require('eslint-v7').RuleTester;
const ESLintTesterV9 = require('eslint-v9').RuleTester;
const ReactHooksESLintPlugin = require('eslint-plugin-react-hooks');
const ReactHooksESLintRule = ReactHooksESLintPlugin.rules['exhaustive-deps'];

Expand Down Expand Up @@ -4673,17 +4676,8 @@ const tests = {
return <div ref={myRef} />;
}
`,
output: `
function MyComponent() {
const myRef = useRef();
useLayoutEffect_SAFE_FOR_SSR(() => {
const handleMove = () => {};
myRef.current.addEventListener('mousemove', handleMove);
return () => myRef.current.removeEventListener('mousemove', handleMove);
});
return <div ref={myRef} />;
}
`,
// No changes
output: null,
errors: [
`The ref value 'myRef.current' will likely have changed by the time ` +
`this effect cleanup function runs. If this ref points to a node ` +
Expand Down Expand Up @@ -7101,6 +7095,19 @@ const tests = {
message:
"React Hook useEffect has a missing dependency: 'local'. " +
'Either include it or remove the dependency array.',
suggestions: [
{
desc: 'Update the dependencies array to be: [local]',
output: normalizeIndent`
function MyComponent() {
const local = {};
useEffect(() => {
console.log(local);
}, [local]);
}
`,
},
],
},
],
// Keep this until major IDEs and VS Code FB ESLint plugin support Suggestions API.
Expand Down Expand Up @@ -8217,30 +8224,45 @@ if (!process.env.CI) {
testsTypescript.invalid = testsTypescript.invalid.filter(predicate);
}

describe('react-hooks', () => {
const parserOptions = {
describe('rules-of-hooks/exhaustive-deps', () => {
const parserOptionsV7 = {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 6,
sourceType: 'module',
};
const languageOptionsV9 = {
ecmaVersion: 6,
sourceType: 'module',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
};

const testsBabelEslint = {
valid: [...testsFlow.valid, ...tests.valid],
invalid: [...testsFlow.invalid, ...tests.invalid],
};

new ESLintTester({
new ESLintTesterV7({
parser: require.resolve('babel-eslint'),
parserOptions,
}).run('parser: babel-eslint', ReactHooksESLintRule, testsBabelEslint);
parserOptions: parserOptionsV7,
}).run(
'eslint: v7, parser: babel-eslint',
ReactHooksESLintRule,
testsBabelEslint
);

new ESLintTester({
parser: require.resolve('@babel/eslint-parser'),
parserOptions,
new ESLintTesterV9({
languageOptions: {
...languageOptionsV9,
parser: require('@babel/eslint-parser'),
},
}).run(
'parser: @babel/eslint-parser',
'eslint: v9, parser: @babel/eslint-parser',
ReactHooksESLintRule,
testsBabelEslint
);
Expand All @@ -8250,49 +8272,119 @@ describe('react-hooks', () => {
invalid: [...testsTypescript.invalid, ...tests.invalid],
};

new ESLintTester({
new ESLintTesterV7({
parser: require.resolve('@typescript-eslint/parser-v2'),
parserOptions,
parserOptions: parserOptionsV7,
}).run(
'eslint: v7, parser: @typescript-eslint/parser@2.x',
ReactHooksESLintRule,
testsTypescriptEslintParser
);

new ESLintTesterV9({
languageOptions: {
...languageOptionsV9,
parser: require('@typescript-eslint/parser-v2'),
},
}).run(
'parser: @typescript-eslint/parser@2.x',
'eslint: v9, parser: @typescript-eslint/parser@2.x',
ReactHooksESLintRule,
testsTypescriptEslintParser
);

new ESLintTester({
new ESLintTesterV7({
parser: require.resolve('@typescript-eslint/parser-v3'),
parserOptions,
parserOptions: parserOptionsV7,
}).run(
'parser: @typescript-eslint/parser@3.x',
'eslint: v7, parser: @typescript-eslint/parser@3.x',
ReactHooksESLintRule,
testsTypescriptEslintParser
);

new ESLintTester({
new ESLintTesterV9({
languageOptions: {
...languageOptionsV9,
parser: require('@typescript-eslint/parser-v3'),
},
}).run(
'eslint: v9, parser: @typescript-eslint/parser@3.x',
ReactHooksESLintRule,
testsTypescriptEslintParser
);

new ESLintTesterV7({
parser: require.resolve('@typescript-eslint/parser-v4'),
parserOptions,
}).run('parser: @typescript-eslint/parser@4.x', ReactHooksESLintRule, {
valid: [
...testsTypescriptEslintParserV4.valid,
...testsTypescriptEslintParser.valid,
],
invalid: [
...testsTypescriptEslintParserV4.invalid,
...testsTypescriptEslintParser.invalid,
],
});
parserOptions: parserOptionsV7,
}).run(
'eslint: v7, parser: @typescript-eslint/parser@4.x',
ReactHooksESLintRule,
{
valid: [
...testsTypescriptEslintParserV4.valid,
...testsTypescriptEslintParser.valid,
],
invalid: [
...testsTypescriptEslintParserV4.invalid,
...testsTypescriptEslintParser.invalid,
],
}
);

new ESLintTester({
new ESLintTesterV9({
languageOptions: {
...languageOptionsV9,
parser: require('@typescript-eslint/parser-v4'),
},
}).run(
'eslint: v9, parser: @typescript-eslint/parser@4.x',
ReactHooksESLintRule,
{
valid: [
...testsTypescriptEslintParserV4.valid,
...testsTypescriptEslintParser.valid,
],
invalid: [
...testsTypescriptEslintParserV4.invalid,
...testsTypescriptEslintParser.invalid,
],
}
);

new ESLintTesterV7({
parser: require.resolve('@typescript-eslint/parser-v5'),
parserOptions,
}).run('parser: @typescript-eslint/parser@^5.0.0-0', ReactHooksESLintRule, {
valid: [
...testsTypescriptEslintParserV4.valid,
...testsTypescriptEslintParser.valid,
],
invalid: [
...testsTypescriptEslintParserV4.invalid,
...testsTypescriptEslintParser.invalid,
],
});
parserOptions: parserOptionsV7,
}).run(
'eslint: v7, parser: @typescript-eslint/parser@^5.0.0-0',
ReactHooksESLintRule,
{
valid: [
...testsTypescriptEslintParserV4.valid,
...testsTypescriptEslintParser.valid,
],
invalid: [
...testsTypescriptEslintParserV4.invalid,
...testsTypescriptEslintParser.invalid,
],
}
);

new ESLintTesterV9({
languageOptions: {
...languageOptionsV9,
parser: require('@typescript-eslint/parser-v5'),
},
}).run(
'eslint: v9, parser: @typescript-eslint/parser@^5.0.0-0',
ReactHooksESLintRule,
{
valid: [
...testsTypescriptEslintParserV4.valid,
...testsTypescriptEslintParser.valid,
],
invalid: [
...testsTypescriptEslintParserV4.invalid,
...testsTypescriptEslintParser.invalid,
],
}
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @jest-environment node
*/

'use strict';

const ESLintTester = require('eslint').RuleTester;
const ESLintTesterV7 = require('eslint-v7').RuleTester;
const ESLintTesterV9 = require('eslint-v9').RuleTester;
const ReactHooksESLintPlugin = require('eslint-plugin-react-hooks');
const BabelEslintParser = require('@babel/eslint-parser');
const ReactHooksESLintRule = ReactHooksESLintPlugin.rules['rules-of-hooks'];

ESLintTester.setDefaultConfig({
parser: require.resolve('babel-eslint'),
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
},
});

/**
* A string template tag that removes padding from the left side of multi-line strings
* @param {Array} strings array of code strings (only one expected)
Expand Down Expand Up @@ -1461,5 +1457,20 @@ if (!process.env.CI) {
tests.invalid = tests.invalid.filter(predicate);
}

const eslintTester = new ESLintTester();
eslintTester.run('react-hooks', ReactHooksESLintRule, tests);
describe('rules-of-hooks/rules-of-hooks', () => {
new ESLintTesterV7({
parser: require.resolve('babel-eslint'),
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
},
}).run('eslint: v7', ReactHooksESLintRule, tests);

new ESLintTesterV9({
languageOptions: {
parser: BabelEslintParser,
ecmaVersion: 6,
sourceType: 'module',
},
}).run('eslint: v9', ReactHooksESLintRule, tests);
});
6 changes: 4 additions & 2 deletions packages/eslint-plugin-react-hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@
},
"homepage": "https://react.dev/",
"peerDependencies": {
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
},
"devDependencies": {
"@babel/eslint-parser": "^7.11.4",
"@typescript-eslint/parser-v2": "npm:@typescript-eslint/parser@^2.26.0",
"@typescript-eslint/parser-v3": "npm:@typescript-eslint/parser@^3.10.0",
"@typescript-eslint/parser-v4": "npm:@typescript-eslint/parser@^4.1.0",
"@typescript-eslint/parser-v5": "npm:@typescript-eslint/parser@^5.0.0-0",
"babel-eslint": "^10.0.3"
"babel-eslint": "^10.0.3",
"eslint-v7": "npm:eslint@^7.7.0",
"eslint-v9": "npm:eslint@^9.0.0"
}
}

0 comments on commit 6f18664

Please sign in to comment.