@qvaroo/configs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +391 -0
- package/eslint/index.js +222 -0
- package/eslint/node.js +126 -0
- package/eslint/react.js +159 -0
- package/eslint/rules/architecture.js +152 -0
- package/eslint/rules/code-quality.js +142 -0
- package/eslint/rules/naming-conventions.js +183 -0
- package/eslint/rules/spellcheck.js +263 -0
- package/index.d.ts +4 -0
- package/index.js +11 -0
- package/package.json +69 -0
- package/prettier/index.js +47 -0
- package/typescript/tsconfig.json +84 -0
- package/typescript/tsconfig.node.json +52 -0
- package/typescript/tsconfig.react.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# @qvaro/configs
|
|
2
|
+
|
|
3
|
+
> **Centralized Qvaro coding standards for TypeScript frontend projects.**
|
|
4
|
+
>
|
|
5
|
+
> This library acts as the **single source of truth** for all coding, architecture, and tooling standards. All rule violations **fail CI/CD pipelines**, removing human discretion from standards enforcement.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@qvaro/configs)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 📦 Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install --save-dev @qvaro/configs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Peer Dependencies
|
|
19
|
+
|
|
20
|
+
Ensure these are installed in your project:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install --save-dev eslint prettier typescript
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 🚀 Quick Setup
|
|
29
|
+
|
|
30
|
+
### 1. ESLint Configuration
|
|
31
|
+
|
|
32
|
+
Create `.eslintrc.js` in your project root:
|
|
33
|
+
|
|
34
|
+
**For React/Next.js projects:**
|
|
35
|
+
```javascript
|
|
36
|
+
module.exports = {
|
|
37
|
+
extends: ['./node_modules/@qvaro/configs/eslint/react.js'],
|
|
38
|
+
parserOptions: {
|
|
39
|
+
project: './tsconfig.json',
|
|
40
|
+
tsconfigRootDir: __dirname,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**For Node.js/Backend projects:**
|
|
46
|
+
```javascript
|
|
47
|
+
module.exports = {
|
|
48
|
+
extends: ['./node_modules/@qvaro/configs/eslint/node.js'],
|
|
49
|
+
parserOptions: {
|
|
50
|
+
project: './tsconfig.json',
|
|
51
|
+
tsconfigRootDir: __dirname,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**For base TypeScript projects:**
|
|
57
|
+
```javascript
|
|
58
|
+
module.exports = {
|
|
59
|
+
extends: ['./node_modules/@qvaro/configs/eslint/index.js'],
|
|
60
|
+
parserOptions: {
|
|
61
|
+
project: './tsconfig.json',
|
|
62
|
+
tsconfigRootDir: __dirname,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 2. Prettier Configuration
|
|
68
|
+
|
|
69
|
+
Create `prettier.config.js`:
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
module.exports = require('@qvaro/configs/prettier');
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. TypeScript Configuration
|
|
76
|
+
|
|
77
|
+
Create `tsconfig.json`:
|
|
78
|
+
|
|
79
|
+
**For React projects:**
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"extends": "@qvaro/configs/typescript/react",
|
|
83
|
+
"compilerOptions": {
|
|
84
|
+
"baseUrl": "."
|
|
85
|
+
},
|
|
86
|
+
"include": ["src/**/*"],
|
|
87
|
+
"exclude": ["node_modules", "dist"]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**For Node.js projects:**
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"extends": "@qvaro/configs/typescript/node",
|
|
95
|
+
"compilerOptions": {
|
|
96
|
+
"baseUrl": "."
|
|
97
|
+
},
|
|
98
|
+
"include": ["src/**/*"],
|
|
99
|
+
"exclude": ["node_modules", "dist"]
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 📐 Enforced Standards
|
|
106
|
+
|
|
107
|
+
### Naming Conventions
|
|
108
|
+
|
|
109
|
+
| Element | Format | Example |
|
|
110
|
+
|---------|--------|---------|
|
|
111
|
+
| Classes, Controllers, Models | `PascalCase` | `UserController` |
|
|
112
|
+
| UI Components | `PascalCase` | `NavigationBar` |
|
|
113
|
+
| Interfaces | `IPascalCase` | `IUserService` |
|
|
114
|
+
| Local variables | `camelCase` | `userData` |
|
|
115
|
+
| Method parameters | `camelCase` | `userId` |
|
|
116
|
+
| Constants | `UPPER_SNAKE_CASE` | `MAX_RETRY_COUNT` |
|
|
117
|
+
| Private methods | `_camelCase` | `_validateInput` |
|
|
118
|
+
| Async methods | `*Async` suffix | `fetchUserAsync` |
|
|
119
|
+
|
|
120
|
+
### Code Quality Limits
|
|
121
|
+
|
|
122
|
+
| Rule | Limit | Severity |
|
|
123
|
+
|------|-------|----------|
|
|
124
|
+
| Method length | 40 lines max | ❌ Error |
|
|
125
|
+
| File/Class length | 300 lines max | ❌ Error |
|
|
126
|
+
| Nested if statements | 2 levels max | ❌ Error |
|
|
127
|
+
| Cyclomatic complexity | 10 max | ❌ Error |
|
|
128
|
+
| Function parameters | 4 max | ❌ Error |
|
|
129
|
+
|
|
130
|
+
### Prohibited Patterns
|
|
131
|
+
|
|
132
|
+
- ❌ Magic strings/numbers (use constants)
|
|
133
|
+
- ❌ Empty catch blocks (must log & rethrow)
|
|
134
|
+
- ❌ Deeply nested code (use guard clauses)
|
|
135
|
+
- ❌ Floating promises (must await or handle)
|
|
136
|
+
- ❌ Any type usage (must be explicit)
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 🏗️ Folder Structure Enforcement
|
|
141
|
+
|
|
142
|
+
Required project structure:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
src/
|
|
146
|
+
├── api/ # API clients & endpoints
|
|
147
|
+
├── components/ # Reusable UI components
|
|
148
|
+
├── services/ # Business logic layer
|
|
149
|
+
├── events/ # Event handlers & emitters
|
|
150
|
+
├── animations/ # Animation definitions
|
|
151
|
+
├── styles/ # Global styles & themes
|
|
152
|
+
├── hooks/ # Custom React hooks
|
|
153
|
+
├── views/ # Page-level components (presentation only)
|
|
154
|
+
├── types/ # TypeScript interfaces & types
|
|
155
|
+
├── constants/ # Application constants
|
|
156
|
+
└── utils/ # Utility functions
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Boundary Rules
|
|
160
|
+
|
|
161
|
+
| Layer | Can Import From |
|
|
162
|
+
|-------|-----------------|
|
|
163
|
+
| `views` | components, styles, hooks, animations, constants |
|
|
164
|
+
| `components` | components, styles, hooks, utils, types, animations |
|
|
165
|
+
| `hooks` | services, api, types, utils |
|
|
166
|
+
| `services` | api, types, utils, constants |
|
|
167
|
+
| `api` | types, utils, constants |
|
|
168
|
+
|
|
169
|
+
> ⚠️ **Views cannot import from `api` or `services` directly!** Use hooks instead.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 🔧 CI/CD Integration
|
|
174
|
+
|
|
175
|
+
### GitHub Actions
|
|
176
|
+
|
|
177
|
+
```yaml
|
|
178
|
+
name: Lint & Type Check
|
|
179
|
+
|
|
180
|
+
on: [push, pull_request]
|
|
181
|
+
|
|
182
|
+
jobs:
|
|
183
|
+
lint:
|
|
184
|
+
runs-on: ubuntu-latest
|
|
185
|
+
steps:
|
|
186
|
+
- uses: actions/checkout@v4
|
|
187
|
+
- uses: actions/setup-node@v4
|
|
188
|
+
with:
|
|
189
|
+
node-version: '20'
|
|
190
|
+
cache: 'npm'
|
|
191
|
+
|
|
192
|
+
- run: npm ci
|
|
193
|
+
- run: npm run lint
|
|
194
|
+
# Fails on any lint error
|
|
195
|
+
- run: npx tsc --noEmit
|
|
196
|
+
# Fails on type errors
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Package.json Scripts
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"scripts": {
|
|
204
|
+
"lint": "eslint . --ext .ts,.tsx --max-warnings 0",
|
|
205
|
+
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
|
206
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,json,css}\"",
|
|
207
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,css}\"",
|
|
208
|
+
"typecheck": "tsc --noEmit"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 📝 Examples
|
|
216
|
+
|
|
217
|
+
### ✅ Correct Naming
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// Constants - UPPER_SNAKE_CASE
|
|
221
|
+
const MAX_RETRY_ATTEMPTS = 3;
|
|
222
|
+
const API_BASE_URL = 'https://api.example.com';
|
|
223
|
+
|
|
224
|
+
// Interface - IPascalCase
|
|
225
|
+
interface IUserProfile {
|
|
226
|
+
id: string;
|
|
227
|
+
displayName: string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Class - PascalCase
|
|
231
|
+
class UserService {
|
|
232
|
+
// Private property - _camelCase
|
|
233
|
+
private readonly _httpClient: IHttpClient;
|
|
234
|
+
|
|
235
|
+
// Async method - ends with Async
|
|
236
|
+
public async fetchUserAsync(userId: string): Promise<IUserProfile> {
|
|
237
|
+
return await this._httpClient.getAsync(`/users/${userId}`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Private async method
|
|
241
|
+
private async _validateTokenAsync(): Promise<boolean> {
|
|
242
|
+
// ...
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### ❌ Incorrect (Will Fail)
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// ❌ Magic number
|
|
251
|
+
if (retryCount > 3) { }
|
|
252
|
+
|
|
253
|
+
// ❌ Interface without I prefix
|
|
254
|
+
interface UserProfile { }
|
|
255
|
+
|
|
256
|
+
// ❌ Async method without Async suffix
|
|
257
|
+
async function fetchUser() { }
|
|
258
|
+
|
|
259
|
+
// ❌ Empty catch block
|
|
260
|
+
try {
|
|
261
|
+
await riskyOperation();
|
|
262
|
+
} catch (e) {
|
|
263
|
+
// Empty - will error!
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ❌ Too much nesting
|
|
267
|
+
if (a) {
|
|
268
|
+
if (b) {
|
|
269
|
+
if (c) { // Error: max depth 2
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### ✅ Guard Clause Pattern
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
// ✅ Preferred: Early returns
|
|
279
|
+
function processUser(user: IUser | null): void {
|
|
280
|
+
if (!user) {
|
|
281
|
+
throw new Error('User is required');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!user.isActive) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Main logic here (flat, readable)
|
|
289
|
+
performAction(user);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ❌ Avoid: Deep nesting
|
|
293
|
+
function processUser(user: IUser | null): void {
|
|
294
|
+
if (user) {
|
|
295
|
+
if (user.isActive) {
|
|
296
|
+
performAction(user);
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
throw new Error('User is required');
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## 🔄 Extending Rules
|
|
307
|
+
|
|
308
|
+
Override specific rules in your project's `.eslintrc.js`:
|
|
309
|
+
|
|
310
|
+
```javascript
|
|
311
|
+
module.exports = {
|
|
312
|
+
extends: ['./node_modules/@qvaro/configs/eslint/react.js'],
|
|
313
|
+
rules: {
|
|
314
|
+
// Relax for specific project needs
|
|
315
|
+
'max-lines-per-function': ['error', { max: 60 }],
|
|
316
|
+
|
|
317
|
+
// Add project-specific rules
|
|
318
|
+
'no-restricted-imports': ['error', {
|
|
319
|
+
patterns: ['lodash/*'],
|
|
320
|
+
}],
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## 📋 Spellcheck Configuration
|
|
328
|
+
|
|
329
|
+
Variable names are checked for spelling. Add project-specific terms:
|
|
330
|
+
|
|
331
|
+
```javascript
|
|
332
|
+
module.exports = {
|
|
333
|
+
extends: ['./node_modules/@qvaro/configs/eslint'],
|
|
334
|
+
rules: {
|
|
335
|
+
'spellcheck/spell-checker': ['warn', {
|
|
336
|
+
skipWords: [
|
|
337
|
+
// Add your domain terms
|
|
338
|
+
'qvaro',
|
|
339
|
+
'oauth',
|
|
340
|
+
'saml',
|
|
341
|
+
],
|
|
342
|
+
}],
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## 🛡️ Enforcement Philosophy
|
|
350
|
+
|
|
351
|
+
> *"All rules are strictly enforced. Violations fail CI/CD pipelines. This library acts as the single source of truth, removing human discretion from coding standards enforcement."*
|
|
352
|
+
|
|
353
|
+
### Why Strict Enforcement?
|
|
354
|
+
|
|
355
|
+
1. **Consistency** - Every project follows identical standards
|
|
356
|
+
2. **Onboarding** - New developers learn patterns immediately
|
|
357
|
+
3. **Code Review** - Focus on logic, not style debates
|
|
358
|
+
4. **Maintainability** - Consistent code is easier to maintain
|
|
359
|
+
5. **Quality** - Prevents common bugs before they ship
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 📁 Package Contents
|
|
364
|
+
|
|
365
|
+
```
|
|
366
|
+
@qvaro/configs/
|
|
367
|
+
├── eslint/
|
|
368
|
+
│ ├── index.js # Base ESLint config
|
|
369
|
+
│ ├── react.js # React/Next.js config
|
|
370
|
+
│ ├── node.js # Node.js/Backend config
|
|
371
|
+
│ └── rules/
|
|
372
|
+
│ ├── naming-conventions.js
|
|
373
|
+
│ ├── code-quality.js
|
|
374
|
+
│ ├── architecture.js
|
|
375
|
+
│ └── spellcheck.js
|
|
376
|
+
├── prettier/
|
|
377
|
+
│ └── index.js # Prettier config
|
|
378
|
+
├── typescript/
|
|
379
|
+
│ ├── tsconfig.json # Base TS config
|
|
380
|
+
│ ├── tsconfig.react.json # React TS config
|
|
381
|
+
│ └── tsconfig.node.json # Node.js TS config
|
|
382
|
+
├── index.js
|
|
383
|
+
├── index.d.ts
|
|
384
|
+
└── package.json
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## 📄 License
|
|
390
|
+
|
|
391
|
+
MIT © Qvaro DevOps Team
|
package/eslint/index.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @qvaroo/configs - ESLint Configuration
|
|
3
|
+
*
|
|
4
|
+
* Strict Qvaroo-wide ESLint rules for TypeScript projects.
|
|
5
|
+
* All violations will fail CI/CD pipelines.
|
|
6
|
+
*
|
|
7
|
+
* @author Qvaroo DevOps Team
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const namingConventionRules = require('./rules/naming-conventions');
|
|
12
|
+
const codeQualityRules = require('./rules/code-quality');
|
|
13
|
+
const architectureRules = require('./rules/architecture');
|
|
14
|
+
const spellcheckRules = require('./rules/spellcheck');
|
|
15
|
+
|
|
16
|
+
/** @type {import('eslint').Linter.Config} */
|
|
17
|
+
module.exports = {
|
|
18
|
+
root: true,
|
|
19
|
+
|
|
20
|
+
parser: '@typescript-eslint/parser',
|
|
21
|
+
|
|
22
|
+
parserOptions: {
|
|
23
|
+
ecmaVersion: 2022,
|
|
24
|
+
sourceType: 'module',
|
|
25
|
+
project: './tsconfig.json',
|
|
26
|
+
tsconfigRootDir: process.cwd(),
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
plugins: [
|
|
30
|
+
'@typescript-eslint',
|
|
31
|
+
'spellcheck',
|
|
32
|
+
'boundaries',
|
|
33
|
+
'import',
|
|
34
|
+
'promise',
|
|
35
|
+
'unicorn',
|
|
36
|
+
'sonarjs',
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
extends: [
|
|
40
|
+
'eslint:recommended',
|
|
41
|
+
'plugin:@typescript-eslint/recommended',
|
|
42
|
+
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
|
43
|
+
'plugin:@typescript-eslint/strict',
|
|
44
|
+
'plugin:import/recommended',
|
|
45
|
+
'plugin:import/typescript',
|
|
46
|
+
'plugin:promise/recommended',
|
|
47
|
+
'plugin:sonarjs/recommended',
|
|
48
|
+
'prettier', // Must be last to override formatting rules
|
|
49
|
+
],
|
|
50
|
+
|
|
51
|
+
settings: {
|
|
52
|
+
'import/resolver': {
|
|
53
|
+
typescript: {
|
|
54
|
+
alwaysTryTypes: true,
|
|
55
|
+
project: './tsconfig.json',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
'boundaries/elements': [
|
|
59
|
+
{ type: 'api', pattern: 'src/api/*' },
|
|
60
|
+
{ type: 'components', pattern: 'src/components/*' },
|
|
61
|
+
{ type: 'services', pattern: 'src/services/*' },
|
|
62
|
+
{ type: 'events', pattern: 'src/events/*' },
|
|
63
|
+
{ type: 'animations', pattern: 'src/animations/*' },
|
|
64
|
+
{ type: 'styles', pattern: 'src/styles/*' },
|
|
65
|
+
{ type: 'utils', pattern: 'src/utils/*' },
|
|
66
|
+
{ type: 'types', pattern: 'src/types/*' },
|
|
67
|
+
{ type: 'constants', pattern: 'src/constants/*' },
|
|
68
|
+
{ type: 'hooks', pattern: 'src/hooks/*' },
|
|
69
|
+
{ type: 'views', pattern: 'src/views/*' },
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
rules: {
|
|
74
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
75
|
+
// NAMING CONVENTIONS - Strict enforcement
|
|
76
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
77
|
+
...namingConventionRules,
|
|
78
|
+
|
|
79
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
80
|
+
// CODE QUALITY - Method/class length, nesting, magic values
|
|
81
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
82
|
+
...codeQualityRules,
|
|
83
|
+
|
|
84
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
85
|
+
// ARCHITECTURE - Folder boundaries and separation of concerns
|
|
86
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
87
|
+
...architectureRules,
|
|
88
|
+
|
|
89
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
90
|
+
// SPELLCHECK - Variable name clarity
|
|
91
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
92
|
+
...spellcheckRules,
|
|
93
|
+
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
95
|
+
// ERROR HANDLING - No empty catches, must log & rethrow
|
|
96
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
97
|
+
'no-empty': ['error', { allowEmptyCatch: false }],
|
|
98
|
+
'@typescript-eslint/no-empty-function': 'error',
|
|
99
|
+
'no-useless-catch': 'error',
|
|
100
|
+
|
|
101
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
102
|
+
// PROMISE/ASYNC HANDLING
|
|
103
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
104
|
+
'@typescript-eslint/no-floating-promises': 'error',
|
|
105
|
+
'@typescript-eslint/no-misused-promises': 'error',
|
|
106
|
+
'@typescript-eslint/promise-function-async': 'error',
|
|
107
|
+
'promise/always-return': 'error',
|
|
108
|
+
'promise/no-return-wrap': 'error',
|
|
109
|
+
'promise/param-names': 'error',
|
|
110
|
+
'promise/catch-or-return': 'error',
|
|
111
|
+
'promise/no-nesting': 'warn',
|
|
112
|
+
|
|
113
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
114
|
+
// IMPORT ORGANIZATION
|
|
115
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
116
|
+
'import/order': [
|
|
117
|
+
'error',
|
|
118
|
+
{
|
|
119
|
+
groups: [
|
|
120
|
+
'builtin',
|
|
121
|
+
'external',
|
|
122
|
+
'internal',
|
|
123
|
+
'parent',
|
|
124
|
+
'sibling',
|
|
125
|
+
'index',
|
|
126
|
+
'type',
|
|
127
|
+
],
|
|
128
|
+
'newlines-between': 'always',
|
|
129
|
+
alphabetize: { order: 'asc', caseInsensitive: true },
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
'import/no-duplicates': 'error',
|
|
133
|
+
'import/no-unresolved': 'error',
|
|
134
|
+
'import/no-cycle': 'error',
|
|
135
|
+
|
|
136
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
137
|
+
// GENERAL BEST PRACTICES
|
|
138
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
139
|
+
'no-console': ['error', { allow: ['warn', 'error', 'info'] }],
|
|
140
|
+
'no-debugger': 'error',
|
|
141
|
+
'no-alert': 'error',
|
|
142
|
+
'prefer-const': 'error',
|
|
143
|
+
'no-var': 'error',
|
|
144
|
+
'eqeqeq': ['error', 'always'],
|
|
145
|
+
'curly': ['error', 'all'],
|
|
146
|
+
'no-eval': 'error',
|
|
147
|
+
'no-implied-eval': 'error',
|
|
148
|
+
'no-new-func': 'error',
|
|
149
|
+
'no-return-await': 'off', // Handled by @typescript-eslint/return-await
|
|
150
|
+
'@typescript-eslint/return-await': ['error', 'in-try-catch'],
|
|
151
|
+
'@typescript-eslint/explicit-function-return-type': [
|
|
152
|
+
'error',
|
|
153
|
+
{
|
|
154
|
+
allowExpressions: true,
|
|
155
|
+
allowTypedFunctionExpressions: true,
|
|
156
|
+
allowHigherOrderFunctions: true,
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
'@typescript-eslint/explicit-member-accessibility': [
|
|
160
|
+
'error',
|
|
161
|
+
{ accessibility: 'explicit' },
|
|
162
|
+
],
|
|
163
|
+
'@typescript-eslint/no-explicit-any': 'error',
|
|
164
|
+
'@typescript-eslint/no-unused-vars': [
|
|
165
|
+
'error',
|
|
166
|
+
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
|
167
|
+
],
|
|
168
|
+
|
|
169
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
170
|
+
// UNICORN - Modern JavaScript practices
|
|
171
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
172
|
+
'unicorn/prefer-module': 'error',
|
|
173
|
+
'unicorn/prefer-node-protocol': 'error',
|
|
174
|
+
'unicorn/prefer-top-level-await': 'error',
|
|
175
|
+
'unicorn/no-null': 'off', // Allow null for React patterns
|
|
176
|
+
'unicorn/prevent-abbreviations': [
|
|
177
|
+
'error',
|
|
178
|
+
{
|
|
179
|
+
replacements: {
|
|
180
|
+
props: false,
|
|
181
|
+
params: false,
|
|
182
|
+
args: false,
|
|
183
|
+
ref: false,
|
|
184
|
+
err: false,
|
|
185
|
+
ctx: false,
|
|
186
|
+
req: false,
|
|
187
|
+
res: false,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
overrides: [
|
|
194
|
+
// Test files - relaxed rules
|
|
195
|
+
{
|
|
196
|
+
files: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx'],
|
|
197
|
+
rules: {
|
|
198
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
199
|
+
'sonarjs/no-duplicate-string': 'off',
|
|
200
|
+
'max-lines-per-function': 'off',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
// Configuration files
|
|
204
|
+
{
|
|
205
|
+
files: ['*.config.js', '*.config.ts', '.eslintrc.js'],
|
|
206
|
+
rules: {
|
|
207
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
208
|
+
'unicorn/prefer-module': 'off',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
|
|
213
|
+
ignorePatterns: [
|
|
214
|
+
'node_modules/',
|
|
215
|
+
'dist/',
|
|
216
|
+
'build/',
|
|
217
|
+
'coverage/',
|
|
218
|
+
'.next/',
|
|
219
|
+
'*.min.js',
|
|
220
|
+
'*.generated.ts',
|
|
221
|
+
],
|
|
222
|
+
};
|