新 ESLint 配置的问题

问题描述 投票:0回答:1

我正在将 ESLint 配置从 8 升级到 9.14.0。但是现在创建

eslint.config.js
文件后,当我运行
npx eslint
时,它给了我奇怪的错误。例如,我有一个名为
QuestionnaireTabNavigator.js
的组件文件,它正在使用一些组件,我在代码中使用它们,但在 ESLint 中仍然遇到问题,例如:

   3:10  error  'Tab' is defined but never used                           no-unused-vars
   3:15  error  'Tabs' is defined but never used                          no-unused-vars
   9:8   error  'AssessmentSelector' is defined but never used            no-unused-vars
  10:8   error  'AssessmentsTable' is defined but never used              no-unused-vars
  11:8   error  'ErrorBoundaryWrapper' is defined but never used          no-unused-vars
  12:8   error  'Loader' is defined but never used                        no-unused-vars
  13:8   error  'QuestionnaireDetailedResults' is defined but never used  no-unused-vars
  14:8   error  'QuestionnaireSummary' is defined but never used  

问题是什么?

eslint.config.mjs

import babelParser from "@babel/eslint-parser";
import pluginJs from "@eslint/js";
import importConfig from "eslint-plugin-import";
import pluginJest from "eslint-plugin-jest";
import jsdocConfig from "eslint-plugin-jsdoc";
import jsoncConfig from "eslint-plugin-jsonc";
import pluginPrettier from "eslint-plugin-prettier";
import pluginReact from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import sortKeysFixConfig from "eslint-plugin-sort-keys-fix";
import spellcheck from "eslint-plugin-spellcheck";
import testingPlugin from "eslint-plugin-testing-library";
import globals from "globals";

const config = [
    pluginJs.configs.recommended,
    {
        "files": ["**/*.{js,mjs,cjs,jsx}"],
        "languageOptions": {
            "ecmaVersion": 2020,
            "globals": {
                ...globals.es2021,
                ...globals.node,
                ...globals.browser,
                "describe": "readonly",
                "expect": "readonly",
                "indexedDB": "readonly",
                "it": "readonly",
                "jest": "readonly",
                "test": "readonly"
            },
            "parser": babelParser,
            "parserOptions": {
                "babelOptions": {
                    "babelrc": false,
                    "configFile": false,
                    "presets": [["@babel/preset-react", { "runtime": "automatic" }], "@babel/preset-env"]
                },
                "ecmaFeatures": {
                    "jsx": true
                },
                "requireConfigFile": false,
                "sourceType": "module"
            }
        },
        "plugins": {
            "import": importConfig,
            "jsdoc": jsdocConfig,
            "jsonc": jsoncConfig,
            "prettier": pluginPrettier,
            "react": pluginReact,
            "react-hooks": reactHooks,
            "sort-keys-fix": sortKeysFixConfig,
            "spellcheck": spellcheck,
            "testing-library": testingPlugin
        },
        "rules": {
            "array-bracket-newline": ["error", "consistent"],
            "array-bracket-spacing": ["error", "never"],
            "array-callback-return": "error",
            "array-element-newline": [
                "error",
                {
                    "ArrayExpression": "consistent",
                    "ArrayPattern": { "minItems": 3 }
                }
            ],
            "arrow-spacing": "error",
            "brace-style": ["error", "1tbs"],
            "camelcase": ["error", { "ignoreDestructuring": true, "properties": "never" }],
            "comma-dangle": ["error", "never"],
            "comma-spacing": [
                "error",
                {
                    "after": true,
                    "before": false
                }
            ],
            "curly": ["error", "all"],
            "default-case": "off",
            "eqeqeq": ["error", "always"],
            "func-call-spacing": ["error", "never"],
            "function-call-argument-newline": ["error", "consistent"],
            "import/first": "off",
            "import/order": ["error", { "groups": ["builtin", "external", "internal", "parent", "sibling", "index"] }],
            "indent": ["error", 4, { "SwitchCase": 1, "ignoredNodes": ["ConditionalExpression"] }],
            "jest/no-mocks-import": "off",
            "jsdoc/newline-after-description": 0,
            // Required for vs code auto formatting
            "jsdoc/require-hyphen-before-param-description": 1,

            "jsdoc/require-jsdoc": [
                "error",
                {
                    "require": {
                        "ArrowFunctionExpression": true,
                        "ClassExpression": true,
                        "FunctionDeclaration": true,
                        "FunctionExpression": true,
                        "MethodDefinition": true
                    }
                }
            ],
            "jsonc/sort-keys": "error",
            "keyword-spacing": ["error", { "after": true, "before": true }],
            "max-len": [
                "error",
                {
                    "code": 120,
                    "ignorePattern": "\".*\": \".*\"" // Ignore pattern for strings in json as they can't be broken in multi lines
                }
            ],
            "no-console": "error",
            "no-dupe-else-if": "error",
            "no-extend-native": "off",
            "no-nested-ternary": "error",
            // "no-unused-vars": "warn",
            "no-useless-escape": "off",
            "no-var": "error",
            "object-curly-newline": ["error", { "consistent": true, "multiline": true }],
            "object-curly-spacing": ["error", "always"],
            "object-property-newline": ["error", { "allowAllPropertiesOnSameLine": true }],
            "padding-line-between-statements": [
                "error",
                // Always one empty line before return statement
                {
                    "blankLine": "always",
                    "next": "return",
                    "prev": "*"
                },
                // Always one empty line between methods
                {
                    "blankLine": "always",
                    "next": ["block-like", "multiline-block-like"],
                    "prev": ["block-like", "multiline-block-like"]
                },
                // Avoids more than one empty line
                {
                    "blankLine": "never",
                    "next": "empty",
                    "prev": "empty"
                }
            ],
            "prefer-const": "error",
            "quote-props": ["error", "always"],
            "quotes": ["error", "double"],
            "radix": "off",
            "react-hooks/exhaustive-deps": "error",
            "react-hooks/rules-of-hooks": "error",
            "react/jsx-boolean-value": ["warn", "always"],
            "react/jsx-closing-bracket-location": "error",
            "react/jsx-closing-tag-location": "error",
            "react/jsx-curly-brace-presence": [
                "error",
                {
                    "children": "ignore",
                    "props": "always"
                }
            ],
            "react/jsx-tag-spacing": ["error", { "beforeSelfClosing": "always" }],
            "react/no-multi-comp": ["error", { "ignoreStateless": true }],
            "react/react-in-jsx-scope": "off",
            "semi": ["error", "always"],
            "sort-keys": [
                "error",
                "asc",
                {
                    "caseSensitive": true,
                    "minKeys": 2,
                    "natural": false
                }
            ],
            "sort-keys-fix/sort-keys-fix": "error",
            "space-before-blocks": "error",
            "space-infix-ops": ["error", { "int32Hint": false }],
            "testing-library/no-node-access": "off"
        },
        "settings": {
            "react": {
                // Only needed for older React versions
                "fragment": "Fragment",
                // Automatically detect React version
                "pragma": "React",
                // Only needed for older React versions
                "runtime": "automatic",
                "version": "detect" // Use React 17+ JSX transform
            }
        }
    },
    {
        "files": ["**/*.test.{js,mjs,cjs,jsx}"],
        "languageOptions": {
            "globals": {
                ...globals.jest,
                ...globals.browser,
                ...globals.node,
                "describe": "readonly",
                "expect": "readonly",
                "indexedDB": "readonly",
                "it": "readonly",
                "jest": "readonly",
                "test": "readonly"
            }
        },
        "plugins": {
            "jest": pluginJest
        },
        "rules": {
            "react/react-in-jsx-scope": "off"
        },
        "settings": {
            "react": {
                "version": "detect"
            }
        }
    }
];

