Migrate ESLint to v 9.x

This bumps needed dependencies and migrates previously used ESLint configs to the new flat config schema.
This commit is contained in:
regexowl 2025-07-08 14:15:19 +02:00 committed by Klara Simickova
parent 10a40aaec4
commit 3f35101f68
12 changed files with 1244 additions and 559 deletions

View file

@ -1,8 +0,0 @@
# Ignore programatically generated API slices
imageBuilderApi.ts
contentSourcesApi.ts
rhsmApi.ts
provisioningApi.ts
edgeApi.ts
complianceApi.ts
composerCloudApi.ts

View file

@ -1,65 +0,0 @@
extends: [
"plugin:jsx-a11y/recommended",
"@redhat-cloud-services/eslint-config-redhat-cloud-services",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-redux/recommended"
]
globals:
insights: 'readonly'
shallow: readonly
render: 'readonly'
mount: 'readonly'
parser: "@typescript-eslint/parser"
parserOptions:
project: ["tsconfig.json"]
plugins:
- import
- disable-autofix
rules:
import/order:
- error
- groups:
- builtin
- external
- internal
- sibling
- parent
- index
alphabetize:
order: asc
caseInsensitive: true
newlines-between: always
pathGroups: # ensures the import of React is always on top
- pattern: react
group: builtin
position: before
pathGroupsExcludedImportTypes:
- react
prefer-const:
- error
- destructuring: any
no-console: error
eqeqeq: error
array-callback-return: warn
"@typescript-eslint/ban-ts-comment":
- error
- ts-expect-error: "allow-with-description"
ts-ignore: "allow-with-description"
ts-nocheck: true
ts-check: true
minimumDescriptionLength: 5
"@typescript-eslint/ban-types": off
disable-autofix/@typescript-eslint/no-unnecessary-condition: warn
# Temporarily disabled
jsx-a11y/no-autofocus: off
rulesdir/forbid-pf-relative-imports: off
overrides:
- files: ["src/tests/**/*.ts"]
extends: "plugin:testing-library/react"
- files: ["playwright/**/*.ts"]
extends: "plugin:playwright/recommended"
rules:
playwright/no-conditional-in-test: off
playwright/no-conditional-expect: off

View file

