diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index acc07069d3..0000000000 --- a/.eslintrc +++ /dev/null @@ -1,93 +0,0 @@ -{ - "env": { - "jest/globals": true, - }, - "parser": '@babel/eslint-parser', - "parserOptions": { - sourceType: 'module', - }, - "extends": [ - "airbnb", - "plugin:react/recommended", - "plugin:react-hooks/recommended", - "plugin:jest-dom/recommended", - "plugin:testing-library/react" - ], - "globals": { - "page": true, - "document": true - }, - "plugins": ["jest", "jest-dom", "react", "react-hooks", "testing-library"], - "rules": { - "import/no-unresolved": [ - 2, { "ignore": ["test-utils"] } - ], - "import/prefer-default-export": "off", - "no-console": "off", - "no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true }], - 'no-unused-vars': 'off', - 'no-undef': 'off', - 'no-restricted-syntax': ['warn', 'WithStatement'], - 'no-restricted-globals': ['error'], - eqeqeq: ['warn', 'smart'], - 'no-use-before-define': [ - 'warn', - { - functions: false, - classes: false, - variables: false, - }, - ], - 'no-mixed-operators': [ - 'warn', - { - groups: [ - ['&', '|', '^', '~', '<<', '>>', '>>>'], - ['==', '!=', '===', '!==', '>', '>=', '<', '<='], - ['&&', '||'], - ['in', 'instanceof'], - ], - allowSamePrecedence: false, - }, - ], - "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], - "require-jsdoc": ["error", { - "require": { - "FunctionDeclaration": true, - "MethodDefinition": true, - "ClassDeclaration": true, - "ArrowFunctionExpression": true, - "FunctionExpression": true - } - }], - "no-underscore-dangle": "off", - "react/prefer-stateless-function": "off", - "sort-keys": ["error", "asc", { - "caseSensitive": false, - "natural": false - }], - "react/jsx-props-no-spreading": "off", - "react/function-component-definition": "off", - "default-param-last": "off", - "arrow-parens": "off", - "import/no-anonymous-default-export": "off", - "max-len": ["error", { - "code": 120, - "ignoreComments": true, - "ignoreStrings": true, - "ignoreTemplateLiterals": true, - "ignoreRegExpLiterals": true - }], - "react/jsx-uses-react": "off", - "react/react-in-jsx-scope": "off", - "react/require-default-props": "off", - "react-hooks/exhaustive-deps": "error", - "testing-library/render-result-naming-convention": "off", - "testing-library/no-render-in-lifecycle": [ - "error", - { - "allowTestingFrameworkSetupHook": "beforeEach" - } - ] - } -} diff --git a/__tests__/src/components/WorkspaceElastic.test.js b/__tests__/src/components/WorkspaceElastic.test.js index e88a99dfbc..30db9441d2 100644 --- a/__tests__/src/components/WorkspaceElastic.test.js +++ b/__tests__/src/components/WorkspaceElastic.test.js @@ -67,6 +67,7 @@ describe('WorkspaceElastic', () => { setWorkspaceViewportPosition: mockDragStop, }); + /** */ container.getBoundingClientRect = () => ({ left: -2500, offsetHeight: 5000, diff --git a/__tests__/src/components/WorkspaceElasticWindow.test.js b/__tests__/src/components/WorkspaceElasticWindow.test.js index 03f565afd1..c4ce05f311 100644 --- a/__tests__/src/components/WorkspaceElasticWindow.test.js +++ b/__tests__/src/components/WorkspaceElasticWindow.test.js @@ -90,6 +90,7 @@ describe('WorkspaceElasticWindow', () => { updateElasticWindowLayout: mockOnResize, }); + /** */ container.getBoundingClientRect = () => ({ left: -2500, offsetHeight: 5000, diff --git a/__tests__/utils/test-utils.js b/__tests__/utils/test-utils.js index 2e30b405cb..ce67f6f340 100644 --- a/__tests__/utils/test-utils.js +++ b/__tests__/utils/test-utils.js @@ -41,5 +41,5 @@ function renderWithProviders( }; } -export * from '@testing-library/react'; +export * from '@testing-library/react'; // eslint-disable-line import/export export { renderWithProviders as render }; diff --git a/babel.config.js b/babel.config.js index 94f006cfcf..10f61c42ea 100644 --- a/babel.config.js +++ b/babel.config.js @@ -8,7 +8,7 @@ const moduleFormatMap = { es: false, }; -// eslint-disable-next-line func-names +// eslint-disable-next-line jsdoc/require-jsdoc module.exports = function (api) { const isDevelopmentEnv = api.env('development'); const isProductionEnv = api.env('production'); diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000..ad5e80c9cd --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,140 @@ +import { fixupConfigRules, fixupPluginRules } from "@eslint/compat"; +import jest from "eslint-plugin-jest"; +import jestDom from "eslint-plugin-jest-dom"; +import jsxA11y from 'eslint-plugin-jsx-a11y'; +import react from "eslint-plugin-react"; +import reactHooks from "eslint-plugin-react-hooks"; +import testingLibrary from "eslint-plugin-testing-library"; +import jsdoc from 'eslint-plugin-jsdoc'; +import babelParser from "@babel/eslint-parser"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + allConfig: js.configs.all, + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, +}); + +export default [{ + ignores: ["**/dist/", "**/config/", "**/coverage/", "**/styles/"], +}, ...fixupConfigRules(compat.extends( + "plugin:import/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:jest-dom/recommended", + "plugin:jsx-a11y/recommended", + "plugin:testing-library/react", +)), { + + languageOptions: { + ecmaVersion: 6, + globals: { + ...jest.environments.globals.globals, + document: true, + page: true, + }, + parser: babelParser, + sourceType: "module", + }, + plugins: { + jest, + "jest-dom": fixupPluginRules(jestDom), + jsdoc, + jsxA11y, + react: fixupPluginRules(react), + "react-hooks": fixupPluginRules(reactHooks), + "testing-library": fixupPluginRules(testingLibrary), + }, + + rules: { + "arrow-parens": "off", + "default-param-last": "off", + eqeqeq: ["warn", "smart"], + "import/no-anonymous-default-export": "off", + + + "import/no-unresolved": [2, { + ignore: ["test-utils"], + }], + + "import/prefer-default-export": "off", + + "jsdoc/require-jsdoc": ["error", { + minLineCount: 6, + require: { + ArrowFunctionExpression: true, + ClassDeclaration: true, + FunctionDeclaration: true, + FunctionExpression: true, + MethodDefinition: true, + }, + }], + + "jsx-a11y/no-autofocus": "warn", + + "max-len": ["error", { + code: 120, + ignoreComments: true, + ignoreRegExpLiterals: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + }], + "no-console": "off", + + "no-mixed-operators": ["warn", { + allowSamePrecedence: false, + groups: [ + ["&", "|", "^", "~", "<<", ">>", ">>>"], + ["==", "!=", "===", "!==", ">", ">=", "<", "<="], + ["&&", "||"], + ["in", "instanceof"], + ], + }], + "no-param-reassign": ["error", { "props": false }], + + "no-restricted-globals": ["error"], + "no-restricted-syntax": ["warn", "WithStatement"], + "no-undef": "off", + "no-underscore-dangle": "off", + "no-unused-expressions": ["error", { + allowShortCircuit: true, + allowTernary: true, + }], + "no-unused-vars": "off", + + "no-use-before-define": ["warn", { + classes: false, + functions: false, + variables: false, + }], + + "react-hooks/exhaustive-deps": "error", + + "react/function-component-definition": "off", + + "react/jsx-filename-extension": [1, { + extensions: [".js", ".jsx"], + }], + + "react/jsx-props-no-spreading": "off", + "react/jsx-uses-react": "off", + "react/prefer-stateless-function": "off", + "react/react-in-jsx-scope": "off", + "react/require-default-props": "off", + "sort-keys": ["error", "asc", { + caseSensitive: false, + natural: false, + }], + + "testing-library/no-render-in-lifecycle": ["error", { + allowTestingFrameworkSetupHook: "beforeEach", + }], + "testing-library/render-result-naming-convention": "off", + + }, +}]; diff --git a/package.json b/package.json index 6a05043cbc..61d60e5811 100644 --- a/package.json +++ b/package.json @@ -87,13 +87,16 @@ "@babel/plugin-transform-runtime": "^7.22.10", "@babel/preset-env": "^7.22.10", "@babel/preset-react": "^7.22.10", + "@eslint/compat": "^1.2.2", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.13.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.4", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.1.5", "@testing-library/react": "^16.0.1", "@testing-library/user-event": "^14.4.3", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^8.12.0", + "@typescript-eslint/parser": "^8.12.0", "babel-jest": "^29.3.1", "babel-loader": "^9.1.0", "babel-plugin-lodash": "^3.3.4", @@ -103,16 +106,15 @@ "canvas": "^2.11.0", "chalk": "^4.1.0", "core-js": "^3.21.1", - "eslint": "^8.11.0", - "eslint-config-airbnb": "^19.0.4", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.4", - "eslint-plugin-jest": "^27.1.5", + "eslint": "^9.0.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jest": "^28.8.3", "eslint-plugin-jest-dom": "^5.1.0", - "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-jsdoc": "^50.4.3", + "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.29.4", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-testing-library": "^6.2.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-testing-library": "^7.0.0-beta.3", "glob": "^10.3.0", "http-server": "^14.1.0", "jest": "^29.3.1", diff --git a/setupJest.js b/setupJest.js index af9f272bcf..5d937f07a6 100644 --- a/setupJest.js +++ b/setupJest.js @@ -43,7 +43,7 @@ jest.mock('react-i18next', () => ({ init: jest.fn(), type: '3rdParty', }, - // this mock makes sure any components using the translate HoC receive the t function as a prop + /** this mock makes sure any components using the translate HoC receive the t function as a prop */ withTranslation: () => (Component) => { Component.defaultProps = { // eslint-disable-line no-param-reassign ...Component.defaultProps, t: k => k, diff --git a/src/components/GalleryViewThumbnail.js b/src/components/GalleryViewThumbnail.js index efa36629d2..6e71532d04 100644 --- a/src/components/GalleryViewThumbnail.js +++ b/src/components/GalleryViewThumbnail.js @@ -64,7 +64,7 @@ export class GalleryViewThumbnail extends Component { this.handleIntersection = this.handleIntersection.bind(this); } - // eslint-disable-next-line require-jsdoc + // eslint-disable-next-line jsdoc/require-jsdoc componentDidMount() { const { selected } = this.props; if (selected) { diff --git a/src/components/SidebarIndexList.js b/src/components/SidebarIndexList.js index d19394ef97..be8154250d 100644 --- a/src/components/SidebarIndexList.js +++ b/src/components/SidebarIndexList.js @@ -54,7 +54,7 @@ export class SidebarIndexList extends Component { { canvasesIdAndLabel.map((canvas, canvasIndex) => { - const onClick = () => { setCanvas(windowId, canvas.id); }; // eslint-disable-line require-jsdoc, max-len + const onClick = () => { setCanvas(windowId, canvas.id); }; // eslint-disable-line jsdoc/require-jsdoc, max-len return ( ({ }, }); +/** */ module.exports = (env, options) => { const isProduction = options.mode === 'production'; const config = baseConfig(options.mode);