export default config;

package.json
文件:

{
    "browserslist": [
        ">0.2%",
        "not dead",
        "not op_mini all"
    ],
    "dependencies": {
        "@types/jest": "^29.5.11",
        "ajv": "^8.17.1",
        "awesome-debounce-promise": "~2.1.0",
        "axios": "~1.7.2",
        "bootstrap": "~5.3.2",
        "dotenv": "^16.4.1",
        "i18next": "~23.15.1",
        "i18next-http-backend": "~2.6.1",
        "jest-mock-axios": "~4.7.3",
        "lodash": "~4.17.21",
        "moment": "~2.30.1",
        "moment-timezone": "^0.5.43",
        "react": "~18.3.1",
        "react-bootstrap": "~2.10.2",
        "react-bootstrap-icons": "~1.11.4",
        "react-component-export-image": "~1.0.6",
        "react-dom": "~18.3.1",
        "react-draggable": "^4.4.6",
        "react-dropzone": "^14.2.3",
        "react-error-boundary": "^4.0.13",
        "react-i18next": "~15.0.1",
        "react-icons": "~5.3.0",
        "react-infinite-scroller": "~1.2.6",
        "react-intersection-observer": "~9.13.0",
        "react-leaflet": "~4.2.1",
        "react-multi-select-component": "~4.3.4",
        "react-router": "~6.26.2",
        "react-router-dom": "~6.26.2",
        "react-router-prompt": "^0.7.0",
        "react-scroll": "~1.9.0",
        "react-select": "~5.8.0",
        "react-switch": "~7.0.0",
        "react-tabs": "~6.0.2",
        "react-toastify": "~10.0.4",
        "socket.io-client": "~4.8.0",
        "use-csv-downloader": "0.0.0",
        "web-vitals": "~4.2.2"
    },
    "devDependencies": {
        "@babel/eslint-parser": "~7.25.9",
        "@eslint/js": "^9.14.0",
        "@testing-library/dom": "~10.4.0",
        "@testing-library/jest-dom": "~6.6.3",
        "@testing-library/react": "~16.0.1",
        "@testing-library/user-event": "~14.5.1",
        "@typescript-eslint/eslint-plugin": "~8.13.0",
        "@typescript-eslint/parser": "~8.13.0",
        "eslint": "~9.14.0",
        "eslint-config-prettier": "~9.1.0",
        "eslint-config-react-app": "~7.0.1",
        "eslint-plugin-import": "~2.31.0",
        "eslint-plugin-jest": "~28.9.0",
        "eslint-plugin-jsdoc": "^50.5.0",
        "eslint-plugin-jsonc": "~2.18.1",
        "eslint-plugin-jsx-a11y": "~6.10.2",
        "eslint-plugin-prettier": "~5.2.1",
        "eslint-plugin-react": "^7.37.2",
        "eslint-plugin-react-hooks": "~5.0.0",
        "eslint-plugin-sort-keys-fix": "~1.1.2",
        "eslint-plugin-spellcheck": "0.0.20",
        "eslint-plugin-testing-library": "~6.4.0",
        "fake-indexeddb": "6.0.0",
        "globals": "^15.12.0",
        "pre-commit": "~1.2.2",
        "prettier": "~3.3.3",
        "prettier-eslint": "~16.3.0",
        "prettier-eslint-cli": "~8.0.1",
        "react-scripts": "~5.0.1",
        "sass": "~1.80.6",
        "stylelint": "~16.10.0",
        "stylelint-config-prettier": "~9.0.5",
        "stylelint-config-standard-scss": "~13.1.0",
        "stylelint-prettier": "~5.0.2",
        "stylelint-scss": "~6.8.1"
    },
    "eslintConfig": {
        "extends": [
            "react-app",
            "react-app/jest"
        ]
    },
    "jest": {
        "collectCoverageFrom": [
            "src/**/*.js",
            "!src/**/*.scss",
            "!src/assets/**/*.js"
        ],
        "coverageThreshold": {
            "global": {
                "branches": 50,
                "functions": 50,
                "lines": 65,
                "statements": 65
            }
        }
    },
    "name": "imp-fe",
    "pre-commit": [
        "lint-pre-commit",
        "test-pre-commit"
    ],
    "private": true,
    "scripts": {
        "build": "react-scripts build",
        "eject": "react-scripts eject",
        "format": "npm run prettier-fix && npm run lint-fix",
        "lint": "npm run lint-check && npm run stylelint",
        "lint-check": "eslint src/ --ignore-pattern 'src/__mocks__/'",
        "lint-fix": "npm run lint-check -- --fix",
        "lint-pre-commit": "FILE_DIFF=$(git diff --name-only --cached --diff-filter=ACMR | grep .js$ | sed 's#/[^/]*$##') && [ '$FILE_DIFF' != '' ] && (eslint --ext .jsx --ext .js --ext .json $(echo $FILE_DIFF) && npm run stylelint) || exit 0",
        "prettier-fix": "npx prettier --write src/",
        "pull-latest-and-verify": "npm run pull-latest-code && node ./.dev/check_if_env_latest.js",
        "pull-latest-code": "git pull && npm i",
        "start": "react-scripts start",
        "stylelint": "npx stylelint 'src/**/*.{css,scss}'",
        "stylelint-fix": "npm run stylelint -- --fix",
        "test": "react-scripts test --maxWorkers 1",
        "test-coverage": "npm run test -- --coverage --watchAll=false",
        "test-no-watch": "npm run test -- --watchAll=false",
        "test-pre-commit": "FILE_DIFF=$(git diff --name-only --cached --diff-filter=ACMR | grep .js$ | sed 's#/[^/]*$##') && [ '$FILE_DIFF' != '' ] && (npm run test-no-watch -- $(echo $FILE_DIFF) --passWithNoTests) || exit 0"
    },
    "version": "24.8.0"
}

