@reasonabletech/eslint-config 0.1.0 → 0.2.1
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/CHANGELOG.md +28 -1
- package/docs/concepts/ai-code-safety.md +268 -0
- package/docs/concepts/architecture.md +394 -0
- package/docs/guides/migration.md +47 -0
- package/docs/guides/usage-guide.md +236 -0
- package/docs/index.md +29 -0
- package/docs/reference/api-reference.md +230 -0
- package/docs/reference/base-config.md +118 -0
- package/docs/reference/frameworks/README.md +61 -0
- package/docs/reference/frameworks/next-config.md +187 -0
- package/docs/reference/frameworks/react-config.md +273 -0
- package/docs/tutorials/refactoring-react-for-type-safety.md +411 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,36 @@
|
|
|
1
1
|
# @reasonabletech/eslint-config
|
|
2
2
|
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- - Automated release.
|
|
8
|
+
|
|
9
|
+
## 0.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [`f862453`](https://github.com/ReasonableTech/core-utils/commit/f86245352ba4ef8df56a124c8f17bf8605ac9085) Thanks [@WillieCubed](https://github.com/WillieCubed)! - Audit and fix custom ESLint rules for correctness, false-positive reduction, and API consistency.
|
|
14
|
+
|
|
15
|
+
#### Breaking changes — action required
|
|
16
|
+
- `no-linter-disabling` is deprecated and no longer enabled by default. If you relied on it, use ESLint's built-in `reportUnusedDisableDirectives` option and the native `-- reason` inline syntax instead. The rule remains in the plugin if you need to opt in explicitly.
|
|
17
|
+
- `no-dependency-bundling` no longer flags interfaces based on property types. Only interfaces and type aliases named `*Dependencies` or `*Deps` are flagged. If you had false-positive suppressions for domain models, you can remove them.
|
|
18
|
+
- `createTerminologyRules()` no longer includes default forbidden terms. Pass `forbiddenTerms` explicitly: `createTerminologyRules({ forbiddenTerms: { toolCall: "action" } })`.
|
|
19
|
+
- `createBarrelExportRules()` and `createCodeQualityRules()` no longer accept options (the parameters were no-ops). Remove any arguments at the call site.
|
|
20
|
+
- `createResultTypeRules()` has been removed (it returned an empty object). Remove any imports.
|
|
21
|
+
|
|
22
|
+
#### New rule
|
|
23
|
+
- `no-constructor-instantiation` replaces the previous `no-restricted-syntax` selector that flagged all `new PascalCase()` calls in constructors. The new rule allows built-in constructors (`Map`, `Date`, `Set`, etc.) and default parameter values (`db: Database = new Database()`). No config changes needed — `createDependencyInjectionRules()` uses it automatically.
|
|
24
|
+
|
|
25
|
+
#### Bug fixes
|
|
26
|
+
- `no-error-message-parsing` now correctly detects `/regex/.test(error.message)` patterns (previously only caught `error.message.test()`, which nobody writes).
|
|
27
|
+
- `mergeRuleConfigurations` no longer silently escalates `"warn"` severity to `"error"` when merging `no-restricted-syntax` patterns.
|
|
28
|
+
- `no-null-undefined-checks` error message now provides actionable guidance on simplifying `T | null | undefined` types.
|
|
29
|
+
|
|
3
30
|
## [Unreleased]
|
|
4
31
|
|
|
5
32
|
Initial release preparation. See [README.md](./README.md) for usage.
|
|
6
33
|
|
|
7
34
|
---
|
|
8
35
|
|
|
9
|
-
|
|
36
|
+
_Changelog entries are automatically generated from [changesets](https://github.com/changesets/changesets) on release._
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# AI Code Safety Through Strict Linting
|
|
2
|
+
|
|
3
|
+
## Philosophy
|
|
4
|
+
|
|
5
|
+
The the codebase is predominantly AI-generated, which presents unique challenges and opportunities for code quality management. Our ESLint configuration is designed with this reality in mind, emphasizing strict rules that force both human developers and AI tools to produce safer, more maintainable code.
|
|
6
|
+
|
|
7
|
+
## Core Principles
|
|
8
|
+
|
|
9
|
+
### 1. **Strict Rules, No Warnings**
|
|
10
|
+
|
|
11
|
+
We have a zero-tolerance policy for ESLint warnings in our codebase:
|
|
12
|
+
|
|
13
|
+
- **All rules are set to `"error"`** - no warnings that can be ignored
|
|
14
|
+
- **Builds fail on any linting violation** - forcing immediate resolution
|
|
15
|
+
- **No `eslint-disable` comments** - rules must be followed, not bypassed
|
|
16
|
+
|
|
17
|
+
**Rationale**: Warnings are too easy to ignore. In a large codebase with frequent AI-generated changes, deferred issues accumulate quickly and become technical debt.
|
|
18
|
+
|
|
19
|
+
### 2. **"Rip the Band-Aid Off Early"**
|
|
20
|
+
|
|
21
|
+
Issues are caught and resolved immediately during development, not during code review:
|
|
22
|
+
|
|
23
|
+
- **Fail fast development cycles** - problems surface during writing, not review
|
|
24
|
+
- **Reduced cognitive load** - developers focus on logic, not style cleanup
|
|
25
|
+
- **Consistent quality gates** - every commit meets the same high standards
|
|
26
|
+
|
|
27
|
+
### 3. **Type Safety is Non-Negotiable**
|
|
28
|
+
|
|
29
|
+
Type-aware ESLint rules are mandatory across all projects:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// Canonical setup (required)
|
|
33
|
+
import { createTypeAwareConfig } from "@reasonabletech/eslint-config";
|
|
34
|
+
export default createTypeAwareConfig(import.meta.dirname);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Why type-aware rules matter**:
|
|
38
|
+
|
|
39
|
+
- Catch more runtime errors during development
|
|
40
|
+
- Force explicit type annotations that improve readability
|
|
41
|
+
- Prevent common AI-generated code issues (implicit any, unsafe assignments)
|
|
42
|
+
- Enable better IDE support and refactoring safety
|
|
43
|
+
|
|
44
|
+
### 4. **Explicit Behavior Over Implicit**
|
|
45
|
+
|
|
46
|
+
We prefer explicit code patterns that make intent clear:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// ❌ Implicit, unclear behavior
|
|
50
|
+
if (process.env.DATABASE_URL) {
|
|
51
|
+
connect(process.env.DATABASE_URL);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ✅ Explicit, safe behavior
|
|
55
|
+
const config = getEnvironmentConfig();
|
|
56
|
+
if (config.database.url) {
|
|
57
|
+
connect(config.database.url);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 5. **Avoid Silent Errors**
|
|
62
|
+
|
|
63
|
+
Code should fail loudly and predictably rather than silently producing incorrect results:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// ❌ Silent failure potential
|
|
67
|
+
const result = data?.user?.profile?.name || "Unknown";
|
|
68
|
+
|
|
69
|
+
// ✅ Explicit error handling
|
|
70
|
+
const result = getUserProfile(data);
|
|
71
|
+
if (!result.success) {
|
|
72
|
+
logger.error("Failed to get user profile", { error: result.error });
|
|
73
|
+
return { success: false, error: "Profile unavailable" };
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Type Safety Requirements
|
|
78
|
+
|
|
79
|
+
### Strict Null/Undefined Handling
|
|
80
|
+
|
|
81
|
+
We minimize nullable types and prefer explicit error handling:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// ❌ Nullable return types
|
|
85
|
+
function getUser(id: string): User | null {
|
|
86
|
+
// Silent failure case
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ✅ Result types for explicit error handling
|
|
90
|
+
function getUser(id: string): Result<User, "not_found" | "database_error"> {
|
|
91
|
+
try {
|
|
92
|
+
const user = database.findUser(id);
|
|
93
|
+
if (!user) {
|
|
94
|
+
return { success: false, error: "not_found" };
|
|
95
|
+
}
|
|
96
|
+
return { success: true, data: user };
|
|
97
|
+
} catch (error) {
|
|
98
|
+
return { success: false, error: "database_error" };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Environment Variable Safety
|
|
104
|
+
|
|
105
|
+
Raw `process.env` access is discouraged. Use configuration wrappers:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// ❌ Direct environment access
|
|
109
|
+
if (process.env.NODE_ENV === "production") {
|
|
110
|
+
// Complex conditional logic
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ✅ Wrapped configuration
|
|
114
|
+
const config = getEnvironmentConfig();
|
|
115
|
+
if (config.isProduction) {
|
|
116
|
+
// Clear intent
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Result Types for Domain Logic
|
|
121
|
+
|
|
122
|
+
Use `Result<T, E>` from `@reasonabletech/utils/result` for operations that can fail:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import type { Result } from "@reasonabletech/utils/result";
|
|
126
|
+
|
|
127
|
+
// Domain operations that can fail should return Results
|
|
128
|
+
async function processPayment(
|
|
129
|
+
amount: number,
|
|
130
|
+
): Promise<Result<PaymentConfirmation, PaymentError>> {
|
|
131
|
+
// Implementation with explicit error cases
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Consumers handle all cases explicitly
|
|
135
|
+
const result = await processPayment(100);
|
|
136
|
+
if (result.success) {
|
|
137
|
+
console.log("Payment processed:", result.data);
|
|
138
|
+
} else {
|
|
139
|
+
handlePaymentError(result.error);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## AI-Specific Benefits
|
|
144
|
+
|
|
145
|
+
### 1. **Forces Better AI Output**
|
|
146
|
+
|
|
147
|
+
Strict linting rules compel AI tools to generate higher-quality code:
|
|
148
|
+
|
|
149
|
+
- **Type annotations**: AI must provide explicit return types
|
|
150
|
+
- **Error handling**: AI cannot ignore potential failure cases
|
|
151
|
+
- **Null safety**: AI must handle undefined/null cases explicitly
|
|
152
|
+
|
|
153
|
+
### 2. **Prevents Common AI Mistakes**
|
|
154
|
+
|
|
155
|
+
- **Unused variables**: AI often generates variables it doesn't use
|
|
156
|
+
- **Unsafe type assertions**: AI may use `any` types inappropriately
|
|
157
|
+
- **Missing await**: AI sometimes forgets async/await patterns
|
|
158
|
+
- **Template literal safety**: AI must handle potentially undefined values in strings
|
|
159
|
+
|
|
160
|
+
### 3. **Consistent Code Patterns**
|
|
161
|
+
|
|
162
|
+
AI learns to follow consistent patterns across the codebase:
|
|
163
|
+
|
|
164
|
+
- Result types for error handling
|
|
165
|
+
- Explicit type annotations
|
|
166
|
+
- Safe environment variable access
|
|
167
|
+
- Structured logging with context
|
|
168
|
+
|
|
169
|
+
## Configuration Details
|
|
170
|
+
|
|
171
|
+
### Key Strict Rules
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
{
|
|
175
|
+
// Type safety (errors, not warnings)
|
|
176
|
+
"@typescript-eslint/explicit-function-return-type": "error",
|
|
177
|
+
"@typescript-eslint/no-explicit-any": "error",
|
|
178
|
+
"@typescript-eslint/strict-boolean-expressions": "error",
|
|
179
|
+
"@typescript-eslint/prefer-nullish-coalescing": "error",
|
|
180
|
+
"@typescript-eslint/no-non-null-assertion": "error",
|
|
181
|
+
|
|
182
|
+
// Runtime safety
|
|
183
|
+
"@typescript-eslint/no-floating-promises": "error",
|
|
184
|
+
"@typescript-eslint/no-misused-promises": "error",
|
|
185
|
+
"@typescript-eslint/await-thenable": "error",
|
|
186
|
+
|
|
187
|
+
// Code quality
|
|
188
|
+
"@typescript-eslint/no-unused-vars": "error",
|
|
189
|
+
"prefer-const": "error",
|
|
190
|
+
"no-throw-literal": "error"
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Non-Null Assertion Safety
|
|
195
|
+
|
|
196
|
+
The non-null assertion operator (`!`) is disabled because it completely bypasses TypeScript's null safety checks, potentially causing runtime crashes:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
// ❌ Dangerous - bypasses type safety
|
|
200
|
+
const token = createAuthToken(user!.id, user!.email);
|
|
201
|
+
const result = dangerousFunction()!.someProperty;
|
|
202
|
+
|
|
203
|
+
// ✅ Safe alternatives - explicit null checking
|
|
204
|
+
if (!user) {
|
|
205
|
+
throw new Error("User is required");
|
|
206
|
+
}
|
|
207
|
+
const token = createAuthToken(user.id, user.email);
|
|
208
|
+
|
|
209
|
+
// ✅ Safe alternatives - optional chaining with defaults
|
|
210
|
+
const token = user?.id ? createAuthToken(user.id, user.email) : null;
|
|
211
|
+
|
|
212
|
+
// ✅ Safe alternatives - type guards
|
|
213
|
+
function isValidUser(user: User | null): user is User {
|
|
214
|
+
return user !== null && user.id !== undefined;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (isValidUser(user)) {
|
|
218
|
+
const token = createAuthToken(user.id, user.email);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Why this matters for AI-generated code**: AI tools often use non-null assertions as shortcuts when they encounter nullable types. By disabling this feature, we force AI to implement proper null checking, leading to more robust code that handles edge cases explicitly.
|
|
223
|
+
|
|
224
|
+
### Canonical Setup Pattern
|
|
225
|
+
|
|
226
|
+
All projects should use one of the package configuration factories:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { createTypeAwareConfig } from "@reasonabletech/eslint-config";
|
|
230
|
+
|
|
231
|
+
export default createTypeAwareConfig(import.meta.dirname);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Benefits
|
|
235
|
+
|
|
236
|
+
### For Human Developers
|
|
237
|
+
|
|
238
|
+
- **Immediate feedback** on code quality issues
|
|
239
|
+
- **Consistent standards** across the entire codebase
|
|
240
|
+
- **Reduced review overhead** - linting catches issues before review
|
|
241
|
+
- **Better IDE support** with comprehensive type information
|
|
242
|
+
|
|
243
|
+
### For AI-Generated Code
|
|
244
|
+
|
|
245
|
+
- **Higher quality output** - AI tools adapt to strict requirements
|
|
246
|
+
- **Consistent patterns** - AI learns project conventions
|
|
247
|
+
- **Fewer runtime errors** - type-aware rules catch more issues
|
|
248
|
+
- **Explicit error handling** - AI is forced to handle edge cases
|
|
249
|
+
|
|
250
|
+
### for the Codebase
|
|
251
|
+
|
|
252
|
+
- **Predictable builds** - all code meets the same quality bar
|
|
253
|
+
- **Reduced technical debt** - issues are resolved immediately
|
|
254
|
+
- **Better maintainability** - explicit patterns are easier to understand
|
|
255
|
+
- **Safer refactoring** - comprehensive type information enables confident changes
|
|
256
|
+
|
|
257
|
+
## Conclusion
|
|
258
|
+
|
|
259
|
+
Our strict ESLint configuration is not about making development harder—it's about making development **safer** and more **predictable** in an AI-first codebase. By enforcing high standards immediately, we ensure that both human and AI contributors produce code that is reliable, maintainable, and explicit in its intent.
|
|
260
|
+
|
|
261
|
+
The investment in strict linting pays dividends in reduced debugging time, fewer production issues, and a codebase that remains comprehensible as it scales.
|
|
262
|
+
|
|
263
|
+
## Related Documentation
|
|
264
|
+
|
|
265
|
+
- [Architecture](./architecture.md) — Package design principles and configuration composition
|
|
266
|
+
- [API Reference](../reference/api-reference.md) — All exported functions and plugin rules
|
|
267
|
+
- [Usage Guide](../guides/usage-guide.md) — Setup instructions and troubleshooting
|
|
268
|
+
- [Custom Rules](../../src/custom-rules/README.md) — Rule catalog and contributing guide
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
This document outlines the architectural design and principles behind `@reasonabletech/eslint-config`, explaining the decisions made to create a maintainable, modular, and consistent ESLint configuration system for the monorepo.
|
|
4
|
+
|
|
5
|
+
## Design Principles
|
|
6
|
+
|
|
7
|
+
### 1. Type-Aware First
|
|
8
|
+
|
|
9
|
+
**Principle:** All configurations prioritize TypeScript type-aware rules as the primary approach.
|
|
10
|
+
|
|
11
|
+
**Rationale:** AI-generated code requires comprehensive static analysis to catch subtle runtime errors that syntax-only rules would miss. Type-aware rules leverage TypeScript's type system to detect:
|
|
12
|
+
|
|
13
|
+
- Unsafe type operations
|
|
14
|
+
- Floating promises
|
|
15
|
+
- Incorrect async/await usage
|
|
16
|
+
- Type assertion issues
|
|
17
|
+
- Boolean expression strictness
|
|
18
|
+
|
|
19
|
+
**Implementation:** The `createTypeAwareConfig()` function is the primary export for all greenfield TypeScript projects.
|
|
20
|
+
|
|
21
|
+
### 2. Modular Composition
|
|
22
|
+
|
|
23
|
+
**Principle:** All configurations are built from composable, shared modules to eliminate duplication.
|
|
24
|
+
|
|
25
|
+
**Rationale:** The original monolithic configuration contained 400+ lines with massive duplication across base, type-aware, React, and Next.js configurations. This led to:
|
|
26
|
+
|
|
27
|
+
- Maintenance overhead when updating rules
|
|
28
|
+
- Inconsistencies between configurations
|
|
29
|
+
- Difficulty understanding rule origins
|
|
30
|
+
- Code bloat
|
|
31
|
+
|
|
32
|
+
**Architecture:**
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
src/
|
|
36
|
+
├── index.ts # Base TypeScript configuration
|
|
37
|
+
├── react.ts # React configuration entry point
|
|
38
|
+
├── next.ts # Next.js configuration entry point
|
|
39
|
+
├── base-configs.ts # Core TypeScript configuration logic
|
|
40
|
+
├── react/ # React-specific modules
|
|
41
|
+
│ ├── config.ts # React configuration builder
|
|
42
|
+
│ ├── plugins.ts # React plugin setups
|
|
43
|
+
│ └── rules.ts # React rule definitions
|
|
44
|
+
├── next/ # Next.js-specific modules
|
|
45
|
+
│ ├── config.ts # Next.js configuration builder
|
|
46
|
+
│ ├── ignores.ts # File ignore patterns
|
|
47
|
+
│ ├── plugins.ts # Plugin loading and fallbacks
|
|
48
|
+
│ ├── rules.ts # Rule configurations
|
|
49
|
+
│ └── settings.ts # Plugin settings
|
|
50
|
+
├── shared/ # Shared utilities
|
|
51
|
+
│ └── react-rules.ts # Common React rules for both React and Next.js
|
|
52
|
+
├── shared-ignores.ts # Centralized ignore patterns
|
|
53
|
+
└── shared-rules.ts # Shared TypeScript rule sets
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 3. Explicit Over Implicit
|
|
57
|
+
|
|
58
|
+
**Principle:** All rules and patterns are explicitly defined rather than relying on defaults.
|
|
59
|
+
|
|
60
|
+
**Rationale:** AI-generated code analysis requires predictable, explicit rule sets. Implicit defaults can lead to:
|
|
61
|
+
|
|
62
|
+
- Inconsistent behavior across projects
|
|
63
|
+
- Difficulty debugging rule conflicts
|
|
64
|
+
- Unclear rule inheritance chains
|
|
65
|
+
|
|
66
|
+
**Implementation:** Each rule is explicitly set with clear documentation of its purpose and behavior.
|
|
67
|
+
|
|
68
|
+
### 4. Framework-Specific Customization
|
|
69
|
+
|
|
70
|
+
**Principle:** Framework configurations extend the base rather than replacing it entirely.
|
|
71
|
+
|
|
72
|
+
**Rationale:** Frameworks like React and Next.js have specific patterns that conflict with strict TypeScript rules, but they should still maintain the core safety guarantees.
|
|
73
|
+
|
|
74
|
+
**Implementation:** Framework overrides are isolated in separate rule sets that can be composed with the base configuration.
|
|
75
|
+
|
|
76
|
+
## Package Structure
|
|
77
|
+
|
|
78
|
+
### Core Components
|
|
79
|
+
|
|
80
|
+
#### 1. Shared Ignore Patterns (`src/shared-ignores.ts`)
|
|
81
|
+
|
|
82
|
+
**Purpose:** Centralized file exclusion patterns for all project types.
|
|
83
|
+
|
|
84
|
+
**Categories:**
|
|
85
|
+
|
|
86
|
+
- Build outputs (`dist/`, `build/`, `.next/`)
|
|
87
|
+
- Dependencies (`node_modules/`, `.pnp.*`)
|
|
88
|
+
- Generated files (`*.d.ts`, `*.generated.*`)
|
|
89
|
+
- Development tooling (`scripts/`, config files)
|
|
90
|
+
- Test infrastructure and coverage
|
|
91
|
+
- IDE and OS-specific files
|
|
92
|
+
|
|
93
|
+
**Design Decision:** Single array with comprehensive patterns rather than categorized objects to maintain ESLint compatibility and simplicity.
|
|
94
|
+
|
|
95
|
+
#### 2. Modular Rule Organization
|
|
96
|
+
|
|
97
|
+
**Purpose:** Framework-specific rule modules that eliminate duplication.
|
|
98
|
+
|
|
99
|
+
**React Module (`src/react/`):**
|
|
100
|
+
|
|
101
|
+
- `rules.ts`: React-specific rule definitions using shared React rules
|
|
102
|
+
- `plugins.ts`: React and React Hooks plugin configurations
|
|
103
|
+
- `config.ts`: Complete React configuration builder
|
|
104
|
+
|
|
105
|
+
**Next.js Module (`src/next/`):**
|
|
106
|
+
|
|
107
|
+
- `rules.ts`: Next.js rule definitions with React rule inheritance
|
|
108
|
+
- `plugins.ts`: Plugin loading with graceful fallbacks
|
|
109
|
+
- `ignores.ts`: Next.js-specific file ignore patterns
|
|
110
|
+
- `settings.ts`: Plugin settings for React and Next.js
|
|
111
|
+
- `config.ts`: Complete Next.js configuration orchestrator
|
|
112
|
+
|
|
113
|
+
**Shared Module (`src/shared/`):**
|
|
114
|
+
|
|
115
|
+
- `react-rules.ts`: Common React rules shared between React and Next.js configs
|
|
116
|
+
|
|
117
|
+
**Design Decision:** Focused modules with single responsibilities rather than monolithic rule objects to improve maintainability and enable better code organization.
|
|
118
|
+
|
|
119
|
+
#### 3. Base Configuration Builders (`src/base-configs.ts`)
|
|
120
|
+
|
|
121
|
+
**Purpose:** Factory functions that compose shared components into complete configurations.
|
|
122
|
+
|
|
123
|
+
**Functions:**
|
|
124
|
+
|
|
125
|
+
- `createTypeAwareBaseConfig()`: Type-aware foundation
|
|
126
|
+
|
|
127
|
+
**Design Decision:** Factory functions rather than static objects to enable parameterization (project directory) and better TypeScript integration.
|
|
128
|
+
|
|
129
|
+
### Framework Configurations
|
|
130
|
+
|
|
131
|
+
#### React Configuration (`react.ts`)
|
|
132
|
+
|
|
133
|
+
**Extends:** Base configuration + React-specific rules
|
|
134
|
+
|
|
135
|
+
**Additions:**
|
|
136
|
+
|
|
137
|
+
- React Hooks plugin with recommended rules
|
|
138
|
+
- JSX transform compatibility (no React import required)
|
|
139
|
+
- Browser and service worker globals
|
|
140
|
+
- Relaxed parameter typing for component props
|
|
141
|
+
|
|
142
|
+
**Design Decision:** Separate file to enable selective imports and clear framework boundaries.
|
|
143
|
+
|
|
144
|
+
#### Next.js Configuration (`next.ts`)
|
|
145
|
+
|
|
146
|
+
**Extends:** Base configuration + React rules + Next.js-specific rules
|
|
147
|
+
|
|
148
|
+
**Additions:**
|
|
149
|
+
|
|
150
|
+
- Next.js Core Web Vitals rules via FlatCompat
|
|
151
|
+
- Server action support (allows async without explicit await)
|
|
152
|
+
- Service worker globals for PWA features
|
|
153
|
+
|
|
154
|
+
**Design Decision:** Uses FlatCompat for Next.js integration to maintain compatibility with Next.js's ESLint plugin ecosystem.
|
|
155
|
+
|
|
156
|
+
## Architectural Patterns
|
|
157
|
+
|
|
158
|
+
### 1. Composition Over Inheritance
|
|
159
|
+
|
|
160
|
+
The package uses functional composition rather than class inheritance:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// ✅ Composition approach
|
|
164
|
+
const config = [
|
|
165
|
+
...createTypeAwareBaseConfig(projectDir),
|
|
166
|
+
reactPlugin.configs.flat.recommended,
|
|
167
|
+
{ rules: reactRuleOverrides },
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
// ❌ Inheritance approach (avoided)
|
|
171
|
+
class ReactConfig extends BaseConfig {
|
|
172
|
+
// Complex inheritance chain
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Benefits:**
|
|
177
|
+
|
|
178
|
+
- Clear data flow and dependencies
|
|
179
|
+
- Easy to understand rule sources
|
|
180
|
+
- No hidden inheritance behavior
|
|
181
|
+
- Better TypeScript inference
|
|
182
|
+
|
|
183
|
+
### 2. Configuration as Data
|
|
184
|
+
|
|
185
|
+
All configurations are plain JavaScript objects/arrays rather than classes:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// ✅ Data-driven approach
|
|
189
|
+
export const baseRules: Linter.RulesRecord = {
|
|
190
|
+
"no-throw-literal": "error",
|
|
191
|
+
// ...
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// ❌ Class-based approach (avoided)
|
|
195
|
+
class RuleManager {
|
|
196
|
+
getRules() {
|
|
197
|
+
/* complex logic */
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Benefits:**
|
|
203
|
+
|
|
204
|
+
- Serializable and inspectable
|
|
205
|
+
- No runtime dependencies
|
|
206
|
+
- Easy to merge and extend
|
|
207
|
+
- Compatible with ESLint's flat config system
|
|
208
|
+
|
|
209
|
+
### 3. Explicit Dependencies
|
|
210
|
+
|
|
211
|
+
All imports are explicit and traceable:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// ✅ Explicit imports
|
|
215
|
+
import { sharedIgnores } from "./shared-ignores.js";
|
|
216
|
+
import { baseRules, typeAwareRules } from "./shared-rules.js";
|
|
217
|
+
|
|
218
|
+
// ❌ Implicit dependencies (avoided)
|
|
219
|
+
import * as config from "./monolithic-config.js";
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Benefits:**
|
|
223
|
+
|
|
224
|
+
- Clear dependency relationships
|
|
225
|
+
- Better tree-shaking
|
|
226
|
+
- Easier refactoring
|
|
227
|
+
- Explicit API boundaries
|
|
228
|
+
|
|
229
|
+
## Rule Philosophy
|
|
230
|
+
|
|
231
|
+
### Error Handling Standards
|
|
232
|
+
|
|
233
|
+
**Principle:** Never parse error messages; always use structured error detection.
|
|
234
|
+
|
|
235
|
+
**Implementation:**
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
"no-throw-literal": "error",
|
|
239
|
+
"prefer-promise-reject-errors": "error",
|
|
240
|
+
"@typescript-eslint/only-throw-error": "error",
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Rationale:** AI-generated code often includes error handling patterns. Parsing error messages leads to brittle code that breaks when error messages change.
|
|
244
|
+
|
|
245
|
+
### TypeScript Safety
|
|
246
|
+
|
|
247
|
+
**Principle:** Maximize type safety while maintaining practical development experience.
|
|
248
|
+
|
|
249
|
+
**Implementation:**
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
"@typescript-eslint/no-explicit-any": "error",
|
|
253
|
+
"@typescript-eslint/no-non-null-assertion": "error",
|
|
254
|
+
"@typescript-eslint/strict-boolean-expressions": "error",
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Rationale:** AI-generated code can introduce subtle type safety issues. Strict rules catch these early in development.
|
|
258
|
+
|
|
259
|
+
### Framework Accommodations
|
|
260
|
+
|
|
261
|
+
**Principle:** Relax rules only where framework patterns make strict rules impractical.
|
|
262
|
+
|
|
263
|
+
**Example - React:**
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
"@typescript-eslint/prefer-readonly-parameter-types": "off", // Component props
|
|
267
|
+
"@typescript-eslint/require-await": "off", // Event handlers
|
|
268
|
+
"@typescript-eslint/unbound-method": "off", // React patterns
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Important Change: Strict Boolean Expressions in React**
|
|
272
|
+
|
|
273
|
+
As of the latest architecture revision, **`@typescript-eslint/strict-boolean-expressions` is no longer disabled for React projects**. This maintains consistent architectural patterns across the platform and prevents subtle rendering bugs.
|
|
274
|
+
|
|
275
|
+
**Rationale:**
|
|
276
|
+
|
|
277
|
+
- **Consistency**: All TypeScript code follows the same strict patterns
|
|
278
|
+
- **Bug Prevention**: Prevents rendering of `0`, `""`, or `[object Object]` in React components
|
|
279
|
+
- **Better Architecture**: Encourages explicit conditional logic over implicit truthiness
|
|
280
|
+
- **AI Code Safety**: Maintains strict type checking even in React contexts
|
|
281
|
+
|
|
282
|
+
React components should use explicit boolean checks:
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
// ❌ Previously allowed, now flagged as error
|
|
286
|
+
{
|
|
287
|
+
items && <ItemList items={items} />;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ✅ Required explicit pattern
|
|
291
|
+
{
|
|
292
|
+
items.length > 0 && <ItemList items={items} />;
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Implementation Approach
|
|
297
|
+
|
|
298
|
+
The current architecture standardizes configuration through a modular design:
|
|
299
|
+
|
|
300
|
+
1. **Shared rule and ignore modules** provide a single source of truth.
|
|
301
|
+
2. **Factory functions** compose complete project-specific configurations.
|
|
302
|
+
3. **Framework adapters** apply React and Next.js behavior without duplicating the base.
|
|
303
|
+
4. **Documentation and examples** define the canonical setup for new packages and apps.
|
|
304
|
+
|
|
305
|
+
## Performance Considerations
|
|
306
|
+
|
|
307
|
+
### Configuration Size
|
|
308
|
+
|
|
309
|
+
**Goal:** Minimize configuration object size while maintaining comprehensive rule coverage.
|
|
310
|
+
|
|
311
|
+
**Implementation:**
|
|
312
|
+
|
|
313
|
+
- Shared ignore patterns reduce duplication
|
|
314
|
+
- Rule objects are composed rather than merged at runtime
|
|
315
|
+
- TypeScript inference eliminates need for runtime type checking
|
|
316
|
+
|
|
317
|
+
### Type Checking Performance
|
|
318
|
+
|
|
319
|
+
**Goal:** Balance comprehensive type checking with reasonable performance.
|
|
320
|
+
|
|
321
|
+
**Implementation:**
|
|
322
|
+
|
|
323
|
+
- Type-aware rules are opt-in via `createTypeAwareConfig()`
|
|
324
|
+
- Project directory parameterization for efficient TypeScript project loading
|
|
325
|
+
- Comprehensive ignore patterns reduce files processed
|
|
326
|
+
|
|
327
|
+
## Extensibility
|
|
328
|
+
|
|
329
|
+
### Adding New Framework Support
|
|
330
|
+
|
|
331
|
+
To add support for a new framework:
|
|
332
|
+
|
|
333
|
+
1. **Create framework-specific rules** in `src/shared-rules.ts`
|
|
334
|
+
2. **Create framework configuration file** (e.g., `svelte.ts`)
|
|
335
|
+
3. **Compose base configuration** with framework-specific additions
|
|
336
|
+
4. **Document usage patterns** in the usage guide
|
|
337
|
+
|
|
338
|
+
### Custom Rule Integration
|
|
339
|
+
|
|
340
|
+
Projects can extend configurations:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
export default [
|
|
344
|
+
...createTypeAwareConfig(import.meta.dirname),
|
|
345
|
+
{
|
|
346
|
+
rules: {
|
|
347
|
+
// Project-specific overrides
|
|
348
|
+
"@typescript-eslint/no-unused-vars": "warn",
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
];
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Quality Assurance
|
|
355
|
+
|
|
356
|
+
### Testing Strategy
|
|
357
|
+
|
|
358
|
+
**Configuration packages are exempt** from comprehensive testing per UIDE-126 standards because:
|
|
359
|
+
|
|
360
|
+
- They contain declarative configuration objects, not business logic
|
|
361
|
+
- Their "testing" happens naturally when consumed by other packages
|
|
362
|
+
- Configuration errors are caught during actual linting operations
|
|
363
|
+
|
|
364
|
+
### Validation Approach
|
|
365
|
+
|
|
366
|
+
**Runtime validation:**
|
|
367
|
+
|
|
368
|
+
- ESLint validates configuration structure when loaded
|
|
369
|
+
- TypeScript ensures configuration object types are correct
|
|
370
|
+
- Consumer packages validate rule effectiveness through linting
|
|
371
|
+
|
|
372
|
+
**Documentation validation:**
|
|
373
|
+
|
|
374
|
+
- All examples are tested in real projects
|
|
375
|
+
- API documentation matches actual exports
|
|
376
|
+
|
|
377
|
+
## Future Considerations
|
|
378
|
+
|
|
379
|
+
### Planned Enhancements
|
|
380
|
+
|
|
381
|
+
1. **Additional framework support** (Svelte, Astro, etc.)
|
|
382
|
+
2. **Rule set customization** for different project types
|
|
383
|
+
3. **Performance optimization** for large monorepos
|
|
384
|
+
4. **Integration improvements** with development tools
|
|
385
|
+
|
|
386
|
+
### Versioning Policy
|
|
387
|
+
|
|
388
|
+
Public exports and behavior follow semantic versioning. Breaking changes are introduced only in major releases with updated package documentation.
|
|
389
|
+
|
|
390
|
+
## Related Documentation
|
|
391
|
+
|
|
392
|
+
- [API Reference](../reference/api-reference.md) - Complete API documentation
|
|
393
|
+
- [Usage Guide](../guides/usage-guide.md) - Detailed usage instructions
|
|
394
|
+
- [Examples](../../examples/) - Configuration examples
|