From d5e3769fac7c8735f08b9db9f6363d6e3016d04a Mon Sep 17 00:00:00 2001 From: HenryBrown0 <26250092+HenryBrown0@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:37:18 +0000 Subject: [PATCH 1/5] [Tests] use `require.resolve` to get absolute paths to parsers --- tests/helpers/parsers.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/helpers/parsers.js b/tests/helpers/parsers.js index 24cc12bdb9..cbd6568d01 100644 --- a/tests/helpers/parsers.js +++ b/tests/helpers/parsers.js @@ -1,6 +1,5 @@ 'use strict'; -const path = require('path'); const semver = require('semver'); const entries = require('object.entries'); const version = require('eslint/package.json').version; @@ -31,13 +30,11 @@ function minEcmaVersion(features, parserOptions) { return Number.isFinite(result) ? result : undefined; } -const NODE_MODULES = '../../node_modules'; - const parsers = { - BABEL_ESLINT: path.join(__dirname, NODE_MODULES, 'babel-eslint'), - '@BABEL_ESLINT': path.join(__dirname, NODE_MODULES, '@babel/eslint-parser'), - TYPESCRIPT_ESLINT: path.join(__dirname, NODE_MODULES, 'typescript-eslint-parser'), - '@TYPESCRIPT_ESLINT': path.join(__dirname, NODE_MODULES, '@typescript-eslint/parser'), + BABEL_ESLINT: require.resolve('babel-eslint'), + '@BABEL_ESLINT': require.resolve('@babel/eslint-parser'), + TYPESCRIPT_ESLINT: require.resolve('typescript-eslint-parser'), + '@TYPESCRIPT_ESLINT': require.resolve('@typescript-eslint/parser'), disableNewTS, skipDueToMultiErrorSorting: semver.satisfies(process.versions.node, '^8 || ^9'), babelParserOptions: function parserOptions(test, features) { From c4fcff988a7d502c38b939e4bcbf7395af9b3f4b Mon Sep 17 00:00:00 2001 From: HenryBrown0 <26250092+HenryBrown0@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:46:10 +0000 Subject: [PATCH 2/5] [Tests] add `@typescript-eslint/parser` v6, v7, v8 - only install peer dependencies with legacy mode when testing @typescript-eslint/parser < v6 --- .github/workflows/node-18+.yml | 62 ++++++++++++++++++++++++++++++- .github/workflows/node-minors.yml | 4 +- CHANGELOG.md | 5 +++ package.json | 2 +- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/.github/workflows/node-18+.yml b/.github/workflows/node-18+.yml index 7dcb4daff5..ee7d126939 100644 --- a/.github/workflows/node-18+.yml +++ b/.github/workflows/node-18+.yml @@ -38,6 +38,64 @@ jobs: - 10 - 9 - 8 + typescript-eslint: + - 5 + - 6 + - 7 + - 8 + exclude: + - eslint: 3 + babel-eslint: 10 + - eslint: 3 + typescript-eslint: 5 + - eslint: 4 + typescript-eslint: 5 + - eslint: 4.14 + typescript-eslint: 5 + - eslint: 5 + typescript-eslint: 5 + - eslint: 3 + typescript-eslint: 6 + - eslint: 4 + typescript-eslint: 6 + - eslint: 4.14 + typescript-eslint: 6 + - eslint: 5 + typescript-eslint: 6 + - eslint: 6 + typescript-eslint: 6 + - eslint: 9 + typescript-eslint: 6 + - eslint: 3 + typescript-eslint: 7 + - eslint: 4 + typescript-eslint: 7 + - eslint: 4.14 + typescript-eslint: 7 + - eslint: 5 + typescript-eslint: 7 + - eslint: 6 + typescript-eslint: 7 + - eslint: 7 + typescript-eslint: 7 + - eslint: 9 + typescript-eslint: 7 + - eslint: 3 + typescript-eslint: 8 + - eslint: 4 + typescript-eslint: 8 + - eslint: 4.14 + typescript-eslint: 8 + - eslint: 5 + typescript-eslint: 8 + - eslint: 6 + typescript-eslint: 8 + - eslint: 7 + typescript-eslint: 8 + - eslint: 9 + typescript-eslint: 5 + - node-version: 19 + typescript-eslint: 7 steps: - uses: actions/checkout@v4 @@ -46,9 +104,9 @@ jobs: with: node-version: ${{ matrix.node-version }} after_install: | - npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@5" "babel-eslint@${{ matrix.babel-eslint }}" + npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.typescript-eslint }}" "babel-eslint@${{ matrix.babel-eslint }}" env: - NPM_CONFIG_LEGACY_PEER_DEPS: true + NPM_CONFIG_LEGACY_PEER_DEPS: "${{ matrix.typescript-eslint >= 6 && 'false' || 'true' }}" - run: npx ls-engines - run: npm run unit-test - uses: codecov/codecov-action@v3.1.5 diff --git a/.github/workflows/node-minors.yml b/.github/workflows/node-minors.yml index 548b571dd2..69f92684ea 100644 --- a/.github/workflows/node-minors.yml +++ b/.github/workflows/node-minors.yml @@ -100,10 +100,10 @@ jobs: with: node-version: ${{ matrix.node-version }} after_install: | - npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.node-version >= 14 && '5' || (matrix.node-version >= 12 && '4' || (matrix.node-version >= 10 && '4.0' || (matrix.node-version >= 8 && '3' || '2'))) }}" "babel-eslint@${{ matrix.babel-eslint }}" + npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.node-version >= 18 && matrix.eslint >= 8 && '8' || (matrix.node-version >= 16 && matrix.eslint >= 7 && '6' || (matrix.node-version >= 14 && '5' || (matrix.node-version >= 12 && '4' || (matrix.node-version >= 10 && '4.0' || (matrix.node-version >= 8 && '3' || '2'))))) }}" "babel-eslint@${{ matrix.babel-eslint }}" skip-ls-check: ${{ matrix.node-version < 10 && true || false }} env: - NPM_CONFIG_LEGACY_PEER_DEPS: true + NPM_CONFIG_LEGACY_PEER_DEPS: "${{ matrix.node-version >= 16 && matrix.eslint >= 7 && 'false' || 'true' }}" - run: npx ls-engines if: ${{ matrix.node-version >= 12 }} - run: npm run unit-test diff --git a/CHANGELOG.md b/CHANGELOG.md index 63bc11a1f8..a6e47db56b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Added * [`no-string-refs`]: allow this.refs in > 18.3.0 ([#3807][] @henryqdineen) +### Changed +* [Tests] add @typescript-eslint/parser v6 ([#3629][] @HenryBrown0) +* [Tests] add @typescript-eslint/parser v7 and v8 ([#3629][] @hampustagerud) + +[#3629]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3629 [#3807]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3807 ## [7.35.2] - 2024.09.03 diff --git a/package.json b/package.json index 3b157996cc..d0ca2ada83 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@types/eslint": "=7.2.10", "@types/estree": "0.0.52", "@types/node": "^4.9.5", - "@typescript-eslint/parser": "^2.34.0 || ^3.10.1 || ^4.0.0 || ^5.0.0", + "@typescript-eslint/parser": "^2.34.0 || ^3.10.1 || ^4 || ^5 || ^6.20 || ^7.14.1 || ^8.4", "babel-eslint": "^8 || ^9 || ^10.1.0", "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint-config-airbnb-base": "^15.0.0", From 30bb5f417271fdf0031bcceea31be962b844fa20 Mon Sep 17 00:00:00 2001 From: HenryBrown0 <26250092+HenryBrown0@users.noreply.github.com> Date: Mon, 4 Sep 2023 20:10:26 +0100 Subject: [PATCH 3/5] [Fix] `function-component-definition`, `boolean-prop-naming`, `jsx-first-prop-new-line`, `jsx-props-no-multi-spaces`, `propTypes`: use type args --- CHANGELOG.md | 4 +++ lib/rules/boolean-prop-naming.js | 12 ++++--- lib/rules/function-component-definition.js | 14 ++++---- lib/rules/jsx-first-prop-new-line.js | 4 ++- lib/rules/jsx-props-no-multi-spaces.js | 11 +++--- lib/util/propTypes.js | 42 ++++++++++++---------- lib/util/props.js | 13 +++++++ 7 files changed, 64 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6e47db56b..12c9e1f850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Change Log + All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](https://keepachangelog.com). @@ -8,6 +9,9 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Added * [`no-string-refs`]: allow this.refs in > 18.3.0 ([#3807][] @henryqdineen) +### Fixed +* [`function-component-definition`], [`boolean-prop-naming`], [`jsx-first-prop-new-line`], [`jsx-props-no-multi-spaces`], `propTypes`: use type args ([#3629][] @HenryBrown0) + ### Changed * [Tests] add @typescript-eslint/parser v6 ([#3629][] @HenryBrown0) * [Tests] add @typescript-eslint/parser v7 and v8 ([#3629][] @hampustagerud) diff --git a/lib/rules/boolean-prop-naming.js b/lib/rules/boolean-prop-naming.js index 27becc4525..afa844a903 100644 --- a/lib/rules/boolean-prop-naming.js +++ b/lib/rules/boolean-prop-naming.js @@ -259,14 +259,16 @@ module.exports = { return; } - const annotationTypeParams = component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters; + const annotationTypeArguments = propsUtil.getTypeArguments( + component.node.parent.id.typeAnnotation.typeAnnotation + ); if ( - annotationTypeParams && ( - annotationTypeParams.type === 'TSTypeParameterInstantiation' - || annotationTypeParams.type === 'TypeParameterInstantiation' + annotationTypeArguments && ( + annotationTypeArguments.type === 'TSTypeParameterInstantiation' + || annotationTypeArguments.type === 'TypeParameterInstantiation' ) ) { - return annotationTypeParams.params.find( + return annotationTypeArguments.params.find( (param) => param.type === 'TSTypeReference' || param.type === 'GenericTypeAnnotation' ); } diff --git a/lib/rules/function-component-definition.js b/lib/rules/function-component-definition.js index 24ad3f48d7..cca665abe2 100644 --- a/lib/rules/function-component-definition.js +++ b/lib/rules/function-component-definition.js @@ -10,6 +10,7 @@ const Components = require('../util/Components'); const docsUrl = require('../util/docsUrl'); const reportC = require('../util/report'); const getText = require('../util/eslint').getText; +const propsUtil = require('../util/props'); // ------------------------------------------------------------------------------ // Rule Definition @@ -34,12 +35,12 @@ const UNNAMED_FUNCTION_TEMPLATES = { }; function hasOneUnconstrainedTypeParam(node) { - const nodeTypeParams = node.typeParameters; + const nodeTypeArguments = propsUtil.getTypeArguments(node); - return nodeTypeParams - && nodeTypeParams.params - && nodeTypeParams.params.length === 1 - && !nodeTypeParams.params[0].constraint; + return nodeTypeArguments + && nodeTypeArguments.params + && nodeTypeArguments.params.length === 1 + && !nodeTypeArguments.params[0].constraint; } function hasName(node) { @@ -202,11 +203,12 @@ module.exports = { varType = node.parent.parent.kind; } + const nodeTypeArguments = propsUtil.getTypeArguments(node); return (fixer) => fixer.replaceTextRange( options.range, buildFunction(options.template, { typeAnnotation, - typeParams: getNodeText(node.typeParameters, source), + typeParams: getNodeText(nodeTypeArguments, source), params: getParams(node, source), returnType: getNodeText(node.returnType, source), body: getBody(node, source), diff --git a/lib/rules/jsx-first-prop-new-line.js b/lib/rules/jsx-first-prop-new-line.js index 7c9d969b51..3014d24f1e 100644 --- a/lib/rules/jsx-first-prop-new-line.js +++ b/lib/rules/jsx-first-prop-new-line.js @@ -7,6 +7,7 @@ const docsUrl = require('../util/docsUrl'); const report = require('../util/report'); +const propsUtil = require('../util/props'); // ------------------------------------------------------------------------------ // Rule Definition @@ -55,7 +56,8 @@ module.exports = { report(context, messages.propOnNewLine, 'propOnNewLine', { node: decl, fix(fixer) { - return fixer.replaceTextRange([(node.typeParameters || node.name).range[1], decl.range[0]], '\n'); + const nodeTypeArguments = propsUtil.getTypeArguments(node); + return fixer.replaceTextRange([(nodeTypeArguments || node.name).range[1], decl.range[0]], '\n'); }, }); } diff --git a/lib/rules/jsx-props-no-multi-spaces.js b/lib/rules/jsx-props-no-multi-spaces.js index ce80338cd8..8402c6d4ff 100644 --- a/lib/rules/jsx-props-no-multi-spaces.js +++ b/lib/rules/jsx-props-no-multi-spaces.js @@ -8,6 +8,7 @@ const docsUrl = require('../util/docsUrl'); const eslintUtil = require('../util/eslint'); const report = require('../util/report'); +const propsUtil = require('../util/props'); const getSourceCode = eslintUtil.getSourceCode; const getText = eslintUtil.getText; @@ -103,18 +104,18 @@ module.exports = { } function containsGenericType(node) { - const nodeTypeParams = node.typeParameters; - if (typeof nodeTypeParams === 'undefined') { + const nodeTypeArguments = propsUtil.getTypeArguments(node); + if (typeof nodeTypeArguments === 'undefined') { return false; } - return nodeTypeParams.type === 'TSTypeParameterInstantiation'; + return nodeTypeArguments.type === 'TSTypeParameterInstantiation'; } function getGenericNode(node) { const name = node.name; if (containsGenericType(node)) { - const type = node.typeParameters; + const nodeTypeArguments = propsUtil.getTypeArguments(node); return Object.assign( {}, @@ -122,7 +123,7 @@ module.exports = { { range: [ name.range[0], - type.range[1], + nodeTypeArguments.range[1], ], } ); diff --git a/lib/util/propTypes.js b/lib/util/propTypes.js index a1dce37d8b..1bba98bad8 100644 --- a/lib/util/propTypes.js +++ b/lib/util/propTypes.js @@ -639,8 +639,8 @@ module.exports = function propTypesInstructions(context, components, utils) { typeName = node.typeName.name; const leftMostName = getLeftMostTypeName(node.typeName); const shouldTraverseTypeParams = genericReactTypesImport.has(leftMostName); - const nodeTypeParams = node.typeParameters; - if (shouldTraverseTypeParams && nodeTypeParams && nodeTypeParams.length !== 0) { + const nodeTypeArguments = propsUtil.getTypeArguments(node); + if (shouldTraverseTypeParams && nodeTypeArguments && nodeTypeArguments.length !== 0) { // All react Generic types are derived from: // type PropsWithChildren
= P & { children?: ReactNode | undefined }
// So we should construct an optional children prop
@@ -662,7 +662,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
const idx = genericTypeParamIndexWherePropsArePresent[
leftMostName !== rightMostName ? rightMostName : importedName
];
- const nextNode = nodeTypeParams.params[idx];
+ const nextNode = nodeTypeArguments.params[idx];
this.visitTSNode(nextNode);
return;
}
@@ -759,10 +759,10 @@ module.exports = function propTypesInstructions(context, components, utils) {
convertReturnTypeToPropTypes(node, rootNode) {
// ReturnType