{ "$schema": "https://json.schemastore.org/eslintrc.json", "plugins": ["@typescript-eslint", "require-form-method", "node", "vitest"], "parserOptions": { "project": "tsconfig.json" }, "extends": [ "next", "next/core-web-vitals", "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking", "plugin:import/recommended", "plugin:import/typescript", "prettier", "plugin:vitest/recommended", "plugin:@saleor/saleor-app/recommended" ], "rules": { // use double quotes, allow template strings "quotes": ["error", "double", { "avoidEscape": true }], // sort imports "import/order": "error", // no let exports "import/no-mutable-exports": "error", "import/no-cycle": "error", "import/no-default-export": "error", // prevent default import from Sentry because it doesn't work 😬 "no-restricted-syntax": [ "error", { "selector": "ImportDeclaration[source.value='@sentry/nextjs'] > ImportDefaultSpecifier", "message": "Use `import * as Sentry from '@sentry/nextjs';`" } ], // allow {} even though it's unsafe but comes handy "@typescript-eslint/ban-types": [ "error", { "types": { "{}": false } } ], "@typescript-eslint/consistent-type-imports": [ "error", { "prefer": "type-imports", "fixStyle": "inline-type-imports", "disallowTypeAnnotations": false } ], "import/no-duplicates": ["error", { "prefer-inline": true }], "@typescript-eslint/no-restricted-imports": [ "error", { "patterns": [ { "group": ["@/__tests__/test-env.mjs"], "message": "Test envs cannot be imported into application code" } ] } ], "node/no-process-env": ["error"], // false negatives "import/namespace": ["off"], // we allow empty interfaces "no-empty-pattern": "off", "@typescript-eslint/no-empty-interface": "off", // we allow empty functions "@typescript-eslint/no-empty-function": "off", // we sometimes use async functions that don't await anything "@typescript-eslint/require-await": "off", // make sure to `await` inside try…catch "@typescript-eslint/return-await": ["error", "in-try-catch"], // allow unused vars prefixed with `_` "@typescript-eslint/no-unused-vars": [ "error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" } ], // numbers and booleans are fine in template strings "@typescript-eslint/restrict-template-expressions": [ "error", { "allowNumber": true, "allowBoolean": true } ], // for security reasons, always require forms to provide method="post" "require-form-method/require-form-method": "error", // for security reasons, always require buttons to provide type="button" ("submit" on rare occasions) "react/button-has-type": ["error", { "button": true, "submit": true, "reset": false }] }, "overrides": [ { "files": ["*.test.tsx", "*.test.ts", "**/__tests__/**/*.ts?(x)"], "rules": { // let's make our lives easier in tests "@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/no-unsafe-return": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-non-null-assertion": "off", // allow imports from testEnv "@typescript-eslint/no-restricted-imports": "off" } }, { // https://github.com/testing-library/eslint-plugin-testing-library#run-the-plugin-only-against-test-files "files": ["**/__tests__/**/*.[jt]sx", "**/?(*.)+(spec|test).[jt]sx"], "extends": ["plugin:testing-library/react"] }, { // We allow process.env access in env.mjs and testEnv.mjs "files": ["**/env.mjs", "**/test-env.mjs", "next.config.mjs"], "rules": { "node/no-process-env": "off" } }, { "files": ["src/pages/**/*.ts?(x)"], "rules": { "import/no-default-export": "off" } }, { "files": ["*.cjs", "*.cts"], "rules": { "@typescript-eslint/no-var-requires": "off" } } ], "ignorePatterns": ["*.js", "*.jsx"] }