组件文件

QuestionnaireTabNavigator.js
:

import PropTypes from "prop-types";
import { useCallback, useContext, useState } from "react";
import { Tab, Tabs } from "react-bootstrap";
import { withTranslation } from "react-i18next";
import { useNavigate, useSearchParams } from "react-router-dom";
import { CATEGORY_WISE_DATA_STRUCTURE, CATEGORY_WISE_DETAILED_RESULT } from "../../App.Constants";
import { QuestionnaireContext } from "../../contexts/QuestionnaireContext";
import { UserContext } from "../../contexts/UserContext";
import AssessmentSelector from "../AssessmentSelector/AssessmentSelector";
import AssessmentsTable from "../AssessmentsTable/AssessmentsTable";
import ErrorBoundaryWrapper from "../ErrorBoundaryWrapper/ErrorBoundaryWrapper";
import Loader from "../Loaders/Loader/Loader";
import QuestionnaireDetailedResults from "../QuestionnaireDetailedResults/QuestionnaireDetailedResults";
import QuestionnaireSummary from "../QuestionnaireSummary/QuestionnaireSummary";
import "./QuestionnaireTabNavigator.scss";

/**
 *
 * @param {*} props - Parent props
 * @returns {Element} - Returns multiple tabs with different sub components
 */
const QuestionnaireTabNavigator = ({ t }) => {
    const navigate = useNavigate();
    const { fetchAssessmentsList, "allAssessmentsData": apiResponse } = useContext(QuestionnaireContext);

    const { user } = useContext(UserContext);
    const [searchParams] = useSearchParams();
    const section = searchParams.get("section");

    /**
     * Added this extra check for apiResponse for smooth transitioning.
     * Loader will be visible based on current state value.
     * Also updating these state values from AssessmentSelector component.
     */
    const [benchmarkingData, setBenchmarkingData] = useState(!apiResponse.length ? CATEGORY_WISE_DATA_STRUCTURE : null);
    const [detailedResults, setDetailedResults] = useState(!apiResponse.length ? CATEGORY_WISE_DETAILED_RESULT : null);

    let tab = "assessments";
    if (window.location.pathname.includes("summary")) {
        tab = "summary";
    } else if (window.location.pathname.includes("detailed-results")) {
        tab = "detailed-results";
    }
    const [selectedTab, setSelectedTab] = useState(tab);

    const handleTabSelect = useCallback(
        (tab) => {
            if (tab === "detailed-results") {
                navigate(
                    `/${user.selectedTenant}/maturity-assessment/detailed-results${
                        section ? `section=${section}` : ""
                    }`,
                    {
                        "state": { "redirect": "no" }
                    }
                );
            } else if (tab === "summary") {
                navigate(`/${user.selectedTenant}/maturity-assessment/summary`, {
                    "state": { "redirect": "no" }
                });
            } else {
                navigate(`/${user.selectedTenant}/maturity-assessment/all-assessments`, {
                    "state": { "redirect": "no" }
                });
            }
        },
        [navigate, section, user.selectedTenant]
    );

    const setStateMethod = selectedTab === "detailed-results" ? setDetailedResults : setBenchmarkingData;

    return (
        <div
            className={"QuestionnaireTabNavigator bottom-border-tab-variant"}
            data-testid={"QuestionnaireTabNavigator"}
        >
            {selectedTab !== "assessments" ? (
                <AssessmentSelector
                    assessmentsList={apiResponse}
                    selectedTab={selectedTab}
                    setStateMethod={setStateMethod}
                />
            ) : null}

            <Tabs
                activeKey={selectedTab}
                id={"questionnaire-tab-navigator"}
                transition={false}
                onSelect={handleTabSelect}
            >
                <Tab eventKey={"assessments"} title={t("questionnaire.tab_navigator.assessments")}>
                    <ErrorBoundaryWrapper componentTitle={"Assessment table"}>
                        <AssessmentsTable apiResponse={apiResponse} fetchAssessmentsList={fetchAssessmentsList} />
                    </ErrorBoundaryWrapper>
                </Tab>
                <Tab eventKey={"summary"} title={t("questionnaire.tab_navigator.summary")}>
                    <ErrorBoundaryWrapper componentTitle={"Questionnaire Summary"}>
                        {benchmarkingData ? (
                            <QuestionnaireSummary benchmarkingData={benchmarkingData} setSelectedTab={setSelectedTab} />
                        ) : (
                            <Loader />
                        )}
                    </ErrorBoundaryWrapper>
                </Tab>
                <Tab eventKey={"detailed-results"} title={t("questionnaire.tab_navigator.detailed-results")}>
                    <ErrorBoundaryWrapper componentTitle={"Questionnaire Detailed Results"}>
                        {detailedResults ? (
                            <QuestionnaireDetailedResults detailedResults={detailedResults} />
                        ) : (
                            <Loader />
                        )}
                    </ErrorBoundaryWrapper>
                </Tab>
            </Tabs>
        </div>
    );
};

QuestionnaireTabNavigator.propTypes = {
    "t": PropTypes.func
};

export default withTranslation()(QuestionnaireTabNavigator);
javascript reactjs visual-studio-code eslint eslint-config-airbnb
1个回答
0
投票

我建议您遵循 ESLint 文档中的迁移指南。您可以开始在现有配置文件上使用配置迁移器

© www.soinside.com 2019 - 2024. All rights reserved.