dev-booster 1.17.2 → 1.18.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/package.json +1 -1
- package/src/index.js +62 -0
- package/template/.devbooster/MANIFEST.md +34 -1
- package/template/.devbooster/boosters/advisor.md +5 -0
- package/template/.devbooster/boosters/audit.md +20 -0
- package/template/.devbooster/boosters/auto-triage.md +5 -0
- package/template/.devbooster/boosters/backend.md +12 -0
- package/template/.devbooster/boosters/builder.md +5 -0
- package/template/.devbooster/boosters/code-audit.md +19 -0
- package/template/.devbooster/boosters/coder.md +5 -0
- package/template/.devbooster/boosters/create.md +5 -0
- package/template/.devbooster/boosters/debug.md +19 -0
- package/template/.devbooster/boosters/deploy.md +12 -0
- package/template/.devbooster/boosters/discovery.md +5 -0
- package/template/.devbooster/boosters/frontend.md +12 -0
- package/template/.devbooster/boosters/implementation.md +5 -0
- package/template/.devbooster/boosters/investigation.md +5 -0
- package/template/.devbooster/boosters/performance.md +12 -0
- package/template/.devbooster/boosters/planning.md +5 -0
- package/template/.devbooster/boosters/refactor.md +12 -0
- package/template/.devbooster/boosters/review.md +12 -0
- package/template/.devbooster/boosters/security.md +14 -0
- package/template/.devbooster/boosters/smart-task.md +27 -16
- package/template/.devbooster/boosters/stack-refresh.md +20 -0
- package/template/.devbooster/boosters/testing.md +12 -0
- package/template/.devbooster/hub/knowledge/angular-patterns.md +185 -0
- package/template/.devbooster/hub/knowledge/dependency-guide.md +175 -0
- package/template/.devbooster/hub/knowledge/eslint-migration.md +206 -0
- package/template/.devbooster/hub/knowledge/index.md +91 -0
- package/template/.devbooster/hub/knowledge/migration-guides.md +137 -0
- package/template/.devbooster/hub/knowledge/monorepo-patterns.md +121 -0
- package/template/.devbooster/hub/knowledge/nestjs-patterns.md +185 -0
- package/template/.devbooster/hub/knowledge/nextjs-pitfalls.md +226 -0
- package/template/.devbooster/hub/knowledge/nodejs-patterns.md +148 -0
- package/template/.devbooster/hub/knowledge/package-manager-patterns.md +143 -0
- package/template/.devbooster/hub/knowledge/prisma-postgresql-patterns.md +188 -0
- package/template/.devbooster/hub/knowledge/react-patterns.md +500 -0
- package/template/.devbooster/hub/knowledge/tailwind-shadcn-patterns.md +146 -0
- package/template/.devbooster/hub/knowledge/tanstack-patterns.md +278 -0
- package/template/.devbooster/hub/knowledge/testing-patterns.md +164 -0
- package/template/.devbooster/hub/knowledge/trpc-patterns.md +212 -0
- package/template/.devbooster/hub/knowledge/typescript-patterns.md +219 -0
- package/template/.devbooster/hub/knowledge/upgrade-fallout.md +154 -0
- package/template/.devbooster/hub/knowledge/vite-patterns.md +177 -0
- package/template/.devbooster/rules/GUIDE.md +24 -0
- package/template/.devbooster/rules/PROTOCOL.md +3 -2
- package/template/.devbooster/rules/TRIGGERS.md +14 -0
- package/template/DEVBOOSTER_INIT.md +22 -1
|
@@ -60,6 +60,7 @@ Purpose:
|
|
|
60
60
|
- run the correct `outdated` commands for the detected package manager and scope
|
|
61
61
|
- run the correct audit/security commands when relevant
|
|
62
62
|
- classify findings into safe, risky, and human-review categories
|
|
63
|
+
- consult the knowledge base only for findings that match a concrete known pattern, following the finding-driven and read-only rules below
|
|
63
64
|
- update the artifact with the detailed findings
|
|
64
65
|
|
|
65
66
|
Stage 1 requires explicit user approval after Stage 0.
|
|
@@ -176,6 +177,25 @@ Load only after the user has approved update execution and validation is actuall
|
|
|
176
177
|
- Do NOT load validation/test assets during Stage 0 mapping.
|
|
177
178
|
- If evidence is missing, stay with the Stage 0 fixed base load only.
|
|
178
179
|
|
|
180
|
+
### Knowledge Base Consultation — Finding-Driven and Read-Only
|
|
181
|
+
Do not consult `.devbooster/hub/knowledge/` during Stage 0 mapping. Consult it only after Stage 1 identifies a concrete outdated package, security finding, runtime mismatch, configuration warning, compatibility issue, or migration surface.
|
|
182
|
+
|
|
183
|
+
Do NOT read the entire knowledge base.
|
|
184
|
+
|
|
185
|
+
For each relevant finding:
|
|
186
|
+
1. Read `.devbooster/hub/knowledge/index.md`.
|
|
187
|
+
2. Locate the matching article and section from the index.
|
|
188
|
+
3. Read only that section using `read_file` with `start_line` and `end_line`.
|
|
189
|
+
4. Read the official source linked by the article or section before recommending an update, migration path, or deferral.
|
|
190
|
+
5. Reconcile the local pattern and official guidance with the actual package versions, package manager, lockfile, workspace topology, runtime, configuration, and dependency graph.
|
|
191
|
+
|
|
192
|
+
The knowledge base is read-only. Never create, modify, append to, or otherwise maintain files in `.devbooster/hub/knowledge/` during Stack Refresh.
|
|
193
|
+
|
|
194
|
+
### Knowledge Base Decision Traceability
|
|
195
|
+
When a knowledge-base section materially informs an upgrade classification, migration path, deferral, or recommendation, record a complete `Knowledge Base Decision Trace` in the execution artifact: project convention observed, article and section consulted, official source, decision, rationale, and validation or follow-up.
|
|
196
|
+
|
|
197
|
+
Keep chat concise: state the project convention, whether it was preserved or changed, and that the conclusion was validated against project context and official guidance. Do not dump article names, section names, or URLs unless the user asks. Never claim that the knowledge base or an official source was consulted unless the relevant local section and source were actually read during the current Stack Refresh.
|
|
198
|
+
|
|
179
199
|
## 4. PRE-FLIGHT DISCIPLINE
|
|
180
200
|
Start working immediately on activation.
|
|
181
201
|
|
|
@@ -52,6 +52,18 @@ Rules:
|
|
|
52
52
|
- Prefer adding one relevant skill/persona at a time.
|
|
53
53
|
- Keep the user inside the same booster mode while expanding context.
|
|
54
54
|
|
|
55
|
+
## 0.3 KNOWLEDGE BASE CONSULTATION — CONDITIONAL AND READ-ONLY
|
|
56
|
+
Consult `.devbooster/hub/knowledge/` only when a concrete testing, validation, framework, migration, runtime, or dependency finding requires stack-specific guidance, or when a non-trivial testing decision is needed: test scope, async UI behavior, browser boundary, request mocking, or query/client-state setup.
|
|
57
|
+
|
|
58
|
+
Do not consult the base for a mechanical test that already follows a valid local fixture, helper, mock, and assertion convention. Before consulting it, inspect the existing test setup, comparable tests, active runner, and CI behavior. Do NOT read the entire knowledge base. Read `index.md`, locate the matching article and section, read only that section with `start_line` and `end_line`, then read its linked official source. Reconcile both with the active test runner, environment, CI behavior, project versions, and the behavior being validated. Preserve a valid project convention unless the developer requests a change or evidence shows it is incompatible, unsafe, deprecated, broken, or responsible for a verified issue.
|
|
59
|
+
|
|
60
|
+
The knowledge base is read-only. Never create, modify, append to, or otherwise maintain files in `.devbooster/hub/knowledge/` during testing work.
|
|
61
|
+
|
|
62
|
+
### Knowledge Base Decision Traceability
|
|
63
|
+
When a knowledge-base section materially informs a testing decision, and a persistent testing artifact is created or updated, record a complete `Knowledge Base Decision Trace` in that artifact: project convention observed, article and section consulted, official source, decision, rationale, and validation.
|
|
64
|
+
|
|
65
|
+
When no persistent artifact exists, keep the chat trace concise: state the project convention, whether it was preserved or changed, and that the decision was validated against project context and official guidance. Do not dump article names, section names, or URLs unless the user asks. Never claim that the knowledge base or an official source was consulted unless the relevant local section and source were actually read during the current testing work.
|
|
66
|
+
|
|
55
67
|
## 1. ALLOWED INVENTORY
|
|
56
68
|
- `.devbooster/hub/personas/agent_test-engineer.md`
|
|
57
69
|
- `.devbooster/hub/personas/agent_qa-automation-engineer.md`
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Angular Patterns for Modern Applications
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Provide practical defaults for modern Angular applications.
|
|
4
|
+
> **Primary official sources:** [Angular Overview](https://angular.dev/overview) · [Version Compatibility](https://angular.dev/reference/versions) · [Angular CLI](https://angular.dev/cli)
|
|
5
|
+
|
|
6
|
+
## Project Convention Decision Rule
|
|
7
|
+
|
|
8
|
+
Before applying this guidance, verify the installed versions, local rules, existing abstractions, configuration, and tests. Preserve a valid established project convention; do not replace it only because another documented approach is also valid. Use official sources to verify API behavior, compatibility, constraints, and migrations. Recommend a change only when the developer requests it or evidence shows the current approach is incompatible, unsafe, deprecated, broken, or responsible for a verified issue.
|
|
9
|
+
|
|
10
|
+
Practical defaults for current Angular applications. Prefer APIs documented at [angular.dev](https://angular.dev/) and verify framework, CLI, TypeScript, and RxJS support before an upgrade.
|
|
11
|
+
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
- [1. Standalone composition and providers](#1-standalone-composition-and-providers)
|
|
15
|
+
- [2. Dependency injection scopes](#2-dependency-injection-scopes)
|
|
16
|
+
- [3. Signals and RxJS boundaries](#3-signals-and-rxjs-boundaries)
|
|
17
|
+
- [4. Templates and change detection](#4-templates-and-change-detection)
|
|
18
|
+
- [5. Reactive forms and validation](#5-reactive-forms-and-validation)
|
|
19
|
+
- [6. HTTP interceptors and errors](#6-http-interceptors-and-errors)
|
|
20
|
+
- [7. Lazy routes and guards](#7-lazy-routes-and-guards)
|
|
21
|
+
- [8. Version, CLI, and TypeScript alignment](#8-version-cli-and-typescript-alignment)
|
|
22
|
+
|
|
23
|
+
## 1. Standalone composition and providers
|
|
24
|
+
|
|
25
|
+
**Problem:** New features depend on large shared modules, making dependencies and lazy-loading boundaries unclear.
|
|
26
|
+
|
|
27
|
+
**Fix:** Use standalone components, directives, and pipes. Import only the template dependencies a component needs. Register application-wide services with `bootstrapApplication` and `ApplicationConfig`; register route-specific providers on the route when their lifetime should match that route subtree.
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
bootstrapApplication(AppComponent, {
|
|
31
|
+
providers: [provideRouter(routes), provideHttpClient()],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
@Component({
|
|
35
|
+
standalone: true,
|
|
36
|
+
imports: [RouterLink],
|
|
37
|
+
template: `<a routerLink="/settings">Settings</a>`,
|
|
38
|
+
})
|
|
39
|
+
export class NavComponent {}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Verify first:** Confirm that a provider is not already registered by a library or a parent injector. Duplicate registrations can create separate service instances.
|
|
43
|
+
|
|
44
|
+
Sources: [Components](https://angular.dev/guide/components), [Dependency Injection](https://angular.dev/guide/di), [Routing providers](https://angular.dev/guide/routing/define-routes).
|
|
45
|
+
|
|
46
|
+
## 2. Dependency injection scopes
|
|
47
|
+
|
|
48
|
+
**Symptom:** State unexpectedly resets, leaks across users of a feature, or differs between eagerly and lazily loaded views.
|
|
49
|
+
|
|
50
|
+
**Fix:** Choose scope intentionally.
|
|
51
|
+
|
|
52
|
+
| Need | Provider location |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| One instance for the application | `@Injectable({ providedIn: 'root' })` |
|
|
55
|
+
| One instance per component subtree | component `providers` |
|
|
56
|
+
| One instance for a route and its child routes | route `providers` |
|
|
57
|
+
|
|
58
|
+
Use `inject()` in an injection context when it makes dependencies clearer; use constructor injection where it improves the class API or compatibility with existing patterns. Avoid service locators and manually constructed services—Angular must create injected services to resolve their dependencies and lifecycle correctly.
|
|
59
|
+
|
|
60
|
+
Source: [Hierarchical injectors](https://angular.dev/guide/di/hierarchical-dependency-injection).
|
|
61
|
+
|
|
62
|
+
## 3. Signals and RxJS boundaries
|
|
63
|
+
|
|
64
|
+
**Problem:** UI state and asynchronous streams are represented interchangeably, causing duplicate subscriptions or unclear ownership.
|
|
65
|
+
|
|
66
|
+
**Fix:** Use signals for synchronous state consumed by templates or derived with `computed`. Keep RxJS for event streams, cancellation, timing, multicasting, and other asynchronous composition. Convert only at a clear boundary:
|
|
67
|
+
|
|
68
|
+
- Use `toSignal()` when a template or signal-based state needs an Observable value.
|
|
69
|
+
- Use `toObservable()` when signal changes need an Observable pipeline.
|
|
70
|
+
- Prefer the `async` pipe for Observable values used only in a template.
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
readonly query = signal('');
|
|
74
|
+
readonly normalizedQuery = computed(() => this.query().trim().toLowerCase());
|
|
75
|
+
|
|
76
|
+
readonly results = toSignal(
|
|
77
|
+
this.search.search(this.normalizedQuery()),
|
|
78
|
+
{ initialValue: [] },
|
|
79
|
+
);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Verify first:** `toSignal()` subscribes to its source. Do not call it repeatedly for the same stream, and provide an initial value unless the `undefined` state is explicitly valid. Model loading, empty, and error states rather than treating absence as an error.
|
|
83
|
+
|
|
84
|
+
Sources: [Signals](https://angular.dev/guide/signals), [RxJS interop](https://angular.dev/ecosystem/rxjs-interop).
|
|
85
|
+
|
|
86
|
+
## 4. Templates and change detection
|
|
87
|
+
|
|
88
|
+
**Fix:** Use built-in control flow for new templates when it improves readability. Track stable identity in repeated collections.
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
@if (user(); as currentUser) {
|
|
92
|
+
<h1>{{ currentUser.name }}</h1>
|
|
93
|
+
} @else {
|
|
94
|
+
<p>Sign in to continue.</p>
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@for (item of items(); track item.id) {
|
|
98
|
+
<app-item [item]="item" />
|
|
99
|
+
} @empty {
|
|
100
|
+
<p>No items.</p>
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Signals read in an `OnPush` component template are tracked by Angular; when they change, Angular marks the component for update. Use `ChangeDetectionStrategy.OnPush` as a performance-oriented default for components with clear input and state boundaries. Do not mutate objects or arrays in place when consumers rely on reference changes; create updated values instead.
|
|
105
|
+
|
|
106
|
+
**Verify first:** If a view is stale, identify whether its state changes through a signal, an input reference, an event, or an Observable consumed with `async` before adding manual change-detection calls.
|
|
107
|
+
|
|
108
|
+
Sources: [Control flow](https://angular.dev/guide/templates/control-flow), [Signals in `OnPush` components](https://angular.dev/guide/signals#reading-signals-in-onpush-components), [Skipping component subtrees](https://angular.dev/best-practices/skipping-subtrees).
|
|
109
|
+
|
|
110
|
+
## 5. Reactive forms and validation
|
|
111
|
+
|
|
112
|
+
**Problem:** Validation is spread through templates, values are weakly typed, or submission accepts stale/invalid data.
|
|
113
|
+
|
|
114
|
+
**Fix:** Use reactive forms for non-trivial forms. Define validators with the controls, show errors after an interaction or submission attempt, and check the form state before submitting. Prefer typed controls and `NonNullableFormBuilder` when `null` is not a meaningful form value.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
readonly form = this.formBuilder.nonNullable.group({
|
|
118
|
+
email: ['', [Validators.required, Validators.email]],
|
|
119
|
+
password: ['', [Validators.required, Validators.minLength(12)]],
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
submit(): void {
|
|
123
|
+
if (this.form.invalid) {
|
|
124
|
+
this.form.markAllAsTouched();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.accountService.register(this.form.getRawValue());
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
For server validation, map known field errors to the relevant control with `setErrors`; keep unexpected failures as form-level or page-level errors. Async validators must complete and should avoid issuing redundant requests.
|
|
132
|
+
|
|
133
|
+
Sources: [Reactive forms](https://angular.dev/guide/forms/reactive-forms), [Form validation](https://angular.dev/guide/forms/form-validation).
|
|
134
|
+
|
|
135
|
+
## 6. HTTP interceptors and errors
|
|
136
|
+
|
|
137
|
+
**Fix:** Configure `HttpClient` with functional interceptors. Keep interceptors narrow: add authentication or tracing headers, normalize a cross-cutting response concern, or apply a documented retry policy. Re-throw errors after any contextual handling so the caller can decide how to present recovery.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
export const authInterceptor: HttpInterceptorFn = (request, next) => {
|
|
141
|
+
const token = inject(AuthService).token();
|
|
142
|
+
const authorized = token
|
|
143
|
+
? request.clone({ setHeaders: { Authorization: `Bearer ${token}` } })
|
|
144
|
+
: request;
|
|
145
|
+
|
|
146
|
+
return next(authorized).pipe(
|
|
147
|
+
catchError((error: HttpErrorResponse) => {
|
|
148
|
+
inject(ErrorReporter).report(error);
|
|
149
|
+
return throwError(() => error);
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Register order deliberately: request processing follows interceptor order, while responses travel back through the chain. Handle request-specific messages near the calling feature; reserve interceptors for reusable transport policy. Do not retry non-idempotent requests without an explicit server-side safety guarantee.
|
|
156
|
+
|
|
157
|
+
Sources: [HTTP interceptors](https://angular.dev/guide/http/interceptors), [Making requests](https://angular.dev/guide/http/making-requests).
|
|
158
|
+
|
|
159
|
+
## 7. Lazy routes and guards
|
|
160
|
+
|
|
161
|
+
**Fix:** Lazy-load feature routes with `loadChildren` and standalone screens with `loadComponent`. Use functional guards for navigation policy and return a `UrlTree` or `RedirectCommand` for redirects rather than navigating imperatively from a guard.
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
export const routes: Routes = [
|
|
165
|
+
{
|
|
166
|
+
path: 'reports',
|
|
167
|
+
loadChildren: () => import('./reports/reports.routes').then((m) => m.REPORT_ROUTES),
|
|
168
|
+
canActivate: [() => inject(AuthService).isAuthenticated() || inject(Router).parseUrl('/login')],
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Verify first:** Client-side guards are not authorization. Enforce access control on the server or API as well. Confirm the intended guard type: `canMatch` affects route matching, while `canActivate` controls activation after a route is selected.
|
|
174
|
+
|
|
175
|
+
Sources: [Define routes](https://angular.dev/guide/routing/define-routes), [Route guards](https://angular.dev/guide/routing/route-guards), [Lazy loading](https://angular.dev/guide/ngmodules/lazy-loading).
|
|
176
|
+
|
|
177
|
+
## 8. Version, CLI, and TypeScript alignment
|
|
178
|
+
|
|
179
|
+
**Problem:** An Angular update fails with peer-dependency or compiler errors, or a generated project differs from repository conventions.
|
|
180
|
+
|
|
181
|
+
**Verify first:** Check the official [version compatibility table](https://angular.dev/reference/versions) for the supported Node.js, TypeScript, and RxJS ranges of the target Angular version. Check the installed CLI with `ng version`; use the workspace’s package manager and lockfile rather than globally installed tooling as the source of truth.
|
|
182
|
+
|
|
183
|
+
**Fix:** Upgrade Angular packages and the Angular CLI using the official [Update Guide](https://angular.dev/update-guide), selecting the current and target versions. Make the required TypeScript and Node.js changes before addressing application-level migration output. Run the repository’s build, tests, and lint commands after each upgrade step.
|
|
184
|
+
|
|
185
|
+
Source: [Angular CLI](https://angular.dev/tools/cli), [Version compatibility](https://angular.dev/reference/versions), [Update Guide](https://angular.dev/update-guide).
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# 📦 Dependency Guide
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Decision model for safe dependency updates and audit interpretation
|
|
4
|
+
> **Primary official sources:** [npm CLI documentation](https://docs.npmjs.com/cli/) · [Yarn documentation](https://yarnpkg.com/) · [pnpm documentation](https://pnpm.io/)
|
|
5
|
+
|
|
6
|
+
## Project Convention Decision Rule
|
|
7
|
+
|
|
8
|
+
Before applying this guidance, verify the installed versions, local rules, existing abstractions, configuration, lockfile, and tests. Preserve a valid established project convention; do not replace it only because another documented approach is also valid. Use official sources to verify API behavior, compatibility, constraints, and migrations. Recommend a change only when the developer requests it or evidence shows the current approach is incompatible, unsafe, deprecated, broken, or responsible for a verified issue.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
1. [Safe-Update Decision Model](#safe-update-decision-model)
|
|
15
|
+
2. [Eligible vs Non-Eligible — Examples](#eligible-vs-non-eligible)
|
|
16
|
+
3. [Method for Analyzing Dependency Usage](#method-for-analyzing-dependency-usage)
|
|
17
|
+
4. [Audit Interpretation Rules](#audit-interpretation-rules)
|
|
18
|
+
5. [Package Manager Behavior](#package-manager-behavior)
|
|
19
|
+
6. [Validation Hierarchy](#validation-hierarchy)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Safe-Update Decision Model
|
|
24
|
+
|
|
25
|
+
### Conditions for considering an update "safe"
|
|
26
|
+
|
|
27
|
+
A dependency is eligible for a safe update **only when ALL of the following conditions are true**:
|
|
28
|
+
|
|
29
|
+
1. **Same major version** — the update stays within the same major version (including a patch or minor update) and the upstream release notes do not identify an incompatible change
|
|
30
|
+
2. **No coupled migration** — it is not part of a known migration family that requires source code adaptation
|
|
31
|
+
3. **Role understood** — the dependency's role is known: runtime, build, types, or security
|
|
32
|
+
4. **Validation path exists** — the project exposes a validation path capable of detecting obvious fallout (lint, build, typecheck)
|
|
33
|
+
5. **No forced operations** — the update does not require lockfile override, `resolutions`, codemod, global rewrite, or behavior not supported by the package manager
|
|
34
|
+
|
|
35
|
+
### Golden rule
|
|
36
|
+
If any condition fails, the update goes to deeper analysis.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Eligible vs Non-Eligible
|
|
41
|
+
|
|
42
|
+
### Eligible (safe update)
|
|
43
|
+
| Category | Example | Reason |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Same-major minor | `next 16.1.x → 16.2.x` | Eligible for release-note review and validation; not inherently free of breaking behavior |
|
|
46
|
+
| Coupled packages | `react + react-dom` | Update together within compatible major versions |
|
|
47
|
+
| Security priority | `axios 1.x → 1.y` | Same-major security update; confirm the advisory path and release notes |
|
|
48
|
+
| Bounded same-major | `@tanstack/react-query 5.x → 5.y` | Same-major update with targeted validation |
|
|
49
|
+
|
|
50
|
+
### Non-Eligible (requires deep analysis)
|
|
51
|
+
| Dependency | Reason |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `tailwindcss 3 → 4` | Breaking change, config migration |
|
|
54
|
+
| `Chakra UI 2 → 3` | Breaking change, component rewrite |
|
|
55
|
+
| `TypeScript 5 → 7` | Two majors, high risk |
|
|
56
|
+
| `ESLint 9 → 10` | Config breaking change |
|
|
57
|
+
| `Zustand 4 → 5` | API breaking change |
|
|
58
|
+
| `date-fns 2 → 4` | Two majors, breaking changes |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Method for Analyzing Dependency Usage
|
|
63
|
+
|
|
64
|
+
### Four layers of evidence
|
|
65
|
+
|
|
66
|
+
Before recommending an update or removal, use these 4 layers:
|
|
67
|
+
|
|
68
|
+
1. **Runtime import evidence**
|
|
69
|
+
- Search the code for imports/requires and API calls
|
|
70
|
+
```bash
|
|
71
|
+
rg -n --glob '*.{js,jsx,ts,tsx,mjs,cjs}' \
|
|
72
|
+
"from ['\"]package-name['\"]|import ['\"]package-name['\"]|require\(['\"]package-name['\"]|import\(['\"]package-name['\"]" src/
|
|
73
|
+
```
|
|
74
|
+
- Also check aliases, generated code, and configuration files; source searches alone are not conclusive.
|
|
75
|
+
|
|
76
|
+
2. **Framework/config evidence**
|
|
77
|
+
- Inspect: framework config, PostCSS/Tailwind, ESLint, scripts, Docker, CI
|
|
78
|
+
- The dependency may be in use even without a direct import in source
|
|
79
|
+
|
|
80
|
+
3. **Type-system evidence**
|
|
81
|
+
- Inspect `tsconfig.json`, exported types
|
|
82
|
+
- Packages that only provide types (e.g., `@types/*`) have no runtime import
|
|
83
|
+
|
|
84
|
+
4. **Dependency provenance**
|
|
85
|
+
- Use `yarn why <package>` / `npm ls <package>` / `pnpm why <package>`
|
|
86
|
+
- Check whether it's a direct or transitive dependency
|
|
87
|
+
|
|
88
|
+
### Result classification
|
|
89
|
+
|
|
90
|
+
| Classification | Meaning | Action |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| **Runtime confirmed** | Direct import/call in source | Do not remove |
|
|
93
|
+
| **Tooling confirmed** | Used by scripts/config/build | Do not remove without checking scripts |
|
|
94
|
+
| **Indirect only** | Required by framework/chain | Check if framework still needs it |
|
|
95
|
+
| **Removal candidate** | No direct or indirect evidence | Remove with validation |
|
|
96
|
+
|
|
97
|
+
### Generic example
|
|
98
|
+
A package like `sharp` may be listed in `package.json` but have no direct import in source — it may be used internally by the framework (e.g., Next.js uses `sharp` for image optimization). **In this case, even without a direct import, do not remove it without confirming whether the framework still uses it.**
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Audit Interpretation Rules
|
|
103
|
+
|
|
104
|
+
### Rules for interpreting `npm audit` / `yarn audit`
|
|
105
|
+
|
|
106
|
+
1. **Audit count ≠ business risk**
|
|
107
|
+
- A package may emit multiple advisories and paths
|
|
108
|
+
- The number of findings is not the number of independent risks
|
|
109
|
+
|
|
110
|
+
2. **Root upgrade does not patch nested framework copy**
|
|
111
|
+
- Root `sharp@0.35` can coexist with `next#sharp@0.34`
|
|
112
|
+
- Root `postcss@8.5` can coexist with `next#postcss@8.4`
|
|
113
|
+
- Updating the root does not necessarily resolve the nested copy
|
|
114
|
+
|
|
115
|
+
3. **Always cross-reference audit output with provenance**
|
|
116
|
+
```bash
|
|
117
|
+
yarn why <package>
|
|
118
|
+
npm ls <package>
|
|
119
|
+
```
|
|
120
|
+
Inspect the upstream package's `package.json` when necessary.
|
|
121
|
+
|
|
122
|
+
4. **Classify risk separately**
|
|
123
|
+
- Findings in toolchain (eslint, webpack, etc.) may be **build-time risk**, not runtime
|
|
124
|
+
- Do not ignore — classify exposure and remediation separately
|
|
125
|
+
|
|
126
|
+
5. **Do not add resolutions/overrides just to lower audit count**
|
|
127
|
+
- Overriding an internal framework range is a policy decision
|
|
128
|
+
- Requires compatibility validation and explicit approval
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Package Manager Behavior
|
|
133
|
+
|
|
134
|
+
### Yarn Classic (1.x)
|
|
135
|
+
|
|
136
|
+
| Command | Important behavior |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `yarn outdated` | Exit code `1` when there are updates — **not an error**, it's a sign of findings |
|
|
139
|
+
| `yarn audit --level moderate` | Returns a severity bitmask: info `1`, low `2`, moderate `4`, high `8`, critical `16`; `--level` filters displayed findings but does not change the exit code |
|
|
140
|
+
| `yarn outdated` | Lists current, wanted, and latest versions; it does not diagnose lockfile synchronization |
|
|
141
|
+
| Peer warnings | May exist even with lint/build passing (e.g., React 18 peer range in libs) |
|
|
142
|
+
|
|
143
|
+
If `package.json` changes, run `yarn install` serially to update `yarn.lock`. In CI, use the project's frozen/immutable lockfile policy to detect unexpected lockfile changes.
|
|
144
|
+
|
|
145
|
+
### Mandatory serialization
|
|
146
|
+
**Never** run two commands that write to the lockfile in parallel:
|
|
147
|
+
```bash
|
|
148
|
+
# ❌ WRONG: parallel
|
|
149
|
+
yarn add package-a & yarn add package-b
|
|
150
|
+
|
|
151
|
+
# ✅ CORRECT: serialized
|
|
152
|
+
yarn add package-a
|
|
153
|
+
yarn add package-b
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Serialize `install`, `add`, `remove`, and equivalents to avoid:
|
|
157
|
+
- Lockfile races
|
|
158
|
+
- Non-deterministic state
|
|
159
|
+
- Loss of updates
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Validation Hierarchy
|
|
164
|
+
|
|
165
|
+
### Available validation matrix
|
|
166
|
+
|
|
167
|
+
| Validation | What it proves | Limitation |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `lint` | Lint config works, no errors | Does not exercise runtime |
|
|
170
|
+
| `build` | The configured production build pipeline (for example, bundling and framework configuration) | Type checking, route coverage, and generated output depend on the project's toolchain and settings; does not verify external APIs or UX |
|
|
171
|
+
| Dedicated typecheck | Type errors (faster than build) | May not exist as a separate script |
|
|
172
|
+
| Automated tests | Regression of behavior | May not exist |
|
|
173
|
+
| Manual smoke test | UX and integration | Requires human execution |
|
|
174
|
+
|
|
175
|
+
---
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# 🧹 ESLint Migration
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Migration guidance and common issues for ESLint 9+ and flat config
|
|
4
|
+
> **Primary official sources:** [ESLint configuration migration guide](https://eslint.org/docs/latest/use/configure/migration-guide) · [ESLint configuration files](https://eslint.org/docs/latest/use/configure/configuration-files) · [Next.js ESLint plugin](https://nextjs.org/docs/app/api-reference/config/eslint)
|
|
5
|
+
|
|
6
|
+
## Project Convention Decision Rule
|
|
7
|
+
|
|
8
|
+
Before applying this guidance, verify the installed versions, local rules, existing abstractions, configuration, and tests. Preserve a valid established project convention; do not replace it only because another documented approach is also valid. Use official sources to verify API behavior, compatibility, constraints, and migrations. Recommend a change only when the developer requests it or evidence shows the current approach is incompatible, unsafe, deprecated, broken, or responsible for a verified issue.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
1. [ESLint 9 — Flat Config by Default](#eslint-9--flat-config-by-default)
|
|
15
|
+
2. [Basic JavaScript + React Hooks Config](#basic-javascript--react-hooks-config)
|
|
16
|
+
3. [Configuration for Next.js](#configuration-for-nextjs)
|
|
17
|
+
4. [ESLint-level Masking](#eslint-level-masking)
|
|
18
|
+
5. [Inline Suppressions](#inline-suppressions)
|
|
19
|
+
6. [reportUnusedDisableDirectives](#reportunuseddisabledirectives)
|
|
20
|
+
7. [Resolutions Affecting the Toolchain](#resolutions-affecting-the-toolchain)
|
|
21
|
+
8. [Legacy Config Mode in ESLint 9](#legacy-config-mode-in-eslint-9)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## ESLint 9 — Flat Config by Default
|
|
26
|
+
|
|
27
|
+
### Status
|
|
28
|
+
Flat config (`eslint.config.*`) is the default configuration format in ESLint 9. Legacy `.eslintrc.*` configuration can still be used in ESLint 9 by setting `ESLINT_USE_FLAT_CONFIG=false`, but that mode is deprecated and is removed in ESLint 10.
|
|
29
|
+
|
|
30
|
+
### Supported config files
|
|
31
|
+
| File | Type |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `eslint.config.js` | ESM or CommonJS, based on `package.json` |
|
|
34
|
+
| `eslint.config.mjs` | ESM |
|
|
35
|
+
| `eslint.config.cjs` | CommonJS |
|
|
36
|
+
| `eslint.config.ts` | TypeScript; requires `jiti` or enabled native Node.js TypeScript support |
|
|
37
|
+
| `eslint.config.mts` | TypeScript ESM; requires the same TypeScript support |
|
|
38
|
+
| `eslint.config.cts` | TypeScript CommonJS; requires the same TypeScript support |
|
|
39
|
+
|
|
40
|
+
For Node.js, TypeScript config files require `jiti` or Node's explicitly enabled native TypeScript support. Node 22.13+ alone is not sufficient without the documented TypeScript-stripping and ESLint feature flags.
|
|
41
|
+
|
|
42
|
+
### Migration checklist
|
|
43
|
+
1. Create `eslint.config.*` at the project root.
|
|
44
|
+
2. Use `@eslint/migrate-config` as a starting point where applicable, then review the result.
|
|
45
|
+
3. Move `.eslintignore` patterns into a flat-config `ignores` object; flat config does not load `.eslintignore` automatically.
|
|
46
|
+
4. For Next.js 16+, replace `next lint` with the ESLint CLI.
|
|
47
|
+
5. Run `eslint .` and use `eslint --inspect-config <file>` to verify important files receive the intended rules.
|
|
48
|
+
6. Update incompatible plugins or use the documented compatibility utilities where necessary.
|
|
49
|
+
7. Remove `.eslintrc.*` and `.eslintignore` only after the flat configuration is verified in local development and CI.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Basic JavaScript + React Hooks Config
|
|
54
|
+
|
|
55
|
+
This example is for JavaScript and JSX only. To lint TypeScript, add a TypeScript parser/configuration such as the [official typescript-eslint flat-config setup](https://typescript-eslint.io/getting-started/); merely adding `*.ts` or `*.tsx` file patterns does not parse TypeScript.
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
// eslint.config.js
|
|
59
|
+
import { defineConfig } from "eslint/config";
|
|
60
|
+
import js from "@eslint/js";
|
|
61
|
+
import pluginReactHooks from "eslint-plugin-react-hooks";
|
|
62
|
+
|
|
63
|
+
export default defineConfig([
|
|
64
|
+
{
|
|
65
|
+
files: ["**/*.{js,jsx,mjs,cjs}"],
|
|
66
|
+
plugins: { js },
|
|
67
|
+
extends: ["js/recommended"],
|
|
68
|
+
rules: {
|
|
69
|
+
semi: "error",
|
|
70
|
+
"no-unused-vars": "warn",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
files: ["**/*.jsx"],
|
|
75
|
+
plugins: { "react-hooks": pluginReactHooks },
|
|
76
|
+
rules: {
|
|
77
|
+
"react-hooks/rules-of-hooks": "error",
|
|
78
|
+
"react-hooks/exhaustive-deps": "warn",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
]);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Configuration for Next.js
|
|
87
|
+
|
|
88
|
+
For a TypeScript Next.js application, use the documented Next.js flat configs. Omit `nextTs` for a JavaScript-only project.
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
// eslint.config.mjs
|
|
92
|
+
import { defineConfig, globalIgnores } from "eslint/config";
|
|
93
|
+
import nextVitals from "eslint-config-next/core-web-vitals";
|
|
94
|
+
import nextTs from "eslint-config-next/typescript";
|
|
95
|
+
|
|
96
|
+
export default defineConfig([
|
|
97
|
+
...nextVitals,
|
|
98
|
+
...nextTs,
|
|
99
|
+
globalIgnores([
|
|
100
|
+
".next/**",
|
|
101
|
+
"out/**",
|
|
102
|
+
"build/**",
|
|
103
|
+
"next-env.d.ts",
|
|
104
|
+
]),
|
|
105
|
+
]);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## ESLint-level Masking
|
|
111
|
+
|
|
112
|
+
### Problem
|
|
113
|
+
Broad disables and ignore patterns can hide problems, but scoped exceptions are sometimes appropriate for generated code, fixtures, or unsupported environments.
|
|
114
|
+
|
|
115
|
+
### Risky patterns
|
|
116
|
+
```js
|
|
117
|
+
// Broad global rule disables require a documented reason.
|
|
118
|
+
const config = {
|
|
119
|
+
rules: {
|
|
120
|
+
"react-hooks/exhaustive-deps": "off",
|
|
121
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Handling
|
|
127
|
+
- Prefer the narrowest rule override, file pattern, or inline suppression that addresses the specific case.
|
|
128
|
+
- Keep test source linted by default; ignore only generated fixtures, vendor assets, or other verified non-source inputs.
|
|
129
|
+
- Document why an exception is needed and review it when dependencies or code change.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Inline Suppressions
|
|
134
|
+
|
|
135
|
+
### Problem
|
|
136
|
+
Comments that suppress ESLint or TypeScript rules need review. Some are legitimate, but each should have a narrow scope and an explanation where the reason is not obvious.
|
|
137
|
+
|
|
138
|
+
### Most common patterns
|
|
139
|
+
```ts
|
|
140
|
+
// @ts-ignore
|
|
141
|
+
// @ts-expect-error — reports an error if no longer needed
|
|
142
|
+
// @ts-nocheck — disables type checking for the entire file
|
|
143
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### How to handle during audit
|
|
147
|
+
1. Count and classify suppressions by type.
|
|
148
|
+
2. Replace `@ts-ignore` with `@ts-expect-error` when an expected error must remain; fix the type when practical.
|
|
149
|
+
3. Do not remove `@ts-nocheck` without reviewing the full file, especially generated code or third-party declarations.
|
|
150
|
+
4. For `exhaustive-deps`, determine whether the dependency can be added safely before suppressing the rule.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## reportUnusedDisableDirectives
|
|
155
|
+
|
|
156
|
+
### Problem
|
|
157
|
+
Disable comments that no longer suppress a finding remain as clutter and can conceal whether an exception is still needed.
|
|
158
|
+
|
|
159
|
+
*Source: [ESLint configuration files — Report Unused Disable Directives](https://eslint.org/docs/latest/use/configure/configuration-files#report-unused-disable-directives)*
|
|
160
|
+
|
|
161
|
+
### Fix
|
|
162
|
+
```js
|
|
163
|
+
// eslint.config.js
|
|
164
|
+
import { defineConfig } from "eslint/config";
|
|
165
|
+
|
|
166
|
+
export default defineConfig([
|
|
167
|
+
{
|
|
168
|
+
linterOptions: {
|
|
169
|
+
reportUnusedDisableDirectives: "error",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
]);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Why use it
|
|
176
|
+
- Detects suppressions that are no longer needed.
|
|
177
|
+
- Helps clean up code as rules evolve.
|
|
178
|
+
- The default is `"warn"`; using `"error"` makes cleanup enforceable in CI.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Resolutions Affecting the Toolchain
|
|
183
|
+
|
|
184
|
+
### Problem
|
|
185
|
+
Yarn `resolutions`, npm `overrides`, and `pnpm.overrides` can alter transitive dependencies used by development tools. A broad or incompatible override can break ESLint and related tooling.
|
|
186
|
+
|
|
187
|
+
### Handling
|
|
188
|
+
1. Remove overrides that are no longer needed.
|
|
189
|
+
2. Document the dependency path and reason for every retained override.
|
|
190
|
+
3. Inspect the dependency tree with the package manager in use:
|
|
191
|
+
```bash
|
|
192
|
+
npm ls ajv
|
|
193
|
+
yarn why ajv
|
|
194
|
+
pnpm why ajv
|
|
195
|
+
```
|
|
196
|
+
4. Run linting and the relevant test/build commands after changing an override.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Legacy Config Mode in ESLint 9
|
|
201
|
+
|
|
202
|
+
### Status
|
|
203
|
+
In ESLint 9, `ESLINT_USE_FLAT_CONFIG=false` can temporarily enable legacy `.eslintrc.*` configuration. ESLint marks that mode as deprecated; it is not available in ESLint 10.
|
|
204
|
+
|
|
205
|
+
### Guidance
|
|
206
|
+
Use legacy mode only as a time-bounded compatibility measure while migrating. Verify plugin and shareable-config compatibility in the actual project, then move to flat config before upgrading to ESLint 10.
|