1
1
// @ts -check
2
2
3
3
import 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' ;
9
7
import importPlugin from 'eslint-plugin-import' ;
10
8
import jestPlugin from 'eslint-plugin-jest' ;
11
- import noSecretsPlugin from 'eslint-plugin-no-secrets' ;
12
9
import 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' ;
14
12
import globals from 'globals' ;
15
13
import path from 'node:path' ;
16
14
import { fileURLToPath } from 'node:url' ;
15
+ import tseslint from 'typescript-eslint' ;
17
16
17
+ // --- SETUP ---
18
+ // Recreate __dirname for ES modules
18
19
const __filename = fileURLToPath ( import . meta. url ) ;
19
20
const __dirname = path . dirname ( __filename ) ;
20
21
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
+ } ,
25
28
26
- export default [
27
- // Base configuration
29
+ // 2. Base Configurations (Applied to all files)
28
30
eslint . configs . recommended ,
31
+ prettierConfig , // Disables ESLint rules that conflict with Prettier. IMPORTANT: Must be after other configs.
29
32
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)
34
34
{
35
- files : [ 'src/**/*.{js,jsx,ts,tsx}' , 'tests/** /*.{js,jsx, ts,tsx}'] ,
35
+ files : [ 'src/ui/** /*.{ts,tsx}' ] ,
36
36
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
+ } ,
40
42
globals : {
41
43
...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.
56
45
} ,
57
46
} ,
58
47
plugins : {
59
- '@typescript-eslint' : typescriptPlugin ,
48
+ '@typescript-eslint' : tseslint . plugin ,
49
+ '@next/next' : nextPlugin ,
50
+ import : importPlugin ,
60
51
react : reactPlugin ,
61
52
'react-hooks' : hooksPlugin ,
62
- import : importPlugin ,
63
- jest : jestPlugin ,
64
- 'no-secrets' : noSecretsPlugin ,
65
53
prettier : prettierPlugin ,
66
54
} ,
67
55
rules : {
68
- // Ccustom rules
69
- complexity : [ 'warn' , { max : 8 } ] ,
70
- curly : [ 'error' , 'all' ] ,
56
+ // --- Base rules to disable in favor of TS versions ---
71
57
'no-unused-vars' : 'off' ,
72
58
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 ---
74
70
'@typescript-eslint/no-unused-vars' : [
75
71
'warn' ,
76
72
{
@@ -79,103 +75,103 @@ export default [
79
75
caughtErrorsIgnorePattern : '^_' ,
80
76
} ,
81
77
] ,
78
+ '@typescript-eslint/no-floating-promises' : 'error' ,
79
+ '@typescript-eslint/no-misused-promises' : 'error' ,
82
80
'@typescript-eslint/no-explicit-any' : 'warn' ,
83
81
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
- ] ,
111
82
'import/order' : [
112
83
'error' ,
113
84
{
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' ,
133
87
alphabetize : { order : 'asc' , caseInsensitive : true } ,
134
88
} ,
135
89
] ,
136
90
137
- // Security
138
- 'no-secrets/no-secrets ' : [ 'error' , { additionalRegexes : { } , ignoreContent : [ ] } ] ,
91
+ 'react/react-in-jsx-scope' : 'off' ,
92
+ 'react/prop-types ' : 'off' ,
139
93
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 } ] ,
142
98
} ,
143
99
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 ,
156
113
} ,
157
- react : {
158
- version : 'detect' ,
114
+ globals : {
115
+ ...globals . jest ,
116
+ ...globals . node , // FIX: Add Node.js globals for `global`, etc.
159
117
} ,
160
118
} ,
119
+ plugins : {
120
+ jest : jestPlugin ,
121
+ } ,
122
+ rules : {
123
+ ...jestPlugin . configs [ 'flat/recommended' ] . rules ,
124
+ '@typescript-eslint/unbound-method' : 'off' ,
125
+ } ,
161
126
} ,
162
127
163
- // Jest-specific rules for test files
128
+ // 5. Configuration for Cypress E2E Test Files (Type-Aware)
164
129
{
165
130
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' ,
169
133
] ,
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
170
147
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' ,
176
152
} ,
177
153
} ,
178
154
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