@silvestv/migration-planificator 7.1.0 → 7.1.2
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/dist/client.bundle.js +200 -182
- package/dist/src/autofix/cli/fix-command.js +6 -4
- package/dist/src/autofix/generators/context-generator.js +71 -2
- package/dist/src/autofix/generators/file-prompt-generator.js +22 -3
- package/dist/src/autofix/prompts/constitution.js +23 -0
- package/dist/src/autofix/prompts/file-prompt-complex.js +129 -0
- package/dist/src/autofix/prompts/file-prompt-diagnostics.js +2 -98
- package/dist/src/autofix/prompts/file-prompt-phases.js +106 -44
- package/dist/src/autofix/prompts/file-prompt-reference.js +7 -25
- package/dist/src/autofix/prompts/file-prompt-routine.js +160 -0
- package/dist/src/autofix/prompts/file-prompt-shared.js +82 -0
- package/dist/src/data/rules/to18/rules-18-obligatoire.json +382 -368
- package/dist/src/data/rules/to18/rules-18-optionnelle.json +135 -131
- package/dist/src/data/rules/to18/rules-18-recommande.json +113 -110
- package/dist/src/data/rules/to19/rules-19-obligatoire.json +204 -15
- package/dist/src/data/rules/to19/rules-19-optionnelle.json +12 -6
- package/dist/src/data/rules/to19/rules-19-recommande.json +11 -5
- package/dist/src/data/rules/to20/rules-20-obligatoire.json +15 -3
- package/dist/src/data/rules/to20/rules-20-optionnelle.json +2 -2
- package/dist/src/data/rules/to20/rules-20-recommande.json +2 -0
- package/dist/src/data/rules/to21/rules-21-obligatoire.json +12 -2
- package/dist/src/data/rules/to21/rules-21-optionnelle.json +2 -1
- package/dist/src/data/rules/to21/rules-21-recommande.json +4 -0
- package/dist/src/models/constants/fix-ai-cli-permissions.js +35 -6
- package/dist/src/models/constants/nx-angular-compatibility.js +50 -0
- package/dist/src/models/interfaces/ai-specification.interface.js +18 -0
- package/dist/src/models/types/routine-type.type.js +2 -0
- package/dist/src/templates/workload/rule-modal.template.js +74 -0
- package/dist/src/utils/autofix/bash-commands-helpers.js +14 -0
- package/dist/src/utils/autofix/compatibility-helpers.js +35 -0
- package/dist/src/utils/core/rule-helpers.js +3 -2
- package/dist/src/utils/shared/rule-helpers.js +32 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -5,14 +5,16 @@
|
|
|
5
5
|
"description": "Angular 19 requiert Node.js 20.18.1 ou supérieur et TypeScript 5.5+. Cette version introduit les linked signals, le support amélioré du zoneless, et un nouveau système de schematics. Les versions antérieures ne sont plus compatibles.",
|
|
6
6
|
"estimated_time_per_occurrence": 20,
|
|
7
7
|
"onFile": "package.json",
|
|
8
|
+
"routineType": "environment-migration",
|
|
8
9
|
"fileTypes": ["package.json"],
|
|
9
10
|
"regex": "\"@angular/(core|cli)\"\\s*:\\s*\"(?:(?:\\^|~)?1[0-8](?:\\.\\d+){0,2})\"",
|
|
10
11
|
"category": "environment",
|
|
11
|
-
"isAutoFixable":
|
|
12
|
+
"isAutoFixable": true,
|
|
13
|
+
"minAngularVersion": 18,
|
|
12
14
|
"migration_command": "npx ng update @angular/core@19 @angular/cli@19",
|
|
13
|
-
"nxMigrationCommand": "npx nx migrate @
|
|
15
|
+
"nxMigrationCommand": "npx nx migrate nx@20.8.4 && npm install && npm install typescript@~5.5.4 && npx nx migrate --run-migrations",
|
|
14
16
|
"risk_level": "high",
|
|
15
|
-
"code_description": "// Migration Angular 19\n//
|
|
17
|
+
"code_description": "// Migration Angular 18 → 19 (Nx)\n// 1. npx nx migrate nx@20.8.4\n// 2. Mettre à jour deps tierces Angular dans package.json vers @19 + !!! Bonne version de typescript si non spécifié !!!\n// 3. npm install && npm install typescript@~5.5.4\n// 4. npx nx migrate --run-migrations",
|
|
16
18
|
"doc_url": "https://angular.dev/reference/migrations"
|
|
17
19
|
},
|
|
18
20
|
{
|
|
@@ -26,7 +28,8 @@
|
|
|
26
28
|
],
|
|
27
29
|
"regex": "\"engines\"\\s*:\\s*\\{[^}]*\"node\"\\s*:\\s*\"(?:(?:[<>=~^]*)(1[0-9]|20\\.(?:[0-9]|1[0-7])(?:\\.[0-9]+)?))\"",
|
|
28
30
|
"category": "environment",
|
|
29
|
-
"isAutoFixable":
|
|
31
|
+
"isAutoFixable": true,
|
|
32
|
+
"minAngularVersion": 19,
|
|
30
33
|
"migration_command": null,
|
|
31
34
|
"risk_level": "high",
|
|
32
35
|
"code_description": "// Vérifier et mettre à jour Node.js\n// Avant: Node v16.x\n// Après: Node v20.18.1+\n// Commande: node --version",
|
|
@@ -44,6 +47,7 @@
|
|
|
44
47
|
"regex": "^(?![\\s\\S]*\"typescript\"[\\s\\S]*\"[<>=~^]*(?:5\\.[5-9]|[6-9]\\d*)\\.)[\\s\\S]+",
|
|
45
48
|
"category": "environment",
|
|
46
49
|
"isAutoFixable": true,
|
|
50
|
+
"minAngularVersion": 19,
|
|
47
51
|
"migration_command": "npm install typescript@~5.5.0",
|
|
48
52
|
"risk_level": "medium",
|
|
49
53
|
"code_description": "// package.json\n// Avant: \"typescript\": \"~5.4.0\"\n// Après: \"typescript\": \"~5.5.0\"",
|
|
@@ -51,19 +55,20 @@
|
|
|
51
55
|
},
|
|
52
56
|
{
|
|
53
57
|
"key": "standalone_default",
|
|
54
|
-
"summary": "Angular 19 : standalone est maintenant true par défaut
|
|
55
|
-
"description": "BREAKING CHANGE MAJEUR : Angular 19 définit `standalone: true` comme valeur par défaut. Les composants/directives/pipes déclarés dans un NgModule (via la propriété 'declarations') causeront une erreur de build : 'Component X is standalone, and cannot be declared in an NgModule'. Solution
|
|
58
|
+
"summary": "Angular 19 : standalone est maintenant true par défaut",
|
|
59
|
+
"description": "BREAKING CHANGE MAJEUR : Angular 19 définit `standalone: true` comme valeur par défaut. Les composants/directives/pipes déclarés dans un NgModule (via la propriété 'declarations') causeront une erreur de build : 'Component X is standalone, and cannot be declared in an NgModule'. Solution recommandée : migrer vers l'architecture standalone via les schematics officiels Angular.",
|
|
56
60
|
"estimated_time_per_occurrence": 1,
|
|
57
61
|
"fileTypes": [
|
|
58
62
|
"*.ts"
|
|
59
63
|
],
|
|
60
64
|
"regex": "declarations:\\s*\\[",
|
|
61
65
|
"category": "architecture",
|
|
62
|
-
"isAutoFixable":
|
|
66
|
+
"isAutoFixable": true,
|
|
67
|
+
"minAngularVersion": 16,
|
|
63
68
|
"migration_command": "npx ng g @angular/core:standalone --mode=convert-to-standalone --path=./ && npx ng g @angular/core:standalone --mode=prune-ng-modules --path=./ && npx ng g @angular/core:standalone --mode=standalone-bootstrap --path=./",
|
|
64
69
|
"nxMigrationCommand": "npx nx g @angular/core:standalone --mode=convert-to-standalone --path=./ && npx nx g @angular/core:standalone --mode=prune-ng-modules --path=./ && npx nx g @angular/core:standalone --mode=standalone-bootstrap --path=./",
|
|
65
70
|
"risk_level": "critical",
|
|
66
|
-
"code_description": "//
|
|
71
|
+
"code_description": "// BREAKING : standalone est true par défaut à partir de v19\n\n// Avant (Angular 18) - Fonctionne :\n@NgModule({\n declarations: [AppComponent, UserComponent]\n})\nexport class AppModule {}\n\n// Angular 19 - ERREUR :\n// \"Component AppComponent is standalone, and cannot be declared in an NgModule\"\n\n// Solution : Migrer vers standalone\n@Component({\n standalone: true,\n imports: [CommonModule, RouterOutlet]\n})\nexport class AppComponent {}",
|
|
67
72
|
"astPattern": {
|
|
68
73
|
"nodeType": "Decorator",
|
|
69
74
|
"name": "NgModule",
|
|
@@ -84,7 +89,183 @@
|
|
|
84
89
|
"fileTypes": ["*.module.ts"],
|
|
85
90
|
"timePerOccurrence": 25
|
|
86
91
|
},
|
|
87
|
-
"doc_url": "https://angular.dev/reference/migrations/standalone"
|
|
92
|
+
"doc_url": "https://angular.dev/reference/migrations/standalone",
|
|
93
|
+
"ai_specification": {
|
|
94
|
+
"isComplex": true,
|
|
95
|
+
"criticalNote": "Le schematic Angular ne migre que 90-95% des cas. Une étude de cas post-schematic est OBLIGATOIRE.",
|
|
96
|
+
"knownLimitations": [
|
|
97
|
+
"SharedModule (importé par plusieurs modules)",
|
|
98
|
+
"CoreModule (contient providers globaux)",
|
|
99
|
+
"Modules avec RouterModule.forChild()",
|
|
100
|
+
"Modules avec providers NGRX (StoreModule.forFeature)",
|
|
101
|
+
"Modules tiers (Material, etc.)",
|
|
102
|
+
"Modules avec bootstrap:[] (AppModule, BrowserModule) - Mode 2 ne les supprime JAMAIS",
|
|
103
|
+
"Pattern bootstrap non-standard (IIFE, async wrapper, lazy bootstrap) - Mode 3 échoue silencieusement",
|
|
104
|
+
"SSR avec CommonEngine + ServerModule - Migration séparée nécessaire",
|
|
105
|
+
"Providers Firebase avec factory inject() - Réécriture manuelle",
|
|
106
|
+
"Tokens custom (ENVIRONMENT, CONFIG) - Extraction vers app.config.ts"
|
|
107
|
+
],
|
|
108
|
+
"stages": [
|
|
109
|
+
{
|
|
110
|
+
"number": 1,
|
|
111
|
+
"name": "PRE-SCHEMATIC",
|
|
112
|
+
"description": "Préparer le code pour la migration automatique",
|
|
113
|
+
"actions": [
|
|
114
|
+
{
|
|
115
|
+
"instruction": "SUPPRIMER tous les `standalone: false` explicites des @Component/@Directive/@Pipe",
|
|
116
|
+
"codeExample": "// AVANT:\n@Component({ selector: 'app-user', standalone: false })\n\n// APRES:\n@Component({ selector: 'app-user' })"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"instruction": "EXCEPTION : Ne pas toucher si commentaire in-code indique de ne pas migrer",
|
|
120
|
+
"codeExample": "// Commentaires à respecter:\n// DO NOT MIGRATE\n// KEEP MODULE\n// NO STANDALONE"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"instruction": "Exécuter les 3 schematics SEQUENTIELLEMENT (attendre la fin de chaque commande avant la suivante)",
|
|
124
|
+
"codeExample": "ng g @angular/core:standalone --mode=convert-to-standalone --path=./\nng g @angular/core:standalone --mode=prune-ng-modules --path=./\nng g @angular/core:standalone --mode=standalone-bootstrap --path=./",
|
|
125
|
+
"codeLang": "bash"
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"number": 2,
|
|
131
|
+
"name": "POST-SCHEMATIC - ETUDE DE CAS",
|
|
132
|
+
"description": "Analyser ce que le schematic n'a pas migré",
|
|
133
|
+
"actions": [
|
|
134
|
+
{
|
|
135
|
+
"instruction": "Rechercher tous les @NgModule restants dans le projet",
|
|
136
|
+
"codeExample": "grep -r \"@NgModule\" --include=\"*.ts\" .",
|
|
137
|
+
"codeLang": "bash"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"instruction": "Vérifier si le bootstrap a été migré (main.ts ou main.browser.ts)",
|
|
141
|
+
"codeExample": "// SI bootstrapApplication() existe → OK\n// SI platformBrowserDynamic().bootstrapModule() persiste → Mode 3 a échoué\n\n// Patterns NON reconnus par le schematic:\n// - IIFE wrapper: (async () => { bootstrapModule(...) })()\n// - Async wrapper: async function bootstrap() {...}\n// - Condition: if (condition) { bootstrapModule(...) }\n// → Migration manuelle obligatoire vers bootstrapApplication()"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"instruction": "Pour chaque module trouvé, déterminer pourquoi il n'a pas été supprimé",
|
|
145
|
+
"codeExample": "// Causes fréquentes:\n// - declarations non vide\n// - bootstrap: [Component] présent (AppModule)\n// - RouterModule.forChild()\n// - providers avec forRoot/forFeature\n// - imports par plusieurs autres modules"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"instruction": "Documenter dans le ledger les modules restants et la stratégie de migration"
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"number": 3,
|
|
154
|
+
"name": "MIGRATION MANUELLE DES MODULES",
|
|
155
|
+
"description": "Migrer manuellement chaque type de module restant",
|
|
156
|
+
"actions": [
|
|
157
|
+
{
|
|
158
|
+
"instruction": "A) SUPPRIMER SharedModule : Rendre chaque composant/directive/pipe standalone, importer directement là où utilisé",
|
|
159
|
+
"codeExample": "@Component({ standalone: true, imports: [...] })\nexport class MySharedComponent {}\n\n// Puis supprimer shared.module.ts"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"instruction": "B) MIGRER CoreModule vers provideCore()",
|
|
163
|
+
"codeExample": "// AVANT:\n@NgModule({ providers: [MyService, {provide: HTTP_INTERCEPTORS, ...}] })\nexport class CoreModule {}\n\n// APRES:\nexport function provideCore(): Provider[] {\n return [\n MyService,\n { provide: HTTP_INTERCEPTORS, multi: true, useClass: AuthInterceptor }\n ];\n}\n// Dans app.config.ts: providers: [provideCore()]"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"instruction": "C) MIGRER RouterModule.forChild() vers fichier routes standalone",
|
|
167
|
+
"codeExample": "// AVANT (feature.module.ts):\n@NgModule({ imports: [RouterModule.forChild(routes)] })\n\n// APRES (feature.routes.ts):\nexport const FEATURE_ROUTES: Routes = [...];\n\n// Dans app.routes.ts:\n{ path: 'feature', loadChildren: () => import('./feature.routes').then(m => m.FEATURE_ROUTES) }"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"instruction": "D) MIGRER NGRX vers providers fonctionnels",
|
|
171
|
+
"codeExample": "// Dans les routes:\nproviders: [\n provideState(featureState),\n provideEffects(FeatureEffects)\n]"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"instruction": "E) MODULES TIERS : Utiliser importProvidersFrom()",
|
|
175
|
+
"codeExample": "// Dans app.config.ts:\nproviders: [importProvidersFrom(SomeThirdPartyModule.forRoot())]"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"instruction": "F) MIGRER BOOTSTRAP MANUELLEMENT (si Mode 3 a échoué)",
|
|
179
|
+
"codeExample": "// AVANT (main.ts avec IIFE ou pattern custom):\n(async () => {\n await platformBrowserDynamic().bootstrapModule(AppModule);\n})();\n\n// APRES (main.ts standalone):\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport { AppComponent } from './app/app.component';\nimport { appConfig } from './app/app.config';\n\nbootstrapApplication(AppComponent, appConfig)\n .catch(err => console.error(err));\n\n// app.config.ts:\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideRouter(routes),\n provideHttpClient(),\n // ... autres providers depuis AppModule\n ]\n};"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"instruction": "G) PROVIDERS FIREBASE / COMPLEXES avec factory inject()",
|
|
183
|
+
"codeExample": "// AVANT (dans NgModule):\nproviders: [\n provideFirebaseApp(() => initializeApp(environment.firebase)),\n provideAppCheck(() => {\n const injector = inject(Injector);\n const options = injector.get(AppCheckOptionsService);\n return initializeAppCheck(getApp(), options.getOptions());\n })\n]\n\n// APRES (dans app.config.ts) - IDENTIQUE mais dans ApplicationConfig:\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideFirebaseApp(() => initializeApp(environment.firebase)),\n provideAppCheck(() => {\n const injector = inject(Injector);\n const options = injector.get(AppCheckOptionsService);\n return initializeAppCheck(getApp(), options.getOptions());\n }),\n provideAuth(() => getAuth()),\n provideFirestore(() => getFirestore())\n ]\n};"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"instruction": "H) TOKENS CUSTOM (ENVIRONMENT, CONFIG, GIT_INFO)",
|
|
187
|
+
"codeExample": "// AVANT (dans NgModule):\nproviders: [\n { provide: ENVIRONMENT, useValue: environment },\n { provide: GIT_INFO, useValue: gitInfo }\n]\n\n// APRES (dans app.config.ts):\nimport { environment } from '../environments/environment';\nimport { gitInfo } from '../.git-info';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n { provide: ENVIRONMENT, useValue: environment },\n { provide: GIT_INFO, useValue: gitInfo },\n // ... autres providers\n ]\n};"
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"number": 4,
|
|
193
|
+
"name": "IMPORTS OBLIGATOIRES",
|
|
194
|
+
"description": "S'assurer que chaque composant standalone a ses imports",
|
|
195
|
+
"actions": [
|
|
196
|
+
{
|
|
197
|
+
"instruction": "Chaque composant standalone doit importer explicitement ses dépendances",
|
|
198
|
+
"codeExample": "@Component({\n standalone: true,\n imports: [\n CommonModule, // ou: NgIf, NgFor, NgClass, AsyncPipe\n FormsModule, // si [(ngModel)]\n ReactiveFormsModule, // si [formGroup]\n RouterLink, // si routerLink\n RouterOutlet, // si <router-outlet>\n MyChildComponent,\n MyPipe,\n MyDirective\n ]\n})"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"instruction": "Utiliser l'IDE/Language Service Angular pour détecter les imports manquants"
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"number": 5,
|
|
207
|
+
"name": "MISE A JOUR DES TESTS",
|
|
208
|
+
"description": "Adapter TestBed pour les composants standalone",
|
|
209
|
+
"actions": [
|
|
210
|
+
{
|
|
211
|
+
"instruction": "Déplacer les composants standalone de declarations vers imports",
|
|
212
|
+
"codeExample": "// AVANT:\nTestBed.configureTestingModule({\n declarations: [MyComponent]\n})\n\n// APRES:\nTestBed.configureTestingModule({\n imports: [MyComponent]\n})"
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"number": 6,
|
|
218
|
+
"name": "SERVICES",
|
|
219
|
+
"description": "Optimiser les services pour tree-shaking",
|
|
220
|
+
"actions": [
|
|
221
|
+
{
|
|
222
|
+
"instruction": "Préférer providedIn: 'root' pour les services singleton",
|
|
223
|
+
"codeExample": "@Injectable({ providedIn: 'root' })\nexport class MyService {}"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"instruction": "Pour les services feature-scoped, utiliser les providers de route"
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"number": 7,
|
|
232
|
+
"name": "SSR (SERVER-SIDE RENDERING)",
|
|
233
|
+
"description": "Migrer le bootstrap serveur si projet SSR/Universal",
|
|
234
|
+
"actions": [
|
|
235
|
+
{
|
|
236
|
+
"instruction": "Vérifier si le projet utilise SSR (présence de main.server.ts ou server.ts)",
|
|
237
|
+
"codeExample": "# Fichiers indicateurs SSR:\n- main.server.ts\n- server.ts\n- angular.json → \"server\" target\n- app.server.module.ts",
|
|
238
|
+
"codeLang": "bash"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"instruction": "SI PAS DE SSR → Skip ce stage",
|
|
242
|
+
"codeExample": "// Si aucun fichier serveur trouvé, passer directement à la validation"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"instruction": "Migrer main.server.ts vers standalone bootstrap",
|
|
246
|
+
"codeExample": "// AVANT (main.server.ts avec NgModule):\nimport { AppServerModule } from './app/app.server.module';\nexport { AppServerModule };\n\n// APRES (main.server.ts standalone):\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport { AppComponent } from './app/app.component';\nimport { config } from './app/app.config.server';\n\nconst bootstrap = () => bootstrapApplication(AppComponent, config);\nexport default bootstrap;"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"instruction": "Créer app.config.server.ts avec les providers serveur",
|
|
250
|
+
"codeExample": "// app.config.server.ts\nimport { ApplicationConfig, mergeApplicationConfig } from '@angular/core';\nimport { provideServerRendering } from '@angular/platform-server';\nimport { appConfig } from './app.config';\n\nconst serverConfig: ApplicationConfig = {\n providers: [\n provideServerRendering()\n ]\n};\n\nexport const config = mergeApplicationConfig(appConfig, serverConfig);"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"instruction": "Migrer CommonEngine si utilisé (Express server)",
|
|
254
|
+
"codeExample": "// AVANT (server.ts avec Module):\nnew CommonEngine().render({\n bootstrap: AppServerModule,\n ...\n})\n\n// APRES (server.ts avec standalone bootstrap):\nimport bootstrap from './main.server';\n\nnew CommonEngine().render({\n bootstrap,\n ...\n})"
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"instruction": "Supprimer AppServerModule après migration",
|
|
258
|
+
"codeExample": "// Supprimer app.server.module.ts une fois la migration terminée\n// Vérifier que le build SSR fonctionne : npm run build:ssr && npm run serve:ssr"
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
],
|
|
263
|
+
"verificationCommands": [
|
|
264
|
+
"grep -r \"@NgModule\" --include=\"*.ts\" . | wc -l",
|
|
265
|
+
"ng build",
|
|
266
|
+
"npm test"
|
|
267
|
+
]
|
|
268
|
+
}
|
|
88
269
|
},
|
|
89
270
|
{
|
|
90
271
|
"key": "template_refs_no_this",
|
|
@@ -105,6 +286,7 @@
|
|
|
105
286
|
},
|
|
106
287
|
"category": "template",
|
|
107
288
|
"isAutoFixable": true,
|
|
289
|
+
"minAngularVersion": 19,
|
|
108
290
|
"migration_command": null,
|
|
109
291
|
"risk_level": "medium",
|
|
110
292
|
"code_description": "// Avant:\n<div #myDiv></div>\n{{ this.myDiv.textContent }}\n\n// Après:\n<div #myDiv></div>\n{{ myDiv.textContent }}",
|
|
@@ -121,7 +303,8 @@
|
|
|
121
303
|
],
|
|
122
304
|
"regex": "BrowserModule\\.withServerTransition",
|
|
123
305
|
"category": "imports",
|
|
124
|
-
"isAutoFixable":
|
|
306
|
+
"isAutoFixable": true,
|
|
307
|
+
"minAngularVersion": 19,
|
|
125
308
|
"migration_command": null,
|
|
126
309
|
"risk_level": "medium",
|
|
127
310
|
"code_description": "// Avant:\nBrowserModule.withServerTransition({ appId: 'my-app' })\n\n// Après:\nimport { APP_ID } from '@angular/core';\nbootstrapApplication(App, {\n providers: [{ provide: APP_ID, useValue: 'my-app' }]\n});",
|
|
@@ -179,6 +362,7 @@
|
|
|
179
362
|
"regex": "\\bExperimentalPendingTasks\\b",
|
|
180
363
|
"category": "api",
|
|
181
364
|
"isAutoFixable": true,
|
|
365
|
+
"minAngularVersion": 19,
|
|
182
366
|
"migration_command": null,
|
|
183
367
|
"risk_level": "low",
|
|
184
368
|
"code_description": "// Avant:\nimport { ExperimentalPendingTasks } from '@angular/core';\n\n// Après:\nimport { PendingTasks } from '@angular/core';",
|
|
@@ -203,7 +387,8 @@
|
|
|
203
387
|
],
|
|
204
388
|
"regex": "router\\.errorHandler\\s*=",
|
|
205
389
|
"category": "routing",
|
|
206
|
-
"isAutoFixable":
|
|
390
|
+
"isAutoFixable": true,
|
|
391
|
+
"minAngularVersion": 19,
|
|
207
392
|
"migration_command": null,
|
|
208
393
|
"risk_level": "medium",
|
|
209
394
|
"code_description": "// Avant:\nthis.router.errorHandler = (error) => { };\n\n// Après:\nprovideRouter(routes,\n withNavigationErrorHandler((error) => { })\n)",
|
|
@@ -232,7 +417,8 @@
|
|
|
232
417
|
],
|
|
233
418
|
"regex": "implements\\s+Resolve<(?!.*RedirectCommand)",
|
|
234
419
|
"category": "routing",
|
|
235
|
-
"isAutoFixable":
|
|
420
|
+
"isAutoFixable": true,
|
|
421
|
+
"minAngularVersion": 19,
|
|
236
422
|
"migration_command": null,
|
|
237
423
|
"risk_level": "medium",
|
|
238
424
|
"code_description": "// Avant:\nResolve<User>\n\n// Après:\nResolve<User | RedirectCommand> {\n return this.service.get().pipe(\n catchError(() => of(new RedirectCommand('/error')))\n );\n}",
|
|
@@ -260,7 +446,8 @@
|
|
|
260
446
|
],
|
|
261
447
|
"regex": "triggerEffect|effect\\(\\s*\\(\\)",
|
|
262
448
|
"category": "test",
|
|
263
|
-
"isAutoFixable":
|
|
449
|
+
"isAutoFixable": true,
|
|
450
|
+
"minAngularVersion": 19,
|
|
264
451
|
"migration_command": null,
|
|
265
452
|
"risk_level": "medium",
|
|
266
453
|
"code_description": "// Avant:\ncomponent.triggerEffect();\nexpect(value).toBe('updated');\n\n// Après:\ncomponent.triggerEffect();\nawait fixture.whenStable();\nexpect(value).toBe('updated');",
|
|
@@ -295,7 +482,8 @@
|
|
|
295
482
|
],
|
|
296
483
|
"regex": "fakeAsync\\s*\\(",
|
|
297
484
|
"category": "test",
|
|
298
|
-
"isAutoFixable":
|
|
485
|
+
"isAutoFixable": true,
|
|
486
|
+
"minAngularVersion": 19,
|
|
299
487
|
"migration_command": null,
|
|
300
488
|
"risk_level": "low",
|
|
301
489
|
"code_description": "// En v19: flush automatique des timers\n// Pour ancien comportement:\nfakeAsync(() => {\n // ...\n}, { flush: false })",
|
|
@@ -326,7 +514,8 @@
|
|
|
326
514
|
],
|
|
327
515
|
"regex": "createComponent\\s*\\(",
|
|
328
516
|
"category": "api",
|
|
329
|
-
"isAutoFixable":
|
|
517
|
+
"isAutoFixable": true,
|
|
518
|
+
"minAngularVersion": 19,
|
|
330
519
|
"migration_command": null,
|
|
331
520
|
"risk_level": "low",
|
|
332
521
|
"code_description": "// Pour éviter fallback par défaut:\ncreateComponent(MyComponent, {\n projectableNodes: [[document.createTextNode('')]]\n});",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
],
|
|
11
11
|
"regex": "\\.get<.*>\\s*\\(",
|
|
12
12
|
"category": "reactive",
|
|
13
|
-
"isAutoFixable":
|
|
13
|
+
"isAutoFixable": true,
|
|
14
|
+
"minAngularVersion": 19,
|
|
14
15
|
"migration_command": null,
|
|
15
16
|
"risk_level": "medium",
|
|
16
17
|
"code_description": "// Avant (HttpClient GET):\nusers$ = this.http.get<User[]>('/api/users').pipe(\n catchError(() => of([])),\n shareReplay(1)\n);\n\n// Template\n<div *ngIf=\"users$ | async as users\">\n <user-list [users]=\"users\"/>\n</div>\n\n// Après (httpResource - Angular 19.2+):\nimport { httpResource } from '@angular/core';\n\nusersResource = httpResource({\n url: '/api/users',\n loader: () => fetch('/api/users').then(r => r.json())\n});\n\n// Template avec signal\n@switch (usersResource.status()) {\n @case('loading') { <spinner/> }\n @case('resolved') { <user-list [users]=\"usersResource.value()\"/> }\n @case('error') { <error-message/> }\n}\n\n// ⚠️ Uniquement pour GET (fetching data)\n// Pour POST/PUT/DELETE, garder HttpClient classique",
|
|
@@ -55,7 +56,8 @@
|
|
|
55
56
|
],
|
|
56
57
|
"regex": "(?<![\"\\'])\\bprovideClientHydration\\s*\\(",
|
|
57
58
|
"category": "ssr",
|
|
58
|
-
"isAutoFixable":
|
|
59
|
+
"isAutoFixable": true,
|
|
60
|
+
"minAngularVersion": 19,
|
|
59
61
|
"migration_command": null,
|
|
60
62
|
"risk_level": "high",
|
|
61
63
|
"code_description": "bootstrapApplication(App, {\n providers: [\n provideClientHydration(withIncrementalHydration())\n ]\n});\n\n// Template:\n@defer (render on server; hydrate on interaction) {\n <heavy-component />\n}",
|
|
@@ -83,7 +85,8 @@
|
|
|
83
85
|
],
|
|
84
86
|
"regex": "^(?![\\s\\S]*(\"applicationMaxAge\"|\"refreshAhead\"))",
|
|
85
87
|
"category": "pwa",
|
|
86
|
-
"isAutoFixable":
|
|
88
|
+
"isAutoFixable": true,
|
|
89
|
+
"minAngularVersion": 19,
|
|
87
90
|
"migration_command": null,
|
|
88
91
|
"risk_level": "low",
|
|
89
92
|
"code_description": "// ngsw-config.json\n{\n \"applicationMaxAge\": \"7d\",\n \"dataGroups\": [{\n \"cacheConfig\": {\n \"maxAge\": \"1h\",\n \"refreshAhead\": \"10m\"\n }\n }]\n}",
|
|
@@ -100,7 +103,8 @@
|
|
|
100
103
|
],
|
|
101
104
|
"regex": "export\\s+const\\s+routes\\s*:\\s*Routes",
|
|
102
105
|
"category": "ssr",
|
|
103
|
-
"isAutoFixable":
|
|
106
|
+
"isAutoFixable": true,
|
|
107
|
+
"minAngularVersion": 19,
|
|
104
108
|
"migration_command": null,
|
|
105
109
|
"risk_level": "medium",
|
|
106
110
|
"code_description": "// app.routes.server.ts\nimport { RenderMode } from '@angular/ssr';\n\nexport const serverRoutes = [\n { path: '', renderMode: RenderMode.Prerender },\n { path: 'blog/**', renderMode: RenderMode.Server },\n { path: 'admin/**', renderMode: RenderMode.Client }\n];",
|
|
@@ -151,7 +155,8 @@
|
|
|
151
155
|
],
|
|
152
156
|
"regex": "\\bcomponent\\s*:\\s*[A-Z]\\w+Component\\b",
|
|
153
157
|
"category": "routing",
|
|
154
|
-
"isAutoFixable":
|
|
158
|
+
"isAutoFixable": true,
|
|
159
|
+
"minAngularVersion": 19,
|
|
155
160
|
"migration_command": "npx ng generate @angular/core:route-lazy-loading --path=./",
|
|
156
161
|
"nxMigrationCommand": "npx nx generate @angular/core:route-lazy-loading --path=./",
|
|
157
162
|
"risk_level": "low",
|
|
@@ -195,7 +200,8 @@
|
|
|
195
200
|
],
|
|
196
201
|
"regex": "constructor\\s*\\([^)]*private\\s+\\w+\\s*:\\s*\\w+",
|
|
197
202
|
"category": "di",
|
|
198
|
-
"isAutoFixable":
|
|
203
|
+
"isAutoFixable": true,
|
|
204
|
+
"minAngularVersion": 19,
|
|
199
205
|
"migration_command": "npx ng generate @angular/core:inject-migration --path=./",
|
|
200
206
|
"nxMigrationCommand": "npx nx generate @angular/core:inject-migration --path=./",
|
|
201
207
|
"risk_level": "low",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"regex": "@Input\\s*\\([^)]*\\)\\s*(?!set\\s|get\\s)\\w+\\s*[:\\=]",
|
|
12
12
|
"category": "signals",
|
|
13
13
|
"isAutoFixable": true,
|
|
14
|
+
"minAngularVersion": 19,
|
|
14
15
|
"migration_command": "npx ng generate @angular/core:signal-input-migration --path=./ --best-effort-mode=false",
|
|
15
16
|
"nxMigrationCommand": "npx nx generate @angular/core:signal-input-migration --path=./ --best-effort-mode=false",
|
|
16
17
|
"risk_level": "medium",
|
|
@@ -39,7 +40,8 @@
|
|
|
39
40
|
],
|
|
40
41
|
"regex": "@Input\\s*\\([^)]*\\)\\s*(get|set)\\s+\\w+",
|
|
41
42
|
"category": "signals",
|
|
42
|
-
"isAutoFixable":
|
|
43
|
+
"isAutoFixable": true,
|
|
44
|
+
"minAngularVersion": 19,
|
|
43
45
|
"migration_command": null,
|
|
44
46
|
"risk_level": "high",
|
|
45
47
|
"code_description": "// Avant (setter @Input - NON migré automatiquement):\n@Input() set selectedItem(value: Item) {\n this._selectedItem = value;\n this.processItem(value);\n}\n\n// Après (migration manuelle vers signal + computed):\nselectedItem = input<Item>();\nprivate processedItem = computed(() => {\n const item = this.selectedItem();\n return this.processItem(item);\n});",
|
|
@@ -67,7 +69,8 @@
|
|
|
67
69
|
],
|
|
68
70
|
"regex": "@Output\\s*\\(\\)",
|
|
69
71
|
"category": "signals",
|
|
70
|
-
"isAutoFixable":
|
|
72
|
+
"isAutoFixable": true,
|
|
73
|
+
"minAngularVersion": 19,
|
|
71
74
|
"migration_command": "npx ng generate @angular/core:output-migration --path=./",
|
|
72
75
|
"nxMigrationCommand": "npx nx generate @angular/core:output-migration --path=./",
|
|
73
76
|
"risk_level": "low",
|
|
@@ -100,7 +103,8 @@
|
|
|
100
103
|
],
|
|
101
104
|
"regex": "@(ViewChild|ViewChildren|ContentChild|ContentChildren)\\s*\\(",
|
|
102
105
|
"category": "signals",
|
|
103
|
-
"isAutoFixable":
|
|
106
|
+
"isAutoFixable": true,
|
|
107
|
+
"minAngularVersion": 19,
|
|
104
108
|
"migration_command": "npx ng generate @angular/core:signal-queries-migration --path=./ --best-effort-mode=false",
|
|
105
109
|
"nxMigrationCommand": "npx nx generate @angular/core:signal-queries-migration --path=./ --best-effort-mode=false",
|
|
106
110
|
"risk_level": "medium",
|
|
@@ -135,7 +139,8 @@
|
|
|
135
139
|
],
|
|
136
140
|
"regex": "effect\\s*\\(\\s*\\(\\)\\s*=>\\s*\\{[^}]*\\.set\\(",
|
|
137
141
|
"category": "signals",
|
|
138
|
-
"isAutoFixable":
|
|
142
|
+
"isAutoFixable": true,
|
|
143
|
+
"minAngularVersion": 19,
|
|
139
144
|
"migration_command": null,
|
|
140
145
|
"risk_level": "low",
|
|
141
146
|
"code_description": "// Avant:\nngOnInit() {\n effect(() => {\n if (this.category() !== 'all') {\n this.itemsPerPage.set(10);\n }\n });\n}\n\n// Après:\nitemsPerPage = linkedSignal({\n source: this.category,\n computation: () => 10\n});",
|
|
@@ -177,7 +182,8 @@
|
|
|
177
182
|
],
|
|
178
183
|
"regex": "provide:\\s*APP_INITIALIZER",
|
|
179
184
|
"category": "architecture",
|
|
180
|
-
"isAutoFixable":
|
|
185
|
+
"isAutoFixable": true,
|
|
186
|
+
"minAngularVersion": 19,
|
|
181
187
|
"migration_command": null,
|
|
182
188
|
"risk_level": "low",
|
|
183
189
|
"code_description": "// Avant:\n{ provide: APP_INITIALIZER, useFactory: ... }\n\n// Après:\nprovideAppInitializer(() => {\n return inject(ConfigService).load();\n})",
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
"description": "Angular 20 requiert Node.js 22.12.0 ou supérieur et TypeScript 5.8+. Cette version active par défaut le build ESM, introduit le support expérimental de Vitest, et adopte un nouveau guide de style sans suffixes. Les versions de Node 22.0 à 22.10 causent des instabilités.",
|
|
6
6
|
"estimated_time_per_occurrence": 25,
|
|
7
7
|
"onFile": "package.json",
|
|
8
|
+
"routineType": "environment-migration",
|
|
8
9
|
"fileTypes": ["package.json"],
|
|
9
10
|
"regex": "\"@angular/(core|cli)\"\\s*:\\s*\"(?:(?:\\^|~)?1[0-9](?:\\.\\d+){0,2})\"",
|
|
10
11
|
"category": "environment",
|
|
11
|
-
"isAutoFixable":
|
|
12
|
+
"isAutoFixable": true,
|
|
12
13
|
"migration_command": "npx ng update @angular/core@20 @angular/cli@20",
|
|
13
|
-
"nxMigrationCommand": "npx nx migrate @
|
|
14
|
+
"nxMigrationCommand": "npx nx migrate nx@21.6.10 && npm install && npm install typescript@~5.8.3 && npx nx migrate --run-migrations",
|
|
14
15
|
"risk_level": "critical",
|
|
15
|
-
"code_description": "// Migration Angular 20\n//
|
|
16
|
+
"code_description": "// Migration Angular 19 → 20 (Nx)\n// 1. npx nx migrate nx@21.6.10\n// 2. Mettre à jour deps tierces Angular dans package.json vers @20 + !!! Bonne version de typescript si non spécifié !!!\n// 3. npm install && npm install typescript@~5.8.3\n// 4. npx nx migrate --run-migrations",
|
|
16
17
|
"doc_url": "https://angular.dev/reference/migrations"
|
|
17
18
|
},
|
|
18
19
|
{
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
"regex": "^(?![\\s\\S]*\"typescript\"[\\s\\S]*\"[<>=~^]*(?:5\\.[8-9]|[6-9]\\d*)\\.)[\\s\\S]+",
|
|
45
46
|
"category": "environment",
|
|
46
47
|
"isAutoFixable": true,
|
|
48
|
+
"minAngularVersion": 19,
|
|
47
49
|
"migration_command": "npm install typescript@~5.8.0",
|
|
48
50
|
"risk_level": "medium",
|
|
49
51
|
"code_description": "// package.json\n// Avant: \"typescript\": \"~5.5.0\"\n// Après: \"typescript\": \"~5.8.0\"",
|
|
@@ -61,6 +63,7 @@
|
|
|
61
63
|
"regex": "\\bafterRender\\s*\\(",
|
|
62
64
|
"category": "api",
|
|
63
65
|
"isAutoFixable": true,
|
|
66
|
+
"minAngularVersion": 19,
|
|
64
67
|
"migration_command": null,
|
|
65
68
|
"risk_level": "low",
|
|
66
69
|
"code_description": "// Avant:\nafterRender(() => { });\n\n// Après:\nafterEveryRender(() => { });",
|
|
@@ -86,6 +89,7 @@
|
|
|
86
89
|
"regex": "provideExperimentalCheckNoChangesForDebug",
|
|
87
90
|
"category": "api",
|
|
88
91
|
"isAutoFixable": true,
|
|
92
|
+
"minAngularVersion": 19,
|
|
89
93
|
"migration_command": null,
|
|
90
94
|
"risk_level": "low",
|
|
91
95
|
"code_description": "// Avant:\nprovideExperimentalCheckNoChangesForDebug()\n\n// Après:\nprovideCheckNoChangesConfig()\n// Note: useNgZoneOnStable supprimé",
|
|
@@ -111,6 +115,7 @@
|
|
|
111
115
|
"regex": "\\bprovideExperimentalZonelessChangeDetection\\s*\\(",
|
|
112
116
|
"category": "api",
|
|
113
117
|
"isAutoFixable": true,
|
|
118
|
+
"minAngularVersion": 19,
|
|
114
119
|
"migration_command": null,
|
|
115
120
|
"risk_level": "medium",
|
|
116
121
|
"code_description": "// Avant:\nprovideExperimentalZonelessChangeDetection()\n\n// Après:\nprovideZonelessChangeDetection()",
|
|
@@ -136,6 +141,7 @@
|
|
|
136
141
|
"regex": "\\bresource\\s*\\(\\s*\\{[^}]*request\\s*:",
|
|
137
142
|
"category": "api",
|
|
138
143
|
"isAutoFixable": true,
|
|
144
|
+
"minAngularVersion": 19,
|
|
139
145
|
"migration_command": null,
|
|
140
146
|
"risk_level": "medium",
|
|
141
147
|
"code_description": "// Avant:\nresource({\n request: () => ({ id: userId() }),\n loader: ({ request }) => fetch(`/users/${request.id}`)\n})\n\n// Après:\nresource({\n params: () => ({ id: userId() }),\n loader: ({ request }) => fetch(`/users/${request.id}`)\n})",
|
|
@@ -168,6 +174,7 @@
|
|
|
168
174
|
"regex": "\\brxResource[\\s\\S]*?loader\\s*:",
|
|
169
175
|
"category": "api",
|
|
170
176
|
"isAutoFixable": true,
|
|
177
|
+
"minAngularVersion": 19,
|
|
171
178
|
"migration_command": null,
|
|
172
179
|
"risk_level": "medium",
|
|
173
180
|
"code_description": "// Avant:\nrxResource({\n loader: () => httpClient.get('/data')\n})\n\n// Après:\nrxResource({\n stream: () => httpClient.get('/data')\n})",
|
|
@@ -200,6 +207,7 @@
|
|
|
200
207
|
"regex": "ResourceStatus\\.(Loading|Idle|Resolved|Error|Reloading|Local)",
|
|
201
208
|
"category": "api",
|
|
202
209
|
"isAutoFixable": true,
|
|
210
|
+
"minAngularVersion": 19,
|
|
203
211
|
"migration_command": null,
|
|
204
212
|
"risk_level": "medium",
|
|
205
213
|
"code_description": "// Avant:\nimport { ResourceStatus } from '@angular/core';\nif (resource.status() === ResourceStatus.Loading) { }\n\n// Après:\nif (resource.status() === 'loading') { }\n// Valeurs: 'idle' | 'loading' | 'resolved' | 'error' | 'reloading' | 'local'",
|
|
@@ -262,6 +270,7 @@
|
|
|
262
270
|
"regex": "TestBed\\.flushEffects\\s*\\(",
|
|
263
271
|
"category": "test",
|
|
264
272
|
"isAutoFixable": true,
|
|
273
|
+
"minAngularVersion": 19,
|
|
265
274
|
"migration_command": null,
|
|
266
275
|
"risk_level": "medium",
|
|
267
276
|
"code_description": "// Avant:\nTestBed.flushEffects();\n\n// Après:\nTestBed.tick();",
|
|
@@ -427,6 +436,7 @@
|
|
|
427
436
|
"regex": "TestBed\\.get\\s*\\(",
|
|
428
437
|
"category": "test",
|
|
429
438
|
"isAutoFixable": true,
|
|
439
|
+
"minAngularVersion": 19,
|
|
430
440
|
"migration_command": null,
|
|
431
441
|
"risk_level": "medium",
|
|
432
442
|
"code_description": "// Avant:\nconst service = TestBed.get(MyService);\n\n// Après:\nconst service = TestBed.inject(MyService);",
|
|
@@ -456,6 +466,7 @@
|
|
|
456
466
|
"regex": "InjectFlags\\.(Optional|Self|SkipSelf|Host)",
|
|
457
467
|
"category": "api",
|
|
458
468
|
"isAutoFixable": true,
|
|
469
|
+
"minAngularVersion": 19,
|
|
459
470
|
"migration_command": null,
|
|
460
471
|
"risk_level": "medium",
|
|
461
472
|
"code_description": "// Avant:\nimport { InjectFlags } from '@angular/core';\ninject(MyService, InjectFlags.Optional);\n\n// Après:\ninject(MyService, { optional: true });",
|
|
@@ -552,6 +563,7 @@
|
|
|
552
563
|
"regex": "\"builder\"[\\s\\S]*?\"@angular/localize\"[\\s\\S]*?\"options\"[\\s\\S]*?\\{[\\s\\S]*?\"name\"[\\s\\S]*?\"[^\"]+\"",
|
|
553
564
|
"category": "config",
|
|
554
565
|
"isAutoFixable": true,
|
|
566
|
+
"minAngularVersion": 19,
|
|
555
567
|
"migration_command": null,
|
|
556
568
|
"risk_level": "low",
|
|
557
569
|
"code_description": "// angular.json\n// Avant:\n\"options\": { \"name\": \"my-project\" }\n\n// Après:\n\"options\": { \"project\": \"my-project\" }",
|
|
@@ -115,12 +115,12 @@
|
|
|
115
115
|
"fileTypes": [
|
|
116
116
|
"angular.json"
|
|
117
117
|
],
|
|
118
|
-
"regex": "^(?![\\s\\S]*\"schematics\"[\\s\\S]*\"@schematics/angular:component\"[\\s\\S]*\"type\"[\\s\\S]*\"component\")[\\s\\S]+",
|
|
118
|
+
"regex": "^(?![\\s\\S]*\"(?:schematics|generators)\"[\\s\\S]*\"@(?:schematics|nx)/angular:component\"[\\s\\S]*\"type\"[\\s\\S]*\"component\")[\\s\\S]+",
|
|
119
119
|
"category": "style",
|
|
120
120
|
"isAutoFixable": false,
|
|
121
121
|
"migration_command": null,
|
|
122
122
|
"risk_level": "low",
|
|
123
|
-
"code_description": "// Par défaut en v20: ng generate component user crée user.ts (sans suffixe)\n// Détecte si config pour GARDER suffixes N'EST PAS présente\n\n// MATCH (routine pertinente - config manquante):\n{\n \"projects\": { ... }\n // pas de config schematics pour type: \"component\"\n}\n\n// NO MATCH (déjà configuré - garde les suffixes):\n// angular.json
|
|
123
|
+
"code_description": "// Par défaut en v20: ng generate component user crée user.ts (sans suffixe)\n// Détecte si config pour GARDER suffixes N'EST PAS présente\n\n// MATCH (routine pertinente - config manquante):\n{\n \"projects\": { ... }\n // pas de config schematics/generators pour type: \"component\"\n}\n\n// NO MATCH (déjà configuré - garde les suffixes):\n// angular.json:\n{\n \"schematics\": {\n \"@schematics/angular:component\": { \"type\": \"component\" }\n }\n}\n// nx.json:\n{\n \"generators\": {\n \"@nx/angular:component\": { \"type\": \"component\" }\n }\n}",
|
|
124
124
|
"doc_url": "https://angular.dev/reference/migrations"
|
|
125
125
|
},
|
|
126
126
|
{
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"regex": "\\*ng(If|For|Switch)",
|
|
13
13
|
"category": "template",
|
|
14
14
|
"isAutoFixable": true,
|
|
15
|
+
"minAngularVersion": 17,
|
|
15
16
|
"migration_command": "npx ng generate @angular/core:control-flow --path=./ --format=true",
|
|
16
17
|
"nxMigrationCommand": "npx nx generate @angular/core:control-flow --path=./ --format=true",
|
|
17
18
|
"risk_level": "high",
|
|
@@ -146,6 +147,7 @@
|
|
|
146
147
|
"regex": "appConfig",
|
|
147
148
|
"category": "architecture",
|
|
148
149
|
"isAutoFixable": true,
|
|
150
|
+
"minAngularVersion": 19,
|
|
149
151
|
"migration_command": null,
|
|
150
152
|
"risk_level": "medium",
|
|
151
153
|
"code_description": "// app.config.ts - Configuration zoneless complete:\nimport { ApplicationConfig, provideZonelessChangeDetection, provideBrowserGlobalErrorListeners } from '@angular/core';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideZonelessChangeDetection(),\n provideBrowserGlobalErrorListeners()\n ]\n};",
|