@ -185,10 +185,13 @@ npx @rtk-query/codegen-openapi ./api/config/foobar.ts &
```
6. Update the `.eslintignore` file by adding a new line for the generated code:
6. Update the `eslint.config.js` file by adding the generated code path to the ignores array:
```
foobarApi.ts
ignores: [
<other ignored files>,
'**/foobarApi.ts',
]
```
7. run api generation
@ -250,8 +253,19 @@ we're planning on using.
## Style Guidelines
This project uses eslint's recommended styling guidelines. These rules can be found here:
https://eslint.org/docs/rules/
This project uses recommended rule sets rom several plugins:
- `@eslint/js`
- `typescript-eslint`
- `eslint-plugin-react`
- `eslint-plugin-react-hooks`
- `eslint-plugin-react-redux`
- `eslint-plugin-import`
- `eslint-plugin-jsx-a11y`
- `eslint-plugin-disable-autofix`
- `eslint-plugin-jest-dom`
- `eslint-plugin-testing-library`
- `eslint-plugin-playwright`
- `@redhat-cloud-services/eslint-config-redhat-cloud-services`
To run the linter, use:
```bash
@ -260,16 +274,10 @@ npm run lint
Any errors that can be fixed automatically, can be corrected by running:
```bash
npm run lint --fix
npm run lint:js:fix
```
All the linting rules and configuration of eslint can be found in [`.eslintrc.yml`](https://github.com/RedHatInsights/image-builder-frontend/blob/main/.eslintrc.yml).
### Additional eslint rules
There are also additional rules added to enforce code style. Those being:
- `import/order` -> enforces the order in import statements and separates them into groups based on their type
- `prefer-const` -> enforces use of `const` declaration for variables that are never reassigned
- `no-console` -> throws an error for any calls of `console` methods leftover after debugging
All the linting rules and configuration of ESLint can be found in [`eslint.config.js`](https://github.com/RedHatInsights/image-builder-frontend/blob/main/eslint.config.js).
## Test Guidelines

144
eslint.config.js Normal file
View file

@ -0,0 +1,144 @@
const js = require('@eslint/js');
const tseslint = require('typescript-eslint');
const pluginReact = require('eslint-plugin-react');
const pluginReactHooks = require('eslint-plugin-react-hooks');
const pluginReactRedux = require('eslint-plugin-react-redux');
const pluginImport = require('eslint-plugin-import');
const fecConfig = require('@redhat-cloud-services/eslint-config-redhat-cloud-services');
const pluginJsxA11y = require('eslint-plugin-jsx-a11y');
const disableAutofix = require('eslint-plugin-disable-autofix');
const jestDom = require('eslint-plugin-jest-dom');
const pluginTestingLibrary = require('eslint-plugin-testing-library');
const pluginPlaywright = require('eslint-plugin-playwright');
const { defineConfig } = require('eslint/config');
const globals = require('globals');
module.exports = defineConfig([
{ // Ignore programatically generated files
ignores: [
'**/mockServiceWorker.js',
'**/imageBuilderApi.ts',
'**/contentSourcesApi.ts',
'**/rhsmApi.ts',
'**/provisioningApi.ts',
'**/edgeApi.ts',
'**/complianceApi.ts',
'**/composerCloudApi.ts'
]
},
{ // Base config for js/ts files
files: ['**/*.{js,ts,jsx,tsx}'],
languageOptions: {
parser: tseslint.parser,
parserOptions: {
project: './tsconfig.json'
},
globals: {
...globals.browser,
// node
'JSX': 'readonly',
'process': 'readonly',
'__dirname': 'readonly',
'require': 'readonly',
// vitest
'describe': 'readonly',
'it': 'readonly',
'test': 'readonly',
'expect': 'readonly',
'vi': 'readonly',
'beforeAll': 'readonly',
'beforeEach': 'readonly',
'afterAll': 'readonly',
'afterEach': 'readonly'
},
},
plugins: {
js,
'@typescript-eslint': tseslint.plugin,
react: pluginReact,
'react-hooks': pluginReactHooks,
'react-redux': pluginReactRedux,
import: pluginImport,
jsxA11y: pluginJsxA11y,
'disable-autofix': disableAutofix,
},
rules: {
...js.configs.recommended.rules,
...tseslint.configs.recommended.rules,
...pluginReact.configs.flat.recommended.rules,
...pluginReactHooks.configs.recommended.rules,
...pluginReactRedux.configs.recommended.rules,
...fecConfig.rules,
'import/order': ['error', {
groups: ['builtin', 'external', 'internal', 'sibling', 'parent', 'index'],
alphabetize: {
order: 'asc',
caseInsensitive: true
},
'newlines-between': 'always',
pathGroups: [ // ensures the import of React is always on top
{
pattern: 'react',
group: 'builtin',
position: 'before'
}
],
pathGroupsExcludedImportTypes: ['react']
}],
'prefer-const': ['error', {
destructuring: 'any',
}],
'no-console': 'error',
'eqeqeq': 'error',
'array-callback-return': 'warn',
'@typescript-eslint/ban-ts-comment': ['error', {
'ts-expect-error': 'allow-with-description',
'ts-ignore': 'allow-with-description',
'ts-nocheck': true,
'ts-check': true,
minimumDescriptionLength: 5,
}],
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unsafe-function-type': 'error',
'@typescript-eslint/no-require-imports': 'error',
'disable-autofix/@typescript-eslint/no-unnecessary-condition': 'warn',
'no-unused-vars': 'off', // disable js rule in favor of @typescript-eslint's rule
'@typescript-eslint/no-unused-vars': 'warn',
'jsx-a11y/no-autofocus': 'off',
},
settings: {
react: {
version: 'detect', // Automatically detect React version
},
},
},
{ // Override for test files
files: ['src/test/**/*.{ts,tsx}'],
plugins: {
'jest-dom': jestDom,
'testing-library': pluginTestingLibrary,
},
rules: {
...jestDom.configs.recommended.rules,
...pluginTestingLibrary.configs.react.rules,
'react/display-name': 'off',
'react/prop-types': 'off',
'testing-library/no-debugging-utils': 'error'
},
},
{ // Override for Playwright tests
files: ['playwright/**/*.ts'],
plugins: {
playwright: pluginPlaywright,
},
rules: {
...pluginPlaywright.configs.recommended.rules,
'playwright/no-conditional-in-test': 'off',
'playwright/no-conditional-expect': 'off',
},
},
]);

1523
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -35,9 +35,10 @@
"@babel/preset-react": "7.27.1",
"@babel/preset-typescript": "7.27.1",
"@currents/playwright": "1.15.1",
"@eslint/js": "9.30.1",
"@patternfly/react-icons": "6.1.0",
"@playwright/test": "1.51.1",
"@redhat-cloud-services/eslint-config-redhat-cloud-services": "2.0.12",
"@redhat-cloud-services/eslint-config-redhat-cloud-services": "3.0.0",
"@redhat-cloud-services/frontend-components-config": "6.3.8",
"@redhat-cloud-services/tsc-transform-imports": "1.0.25",
"@rtk-query/codegen-openapi": "2.0.0",
@ -60,7 +61,7 @@
"chartjs-plugin-annotation": "3.1.0",
"copy-webpack-plugin": "13.0.0",
"css-loader": "7.1.2",
"eslint": "8.57.1",
"eslint": "9.30.1",
"eslint-plugin-disable-autofix": "5.0.1",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-jest-dom": "5.5.0",
@ -71,6 +72,7 @@
"eslint-plugin-react-redux": "4.2.2",
"eslint-plugin-testing-library": "7.5.4",
"git-revision-webpack-plugin": "5.0.0",
"globals": "16.3.0",
"history": "5.3.0",
"identity-obj-proxy": "3.0.0",
"jsdom": "26.1.0",
@ -90,6 +92,7 @@
"ts-node": "10.9.2",
"ts-patch": "3.3.0",
"typescript": "5.8.3",
"typescript-eslint": "8.35.1",
"uuid": "11.1.0",
"vitest": "3.2.4",
"vitest-canvas-mock": "0.3.3",

View file

@ -11,7 +11,6 @@ export interface Cleanup {
}
export const test = oldTest.extend<WithCleanup>({
// eslint-disable-next-line no-empty-pattern
cleanup: async ({}, use) => {
const cleanupFns: Map<symbol, () => Promise<unknown>> = new Map();

View file

@ -11,7 +11,6 @@ export const test = base.extend<PopupHandlerFixture>({
popupHandler: [
async ({ page }, use) => {
await closePopupsIfExist(page);
// eslint-disable-next-line react-hooks/rules-of-hooks
await use(undefined);
},
{ auto: true },

View file

@ -814,8 +814,6 @@ const Packages = () => {
return [];
}
}
return combinedGroupData;
}, [
dataDistroGroups,
dataCustomGroups,

View file

@ -2,7 +2,6 @@ import React, { useState } from 'react';
import { Button, Popover, Content, Flex } from '@patternfly/react-core';
import { ExternalLinkAltIcon, HelpIcon } from '@patternfly/react-icons';
// eslint-disable-next-line rulesdir/disallow-fec-relative-imports
import {
OpenSourceBadge,
PageHeader,

View file

@ -1,18 +0,0 @@
{
"env": {
"es6": true
},
"plugins": [
"testing-library",
"jest-dom"
],
"rules": {
"react/display-name": "off",
"react/prop-types": "off",
"testing-library/no-debugging-utils": "error"
},
"extends": [
"plugin:testing-library/react",
"plugin:jest-dom/recommended"
]
}

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import path from 'path';
import { mockComposes } from '../../fixtures/composes';