1+ import tseslint from 'typescript-eslint' ;
2+ import pluginN from 'eslint-plugin-n' ;
3+ import pluginImportX from 'eslint-plugin-import-x' ;
4+ import pluginPromise from 'eslint-plugin-promise' ;
5+ import pluginSecurity from 'eslint-plugin-security' ;
6+ import pluginUnicorn from 'eslint-plugin-unicorn' ;
7+
8+ export default tseslint . config (
9+
10+ // ─── Global Ignores ──────────────────────────────────────────────────────────
11+ {
12+ ignores : [
13+ 'dist/**' ,
14+ 'build/**' ,
15+ 'node_modules/**' ,
16+ 'coverage/**' ,
17+ 'prisma/migrations/**' ,
18+ '**/*.d.ts' ,
19+ ] ,
20+ } ,
21+
22+ // ─── Base: ESLint Recommended + TypeScript ──────────────────────────────────
23+ ...tseslint . configs . recommendedTypeChecked ,
24+
25+ // ─── Main Config ────────────────────────────────────────────────────────────
26+ {
27+ files : [ 'src/**/*.ts' ] ,
28+
29+ languageOptions : {
30+ parserOptions : {
31+ projectService : true ,
32+ tsconfigRootDir : import . meta. dirname ,
33+ } ,
34+ } ,
35+
36+ plugins : {
37+ n : pluginN ,
38+ 'import-x' : pluginImportX ,
39+ promise : pluginPromise ,
40+ security : pluginSecurity ,
41+ unicorn : pluginUnicorn ,
42+ } ,
43+
44+ settings : {
45+ 'import-x/resolver' : {
46+ typescript : { project : './tsconfig.json' } ,
47+ node : true ,
48+ } ,
49+ node : { version : '>=18.0.0' } ,
50+ } ,
51+
52+ rules : {
53+
54+ // ── TypeScript: Type Safety: currently off ─────────────────────────────────────────────
55+ '@typescript-eslint/no-explicit-any' : 'off' ,
56+ '@typescript-eslint/no-unsafe-argument' : 'off' ,
57+ '@typescript-eslint/no-unsafe-assignment' : 'off' ,
58+ '@typescript-eslint/no-unsafe-call' : 'off' ,
59+ '@typescript-eslint/no-unsafe-member-access' : 'off' ,
60+ '@typescript-eslint/no-unsafe-return' : 'off' ,
61+ '@typescript-eslint/no-non-null-assertion' : 'off' ,
62+ '@typescript-eslint/no-unnecessary-type-assertion' : 'off' ,
63+ '@typescript-eslint/prefer-nullish-coalescing' : 'off' ,
64+ '@typescript-eslint/prefer-optional-chain' : 'off' ,
65+ '@typescript-eslint/strict-boolean-expressions' : 'off' ,
66+
67+ // ── TypeScript: Async / Promises: currently off ────────────────────────────────────────
68+ '@typescript-eslint/no-floating-promises' : 'off' ,
69+ '@typescript-eslint/no-misused-promises' : 'off' ,
70+ '@typescript-eslint/await-thenable' : 'off' ,
71+ '@typescript-eslint/require-await' : 'off' ,
72+ '@typescript-eslint/return-await' : 'off' ,
73+
74+ // ── TypeScript: Imports ─────────────────────────────────────────────────
75+ '@typescript-eslint/consistent-type-imports' : [
76+ 'error' ,
77+ { prefer : 'type-imports' , fixStyle : 'inline-type-imports' } ,
78+ ] ,
79+ '@typescript-eslint/consistent-type-exports' : 'error' ,
80+ '@typescript-eslint/no-import-type-side-effects' : 'error' ,
81+
82+ // ── TypeScript: Code Quality ────────────────────────────────────────────
83+ '@typescript-eslint/no-unused-vars' : [
84+ 'error' ,
85+ {
86+ argsIgnorePattern : '^_' ,
87+ varsIgnorePattern : '^_' ,
88+ caughtErrorsIgnorePattern : '^_' ,
89+ } ,
90+ ] ,
91+ '@typescript-eslint/explicit-function-return-type' : [
92+ 'warn' ,
93+ {
94+ allowExpressions : true ,
95+ allowTypedFunctionExpressions : true ,
96+ } ,
97+ ] ,
98+ '@typescript-eslint/prefer-as-const' : 'error' ,
99+ '@typescript-eslint/no-redundant-type-constituents' : 'warn' ,
100+ '@typescript-eslint/no-shadow' : 'error' ,
101+ '@typescript-eslint/no-use-before-define' : [ 'error' , { functions : false } ] ,
102+
103+ // ── Node.js ─────────────────────────────────────────────────────────────
104+ 'n/no-deprecated-api' : 'error' ,
105+ 'n/no-extraneous-import' : 'error' ,
106+ 'n/no-process-exit' : 'off' ,
107+ 'n/prefer-global/buffer' : [ 'error' , 'always' ] ,
108+ 'n/prefer-global/process' : [ 'error' , 'always' ] ,
109+ 'n/prefer-promises/fs' : 'error' ,
110+ 'n/prefer-promises/dns' : 'error' ,
111+ 'n/no-sync' : 'warn' ,
112+
113+ // ── Imports (import-x) ──────────────────────────────────────────────────
114+ 'import-x/no-duplicates' : 'error' ,
115+ 'import-x/no-cycle' : 'off' ,
116+ 'import-x/no-self-import' : 'error' ,
117+ 'import-x/first' : 'error' ,
118+ 'import-x/newline-after-import' : 'error' ,
119+ 'import-x/order' : [
120+ 'error' ,
121+ {
122+ groups : [ 'builtin' , 'external' , 'internal' , 'parent' , 'sibling' , 'index' , 'type' ] ,
123+ 'newlines-between' : 'always' ,
124+ alphabetize : { order : 'asc' , caseInsensitive : true } ,
125+ } ,
126+ ] ,
127+
128+ // ── Promises ────────────────────────────────────────────────────────────
129+ 'promise/always-return' : 'off' ,
130+ 'promise/catch-or-return' : 'off' ,
131+ 'promise/no-new-statics' : 'error' ,
132+ 'promise/no-return-wrap' : 'error' ,
133+ 'promise/param-names' : 'error' ,
134+ 'promise/no-promise-in-callback' : 'warn' ,
135+
136+ // ── Security ────────────────────────────────────────────────────────────
137+ 'security/detect-object-injection' : 'off' ,
138+ 'security/detect-non-literal-regexp' : 'warn' ,
139+ 'security/detect-non-literal-fs-filename' : 'warn' ,
140+ 'security/detect-eval-with-expression' : 'error' ,
141+ 'security/detect-child-process' : 'warn' ,
142+ 'security/detect-possible-timing-attacks' : 'warn' ,
143+
144+ // ── Unicorn ─────────────────────────────────────────────────────────────
145+ 'unicorn/prefer-node-protocol' : 'error' ,
146+ 'unicorn/no-process-exit' : 'off' ,
147+ 'unicorn/error-message' : 'off' ,
148+ 'unicorn/throw-new-error' : 'off' ,
149+ 'unicorn/no-useless-undefined' : 'off' ,
150+ 'unicorn/prefer-string-slice' : 'warn' ,
151+ 'unicorn/no-for-loop' : 'off' ,
152+ 'unicorn/prefer-includes' : 'warn' ,
153+ 'unicorn/no-array-for-each' : 'off' ,
154+ 'unicorn/prefer-ternary' : 'off' ,
155+ 'unicorn/prevent-abbreviations' : 'off' ,
156+
157+ // ── Core ESLint ─────────────────────────────────────────────────────────
158+ 'no-console' : 'warn' ,
159+ 'eqeqeq' : [ 'error' , 'always' ] ,
160+ 'no-var' : 'error' ,
161+ 'prefer-const' : 'error' ,
162+ 'no-throw-literal' : 'error' ,
163+ 'curly' : [ 'error' , 'all' ] ,
164+ 'object-shorthand' : 'error' ,
165+ 'no-lonely-if' : 'warn' ,
166+ 'no-nested-ternary' : 'off' ,
167+ 'prefer-rest-params' : 'error' ,
168+ 'prefer-spread' : 'error' ,
169+ 'no-param-reassign' : [
170+ 'error' ,
171+ {
172+ props : true ,
173+ ignorePropertyModificationsFor : [ 'acc' , 'request' , 'reply' ] ,
174+ } ,
175+ ] ,
176+ } ,
177+ } ,
178+
179+ // ─── Test File Overrides ────────────────────────────────────────────────────
180+ {
181+ files : [ '**/*.test.ts' , '**/*.spec.ts' , 'src/__tests__/**/*.ts' ] ,
182+ rules : {
183+ '@typescript-eslint/no-explicit-any' : 'off' ,
184+ '@typescript-eslint/no-unsafe-assignment' : 'off' ,
185+ '@typescript-eslint/no-unsafe-member-access' : 'off' ,
186+ '@typescript-eslint/no-non-null-assertion' : 'off' ,
187+ '@typescript-eslint/no-floating-promises' : 'off' ,
188+ 'security/detect-object-injection' : 'off' ,
189+ 'no-console' : 'off' ,
190+ } ,
191+ } ,
192+
193+ // ─── Prisma Seed / Scripts Override ────────────────────────────────────────
194+ {
195+ files : [ 'prisma/**/*.ts' , 'scripts/**/*.ts' ] ,
196+ rules : {
197+ 'n/no-process-exit' : 'off' ,
198+ 'unicorn/no-process-exit' : 'off' ,
199+ 'no-console' : 'off' ,
200+ } ,
201+ } ,
202+ ) ;
0 commit comments