11// @ts -check
22
33import eslint from '@eslint/js' ;
4- import typescriptPlugin from '@typescript-eslint/eslint-plugin' ;
5- import typescriptParser from '@typescript-eslint/parser' ;
6- import { FlatCompat } from '@eslint/eslintrc' ;
7- import reactPlugin from 'eslint-plugin-react' ;
8- import hooksPlugin from 'eslint-plugin-react-hooks' ;
4+ import nextPlugin from '@next/eslint-plugin-next' ;
5+ import prettierConfig from 'eslint-config-prettier' ;
6+ import cypressPlugin from 'eslint-plugin-cypress' ;
97import importPlugin from 'eslint-plugin-import' ;
108import jestPlugin from 'eslint-plugin-jest' ;
11- import noSecretsPlugin from 'eslint-plugin-no-secrets' ;
129import prettierPlugin from 'eslint-plugin-prettier' ;
13- import prettierConfig from 'eslint-config-prettier' ;
10+ import reactPlugin from 'eslint-plugin-react' ;
11+ import hooksPlugin from 'eslint-plugin-react-hooks' ;
1412import globals from 'globals' ;
1513import path from 'node:path' ;
1614import { fileURLToPath } from 'node:url' ;
15+ import tseslint from 'typescript-eslint' ;
1716
17+ // --- SETUP ---
18+ // Recreate __dirname for ES modules
1819const __filename = fileURLToPath ( import . meta. url ) ;
1920const __dirname = path . dirname ( __filename ) ;
2021
21- const compat = new FlatCompat ( {
22- baseDirectory : __dirname ,
23- recommendedConfig : eslint . configs . recommended ,
24- } ) ;
22+ // --- EXPORT ESLINT CONFIG ---
23+ export default tseslint . config (
24+ // 1. Global Ignores
25+ {
26+ ignores : [ 'node_modules/' , '.next/' , 'dist/' , 'coverage/' , '.DS_Store' ] ,
27+ } ,
2528
26- export default [
27- // Base configuration
29+ // 2. Base Configurations (Applied to all files)
2830 eslint . configs . recommended ,
31+ prettierConfig , // Disables ESLint rules that conflict with Prettier. IMPORTANT: Must be after other configs.
2932
30- // Next.js configuration using FlatCompat
31- ...compat . extends ( 'next/core-web-vitals' ) ,
32-
33- // --- Main Configuration ---
33+ // 3. Configuration for App Source Code (Next.js with Type-Aware Linting)
3434 {
35- files : [ 'src/**/*.{js,jsx,ts,tsx}' , 'tests/** /*.{js,jsx, ts,tsx}'] ,
35+ files : [ 'src/ui/** /*.{ts,tsx}' ] ,
3636 languageOptions : {
37- parser : typescriptParser ,
38- ecmaVersion : 2024 ,
39- sourceType : 'module' ,
37+ parser : tseslint . parser ,
38+ parserOptions : {
39+ project : true , // Enable type-aware linting
40+ tsconfigRootDir : __dirname ,
41+ } ,
4042 globals : {
4143 ...globals . browser ,
42- ...globals . node ,
43- ...globals . jest ,
44- } ,
45- parserOptions : {
46- ecmaFeatures : {
47- jsx : true ,
48- } ,
49- project : [
50- './src/ui/tsconfig.json' ,
51- './tsconfig.test.json' ,
52- './tsconfig.cypress.json' ,
53- ] ,
54- tsconfigRootDir : import . meta. dirname ,
55- noWarnOnMultipleProjects : true ,
44+ ...globals . node , // Add Node.js globals for `process` etc.
5645 } ,
5746 } ,
5847 plugins : {
59- '@typescript-eslint' : typescriptPlugin ,
48+ '@typescript-eslint' : tseslint . plugin ,
49+ '@next/next' : nextPlugin ,
50+ import : importPlugin ,
6051 react : reactPlugin ,
6152 'react-hooks' : hooksPlugin ,
62- import : importPlugin ,
63- jest : jestPlugin ,
64- 'no-secrets' : noSecretsPlugin ,
6553 prettier : prettierPlugin ,
6654 } ,
6755 rules : {
68- // Ccustom rules
69- complexity : [ 'warn' , { max : 8 } ] ,
70- curly : [ 'error' , 'all' ] ,
56+ // --- Base rules to disable in favor of TS versions ---
7157 'no-unused-vars' : 'off' ,
7258
73- // TypeScript rules
59+ // --- Recommended rules from plugins ---
60+ ...tseslint . configs . recommendedTypeChecked . rules ,
61+ ...nextPlugin . configs . recommended . rules ,
62+ ...nextPlugin . configs [ 'core-web-vitals' ] . rules ,
63+ ...reactPlugin . configs . recommended . rules ,
64+ ...hooksPlugin . configs . recommended . rules ,
65+
66+ // --- Prettier ---
67+ 'prettier/prettier' : 'error' ,
68+
69+ // --- Custom Rules & Overrides ---
7470 '@typescript-eslint/no-unused-vars' : [
7571 'warn' ,
7672 {
@@ -79,103 +75,103 @@ export default [
7975 caughtErrorsIgnorePattern : '^_' ,
8076 } ,
8177 ] ,
78+ '@typescript-eslint/no-floating-promises' : 'error' ,
79+ '@typescript-eslint/no-misused-promises' : 'error' ,
8280 '@typescript-eslint/no-explicit-any' : 'warn' ,
8381
84- // Next.js overrides
85- '@next/next/no-img-element' : 'off' , // Allow img tags if needed
86- '@next/next/no-page-custom-font' : 'warn' ,
87-
88- // React rules
89- 'react/react-in-jsx-scope' : 'off' , // Not needed in Next.js
90- 'react/prop-types' : 'off' , // Using TypeScript
91- 'react-hooks/rules-of-hooks' : 'error' ,
92- 'react-hooks/exhaustive-deps' : 'warn' ,
93-
94- // Import rules
95- 'import/no-extraneous-dependencies' : [
96- 'error' ,
97- {
98- devDependencies : [
99- '**/*.test.{js,jsx,ts,tsx}' ,
100- '**/*.d.ts' ,
101- '**/*.interfaces.ts' ,
102- '**/*.setup.{js,ts}' ,
103- '**/*.config.{js,mjs,ts}' ,
104- 'tests/**/*' ,
105- 'cypress/**/*' ,
106- ] ,
107- optionalDependencies : false ,
108- peerDependencies : false ,
109- } ,
110- ] ,
11182 'import/order' : [
11283 'error' ,
11384 {
114- groups : [
115- [ 'builtin' , 'external' ] ,
116- [ 'internal' , 'parent' , 'sibling' , 'index' ] ,
117- ] ,
118- 'newlines-between' : 'always-and-inside-groups' ,
119- pathGroups : [
120- {
121- pattern :
122- '@{app,assets,classes,components,hooks,lib,pages,store,tests,types,utils}/**' ,
123- group : 'internal' ,
124- position : 'before' ,
125- } ,
126- {
127- pattern : '{.,..}/**' ,
128- group : 'internal' ,
129- position : 'after' ,
130- } ,
131- ] ,
132- pathGroupsExcludedImportTypes : [ 'builtin' ] ,
85+ groups : [ [ 'builtin' , 'external' ] , 'internal' , [ 'parent' , 'sibling' , 'index' ] ] ,
86+ 'newlines-between' : 'always' ,
13387 alphabetize : { order : 'asc' , caseInsensitive : true } ,
13488 } ,
13589 ] ,
13690
137- // Security
138- 'no-secrets/no-secrets ' : [ 'error' , { additionalRegexes : { } , ignoreContent : [ ] } ] ,
91+ 'react/react-in-jsx-scope' : 'off' ,
92+ 'react/prop-types ' : 'off' ,
13993
140- // Prettier
141- 'prettier/prettier' : 'error' ,
94+ '@next/next/no-html-link-for-pages' : 'off' ,
95+ '@next/next/no-img-element' : 'off' ,
96+
97+ complexity : [ 'warn' , { max : 8 } ] ,
14298 } ,
14399 settings : {
144- next : {
145- rootDir : [ 'src/ui/' , 'tests/ui/' ] ,
146- } ,
147- 'import/resolver' : {
148- typescript : {
149- project : [
150- './src/ui/tsconfig.json' ,
151- './tsconfig.test.json' ,
152- './tsconfig.cypress.json' ,
153- ] ,
154- noWarnOnMultipleProjects : true ,
155- } ,
100+ react : { version : 'detect' } ,
101+ 'import/resolver' : { typescript : true , node : true } ,
102+ } ,
103+ } ,
104+
105+ // 4. Configuration for Jest Test Files (Type-Aware)
106+ {
107+ files : [ 'tests/ui/**/*.{test,spec}.{ts,tsx}' , 'jest.setup.ts' ] ,
108+ languageOptions : {
109+ parser : tseslint . parser , // Explicitly set parser
110+ parserOptions : {
111+ project : './tsconfig.test.json' ,
112+ tsconfigRootDir : __dirname ,
156113 } ,
157- react : {
158- version : 'detect' ,
114+ globals : {
115+ ...globals . jest ,
116+ ...globals . node , // FIX: Add Node.js globals for `global`, etc.
159117 } ,
160118 } ,
119+ plugins : {
120+ jest : jestPlugin ,
121+ } ,
122+ rules : {
123+ ...jestPlugin . configs [ 'flat/recommended' ] . rules ,
124+ '@typescript-eslint/unbound-method' : 'off' ,
125+ } ,
161126 } ,
162127
163- // Jest-specific rules for test files
128+ // 5. Configuration for Cypress E2E Test Files (Type-Aware)
164129 {
165130 files : [
166- 'tests/**/*.{js,jsx,ts,tsx}' ,
167- '**/*.test.{js,jsx,ts,tsx}' ,
168- '**/*.spec.{js,jsx,ts,tsx}' ,
131+ 'tests/ui/cypress/**/*.{cy,e2e}.{ts,tsx}' ,
132+ 'tests/ui/cypress/support/**/*.ts' ,
169133 ] ,
134+ languageOptions : {
135+ parser : tseslint . parser , // Explicitly set parser
136+ parserOptions : {
137+ project : './tsconfig.cypress.json' ,
138+ tsconfigRootDir : __dirname ,
139+ } ,
140+ // FIX: This is the correct way to get globals from the Cypress plugin's recommended config.
141+ globals : cypressPlugin . configs . recommended . languageOptions . globals ,
142+ } ,
143+ plugins : {
144+ cypress : cypressPlugin ,
145+ } ,
146+ // Apply recommended rules and then add our overrides
170147 rules : {
171- 'jest/expect-expect' : 'error' ,
172- 'jest/no-focused-tests' : 'error' ,
173- 'jest/no-identical-title' : 'error' ,
174- 'jest/prefer-to-have-length' : 'warn' ,
175- 'jest/valid-expect' : 'error' ,
148+ ...cypressPlugin . configs . recommended . rules ,
149+ 'jest/expect-expect' : 'off' ,
150+ 'jest/no-standalone-expect' : 'off' ,
151+ '@typescript-eslint/no-floating-promises' : 'off' ,
176152 } ,
177153 } ,
178154
179- // Prettier config (disables conflicting rules)
180- prettierConfig ,
181- ] ;
155+ // 6. Configuration for JS/TS config files
156+ {
157+ files : [ '**/*.config.{js,mjs,ts}' ] ,
158+ languageOptions : {
159+ globals : {
160+ ...globals . node ,
161+ } ,
162+ } ,
163+ rules : {
164+ '@typescript-eslint/no-var-requires' : 'off' ,
165+ } ,
166+ } ,
167+
168+ // 7. Configuration for JS/TS mock files and test helpers
169+ {
170+ files : [ 'tests/ui/**/__mocks__/**/*.{js,ts}' , 'tests/ui/unit/mocks/**/*.ts' ] ,
171+ languageOptions : {
172+ globals : {
173+ ...globals . node ,
174+ } ,
175+ } ,
176+ }
177+ ) ;
0 commit comments