eslint.config.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import js from "@eslint/js";
  2. import tseslint from "typescript-eslint";
  3. import react from "eslint-plugin-react";
  4. import reactHooks from "eslint-plugin-react-hooks";
  5. import reactRefresh from "eslint-plugin-react-refresh";
  6. import importX from "eslint-plugin-import-x";
  7. import tailwindcss from "eslint-plugin-tailwindcss";
  8. import unusedImports from "eslint-plugin-unused-imports";
  9. import globals from "globals";
  10. export default tseslint.config(
  11. {
  12. ignores: ["dist/**", "node_modules/**", "public/**"],
  13. },
  14. {
  15. files: ["src/**/*.{ts,tsx,js,jsx}"],
  16. extends: [js.configs.recommended, ...tseslint.configs.recommended],
  17. plugins: {
  18. react,
  19. "react-hooks": reactHooks, // for following React rules such as dependencies in hooks, keys in lists, etc.
  20. "react-refresh": reactRefresh, // for Vite HMR compatibility
  21. "import-x": importX, // for import order/sorting. It also detercts circular dependencies and duplicate imports.
  22. tailwindcss, // for detecting invalid Tailwind classnames and enforcing classname order
  23. "unused-imports": unusedImports, // for detecting unused imports
  24. },
  25. languageOptions: {
  26. globals: {
  27. ...globals.browser,
  28. },
  29. parserOptions: {
  30. ecmaFeatures: { jsx: true },
  31. },
  32. },
  33. settings: {
  34. react: { version: "detect" },
  35. },
  36. rules: {
  37. // --- Unused imports/vars ---
  38. "unused-imports/no-unused-imports": "warn",
  39. "unused-imports/no-unused-vars": [
  40. "warn",
  41. {
  42. vars: "all",
  43. varsIgnorePattern: "^_",
  44. args: "after-used",
  45. argsIgnorePattern: "^_",
  46. },
  47. ],
  48. "no-unused-vars": "off",
  49. "@typescript-eslint/no-unused-vars": "off",
  50. // --- React ---
  51. "react/jsx-key": "warn",
  52. "react/jsx-no-duplicate-props": "error",
  53. "react/jsx-no-undef": "error",
  54. "react/no-children-prop": "warn",
  55. "react/no-danger-with-children": "error",
  56. "react/no-direct-mutation-state": "error",
  57. "react/no-unknown-property": "warn",
  58. "react/react-in-jsx-scope": "off",
  59. // --- React Hooks ---
  60. "react-hooks/rules-of-hooks": "error",
  61. "react-hooks/exhaustive-deps": "warn",
  62. // --- React Refresh (Vite HMR) ---
  63. "react-refresh/only-export-components": [
  64. "warn",
  65. { allowConstantExport: true },
  66. ],
  67. // --- Import ordering & hygiene ---
  68. "import-x/no-duplicates": "warn",
  69. "import-x/order": [
  70. "warn",
  71. {
  72. groups: [
  73. "builtin",
  74. "external",
  75. "internal",
  76. "parent",
  77. "sibling",
  78. "index",
  79. ],
  80. "newlines-between": "never",
  81. },
  82. ],
  83. // --- Tailwind CSS ---
  84. "tailwindcss/classnames-order": "warn",
  85. "tailwindcss/no-contradicting-classname": "warn",
  86. "tailwindcss/no-unnecessary-arbitrary-value": "warn",
  87. // --- Disabled base rules ---
  88. "@typescript-eslint/no-explicit-any": "off",
  89. "@typescript-eslint/no-require-imports": "off",
  90. "no-case-declarations": "off",
  91. "no-control-regex": "off",
  92. "no-useless-escape": "off",
  93. },
  94. }
  95. );