@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,600 @@
1
+ # Guide Migration Angular 18→19 avec Exemples
2
+
3
+ ## 🔴 RÈGLES OBLIGATOIRES (Breaking Changes)
4
+
5
+ ### 1. Environnement
6
+ ```bash
7
+ # ❌ Avant: TypeScript 5.4
8
+ # ✅ Après:
9
+ npm install typescript@~5.5.0 # Minimum 5.5, 5.4 n'est plus supporté
10
+ ng update @angular/core@19 @angular/cli@19
11
+ ng update @angular/material@19 # Si Material est utilisé
12
+ ```
13
+
14
+ ### 2. Standalone par défaut & Migration
15
+ ```typescript
16
+ // ⚠️ BREAKING CHANGE: standalone est maintenant true par défaut
17
+
18
+ // Pour les projets existants, 2 options:
19
+
20
+ // Option 1: Quick fix - Ajouter standalone: false partout
21
+ @Component({
22
+ selector: 'app-legacy',
23
+ standalone: false, // Ajout obligatoire pour composants non-standalone
24
+ template: `...`
25
+ })
26
+
27
+ // Option 2: Migration complète (recommandée)
28
+ // Exécuter les 3 commandes dans l'ordre:
29
+ ```
30
+
31
+ ```bash
32
+ # 1. Convertir en standalone
33
+ ng generate @angular/core:standalone
34
+ # → "Convert all components, directives and pipes to standalone"
35
+
36
+ # 2. Supprimer NgModules inutiles
37
+ ng generate @angular/core:standalone
38
+ # → "Remove unnecessary NgModule classes"
39
+
40
+ # 3. Bootstrap standalone
41
+ ng generate @angular/core:standalone
42
+ # → "Bootstrap the project using standalone APIs"
43
+ ```
44
+
45
+ ### 3. Template Reference Variables
46
+ ```typescript
47
+ // ❌ Avant
48
+ @Component({
49
+ template: `
50
+ <div #myDiv></div>
51
+ <button (click)="onClick(this.myDiv)">{{ this.myDiv.textContent }}</button>
52
+ `
53
+ })
54
+
55
+ // ✅ Après
56
+ @Component({
57
+ template: `
58
+ <div #myDiv></div>
59
+ <button (click)="onClick(myDiv)">{{ myDiv.textContent }}</button>
60
+ `
61
+ })
62
+ ```
63
+
64
+ ### 4. BrowserModule.withServerTransition
65
+ ```typescript
66
+ // ❌ Avant
67
+ @NgModule({
68
+ imports: [
69
+ BrowserModule.withServerTransition({ appId: 'my-app' })
70
+ ]
71
+ })
72
+
73
+ // ✅ Après
74
+ import { APP_ID } from '@angular/core';
75
+
76
+ bootstrapApplication(AppComponent, {
77
+ providers: [
78
+ { provide: APP_ID, useValue: 'my-app' }
79
+ ]
80
+ });
81
+ ```
82
+
83
+ ### 5. KeyValueDiffers factories
84
+ ```typescript
85
+ // ❌ Avant
86
+ const differs = inject(KeyValueDiffers);
87
+ const factories = differs.factories; // Propriété supprimée
88
+
89
+ // ✅ Après
90
+ const differs = inject(KeyValueDiffers);
91
+ // Utiliser directement les méthodes find() et create()
92
+ const differ = differs.find({}).create();
93
+ ```
94
+
95
+ ### 6. Angular.json Localize
96
+ ```json
97
+ // ❌ Avant
98
+ {
99
+ "builder": "@angular/localize:extract",
100
+ "options": {
101
+ "name": "my-project"
102
+ }
103
+ }
104
+
105
+ // ✅ Après
106
+ {
107
+ "builder": "@angular/localize:extract",
108
+ "options": {
109
+ "project": "my-project" // "name" → "project"
110
+ }
111
+ }
112
+ ```
113
+
114
+ ### 7. PendingTasks (ExperimentalPendingTasks)
115
+ ```typescript
116
+ // ❌ Avant
117
+ import { ExperimentalPendingTasks } from '@angular/core';
118
+
119
+ @Injectable()
120
+ export class MyService {
121
+ tasks = inject(ExperimentalPendingTasks);
122
+ }
123
+
124
+ // ✅ Après
125
+ import { PendingTasks } from '@angular/core';
126
+
127
+ @Injectable()
128
+ export class MyService {
129
+ tasks = inject(PendingTasks);
130
+ }
131
+ ```
132
+
133
+ ### 8. Router.errorHandler Migration
134
+ ```typescript
135
+ // ❌ Avant
136
+ @Injectable()
137
+ export class MyErrorHandler {
138
+ constructor(private router: Router) {
139
+ this.router.errorHandler = (error) => {
140
+ console.error('Navigation error:', error);
141
+ };
142
+ }
143
+ }
144
+
145
+ // ✅ Après
146
+ bootstrapApplication(AppComponent, {
147
+ providers: [
148
+ provideRouter(routes,
149
+ withNavigationErrorHandler((error) => {
150
+ console.error('Navigation error:', error);
151
+ })
152
+ )
153
+ ]
154
+ });
155
+ ```
156
+
157
+ ### 9. Resolve Interface avec RedirectCommand
158
+ ```typescript
159
+ // ❌ Avant
160
+ class UserResolver implements Resolve<User> {
161
+ resolve(): Observable<User> | Promise<User> | User {
162
+ return this.userService.getUser();
163
+ }
164
+ }
165
+
166
+ // ✅ Après
167
+ import { RedirectCommand } from '@angular/router';
168
+
169
+ class UserResolver implements Resolve<User | RedirectCommand> {
170
+ resolve(): Observable<User | RedirectCommand> | Promise<User | RedirectCommand> | User | RedirectCommand {
171
+ return this.userService.getUser().pipe(
172
+ catchError(() => of(new RedirectCommand('/error')))
173
+ );
174
+ }
175
+ }
176
+ ```
177
+
178
+ ### 10. Tests Effects Timing
179
+ ```typescript
180
+ // ❌ Avant - Tests avec effects
181
+ it('should update on effect', () => {
182
+ component.triggerEffect();
183
+ expect(component.value).toBe('updated'); // Peut échouer
184
+ });
185
+
186
+ // ✅ Après
187
+ it('should update on effect', async () => {
188
+ component.triggerEffect();
189
+ await fixture.whenStable(); // Attendre les effects
190
+ // OU
191
+ fixture.detectChanges(); // Déclencher manuellement
192
+ expect(component.value).toBe('updated');
193
+ });
194
+ ```
195
+
196
+ ### 11. FakeAsync Flush par défaut
197
+ ```typescript
198
+ // ❌ Avant
199
+ it('should work', fakeAsync(() => {
200
+ setTimeout(() => value = true, 100);
201
+ tick(100);
202
+ // Les timers ne sont pas automatiquement flush
203
+ }));
204
+
205
+ // ✅ Après
206
+ it('should work', fakeAsync(() => {
207
+ setTimeout(() => value = true, 100);
208
+ tick(100);
209
+ // Les timers sont automatiquement flush
210
+ }));
211
+
212
+ // Pour l'ancien comportement
213
+ it('should work', fakeAsync(() => {
214
+ // Code...
215
+ }, {flush: false})); // Désactiver le flush automatique
216
+ ```
217
+
218
+ ### 12. CreateComponent et ng-content
219
+ ```typescript
220
+ // ❌ Avant
221
+ const componentRef = createComponent(MyComponent, {
222
+ // Pas de contenu projeté → affiche le fallback par défaut
223
+ });
224
+
225
+ // ✅ Après
226
+ const componentRef = createComponent(MyComponent, {
227
+ projectableNodes: [[document.createTextNode('')]] // Évite le fallback
228
+ });
229
+ ```
230
+
231
+ ---
232
+
233
+ ## 🟡 RÈGLES RECOMMANDÉES
234
+
235
+ ### 1. Migrations vers Signals (Séparées)
236
+ ```typescript
237
+ // Migration @Input vers input()
238
+ ng generate @angular/core:signal-input-migration
239
+
240
+ // ❌ Avant
241
+ @Input() name: string;
242
+ @Input() required age: number;
243
+
244
+ // ✅ Après
245
+ readonly name = input<string>();
246
+ readonly age = input.required<number>();
247
+
248
+ // Migration @Output vers output()
249
+ ng generate @angular/core:output-migration
250
+
251
+ // ❌ Avant
252
+ @Output() userChange = new EventEmitter<User>();
253
+
254
+ // ✅ Après
255
+ readonly userChange = output<User>();
256
+ ```
257
+
258
+ ### 2. LinkedSignal pour état réactif
259
+ ```typescript
260
+ // ❌ Avant - Gestion manuelle de dépendances
261
+ export class FilterComponent {
262
+ category = signal('all');
263
+ itemsPerPage = signal(10);
264
+
265
+ ngOnInit() {
266
+ effect(() => {
267
+ if (this.category() !== 'all') {
268
+ this.itemsPerPage.set(10); // Reset manuel
269
+ }
270
+ });
271
+ }
272
+ }
273
+
274
+ // ✅ Après avec linkedSignal
275
+ export class FilterComponent {
276
+ category = signal('all');
277
+ itemsPerPage = linkedSignal({
278
+ source: this.category,
279
+ computation: () => 10 // Reset automatique
280
+ });
281
+ }
282
+ ```
283
+
284
+ ### 4. Nouveaux Initialisateurs
285
+ ```typescript
286
+ // ❌ Avant
287
+ export const appConfig = {
288
+ providers: [
289
+ {
290
+ provide: APP_INITIALIZER,
291
+ useFactory: () => () => inject(ConfigService).load(),
292
+ multi: true,
293
+ deps: [ConfigService]
294
+ }
295
+ ]
296
+ };
297
+
298
+ // ✅ Après
299
+ import { provideAppInitializer } from '@angular/core';
300
+
301
+ export const appConfig = {
302
+ providers: [
303
+ provideAppInitializer(() => {
304
+ const configService = inject(ConfigService);
305
+ return configService.load();
306
+ })
307
+ ]
308
+ };
309
+ ```
310
+
311
+ ### 5. Partage via RouterOutlet
312
+ ```typescript
313
+ // ❌ Avant - Props drilling ou services
314
+ @Component({
315
+ template: `<router-outlet></router-outlet>`
316
+ })
317
+ export class ParentComponent {
318
+ // Données passées via services ou inputs complexes
319
+ }
320
+
321
+ // ✅ Après avec routerOutletData
322
+ @Component({
323
+ template: `
324
+ <router-outlet [routerOutletData]="sharedData"></router-outlet>
325
+ `
326
+ })
327
+ export class ParentComponent {
328
+ sharedData = signal({ theme: 'dark', user: currentUser });
329
+ }
330
+
331
+ // Dans le composant enfant
332
+ export class ChildComponent {
333
+ data = inject(ROUTER_OUTLET_DATA); // Signal réactif
334
+ }
335
+ ```
336
+
337
+ ---
338
+
339
+ ## 🟢 RÈGLES OPTIONNELLES
340
+
341
+ ### 1. API Resource pour HTTP
342
+ ```typescript
343
+ // ✅ Nouvelle approche optionnelle
344
+ import { resource, ResourceStatus } from '@angular/core';
345
+
346
+ @Component({
347
+ template: `
348
+ @switch (userResource.status()) {
349
+ @case (ResourceStatus.Loading) { <p>Chargement...</p> }
350
+ @case (ResourceStatus.Error) { <p>Erreur: {{ userResource.error() }}</p> }
351
+ @case (ResourceStatus.Resolved) {
352
+ <p>{{ userResource.value().name }}</p>
353
+ <button (click)="userResource.reload()">Recharger</button>
354
+ }
355
+ }
356
+ `
357
+ })
358
+ export class UserComponent {
359
+ userResource = resource({
360
+ loader: () => fetch('/api/user').then(r => r.json())
361
+ });
362
+ }
363
+
364
+ // Avec paramètres réactifs
365
+ export class SearchComponent {
366
+ searchTerm = signal('');
367
+ results = resource({
368
+ request: this.searchTerm,
369
+ loader: ({ request }) =>
370
+ fetch(`/api/search?q=${request}`).then(r => r.json())
371
+ });
372
+ }
373
+ ```
374
+
375
+ ### 2. Hydratation Incrémentale
376
+ ```typescript
377
+ // ✅ Nouveau - Hydratation différée
378
+ @Component({
379
+ template: `
380
+ @defer (render on server; hydrate on interaction) {
381
+ <heavy-component />
382
+ } @placeholder {
383
+ <loading-skeleton />
384
+ }
385
+ `
386
+ })
387
+
388
+ // main.ts
389
+ bootstrapApplication(App, {
390
+ providers: [
391
+ provideClientHydration(withIncrementalHydration())
392
+ ]
393
+ });
394
+ ```
395
+
396
+ ### 2. Service Worker Amélioré
397
+ ```json
398
+ // ngsw-config.json
399
+ {
400
+ "applicationMaxAge": "7d", // Nouveau
401
+ "dataGroups": [{
402
+ "name": "api-cache",
403
+ "urls": ["/api/**"],
404
+ "cacheConfig": {
405
+ "maxAge": "1h",
406
+ "refreshAhead": "10m" // Nouveau
407
+ }
408
+ }]
409
+ }
410
+ ```
411
+
412
+ ### 3. Rendu Hybride
413
+ ```typescript
414
+ // app.routes.server.ts (nouveau fichier)
415
+ import { RenderMode } from '@angular/ssr';
416
+
417
+ export const serverRoutes = [
418
+ { path: '', renderMode: RenderMode.Prerender },
419
+ { path: 'blog/**', renderMode: RenderMode.Server },
420
+ { path: 'admin/**', renderMode: RenderMode.Client }
421
+ ];
422
+
423
+ // Installation
424
+ // ng add @angular/ssr --server-routing
425
+ ```
426
+
427
+ ### 4. Control Flow Migration
428
+ ```typescript
429
+ // ❌ Avant - Directives
430
+ <div *ngIf="show">Content</div>
431
+ <div *ngFor="let item of items">{{ item }}</div>
432
+
433
+ // ✅ Après - Control Flow
434
+ @if (show) {
435
+ <div>Content</div>
436
+ }
437
+ @for (item of items; track item.id) {
438
+ <div>{{ item }}</div>
439
+ }
440
+
441
+ // Migration automatique
442
+ // ng generate @angular/core:control-flow
443
+ ```
444
+
445
+ ### 6. Lazy Loading Routes Migration
446
+ ```bash
447
+ # Migration automatique vers lazy loading
448
+ ng generate @angular/core:route-lazy-loading
449
+
450
+ # Pour un dossier spécifique
451
+ ng generate @angular/core:route-lazy-loading --path src/app/features
452
+ ```
453
+
454
+ ```typescript
455
+ // ❌ Avant - Eager loading
456
+ const routes: Routes = [
457
+ {
458
+ path: 'users',
459
+ component: UsersComponent // Composant standalone chargé eagerly
460
+ }
461
+ ];
462
+
463
+ // ✅ Après - Lazy loading automatique
464
+ const routes: Routes = [
465
+ {
466
+ path: 'users',
467
+ loadComponent: () => import('./users/users.component').then(m => m.UsersComponent)
468
+ }
469
+ ];
470
+ ```
471
+
472
+ ---
473
+
474
+ ## 📊 Checklist Migration Complète
475
+
476
+ ```typescript
477
+ interface MigrationStatus19 {
478
+ obligatoire: {
479
+ typescript55: boolean; // v5.5+
480
+ standaloneDefault: boolean; // standalone: false explicite
481
+ templateRefs: boolean; // Supprimer this.
482
+ browserModule: boolean; // APP_ID token
483
+ keyValueDiffers: boolean; // Supprimer .factories
484
+ localizeName: boolean; // name → project
485
+ pendingTasks: boolean; // Experimental → stable
486
+ routerErrorHandler: boolean; // withNavigationErrorHandler
487
+ resolveRedirect: boolean; // RedirectCommand dans Resolve
488
+ effectsTiming: boolean; // whenStable() pour tests
489
+ fakeAsyncFlush: boolean; // {flush: false} si nécessaire
490
+ createComponent: boolean; // projectableNodes vide
491
+ };
492
+ recommandee: {
493
+ signalsMigration?: boolean; // @Input → input()
494
+ resourceAPI?: boolean; // Gestion état HTTP
495
+ linkedSignal?: boolean; // Signaux liés
496
+ newInitializers?: boolean; // provideAppInitializer
497
+ routerOutletData?: boolean; // Partage parent-enfant
498
+ };
499
+ optionnelle: {
500
+ incrementalHydration?: boolean; // @defer hydrate
501
+ serviceWorker?: boolean; // refreshAhead, maxAge
502
+ hybridRendering?: boolean; // Rendu par route
503
+ controlFlow?: boolean; // @if, @for, @switch
504
+ injectFunction?: boolean; // inject() vs constructor
505
+ };
506
+ }
507
+ ```
508
+
509
+ ## 🚀 Script Migration Automatisé
510
+
511
+ ```bash
512
+ #!/bin/bash
513
+ # migration-v19.sh
514
+
515
+ echo "🔄 Angular 18 -> 19 Migration Starting..."
516
+
517
+ # 1. Backup
518
+ git checkout -b migration-angular-19
519
+ git add . && git commit -m "Pre-migration v19 backup"
520
+
521
+ # 2. Core updates
522
+ echo "📦 Updating to Angular 19..."
523
+ npm install typescript@~5.5.0
524
+ ng update @angular/core@19 @angular/cli@19 --verbose
525
+ ng update @angular/material@19 # Si utilisé
526
+
527
+ # 3. Fix automatiques obligatoires
528
+ echo "🔧 Applying mandatory fixes..."
529
+ find . -name "*.ts" -not -path "*/node_modules/*" | while read file; do
530
+ # Remove this. prefix from template refs
531
+ sed -i 's/this\.\([a-zA-Z_][a-zA-Z0-9_]*\)/\1/g' "$file"
532
+
533
+ # Rename ExperimentalPendingTasks
534
+ sed -i 's/ExperimentalPendingTasks/PendingTasks/g' "$file"
535
+ done
536
+
537
+ # 4. Angular.json updates
538
+ sed -i 's/"name":/"project":/g' angular.json
539
+
540
+ # 5. Migrations recommandées (interactives)
541
+ echo "🎯 Running recommended migrations..."
542
+
543
+ # Migration Standalone (3 étapes)
544
+ echo "📦 Step 1/3: Converting to standalone..."
545
+ ng generate @angular/core:standalone # Choisir option 1
546
+
547
+ echo "📦 Step 2/3: Removing unnecessary modules..."
548
+ ng generate @angular/core:standalone # Choisir option 2
549
+
550
+ echo "📦 Step 3/3: Bootstrap with standalone API..."
551
+ ng generate @angular/core:standalone # Choisir option 3
552
+
553
+ # Migrations des signals (séparées)
554
+ echo "🎯 Migrating inputs to signals..."
555
+ ng generate @angular/core:signal-input-migration --best-effort-mode
556
+
557
+ echo "🎯 Migrating outputs to signals..."
558
+ ng generate @angular/core:output-migration
559
+
560
+ echo "🎯 Migrating queries to signals..."
561
+ ng generate @angular/core:signal-queries-migration
562
+
563
+ # 6. Migrations optionnelles
564
+ read -p "Apply optional migrations? (y/n) " -n 1 -r
565
+ echo
566
+ if [[ $REPLY =~ ^[Yy]$ ]]
567
+ then
568
+ echo "🔄 Applying optional migrations..."
569
+ ng generate @angular/core:control-flow
570
+ ng generate @angular/core:inject
571
+ ng generate @angular/core:route-lazy-loading
572
+ fi
573
+
574
+ # 7. Tests
575
+ echo "🧪 Running validation..."
576
+ ng test --no-watch --code-coverage
577
+ ng build --configuration production
578
+
579
+ echo "✅ Migration complete! Review changes with: git diff"
580
+ echo "📝 Check for TODOs: grep -r 'TODO' src/"
581
+ ```
582
+
583
+ ## ⚠️ Points d'Attention & Validation
584
+
585
+ | Catégorie | Risque | Solution | Vérification |
586
+ |-----------|--------|----------|--------------|
587
+ | Standalone | Composants legacy cassés | Ajouter `standalone: false` | Build sans erreurs |
588
+ | Effects | Tests timing incorrects | Utiliser `whenStable()` | Tests passent |
589
+ | FakeAsync | Comportement modifié | Option `{flush: false}` | Tests timing OK |
590
+ | Signals | Migration incomplète | Mode `--best-effort` | Vérifier TODOs |
591
+ | Hydratation | SSR performance | Activer incremental | Mesurer LCP |
592
+ | Router | ErrorHandler obsolète | Migration provider | Gestion erreurs OK |
593
+
594
+ ## 📈 Métriques Cibles
595
+
596
+ - **Bundle**: -15% avec signals et lazy loading
597
+ - **Hydratation**: -30% TTI avec incremental
598
+ - **Build**: -20% temps avec esbuild
599
+ - **Tests**: -40% durée avec esbuild runner
600
+ - **Coverage**: Maintenir >80%