Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .eslintrc.json

This file was deleted.

149 changes: 149 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { defineConfig } from "eslint/config";
import eslintPlugin from "@eslint/js";
import tseslintPlugin from "@typescript-eslint/eslint-plugin";
import tseslintParser from "@typescript-eslint/parser";
import reactPlugin from "eslint-plugin-react";
import reactHooksPlugin from "eslint-plugin-react-hooks";
import jsxA11yPlugin from "eslint-plugin-jsx-a11y";
import nextPlugin from "@next/eslint-plugin-next";

// Global ignores configuration
// Must be in its own config object to act as global ignores
const ignoresConfig = defineConfig([
{
name: "project/ignores",
ignores: [
".next/",
"node_modules/",
"public/",
".vscode/",
"next-env.d.ts",
],
},
]);

// ESLint recommended rules for JavaScript/TypeScript
const eslintConfig = defineConfig([
{
name: "project/javascript-recommended",
files: ["**/*.{js,mjs,ts,tsx}"],
...eslintPlugin.configs.recommended,
},
]);

// TypeScript configuration with type-checked rules
const typescriptConfig = defineConfig([
{
name: "project/typescript-strict",
files: ["**/*.{ts,tsx,mjs}"],
plugins: {
"@typescript-eslint": tseslintPlugin,
},
languageOptions: {
parser: tseslintParser,
parserOptions: {
project: ["./tsconfig.json"],
tsconfigRootDir: import.meta.dirname,
ecmaFeatures: {
jsx: true,
},
warnOnUnsupportedTypeScriptVersion: true,
},
},
extends: [
"@typescript-eslint/strict-type-checked",
"@typescript-eslint/stylistic-type-checked",
],
rules: {
// Disable rules that conflict with TypeScript's own error checking
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/triple-slash-reference": "off",
// disabled next rule due to bug:
// https://github.com/typescript-eslint/typescript-eslint/issues/11732
// https://github.com/eslint/eslint/issues/20272
"@typescript-eslint/unified-signatures": "off",
// Allow ts-expect-error and ts-ignore with descriptions
"@typescript-eslint/ban-ts-comment": [
"error",
{
"ts-expect-error": "allow-with-description",
"ts-ignore": "allow-with-description",
"ts-nocheck": false,
"ts-check": false,
minimumDescriptionLength: 3,
},
],
},
},
// For plain JS files, you may want to disable type-checked rules
{
name: "project/javascript-disable-type-check",
files: ["**/*.{js,mjs,cjs}"],
plugins: {
"@typescript-eslint": tseslintPlugin,
},
extends: ["@typescript-eslint/disable-type-checked"],
},
]);

// React and Next.js configuration
const reactConfig = defineConfig([
{
name: "project/react-next",
files: ["**/*.{jsx,tsx}"],
plugins: {
react: reactPlugin,
"react-hooks": reactHooksPlugin,
"jsx-a11y": jsxA11yPlugin,
"@next/next": nextPlugin,
},
rules: {
// React recommended rules
...reactPlugin.configs.recommended.rules,
...reactPlugin.configs["jsx-runtime"].rules,
// React Hooks rules (use recommended-latest for latest features)
...reactHooksPlugin.configs["recommended-latest"].rules,
// Accessibility rules (strict mode for better a11y)
...jsxA11yPlugin.configs.strict.rules,
// Next.js recommended rules
...nextPlugin.configs.recommended.rules,
// Next.js Core Web Vitals rules
...nextPlugin.configs["core-web-vitals"].rules,

// Customizations for modern React/Next.js
"react/react-in-jsx-scope": "off", // Not needed in Next.js
"react/prop-types": "off", // Use TypeScript instead
"react/no-unknown-property": "off", // Conflicts with custom attributes
"react/jsx-no-target-blank": "off", // Next.js handles this

// Fine-tuned accessibility rules
"jsx-a11y/alt-text": [
"warn",
{
elements: ["img"],
img: ["Image"], // Next.js Image component
},
],
"jsx-a11y/media-has-caption": "warn",
"jsx-a11y/aria-props": "warn",
"jsx-a11y/aria-proptypes": "warn",
"jsx-a11y/aria-unsupported-elements": "warn",
"jsx-a11y/role-has-required-aria-props": "warn",
"jsx-a11y/role-supports-aria-props": "warn",
},
settings: {
react: {
version: "detect", // Automatically detect React version
},
},
},
]);

// Export the complete configuration
// Order matters: ignores first, then general configs, then specific overrides
export default defineConfig([
...ignoresConfig,
...eslintConfig,
...typescriptConfig,
...reactConfig,
]);
2 changes: 1 addition & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const nextConfig: NextConfig = {
"sharp",
],
},
async headers() {
headers() {
return [
{
source: "/(.*)",
Expand Down
44 changes: 27 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@
"scripts": {
"dev": "pnpm open-browser && next dev --turbopack",
"open-browser": "start http://localhost:3000",
"build": "next build",
"build": "pnpm run lint && next build",
"start": "next start",
"lint": "next lint",
"test": "prettier . --write && next lint && next build && playwright test",
"test-only": "next lint && playwright test",
"lint": "eslint",
"lint:fix": "eslint --fix",
"test": "prettier . --write && pnpm run lint && next build && playwright test",
"test-only": "pnpm run lint && playwright test",
"pretty": "prettier . --write",
"pretty-check": "prettier . --check",
"pretty-lint": "prettier . --write && next lint",
"pretty-lint": "prettier . --write && pnpm run lint",
"prepare": "husky"
},
"dependencies": {
"@mantine/core": "^7.17.8",
"@mantine/form": "^7.17.8",
"@mantine/hooks": "^7.17.8",
"@mantine/core": "^8.3.14",
"@mantine/form": "^8.3.14",
"@mantine/hooks": "^8.3.14",
"@tabler/icons-react": "^3.36.1",
"@vercel/analytics": "^1.6.1",
"@vercel/postgres": "^0.10.0",
"@vercel/speed-insights": "^1.3.1",
"bcrypt": "^6.0.0",
"dotenv": "^17.2.3",
"eslint": "^9.39.2",
"next": "^15.5.10",
"next": "^16.1.6",
"next-auth": "5.0.0-beta.30",
"react": "^19.2.4",
"react-dom": "^19.2.4",
Expand All @@ -35,20 +35,30 @@
"zod": "^4.3.6"
},
"devDependencies": {
"@playwright/test": "^1.58.0",
"@eslint/js": "^9.39.2",
"@next/eslint-plugin-next": "16.1.6",
"@playwright/test": "^1.58.1",
"@types/bcrypt": "^6.0.0",
"@types/node": "^24.10.9",
"@types/react": "^19.2.9",
"@types/node": "^25.2.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"eslint-config-next": "15.5.4",
"@typescript-eslint/eslint-plugin": "^8.54.0",
"@typescript-eslint/parser": "^8.54.0",
"eslint": "^9.39.2",
"eslint-config-next": "16.1.6",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jsx-a11y": "6.10.2",
"eslint-plugin-next": "^0.0.0",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "7.0.1",
"husky": "^9.1.7",
"lint-staged": "^15.5.2",
"lint-staged": "^16.2.7",
"postcss": "^8.5.6",
"postcss-preset-mantine": "^1.18.0",
"postcss-simple-vars": "^7.0.1",
"prettier": "3.6.2",
"typescript": "^5.9.3"
"prettier": "3.8.1",
"typescript": "^5.9.3",
"typescript-eslint": "8.54.0"
},
"lint-staged": {
"**/*": "prettier --write --ignore-unknown"
Expand Down
Loading