@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,190 @@
1
+ [
2
+ {
3
+ "key": "httpResource_api",
4
+ "summary": "httpResource pour requêtes HTTP réactives",
5
+ "description": "La nouvelle API httpResource expérimentale simplifie les requêtes HTTP réactives avec tracking automatique du status et des erreurs. Alternative moderne aux patterns HttpClient + AsyncPipe, s'intègre nativement avec les signaux pour une réactivité fine-grained.",
6
+ "estimated_time_per_occurrence": 15,
7
+ "onFile": null,
8
+ "fileTypes": [
9
+ "*.ts"
10
+ ],
11
+ "regex": "\\bhttpResource\\s*\\(",
12
+ "category": "reactive",
13
+ "auto_fixable": false,
14
+ "migration_command": null,
15
+ "risk_level": "medium",
16
+ "code_description": "// Nouvelle API expérimentale\n\nconst userResource = httpResource<User>(() => \n `https://api.example.com/users/${userId()}`\n);",
17
+ "astPattern": {
18
+ "nodeType": "CallExpression",
19
+ "functionName": "httpResource",
20
+ "excludeContext": [
21
+ "StringLiteral",
22
+ "Comment"
23
+ ]
24
+ },
25
+ "doc_url": "https://angular.dev/reference/migrations"
26
+ },
27
+ {
28
+ "key": "resource_streaming",
29
+ "summary": "Resource streaming pour websockets",
30
+ "description": "L'API resource streaming permet de créer des ressources qui se mettent à jour en continu via WebSocket ou Server-Sent Events. Le signal retourné se met à jour automatiquement à chaque message, idéal pour les données temps réel (chat, dashboards).",
31
+ "estimated_time_per_occurrence": 30,
32
+ "onFile": null,
33
+ "fileTypes": [
34
+ "*.ts"
35
+ ],
36
+ "regex": "new\\s+WebSocket\\s*\\(",
37
+ "category": "reactive",
38
+ "auto_fixable": false,
39
+ "migration_command": null,
40
+ "risk_level": "high",
41
+ "code_description": "const streamResource = resource({\n stream: () => new Promise<Signal<ResourceStreamItem>>((resolve) => {\n const result = signal<{ value: Data }>({ value: initialData });\n \n websocket.onmessage = (event) => {\n result.update(current => ({\n value: [...current.value, event.data]\n }));\n };\n \n resolve(result);\n })\n});",
42
+ "astPattern": {
43
+ "nodeType": "CallExpression",
44
+ "functionName": "resource",
45
+ "arguments": {
46
+ "properties": {
47
+ "stream": {
48
+ "exists": true
49
+ }
50
+ }
51
+ },
52
+ "excludeContext": [
53
+ "StringLiteral",
54
+ "Comment"
55
+ ]
56
+ },
57
+ "doc_url": "https://angular.dev/reference/migrations"
58
+ },
59
+ {
60
+ "key": "createComponent_bindings",
61
+ "summary": "createComponent avec bindings dynamiques",
62
+ "description": "createComponent supporte maintenant les bindings dynamiques (input, output, two-way) et l'application de directives au runtime. Permet de créer des composants programmatiquement avec la même flexibilité que les templates, idéal pour les dialogs et overlays.",
63
+ "estimated_time_per_occurrence": 15,
64
+ "onFile": null,
65
+ "fileTypes": [
66
+ "*.ts"
67
+ ],
68
+ "regex": "(?<!TestBed\\.)createComponent\\s*\\([^,]+,\\s*\\{[^}]*bindings\\s*:",
69
+ "category": "api",
70
+ "auto_fixable": false,
71
+ "migration_command": null,
72
+ "risk_level": "medium",
73
+ "code_description": "createComponent(MyDialog, {\n bindings: [\n inputBinding('title', titleSignal),\n outputBinding('onClose', (result) => console.log(result)),\n twoWayBinding('value', valueSignal)\n ],\n directives: [\n FocusTrap,\n {\n type: HasColor,\n bindings: [inputBinding('color', () => 'primary')]\n }\n ]\n});",
74
+ "astPattern": {
75
+ "nodeType": "CallExpression",
76
+ "functionName": "createComponent",
77
+ "arguments": {
78
+ "properties": {
79
+ "bindings": {
80
+ "exists": true
81
+ }
82
+ }
83
+ },
84
+ "excludeContext": [
85
+ "StringLiteral",
86
+ "Comment"
87
+ ]
88
+ },
89
+ "doc_url": "https://angular.dev/reference/migrations"
90
+ },
91
+ {
92
+ "key": "vitest_support",
93
+ "summary": "Support Vitest expérimental",
94
+ "description": "Angular 20 ajoute le support expérimental de Vitest comme test runner alternatif à Karma/Jasmine. Vitest offre un démarrage instantané, un watch mode performant et une compatibilité Jest. Configuration via angular.json avec le builder @angular/build:unit-test.",
95
+ "estimated_time_per_occurrence": 840,
96
+ "onFile": "angular.json",
97
+ "fileTypes": [
98
+ "angular.json"
99
+ ],
100
+ "regex": "\"test\"[\\s\\S]*?\"builder\"[\\s\\S]*?(?!\"runner\"[\\s\\S]*?\"vitest\")\"@angular",
101
+ "category": "test",
102
+ "auto_fixable": false,
103
+ "migration_command": "npm i vitest jsdom --save-dev",
104
+ "risk_level": "high",
105
+ "code_description": "// angular.json - Détecte si vitest N'EST PAS encore configuré\n// MATCH (routine pertinente):\n\"test\": {\n \"builder\": \"@angular/build:karma\"\n}\n// OU\n\"test\": {\n \"builder\": \"@angular/build:unit-test\"\n // pas de \"runner\": \"vitest\"\n}\n\n// NO MATCH (déjà configuré):\n\"test\": {\n \"builder\": \"@angular/build:unit-test\",\n \"options\": {\n \"runner\": \"vitest\"\n }\n}\n\n// Installation:\n// npm i vitest jsdom --save-dev",
106
+ "doc_url": "https://angular.dev/reference/migrations"
107
+ },
108
+ {
109
+ "key": "style_guide_no_suffix",
110
+ "summary": "Guide de style sans suffixes",
111
+ "description": "Angular 20 adopte un nouveau guide de style par défaut sans suffixes (.component, .service, etc.) pour les fichiers générés. Pour les projets existants, ng update ajoute automatiquement la config de schematics pour garder les suffixes. Nouveau style: user.ts au lieu de user.component.ts.",
112
+ "estimated_time_per_occurrence": 10,
113
+ "onFile": "angular.json",
114
+ "onFileNx": "nx.json",
115
+ "fileTypes": [
116
+ "angular.json"
117
+ ],
118
+ "regex": "^(?![\\s\\S]*\"schematics\"[\\s\\S]*\"@schematics/angular:component\"[\\s\\S]*\"type\"[\\s\\S]*\"component\")[\\s\\S]+",
119
+ "category": "style",
120
+ "auto_fixable": false,
121
+ "migration_command": null,
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 ou nx.json:\n{\n \"schematics\": {\n \"@schematics/angular:component\": { \"type\": \"component\" }\n }\n}",
124
+ "doc_url": "https://angular.dev/reference/migrations"
125
+ },
126
+ {
127
+ "key": "host_bindings_type_checking",
128
+ "summary": "Type checking pour host bindings",
129
+ "description": "Le compilateur Angular 20 active par défaut le type checking strict pour les host bindings en v21 avec typeCheckHostBindings: true. Permet de détecter les erreurs de typage dans les bindings de classe, styles et événements définis dans le décorateur host.",
130
+ "estimated_time_per_occurrence": 5,
131
+ "fileTypes": [
132
+ "tsconfig.json",
133
+ "*.ts"
134
+ ],
135
+ "regex": "\"angularCompilerOptions\"[\\s\\S]*?\"typeCheckHostBindings\"\\s*:\\s*true",
136
+ "category": "config",
137
+ "auto_fixable": false,
138
+ "migration_command": null,
139
+ "risk_level": "low",
140
+ "code_description": "// tsconfig.json ou tsconfig.base.json pour projet Nx\n{\n \"angularCompilerOptions\": {\n \"typeCheckHostBindings\": true // Activé par défaut en v21\n }\n}\n\n// Maintenant avec vérification:\n@Component({\n host: {\n '[class.active]': 'isActive()',\n '(click)': 'onClick($event)'\n }\n})",
141
+ "astPattern": {
142
+ "nodeType": "Decorator",
143
+ "name": "Component",
144
+ "properties": {
145
+ "host": {
146
+ "exists": true
147
+ }
148
+ },
149
+ "inFile": {
150
+ "tsconfig": {
151
+ "angularCompilerOptions": {
152
+ "typeCheckHostBindings": {
153
+ "missing": true
154
+ }
155
+ }
156
+ }
157
+ }
158
+ },
159
+ "doc_url": "https://angular.dev/reference/migrations"
160
+ },
161
+ {
162
+ "key": "datePipe_warnings",
163
+ "summary": "DatePipe warnings pour format Y sans w",
164
+ "description": "Le DatePipe émet maintenant un warning si le format 'Y' (année ISO) est utilisé sans 'w' (semaine). Ce pattern est suspect car l'année ISO n'a de sens qu'avec la semaine ISO. Utiliser 'y' pour l'année standard ou 'Y w' ensemble.",
165
+ "estimated_time_per_occurrence": 3,
166
+ "onFile": null,
167
+ "fileTypes": [
168
+ "*.html",
169
+ "*.ts"
170
+ ],
171
+ "regex": "\\|\\s*date\\s*:\\s*['\"]Y['\"]",
172
+ "astPattern": {
173
+ "nodeType": "PipeExpression",
174
+ "pipeName": "date",
175
+ "pipeArgs": {
176
+ "formatMatches": "^Y[^w]*$"
177
+ },
178
+ "excludeContext": [
179
+ "StringLiteral",
180
+ "Comment"
181
+ ]
182
+ },
183
+ "category": "template",
184
+ "auto_fixable": false,
185
+ "migration_command": null,
186
+ "risk_level": "low",
187
+ "code_description": "// ⚠️ Avertissement:\n{{ date | date:'Y' }} // Suspect: année sans semaine\n\n// ✅ Correct:\n{{ date | date:'y' }} // Année standard\n{{ date | date:'Y w' }} // Année et semaine ensemble",
188
+ "doc_url": "https://angular.dev/reference/migrations"
189
+ }
190
+ ]
@@ -0,0 +1,151 @@
1
+ [
2
+ {
3
+ "key": "control_flow_deprecation",
4
+ "summary": "⚠️ DÉPRÉCIÉ: *ngIf/*ngFor/*ngSwitch (retrait v22)",
5
+ "description": "Les directives structurelles *ngIf, *ngFor et *ngSwitch sont officiellement dépréciées en Angular 20 et seront complètement retirées en v22. Migrer dès maintenant vers la syntaxe Control Flow (@if, @for, @switch) pour éviter les breaking changes futurs.",
6
+ "estimated_time_per_occurrence": 3,
7
+ "onFile": null,
8
+ "fileTypes": [
9
+ "*.html",
10
+ "*.ts"
11
+ ],
12
+ "regex": "\\*ng(If|For|Switch)",
13
+ "category": "template",
14
+ "auto_fixable": false,
15
+ "migration_command": "ng generate @angular/core:control-flow",
16
+ "risk_level": "high",
17
+ "code_description": "// ⚠️ DÉPRÉCIÉ - Retrait prévu en v22\n<div *ngIf=\"condition\">Content</div>\n<div *ngFor=\"let item of items\">{{ item }}</div>\n\n// Migrer vers Control Flow:\n@if (condition) {\n <div>Content</div>\n}\n@for (item of items; track item.id) {\n <div>{{ item }}</div>\n}",
18
+ "astPattern": {
19
+ "nodeType": "Attribute",
20
+ "name": [
21
+ "*ngIf",
22
+ "*ngFor",
23
+ "*ngSwitch",
24
+ "*ngSwitchCase",
25
+ "*ngSwitchDefault"
26
+ ],
27
+ "excludeContext": [
28
+ "StringLiteral",
29
+ "Comment"
30
+ ]
31
+ },
32
+ "doc_url": "https://angular.dev/reference/migrations"
33
+ },
34
+ {
35
+ "key": "signals_stable",
36
+ "summary": "APIs Signals stabilisées (effect, linkedSignal, toSignal, computed)",
37
+ "description": "Toutes les APIs de signaux sortent de leur phase expérimentale et deviennent stables en Angular 20: effect, linkedSignal, toSignal, computed. Adopter ces APIs maintenant garantit une stabilité à long terme et des performances optimales.",
38
+ "estimated_time_per_occurrence": 5,
39
+ "onFile": null,
40
+ "fileTypes": [
41
+ "*.ts"
42
+ ],
43
+ "regex": "\\b(effect|linkedSignal|toSignal|computed)\\s*\\(",
44
+ "category": "signals",
45
+ "auto_fixable": false,
46
+ "migration_command": null,
47
+ "risk_level": "low",
48
+ "code_description": "// ✅ Maintenant stables (plus 'experimental')\n\neffect(() => {\n console.log('Value:', mySignal());\n});\n\nconst linked = linkedSignal({\n source: sourceSignal,\n computation: () => 'default'\n});\n\nconst fromObs = toSignal(observable$, {\n initialValue: 'default'\n});",
49
+ "astPattern": {
50
+ "nodeType": "CallExpression",
51
+ "functionName": [
52
+ "effect",
53
+ "linkedSignal",
54
+ "toSignal",
55
+ "computed"
56
+ ],
57
+ "excludeContext": [
58
+ "StringLiteral",
59
+ "Comment"
60
+ ]
61
+ },
62
+ "doc_url": "https://angular.dev/reference/migrations"
63
+ },
64
+ {
65
+ "key": "incremental_hydration_stable",
66
+ "summary": "Hydratation incrémentale stable",
67
+ "description": "L'hydratation incrémentale passe de expérimental à stable, permettant d'hydrater progressivement les composants Angular côté client. Combiné avec @defer et les triggers d'hydratation, réduit drastiquement le TTI et le JavaScript initial sur mobile.",
68
+ "estimated_time_per_occurrence": 15,
69
+ "onFile": null,
70
+ "fileTypes": [
71
+ "*.ts",
72
+ "*.html"
73
+ ],
74
+ "regex": "(?<![\"\\'])\\bprovideClientHydration\\s*\\(",
75
+ "category": "ssr",
76
+ "auto_fixable": false,
77
+ "migration_command": null,
78
+ "risk_level": "medium",
79
+ "code_description": "// ✅ API stable en v20\n\nbootstrapApplication(App, {\n providers: [\n provideClientHydration(withIncrementalHydration())\n ]\n});\n\n// Template:\n@defer (hydrate on viewport) {\n <heavy-component />\n}",
80
+ "astPattern": {
81
+ "nodeType": "CallExpression",
82
+ "functionName": "provideClientHydration",
83
+ "arguments": {
84
+ "containsCall": {
85
+ "functionName": "withIncrementalHydration"
86
+ }
87
+ },
88
+ "excludeContext": [
89
+ "StringLiteral",
90
+ "Comment"
91
+ ]
92
+ },
93
+ "doc_url": "https://angular.dev/reference/migrations"
94
+ },
95
+ {
96
+ "key": "server_routes_stable",
97
+ "summary": "Configuration rendu par route stable",
98
+ "description": "L'API de configuration du rendu par route devient stable, permettant de définir précisément la stratégie (Prerender/Server/Client) pour chaque route. getPrerenderParams génère dynamiquement les paramètres pour le SSG, idéal pour les blogs et e-commerce.",
99
+ "estimated_time_per_occurrence": 20,
100
+ "onFile": null,
101
+ "fileTypes": [
102
+ "*.ts"
103
+ ],
104
+ "regex": "export\\s+const\\s+serverRoutes",
105
+ "category": "ssr",
106
+ "auto_fixable": false,
107
+ "migration_command": null,
108
+ "risk_level": "medium",
109
+ "code_description": "// app.routes.server.ts - ✅ API stable\n\nexport const serverRoutes: ServerRoute[] = [\n { path: '/', renderMode: RenderMode.Prerender },\n { path: '/api/**', renderMode: RenderMode.Server },\n { path: '/admin/**', renderMode: RenderMode.Client },\n {\n path: '/product/:id',\n renderMode: RenderMode.Prerender,\n async getPrerenderParams() {\n return ids.map(id => ({ id }));\n }\n }\n];",
110
+ "astPattern": {
111
+ "nodeType": "VariableDeclaration",
112
+ "name": "serverRoutes",
113
+ "type": "ServerRoute[]",
114
+ "exported": true,
115
+ "excludeContext": [
116
+ "StringLiteral",
117
+ "Comment"
118
+ ]
119
+ },
120
+ "doc_url": "https://angular.dev/reference/migrations"
121
+ },
122
+ {
123
+ "key": "zoneless_preview",
124
+ "summary": "Zoneless en preview développeur avec error handling",
125
+ "description": "Le mode zoneless entre en preview développeur avec provideBrowserGlobalErrorListeners pour capturer les erreurs non gérées. Élimine Zone.js (~50KB), améliore les performances de 35% (cf YouTube), mais nécessite des tests approfondis avant production.",
126
+ "estimated_time_per_occurrence": 30,
127
+ "onFile": null,
128
+ "fileTypes": [
129
+ "*.ts",
130
+ "angular.json"
131
+ ],
132
+ "regex": "\\bprovideZonelessChangeDetection\\b\\s*\\(",
133
+ "category": "architecture",
134
+ "auto_fixable": false,
135
+ "migration_command": null,
136
+ "risk_level": "high",
137
+ "code_description": "// ✅ Preview développeur\n\nbootstrapApplication(App, {\n providers: [\n provideZonelessChangeDetection(),\n provideBrowserGlobalErrorListeners() // Nouveau\n ]\n});\n\n// angular.json: retirer \"zone.js\"",
138
+ "astPattern": {
139
+ "nodeType": "CallExpression",
140
+ "functionName": "provideZonelessChangeDetection",
141
+ "nextProvider": {
142
+ "missing": "provideBrowserGlobalErrorListeners"
143
+ },
144
+ "excludeContext": [
145
+ "StringLiteral",
146
+ "Comment"
147
+ ]
148
+ },
149
+ "doc_url": "https://angular.dev/reference/migrations"
150
+ }
151
+ ]
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const args_parser_1 = require("./utils/core/args-parser");
40
+ const project_detector_1 = require("./core/project-detector");
41
+ const logger_1 = require("./utils/core/logger");
42
+ const index_page_template_1 = require("./templates/page/index-page.template");
43
+ const main_template_1 = require("./templates/page/main.template");
44
+ const workload_report_template_1 = require("./templates/page/workload-report.template");
45
+ const migration_guide_template_1 = require("./templates/page/migration-guide.template");
46
+ const rules_loader_1 = require("./core/rules-loader");
47
+ const scanner_orchestrator_1 = require("./core/scanner-orchestrator");
48
+ const workload_1 = require("./core/workload");
49
+ const scan_reporter_1 = require("./core/scan-reporter");
50
+ function generateReport() {
51
+ const globalStartTime = Date.now();
52
+ try {
53
+ // Lire la version du package.json
54
+ const packageJsonPath = path.join(__dirname, '../..', 'package.json');
55
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
56
+ const version = packageJson.version;
57
+ const args = (0, args_parser_1.parseArgs)(process.argv.slice(2));
58
+ const projectInfo = (0, project_detector_1.detectProject)(args.projectPath);
59
+ // Charger les règles selon les migrations sélectionnées
60
+ const allRules = args.rules.flatMap(migration => (0, rules_loader_1.getRulesForMigration)(migration));
61
+ // Afficher la bannière de démarrage
62
+ (0, scan_reporter_1.logScanStart)(projectInfo, args.scannerType, allRules);
63
+ // Exécuter le scan avec l'orchestrateur
64
+ const scanResult = (0, scanner_orchestrator_1.executeScan)(projectInfo, allRules, args.scannerType);
65
+ const allMatches = scanResult.matches;
66
+ // Afficher les statistiques générales
67
+ const uniqueFiles = allMatches.length > 0 ? new Set(allMatches.map(m => m.filePath)).size : 0;
68
+ const uniqueRules = allMatches.length > 0 ? new Set(allMatches.map(m => m.ruleKey)).size : 0;
69
+ if (allMatches.length > 0) {
70
+ logger_1.logger.blank();
71
+ logger_1.logger.info(`📊 Résumé global:`);
72
+ logger_1.logger.info(` • Fichiers impactés: ${uniqueFiles}`);
73
+ logger_1.logger.info(` • Règles détectées: ${uniqueRules}`);
74
+ logger_1.logger.info(` • Occurrences totales: ${allMatches.length}`);
75
+ // Top 10 règles
76
+ (0, scan_reporter_1.logTopRules)(allMatches, 10);
77
+ }
78
+ // Calculer et afficher le rapport de charge de travail
79
+ const workloadReport = (0, workload_1.calculateWorkloadReport)(projectInfo, allMatches, allRules);
80
+ (0, scan_reporter_1.logWorkloadReport)(workloadReport);
81
+ // Génération des rapports HTML
82
+ logger_1.logger.blank();
83
+ logger_1.logger.step('Génération des rapports HTML...');
84
+ const timestamp = new Date().toISOString();
85
+ const dateStr = timestamp.split('T')[0];
86
+ const outputDir = path.join(process.cwd(), 'output');
87
+ if (!fs.existsSync(outputDir)) {
88
+ fs.mkdirSync(outputDir, { recursive: true });
89
+ }
90
+ // Lire CSS et JS depuis le répertoire du package installé
91
+ const cssPath = path.join(__dirname, '..', 'styles.css');
92
+ const jsPath = path.join(__dirname, '..', 'client.bundle.js');
93
+ let cssContent = '';
94
+ let jsContent = '';
95
+ if (fs.existsSync(cssPath)) {
96
+ cssContent = fs.readFileSync(cssPath, 'utf-8');
97
+ }
98
+ if (fs.existsSync(jsPath)) {
99
+ jsContent = fs.readFileSync(jsPath, 'utf-8');
100
+ }
101
+ // Préparer données pour HTML
102
+ const htmlData = {
103
+ workloadReport,
104
+ matches: allMatches,
105
+ rules: allRules,
106
+ scannerType: args.scannerType,
107
+ timestamp
108
+ };
109
+ // Générer 4 fichiers HTML
110
+ // 1. index.html : Page "Applications Analysées" + bouton vers migration-planner.html
111
+ const indexHtml = (0, main_template_1.renderMainPage)(projectInfo, cssContent, workloadReport, uniqueRules, uniqueFiles, 'migration-planner.html', version);
112
+ // 2. migration-planner.html : Landing page avec 2 boutons (Dashboard Global | Migration Guide)
113
+ const migrationPlannerHtml = (0, index_page_template_1.renderIndexPage)(projectInfo, cssContent, timestamp, version);
114
+ // 3. workload-planner.html : Dashboard interactif complet
115
+ const workloadPlannerHtml = (0, workload_report_template_1.renderWorkloadReport)(htmlData, cssContent, jsContent, version);
116
+ // 4. migration-guide.html : Guide méthodologique étape par étape
117
+ // IMPORTANT: Charger TOUTES les règles pour le guide, pas seulement celles scannées
118
+ const migrationRulesStructure = (0, rules_loader_1.loadMigrationRules)();
119
+ const rulePriorityMap = {};
120
+ const ruleMigrationMap = {};
121
+ const allRulesForGuide = [];
122
+ // Parcourir toutes les migrations et priorités pour créer les maps ET la liste complète
123
+ for (const migration of ['to18', 'to19', 'to20']) {
124
+ for (const priority of ['obligatoire', 'recommande', 'optionnelle']) {
125
+ migrationRulesStructure[migration][priority].forEach(rule => {
126
+ rulePriorityMap[rule.key] = priority;
127
+ ruleMigrationMap[rule.key] = migration;
128
+ allRulesForGuide.push(rule);
129
+ });
130
+ }
131
+ }
132
+ const migrationGuideHtml = (0, migration_guide_template_1.renderMigrationGuidePage)({ rules: allRulesForGuide, matches: allMatches, projectInfo, rulePriorityMap, ruleMigrationMap }, cssContent, jsContent, timestamp, version);
133
+ // Écrire fichiers
134
+ const indexPath = path.join(outputDir, 'index.html');
135
+ const migrationPlannerPath = path.join(outputDir, 'migration-planner.html');
136
+ const workloadPlannerPath = path.join(outputDir, 'workload-planner.html');
137
+ const migrationGuidePath = path.join(outputDir, 'migration-guide.html');
138
+ fs.writeFileSync(indexPath, indexHtml, 'utf-8');
139
+ fs.writeFileSync(migrationPlannerPath, migrationPlannerHtml, 'utf-8');
140
+ fs.writeFileSync(workloadPlannerPath, workloadPlannerHtml, 'utf-8');
141
+ fs.writeFileSync(migrationGuidePath, migrationGuideHtml, 'utf-8');
142
+ const totalDuration = Date.now() - globalStartTime;
143
+ logger_1.logger.blank();
144
+ logger_1.logger.success(`✓ Rapports générés :`);
145
+ logger_1.logger.info(` • Page principale : ${indexPath}`);
146
+ logger_1.logger.info(` • Migration planner : ${migrationPlannerPath}`);
147
+ logger_1.logger.info(` • Workload planner : ${workloadPlannerPath}`);
148
+ logger_1.logger.info(` • Migration guide : ${migrationGuidePath}`);
149
+ logger_1.logger.blank();
150
+ logger_1.logger.info(`Ouvrez index.html dans votre navigateur pour voir le rapport.`);
151
+ // Utiliser stats pré-calculées du workloadReport
152
+ (0, scan_reporter_1.logScanComplete)(totalDuration, workloadReport.stats.totalOccurrences, workloadReport.stats.totalRoutineRules, workloadReport.stats.totalSpecialWorkloadFiles);
153
+ }
154
+ catch (error) {
155
+ logger_1.logger.blank();
156
+ logger_1.logger.error(error instanceof Error ? error.message : 'Erreur inconnue');
157
+ logger_1.logger.blank();
158
+ process.exit(1);
159
+ }
160
+ }
161
+ generateReport();
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ /**
3
+ * Configuration centralisée des chips visuels
4
+ * Utilisé par: chips.ts, html-helpers.ts, filters.ts
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.DEFAULT_CHIP_CONFIG = exports.RULE_TYPE_CONFIG = exports.CATEGORY_CONFIG = exports.RISK_CONFIG = void 0;
8
+ /**
9
+ * Configuration des niveaux de risque
10
+ */
11
+ exports.RISK_CONFIG = {
12
+ critical: { emoji: '🔴', color: 'red', label: 'Critical' },
13
+ high: { emoji: '🟠', color: 'orange', label: 'High' },
14
+ medium: { emoji: '🟡', color: 'yellow', label: 'Medium' },
15
+ low: { emoji: '🟢', color: 'green', label: 'Low' }
16
+ };
17
+ /**
18
+ * Configuration des catégories
19
+ */
20
+ exports.CATEGORY_CONFIG = {
21
+ environment: { emoji: '🌍', color: 'blue', label: 'Environment' },
22
+ imports: { emoji: '📦', color: 'indigo', label: 'Imports' },
23
+ api: { emoji: '🔌', color: 'purple', label: 'API' },
24
+ routing: { emoji: '🛣️', color: 'pink', label: 'Routing' },
25
+ template: { emoji: '📄', color: 'teal', label: 'Template' },
26
+ test: { emoji: '🧪', color: 'cyan', label: 'Test' },
27
+ ssr: { emoji: '⚡', color: 'amber', label: 'SSR' }
28
+ };
29
+ /**
30
+ * Configuration des types de règles
31
+ */
32
+ exports.RULE_TYPE_CONFIG = {
33
+ standard: { emoji: '📋', color: 'blue', label: 'Standard' },
34
+ routine: { emoji: '🔧', color: 'teal', label: 'Routine' },
35
+ special: { emoji: '⭐', color: 'pink', label: 'Special' },
36
+ combined: { emoji: '🔀', color: 'purple', label: 'Combined' }
37
+ };
38
+ /**
39
+ * Config par défaut pour valeurs inconnues
40
+ */
41
+ exports.DEFAULT_CHIP_CONFIG = {
42
+ emoji: '🏷️',
43
+ color: 'gray',
44
+ label: 'Unknown'
45
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * Interfaces pour l'analyse AST et les matchers
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Interfaces client-side pour l'UI et la gestion d'état
4
+ * Centralisées depuis client/components et client/state
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });