@silvestv/migration-planificator 3.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.
Files changed (122) hide show
  1. package/LICENSE +96 -0
  2. package/README.fr.md +359 -0
  3. package/README.md +360 -0
  4. package/SECURITY.md +187 -0
  5. package/dist/client.bundle.js +357 -0
  6. package/dist/src/core/app-analyzer.js +134 -0
  7. package/dist/src/core/ast/matchers/html/html-attribute-matcher.js +86 -0
  8. package/dist/src/core/ast/matchers/html/html-component-matcher.js +40 -0
  9. package/dist/src/core/ast/matchers/html/html-element-matcher.js +54 -0
  10. package/dist/src/core/ast/matchers/html/html-parser.js +58 -0
  11. package/dist/src/core/ast/matchers/html/html-pipe-matcher.js +95 -0
  12. package/dist/src/core/ast/matchers/html/html-text-matcher.js +53 -0
  13. package/dist/src/core/ast/matchers/html/index.js +118 -0
  14. package/dist/src/core/ast/matchers/index.js +377 -0
  15. package/dist/src/core/ast/matchers/ts/collection-matcher.js +51 -0
  16. package/dist/src/core/ast/matchers/ts/context-matcher.js +275 -0
  17. package/dist/src/core/ast/matchers/ts/decorator-matcher.js +465 -0
  18. package/dist/src/core/ast/matchers/ts/expression-matcher.js +237 -0
  19. package/dist/src/core/ast/matchers/ts/file-matcher.js +97 -0
  20. package/dist/src/core/ast/matchers/ts/hierarchy-matcher.js +172 -0
  21. package/dist/src/core/ast/matchers/ts/import-matcher.js +39 -0
  22. package/dist/src/core/ast/matchers/ts/index.js +53 -0
  23. package/dist/src/core/ast/matchers/ts/node-matcher.js +156 -0
  24. package/dist/src/core/ast/matchers/ts/symbol-matcher.js +281 -0
  25. package/dist/src/core/ast/matchers/ts/type-matcher.js +207 -0
  26. package/dist/src/core/ast/matchers/utils/matcher-helpers.js +37 -0
  27. package/dist/src/core/ast/scanner-ast.js +444 -0
  28. package/dist/src/core/project-detector.js +196 -0
  29. package/dist/src/core/project-strategy/index.js +9 -0
  30. package/dist/src/core/project-strategy/nx-strategy.js +130 -0
  31. package/dist/src/core/project-strategy/project-strategy.interface.js +2 -0
  32. package/dist/src/core/project-strategy/standalone-strategy.js +74 -0
  33. package/dist/src/core/project-strategy/strategy-factory.js +15 -0
  34. package/dist/src/core/rules-loader.js +89 -0
  35. package/dist/src/core/scan-reporter.js +316 -0
  36. package/dist/src/core/scanner-delta.js +339 -0
  37. package/dist/src/core/scanner-orchestrator.js +266 -0
  38. package/dist/src/core/scanner-regex.js +298 -0
  39. package/dist/src/core/workload/calculator.js +82 -0
  40. package/dist/src/core/workload/constants.js +15 -0
  41. package/dist/src/core/workload/grouping.js +18 -0
  42. package/dist/src/core/workload/hierarchy-calculator.js +127 -0
  43. package/dist/src/core/workload/index.js +11 -0
  44. package/dist/src/core/workload/metadata.js +20 -0
  45. package/dist/src/core/workload/special-workload.js +101 -0
  46. package/dist/src/core/workload/target-resolver.js +34 -0
  47. package/dist/src/data/angular-migration-rules.json +2337 -0
  48. package/dist/src/data/markdown/angular-migration-17-18.md +408 -0
  49. package/dist/src/data/markdown/angular-migration-18-19.md +600 -0
  50. package/dist/src/data/markdown/angular-migration-19-20.md +521 -0
  51. package/dist/src/data/rules/rearchitecture/rearchitecture-rules.json +66 -0
  52. package/dist/src/data/rules/to18/rules-18-obligatoire.json +374 -0
  53. package/dist/src/data/rules/to18/rules-18-optionnelle.json +188 -0
  54. package/dist/src/data/rules/to18/rules-18-recommande.json +218 -0
  55. package/dist/src/data/rules/to19/rules-19-obligatoire.json +348 -0
  56. package/dist/src/data/rules/to19/rules-19-optionnelle.json +223 -0
  57. package/dist/src/data/rules/to19/rules-19-recommande.json +200 -0
  58. package/dist/src/data/rules/to20/rules-20-obligatoire.json +556 -0
  59. package/dist/src/data/rules/to20/rules-20-optionnelle.json +190 -0
  60. package/dist/src/data/rules/to20/rules-20-recommande.json +151 -0
  61. package/dist/src/index.js +161 -0
  62. package/dist/src/models/chip-config.js +45 -0
  63. package/dist/src/models/interfaces/app-details.interface.js +2 -0
  64. package/dist/src/models/interfaces/ast-interfaces.js +5 -0
  65. package/dist/src/models/interfaces/ast-pattern.interface.js +2 -0
  66. package/dist/src/models/interfaces/client-interfaces.js +6 -0
  67. package/dist/src/models/interfaces/detection-stats.interface.js +2 -0
  68. package/dist/src/models/interfaces/html-match.interface.js +2 -0
  69. package/dist/src/models/interfaces/html-report-data.interface.js +2 -0
  70. package/dist/src/models/interfaces/lib-details.interface.js +2 -0
  71. package/dist/src/models/interfaces/migration-rules.interface.js +2 -0
  72. package/dist/src/models/interfaces/parsed-args.interface.js +2 -0
  73. package/dist/src/models/interfaces/project-info.interface.js +2 -0
  74. package/dist/src/models/interfaces/project-overview-data.interface.js +2 -0
  75. package/dist/src/models/interfaces/rule-match.interface.js +2 -0
  76. package/dist/src/models/interfaces/rule.interface.js +2 -0
  77. package/dist/src/models/interfaces/rules-by-priority.interface.js +2 -0
  78. package/dist/src/models/interfaces/scanner-comparison.interface.js +2 -0
  79. package/dist/src/models/interfaces/special-workload.interface.js +2 -0
  80. package/dist/src/models/interfaces/workload-report.interface.js +2 -0
  81. package/dist/src/models/types/build-block-blob.type.js +2 -0
  82. package/dist/src/models/types/migration-version.type.js +2 -0
  83. package/dist/src/models/types/project-type.type.js +2 -0
  84. package/dist/src/models/types/risk-level.type.js +2 -0
  85. package/dist/src/models/types/rule-category.type.js +2 -0
  86. package/dist/src/models/types/rule-priority.type.js +2 -0
  87. package/dist/src/models/types/rule-workload-type.type.js +2 -0
  88. package/dist/src/templates/landing/applications-analyzed.template.js +18 -0
  89. package/dist/src/templates/landing/card-app-info.template.js +63 -0
  90. package/dist/src/templates/landing/card-lib-info.template.js +67 -0
  91. package/dist/src/templates/landing/libs-analyzed.template.js +22 -0
  92. package/dist/src/templates/landing/nx-summary.template.js +115 -0
  93. package/dist/src/templates/landing/project-overview.template.js +27 -0
  94. package/dist/src/templates/page/index-page.template.js +95 -0
  95. package/dist/src/templates/page/main.template.js +83 -0
  96. package/dist/src/templates/page/migration-guide.template.js +175 -0
  97. package/dist/src/templates/page/workload-report.template.js +53 -0
  98. package/dist/src/templates/workload/dashboard.template.js +184 -0
  99. package/dist/src/templates/workload/filters-panel.template.js +215 -0
  100. package/dist/src/templates/workload/guide-rule-card.template.js +107 -0
  101. package/dist/src/templates/workload/hierarchy-nx.template.js +104 -0
  102. package/dist/src/templates/workload/hierarchy-shared.js +163 -0
  103. package/dist/src/templates/workload/hierarchy-standalone.template.js +36 -0
  104. package/dist/src/templates/workload/hierarchy.template.js +35 -0
  105. package/dist/src/templates/workload/rule-modal.template.js +280 -0
  106. package/dist/src/utils/core/args-parser.js +123 -0
  107. package/dist/src/utils/core/array-helpers.js +18 -0
  108. package/dist/src/utils/core/ast-helpers.js +99 -0
  109. package/dist/src/utils/core/file-helpers.js +109 -0
  110. package/dist/src/utils/core/html-helpers.js +36 -0
  111. package/dist/src/utils/core/index.js +28 -0
  112. package/dist/src/utils/core/logger.js +38 -0
  113. package/dist/src/utils/core/rule-helpers.js +15 -0
  114. package/dist/src/utils/core/workload-formatter.js +6 -0
  115. package/dist/src/utils/shared/array-helpers.js +25 -0
  116. package/dist/src/utils/shared/date-helpers.js +109 -0
  117. package/dist/src/utils/shared/html-helpers.js +37 -0
  118. package/dist/src/utils/shared/index.js +25 -0
  119. package/dist/src/utils/shared/rule-helpers.js +20 -0
  120. package/dist/src/utils/shared/time-formatters.js +76 -0
  121. package/dist/styles.css +2 -0
  122. package/package.json +107 -0
@@ -0,0 +1,521 @@
1
+ # Guide Migration Angular 19→20 avec Exemples
2
+
3
+ ## 🔴 RÈGLES OBLIGATOIRES (Breaking Changes)
4
+
5
+ ### 1. Environnement & Dépendances
6
+ ```bash
7
+ # ❌ Avant: TypeScript 5.5, Node.js 18.x
8
+ # ✅ Après:
9
+ npm install typescript@~5.8.0
10
+ # Node.js 20.11.1+ requis (PAS v18, ni v22.0-22.10)
11
+ # Vérifier: node --version >= 20.11.1
12
+ ng update @angular/core@20 @angular/cli@20
13
+ ng update @angular/material@20 # Si Material utilisé
14
+ ```
15
+
16
+ ### 2. Renommages d'APIs critiques
17
+ ```typescript
18
+ // ❌ Avant - Angular 19
19
+ afterRender(() => { /* code */ });
20
+ provideExperimentalCheckNoChangesForDebug();
21
+ provideExperimentalZonelessChangeDetection();
22
+
23
+ // ✅ Après - Angular 20
24
+ afterEveryRender(() => { /* code */ });
25
+ provideCheckNoChangesConfig(); // Note: useNgZoneOnStable supprimé
26
+ provideZonelessChangeDetection();
27
+ ```
28
+
29
+ ### 3. Resource API - Changements de propriétés
30
+ ```typescript
31
+ // ❌ Avant
32
+ const userResource = resource({
33
+ request: () => ({id: userId()}),
34
+ loader: ({request}) => fetch(`/users/${request.id}`)
35
+ });
36
+
37
+ const rxResource = rxResource({
38
+ loader: () => httpClient.get('/data')
39
+ });
40
+
41
+ // ✅ Après
42
+ const userResource = resource({
43
+ params: () => ({id: userId()}), // request → params
44
+ loader: ({request}) => fetch(`/users/${request.id}`)
45
+ });
46
+
47
+ const rxResource = rxResource({
48
+ stream: () => httpClient.get('/data') // loader → stream
49
+ });
50
+ ```
51
+
52
+ ### 4. ResourceStatus n'est plus un enum
53
+ ```typescript
54
+ // ❌ Avant
55
+ import { ResourceStatus } from '@angular/core';
56
+ if (resource.status() === ResourceStatus.Loading) { }
57
+
58
+ // ✅ Après - Utiliser les strings
59
+ if (resource.status() === 'loading') { }
60
+ // Valeurs: 'idle' | 'loading' | 'resolved' | 'error' | 'reloading' | 'local'
61
+ ```
62
+
63
+ ### 5. Opérateurs JS dans templates
64
+ ```typescript
65
+ // ❌ Avant - 'in' et 'void' comme propriétés
66
+ @Component({
67
+ template: `{{ in }} {{ void }}`
68
+ })
69
+ class MyComponent {
70
+ in = 'value';
71
+ void = 'data';
72
+ }
73
+
74
+ // ✅ Après - Utiliser this pour éviter conflit
75
+ @Component({
76
+ template: `{{ this.in }} {{ this.void }}`
77
+ })
78
+ // OU renommer les propriétés
79
+ class MyComponent {
80
+ inValue = 'value';
81
+ voidData = 'data';
82
+ }
83
+ ```
84
+
85
+ ### 6. TestBed.flushEffects() supprimé
86
+ ```typescript
87
+ // ❌ Avant
88
+ it('should test effects', () => {
89
+ TestBed.flushEffects();
90
+ expect(component.value).toBe('updated');
91
+ });
92
+
93
+ // ✅ Après
94
+ it('should test effects', () => {
95
+ TestBed.tick(); // Plus proche équivalent
96
+ expect(component.value).toBe('updated');
97
+ });
98
+ ```
99
+
100
+ ### 7. ng-reflect attributes supprimés
101
+ ```typescript
102
+ // ❌ Avant - Dépendance sur ng-reflect-*
103
+ const value = element.getAttribute('ng-reflect-disabled');
104
+
105
+ // ✅ Après - Migration temporaire si nécessaire
106
+ bootstrapApplication(App, {
107
+ providers: [
108
+ provideNgReflectAttributes() // Dev mode uniquement
109
+ ]
110
+ });
111
+ // Mais refactoriser le code pour ne pas en dépendre
112
+ ```
113
+
114
+ ### 8. Guards avec RedirectFn asynchrones
115
+ ```typescript
116
+ // ❌ Avant
117
+ const redirectFn: RedirectFn = () => '/login';
118
+
119
+ // ✅ Après - Peut retourner Observable/Promise
120
+ const redirectFn: RedirectFn = () => {
121
+ // Peut retourner:
122
+ return '/login'; // string
123
+ return of('/login'); // Observable
124
+ return Promise.resolve('/login'); // Promise
125
+ };
126
+ ```
127
+
128
+ ### 9. Route Guards - Suppression du type 'any'
129
+ ```typescript
130
+ // ❌ Avant
131
+ const routes: Routes = [{
132
+ canActivate: ['authGuard'] // string deprecated
133
+ }];
134
+
135
+ // ✅ Après
136
+ const routes: Routes = [{
137
+ canActivate: [AuthGuard] // ProviderToken<T> ou fonction
138
+ }];
139
+ ```
140
+
141
+ ### 10. Parenthèses respectées dans templates
142
+ ```typescript
143
+ // ❌ Avant - Fonctionnait par accident
144
+ template: `{{ (foo?.bar).baz }}` // Ne crashait pas si foo null
145
+
146
+ // ✅ Après - Comportement JS natif
147
+ template: `{{ foo?.bar?.baz }}` // Utiliser optional chaining correctement
148
+ // (foo?.bar).baz lancera une erreur si foo est null
149
+ ```
150
+
151
+ ### 11. TestBed.get() complètement supprimé
152
+ ```typescript
153
+ // ❌ Avant
154
+ const service = TestBed.get(MyService);
155
+
156
+ // ✅ Après
157
+ const service = TestBed.inject(MyService);
158
+ ```
159
+
160
+ ### 12. InjectFlags enum supprimé
161
+ ```typescript
162
+ // ❌ Avant
163
+ import { InjectFlags } from '@angular/core';
164
+ inject(MyService, InjectFlags.Optional);
165
+
166
+ // ✅ Après
167
+ inject(MyService, { optional: true });
168
+ ```
169
+
170
+ ### 13. PendingTasks.run changements
171
+ ```typescript
172
+ // ❌ Avant - Retour utilisé
173
+ const result = await pendingTasks.run(() => promise);
174
+
175
+ // ✅ Après - Utiliser add + gérer manuellement
176
+ const taskId = pendingTasks.add();
177
+ try {
178
+ const result = await promise;
179
+ // Gérer result
180
+ } finally {
181
+ pendingTasks.remove(taskId);
182
+ }
183
+ ```
184
+
185
+ ### 14. Erreurs AsyncPipe vers ErrorHandler
186
+ ```typescript
187
+ // ❌ Avant - Erreurs silencieuses dans tests
188
+ template: `{{ observableWithError$ | async }}`
189
+
190
+ // ✅ Après - Erreurs reportées à ErrorHandler
191
+ // Dans les tests:
192
+ TestBed.configureTestingModule({
193
+ providers: [{
194
+ provide: ErrorHandler,
195
+ useValue: { handleError: jasmine.createSpy('handleError') }
196
+ }]
197
+ });
198
+ ```
199
+
200
+ ---
201
+
202
+ ## 🟡 RÈGLES RECOMMANDÉES
203
+
204
+ ### 1. Dépréciation des directives structurelles
205
+ ```typescript
206
+ // ⚠️ DÉPRÉCIÉ - Retrait prévu en v22
207
+ <div *ngIf="condition">Content</div>
208
+ <div *ngFor="let item of items">{{ item }}</div>
209
+ <div [ngSwitch]="value">
210
+ <div *ngSwitchCase="'a'">A</div>
211
+ </div>
212
+
213
+ // ✅ Migration vers Control Flow
214
+ @if (condition) {
215
+ <div>Content</div>
216
+ }
217
+ @for (item of items; track item.id) {
218
+ <div>{{ item }}</div>
219
+ }
220
+ @switch (value) {
221
+ @case ('a') { <div>A</div> }
222
+ }
223
+
224
+ // Migration automatique
225
+ ng generate @angular/core:control-flow
226
+ ```
227
+
228
+ ### 2. APIs Signals stabilisées
229
+ ```typescript
230
+ // ✅ Maintenant stables (plus de 'experimental')
231
+ effect(() => {
232
+ console.log('Value changed:', mySignal());
233
+ });
234
+
235
+ const linked = linkedSignal({
236
+ source: sourceSignal,
237
+ computation: () => 'default'
238
+ });
239
+
240
+ const signalFromObs = toSignal(observable$, {
241
+ initialValue: 'default'
242
+ });
243
+ ```
244
+
245
+ ### 3. Hydratation incrémentale stable
246
+ ```typescript
247
+ // ✅ API stable
248
+ bootstrapApplication(App, {
249
+ providers: [
250
+ provideClientHydration(withIncrementalHydration())
251
+ ]
252
+ });
253
+
254
+ // Dans les templates
255
+ @defer (hydrate on viewport) {
256
+ <heavy-component />
257
+ }
258
+ ```
259
+
260
+ ### 4. Configuration rendu par route stable
261
+ ```typescript
262
+ // app.routes.server.ts - ✅ API stable
263
+ export const serverRoutes: ServerRoute[] = [
264
+ { path: '/', renderMode: RenderMode.Prerender },
265
+ { path: '/api/**', renderMode: RenderMode.Server },
266
+ { path: '/admin/**', renderMode: RenderMode.Client },
267
+ {
268
+ path: '/product/:id',
269
+ renderMode: RenderMode.Prerender,
270
+ async getPrerenderParams() {
271
+ const ids = await getProductIds();
272
+ return ids.map(id => ({ id }));
273
+ }
274
+ }
275
+ ];
276
+ ```
277
+
278
+ ### 5. Zoneless avec gestion d'erreurs
279
+ ```typescript
280
+ // ✅ Preview développeur avec error handling
281
+ bootstrapApplication(App, {
282
+ providers: [
283
+ provideZonelessChangeDetection(),
284
+ provideBrowserGlobalErrorListeners() // Nouveau
285
+ ]
286
+ });
287
+
288
+ // Suppression zone.js de angular.json
289
+ "polyfills": [
290
+ // "zone.js" ← Supprimer
291
+ ]
292
+ ```
293
+
294
+ ---
295
+
296
+ ## 🟢 RÈGLES OPTIONNELLES
297
+
298
+ ### 1. Nouvelles APIs Resource expérimentales
299
+ ```typescript
300
+ // httpResource pour requêtes HTTP réactives
301
+ const userResource = httpResource<User>(() =>
302
+ `https://api.example.com/users/${userId()}`
303
+ );
304
+
305
+ // Resource streaming
306
+ const streamResource = resource({
307
+ stream: () => new Promise<Signal<ResourceStreamItem<Data>>>((resolve) => {
308
+ const result = signal<{ value: Data }>({ value: initialData });
309
+
310
+ websocket.onmessage = (event) => {
311
+ result.update(current => ({
312
+ value: [...current.value, event.data]
313
+ }));
314
+ };
315
+
316
+ resolve(result);
317
+ })
318
+ });
319
+ ```
320
+
321
+ ### 2. createComponent avec bindings
322
+ ```typescript
323
+ // Nouveau: directives et bindings dynamiques
324
+ createComponent(MyDialog, {
325
+ bindings: [
326
+ inputBinding('title', titleSignal),
327
+ outputBinding('onClose', (result) => console.log(result)),
328
+ twoWayBinding('value', valueSignal)
329
+ ],
330
+ directives: [
331
+ FocusTrap,
332
+ {
333
+ type: HasColor,
334
+ bindings: [inputBinding('color', () => 'primary')]
335
+ }
336
+ ]
337
+ });
338
+ ```
339
+
340
+ ### 3. Support Vitest expérimental
341
+ ```bash
342
+ npm i vitest jsdom --save-dev
343
+ ```
344
+
345
+ ```json
346
+ // angular.json
347
+ "test": {
348
+ "builder": "@angular/build:unit-test",
349
+ "options": {
350
+ "runner": "vitest"
351
+ }
352
+ }
353
+ ```
354
+
355
+ ### 4. Guide de style simplifié
356
+ ```bash
357
+ # Plus de suffixes par défaut dans v20
358
+ ng generate component user
359
+ # Crée: user.ts (pas user.component.ts)
360
+
361
+ # Pour garder les suffixes (projets existants)
362
+ # ng update ajoutera automatiquement dans angular.json:
363
+ ```
364
+
365
+ ```json
366
+ {
367
+ "schematics": {
368
+ "@schematics/angular:component": { "type": "component" }
369
+ }
370
+ }
371
+ ```
372
+
373
+ ### 5. Host bindings avec type checking
374
+ ```typescript
375
+ // tsconfig.json
376
+ {
377
+ "angularCompilerOptions": {
378
+ "typeCheckHostBindings": true // Activé par défaut en v21
379
+ }
380
+ }
381
+
382
+ // Maintenant avec vérification de type
383
+ @Component({
384
+ host: {
385
+ '[class.active]': 'isActive()', // Vérifié
386
+ '(click)': 'onClick($event)' // Types vérifiés
387
+ }
388
+ })
389
+ ```
390
+
391
+ ### 6. DatePipe avec avertissements
392
+ ```typescript
393
+ // ⚠️ Avertissement si Y sans w
394
+ {{ date | date:'Y' }} // Suspect: année sans semaine
395
+
396
+ // ✅ Correct
397
+ {{ date | date:'y' }} // Année standard
398
+ {{ date | date:'Y w' }} // Année et semaine ensemble
399
+ ```
400
+
401
+ ---
402
+
403
+ ## 📊 Checklist Migration Complète
404
+
405
+ ```typescript
406
+ interface MigrationStatus20 {
407
+ obligatoire: {
408
+ nodeVersion: boolean; // 20.11.1+
409
+ typescript58: boolean; // v5.8+
410
+ apiRenames: boolean; // afterEveryRender, etc.
411
+ resourceParams: boolean; // request→params, loader→stream
412
+ resourceStatus: boolean; // enum→string
413
+ templateOperators: boolean; // this.in, this.void
414
+ testBedFlush: boolean; // flushEffects→tick
415
+ ngReflect: boolean; // Supprimer dépendances
416
+ redirectAsync: boolean; // Support Observable/Promise
417
+ routeGuards: boolean; // Pas de strings
418
+ parentheses: boolean; // Respect JS natif
419
+ testBedGet: boolean; // get→inject
420
+ injectFlags: boolean; // enum→options
421
+ pendingTasks: boolean; // run→add
422
+ asyncPipeErrors: boolean; // ErrorHandler
423
+ };
424
+ recommandee: {
425
+ controlFlow: boolean; // Migration *ngIf/*ngFor
426
+ signalsStable: boolean; // effect, linkedSignal, toSignal
427
+ hydratationStable: boolean; // Incremental hydration
428
+ renderModes: boolean; // Server routes config
429
+ zoneless: boolean; // Preview avec error handling
430
+ };
431
+ optionnelle: {
432
+ httpResource?: boolean; // Nouvelle API
433
+ createComponent?: boolean; // Bindings dynamiques
434
+ vitest?: boolean; // Test runner
435
+ styleGuide?: boolean; // Sans suffixes
436
+ hostBindings?: boolean; // Type checking
437
+ datePipe?: boolean; // Warnings Y/w
438
+ };
439
+ }
440
+ ```
441
+
442
+ ## 🚀 Script Migration Automatisé
443
+
444
+ ```bash
445
+ #!/bin/bash
446
+ # migration-v20.sh
447
+
448
+ echo "🔄 Angular 19 -> 20 Migration Starting..."
449
+
450
+ # 1. Vérification Node.js
451
+ NODE_VERSION=$(node -v | cut -d'v' -f2)
452
+ if [[ ! "$NODE_VERSION" > "20.11.0" ]]; then
453
+ echo "❌ Node.js 20.11.1+ required"
454
+ exit 1
455
+ fi
456
+
457
+ # 2. Backup
458
+ git checkout -b migration-angular-20
459
+ git add . && git commit -m "Pre-migration v20 backup"
460
+
461
+ # 3. Core updates
462
+ echo "📦 Updating to Angular 20..."
463
+ npm install typescript@~5.8.0
464
+ ng update @angular/core@20 @angular/cli@20 --verbose
465
+ ng update @angular/material@20
466
+
467
+ # 4. Renommages automatiques
468
+ echo "🔧 Applying renames..."
469
+ find . -name "*.ts" -not -path "*/node_modules/*" | while read file; do
470
+ # API renames
471
+ sed -i 's/afterRender(/afterEveryRender(/g' "$file"
472
+ sed -i 's/provideExperimentalCheckNoChangesForDebug/provideCheckNoChangesConfig/g' "$file"
473
+ sed -i 's/provideExperimentalZonelessChangeDetection/provideZonelessChangeDetection/g' "$file"
474
+ sed -i 's/ExperimentalPendingTasks/PendingTasks/g' "$file"
475
+
476
+ # TestBed migrations
477
+ sed -i 's/TestBed\.flushEffects()/TestBed.tick()/g' "$file"
478
+ sed -i 's/TestBed\.get(/TestBed.inject(/g' "$file"
479
+
480
+ # Resource API
481
+ sed -i 's/request:/params:/g' "$file"
482
+ sed -i 's/loader:/stream:/g' "$file"
483
+
484
+ # ResourceStatus enum to strings
485
+ sed -i 's/ResourceStatus\.Loading/'\''loading'\''/g' "$file"
486
+ sed -i 's/ResourceStatus\.Idle/'\''idle'\''/g' "$file"
487
+ sed -i 's/ResourceStatus\.Resolved/'\''resolved'\''/g' "$file"
488
+ sed -i 's/ResourceStatus\.Error/'\''error'\''/g' "$file"
489
+ done
490
+
491
+ # 5. Migration Control Flow (recommandée)
492
+ echo "🎯 Migrating to Control Flow..."
493
+ ng generate @angular/core:control-flow
494
+
495
+ # 6. Tests
496
+ echo "🧪 Running validation..."
497
+ ng test --no-watch --code-coverage
498
+ ng build --configuration production
499
+
500
+ echo "✅ Migration complete! Check for TODOs:"
501
+ grep -r "TODO" src/ | grep -v node_modules
502
+ ```
503
+
504
+ ## ⚠️ Points d'Attention
505
+
506
+ | Catégorie | Risque | Solution | Vérification |
507
+ |-----------|--------|----------|--------------|
508
+ | Node.js | Version incompatible | v20.11.1+ obligatoire | `node -v` |
509
+ | Parenthèses | Nullish coalescing crash | Corriger chaînage | Tests unitaires |
510
+ | AsyncPipe | Erreurs cachées | Mock ErrorHandler | Tests passent |
511
+ | Control Flow | Dépréciation v22 | Migrer maintenant | 0 *ngIf/*ngFor |
512
+ | ng-reflect | Tests cassés | Refactorer ou provider | Pas de dépendance |
513
+ | Zoneless | SSR errors | Error handlers | Tests SSR |
514
+
515
+ ## 📈 Métriques Cibles
516
+
517
+ - **Performance**: +35% avec zoneless (cf YouTube)
518
+ - **Bundle**: -20% sans Zone.js (~50KB)
519
+ - **Tests**: +40% vitesse avec Vitest
520
+ - **Hydratation**: -30% JavaScript initial
521
+ - **DevTools**: Intégration Chrome native
@@ -0,0 +1,66 @@
1
+ [
2
+ {
3
+ "key": "split_large_components",
4
+ "summary": "Réorganiser composants/directives/pipes > 400 lignes en unités plus petites",
5
+ "description": "Les fichiers TypeScript contenant des composants, directives ou pipes de plus de 400 lignes doivent être réorganisés en unités plus petites et modulaires. Cette refactorisation améliore la maintenabilité, la testabilité et la réutilisabilité du code. Décomposer en sous-composants, extraire la logique métier dans des services, et séparer les préoccupations selon le principe de responsabilité unique.",
6
+ "estimated_time_per_occurrence": 150,
7
+ "onFile": null,
8
+ "fileTypes": [
9
+ "*.ts"
10
+ ],
11
+ "regex": "@(Component|Directive|Pipe)\\s*\\(",
12
+ "astPattern": {
13
+ "nodeType": "Decorator",
14
+ "name": [
15
+ "Component",
16
+ "Directive",
17
+ "Pipe"
18
+ ],
19
+ "excludeContext": [
20
+ "Comment",
21
+ "StringLiteral"
22
+ ],
23
+ "fileMatches": {
24
+ "minLines": 400
25
+ }
26
+ },
27
+ "category": "architecture",
28
+ "auto_fixable": false,
29
+ "migration_command": null,
30
+ "risk_level": "medium",
31
+ "code_description": "// Avant: composant monolithique (> 400 lignes)\n@Component({\n selector: 'app-user-dashboard',\n templateUrl: './user-dashboard.component.html'\n})\nexport class UserDashboardComponent {\n // 400+ lignes de logique métier, UI, gestion état...\n}\n\n// Après: décomposition en sous-composants\n@Component({\n selector: 'app-user-dashboard',\n template: `\n <app-user-profile [user]=\"user\"></app-user-profile>\n <app-user-stats [stats]=\"stats\"></app-user-stats>\n <app-user-actions [user]=\"user\"></app-user-actions>\n `\n})\nexport class UserDashboardComponent {\n // Orchestration uniquement (~50 lignes)\n user = inject(UserService).currentUser;\n stats = inject(UserStatsService).stats;\n}\n\n// + Extraire logique métier dans services\n// + Créer sous-composants spécialisés\n// + Séparer concerns (présentation, logique, état)",
32
+ "doc_url": "https://angular.dev/style-guide#single-responsibility"
33
+ },
34
+ {
35
+ "key": "split_large_functions",
36
+ "summary": "Refactoriser fonctions > 75 lignes pour réduire la complexité",
37
+ "description": "Les fonctions de plus de 75 lignes indiquent généralement une complexité excessive et violent le principe de responsabilité unique. Ces fonctions doivent être décomposées en sous-fonctions plus petites, plus lisibles et plus testables. Extraire les blocs logiques en fonctions distinctes, réduire le niveau d'imbrication et améliorer la séparation des préoccupations.",
38
+ "estimated_time_per_occurrence": 45,
39
+ "onFile": null,
40
+ "fileTypes": [
41
+ "*.ts"
42
+ ],
43
+ "regex": "(function\\s+\\w+|\\w+\\s*\\([^)]*\\)\\s*\\{|=>\\s*\\{)",
44
+ "astPattern": {
45
+ "nodeType": [
46
+ "FunctionDeclaration",
47
+ "MethodDeclaration",
48
+ "ArrowFunction",
49
+ "FunctionExpression"
50
+ ],
51
+ "excludeContext": [
52
+ "Comment",
53
+ "StringLiteral"
54
+ ],
55
+ "body": {
56
+ "minLines": 75
57
+ }
58
+ },
59
+ "category": "architecture",
60
+ "auto_fixable": false,
61
+ "migration_command": null,
62
+ "risk_level": "medium",
63
+ "code_description": "// Avant: fonction complexe (> 75 lignes)\nexport class UserService {\n processUserData(user: User): ProcessedUser {\n // 75+ lignes de logique\n // - Validation\n // - Transformation\n // - Calculs\n // - Formatage\n // - Gestion erreurs\n // ...\n }\n}\n\n// Après: décomposition en fonctions plus petites\nexport class UserService {\n processUserData(user: User): ProcessedUser {\n const validated = this.validateUser(user);\n const transformed = this.transformUserData(validated);\n const calculated = this.calculateMetrics(transformed);\n return this.formatOutput(calculated);\n }\n\n private validateUser(user: User): ValidatedUser {\n // Validation uniquement (~10 lignes)\n }\n\n private transformUserData(user: ValidatedUser): TransformedUser {\n // Transformation uniquement (~15 lignes)\n }\n\n private calculateMetrics(user: TransformedUser): CalculatedUser {\n // Calculs uniquement (~20 lignes)\n }\n\n private formatOutput(user: CalculatedUser): ProcessedUser {\n // Formatage uniquement (~10 lignes)\n }\n}\n\n// Bénéfices:\n// - Chaque fonction a une responsabilité unique\n// - Code plus lisible et maintenable\n// - Tests unitaires plus faciles\n// - Réutilisation possible des sous-fonctions",
64
+ "doc_url": "https://angular.dev/style-guide#small-functions"
65
+ }
66
+ ]