@silvestv/migration-planificator 3.0.0 → 4.1.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 (43) hide show
  1. package/LICENSE +201 -96
  2. package/NOTICE +105 -0
  3. package/README.fr.md +30 -24
  4. package/README.md +29 -25
  5. package/SECURITY.md +223 -187
  6. package/dist/client.bundle.js +51 -48
  7. package/dist/src/core/ast/matchers/html/html-pipe-variable-matcher.js +250 -0
  8. package/dist/src/core/ast/matchers/html/html-variable-resolver.js +105 -0
  9. package/dist/src/core/ast/matchers/index.js +7 -0
  10. package/dist/src/core/ast/matchers/ts/hierarchy-matcher.js +2 -1
  11. package/dist/src/core/ast/matchers/ts/rxjs-matcher.js +128 -0
  12. package/dist/src/core/workload/hierarchy-calculator.js +4 -4
  13. package/dist/src/core/workload/special-workload.js +2 -2
  14. package/dist/src/data/angular-migration-rules.json +2336 -2336
  15. package/dist/src/data/rules/rearchitecture/rearchitecture-rules.json +2 -2
  16. package/dist/src/data/rules/to18/rules-18-obligatoire.json +373 -373
  17. package/dist/src/data/rules/to18/rules-18-optionnelle.json +187 -187
  18. package/dist/src/data/rules/to18/rules-18-recommande.json +217 -217
  19. package/dist/src/data/rules/to19/rules-19-obligatoire.json +347 -347
  20. package/dist/src/data/rules/to19/rules-19-optionnelle.json +217 -222
  21. package/dist/src/data/rules/to19/rules-19-recommande.json +174 -199
  22. package/dist/src/data/rules/to20/rules-20-obligatoire.json +558 -555
  23. package/dist/src/data/rules/to20/rules-20-optionnelle.json +189 -189
  24. package/dist/src/data/rules/to20/rules-20-recommande.json +150 -150
  25. package/dist/src/models/interfaces/{ast-interfaces.js → angular-artifact-counts.interface.js} +0 -3
  26. package/dist/src/models/interfaces/base-target.interface.js +2 -0
  27. package/dist/src/models/interfaces/checklist-state.interface.js +2 -0
  28. package/dist/src/models/interfaces/dependency-counts.interface.js +2 -0
  29. package/dist/src/models/interfaces/migration-guide-data.interface.js +2 -0
  30. package/dist/src/models/interfaces/module-info.interface.js +2 -0
  31. package/dist/src/models/interfaces/parallelization.interface.js +2 -0
  32. package/dist/src/models/interfaces/refer-to-pattern.interface.js +2 -0
  33. package/dist/src/models/interfaces/summary-totals.interface.js +2 -0
  34. package/dist/src/models/interfaces/window-with-data.interface.js +2 -0
  35. package/dist/src/templates/workload/dashboard.template.js +7 -44
  36. package/dist/src/templates/workload/guide-rule-card.template.js +1 -1
  37. package/dist/src/templates/workload/rule-modal.template.js +6 -21
  38. package/dist/src/templates/workload/unified-settings-panel.template.js +149 -0
  39. package/dist/src/utils/core/args-parser.js +16 -1
  40. package/dist/styles.css +1 -1
  41. package/package.json +8 -7
  42. /package/dist/src/models/{chip-config.js → constants/chip-config.js} +0 -0
  43. /package/dist/src/models/interfaces/{client-interfaces.js → client-interfaces.interface.js} +0 -0
@@ -1,151 +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
- }
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
+ "isAutoFixable": 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
+ "isAutoFixable": 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
+ "isAutoFixable": 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
+ "isAutoFixable": 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
+ "isAutoFixable": 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
151
  ]
@@ -1,5 +1,2 @@
1
1
  "use strict";
2
- /**
3
- * Interfaces pour l'analyse AST et les matchers
4
- */
5
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 });
@@ -5,59 +5,22 @@
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.renderDashboard = renderDashboard;
7
7
  const core_1 = require("../../utils/core");
8
+ const unified_settings_panel_template_1 = require("./unified-settings-panel.template");
8
9
  function renderDashboard(workload) {
9
10
  const stats = workload.stats;
10
11
  const time = workload.totalTime;
11
12
  // Date de départ par défaut : aujourd'hui
12
13
  const today = new Date().toISOString().split('T')[0]; // Format YYYY-MM-DD
13
14
  return `
15
+ <!-- Unified Settings Panel (Migrations + Priorités) -->
16
+ ${(0, unified_settings_panel_template_1.renderUnifiedSettingsPanel)()}
17
+
14
18
  <div class="bg-white rounded-2xl shadow-xl p-8 mb-8">
15
- <!-- Header avec titre et sélecteur de migrations -->
16
- <div class="flex flex-col md:flex-row md:justify-between md:items-center gap-4 mb-6">
17
- <h2 class="text-3xl font-bold text-gray-800 flex items-center">
19
+ <!-- Header avec titre -->
20
+ <div class="flex items-center mb-6">
21
+ <h2 class="text-3xl font-bold text-gray-800">
18
22
  📊 Dashboard Global
19
- <span data-migration-count class="ml-2 px-2 py-1 bg-green-100 text-green-700 text-xs font-semibold rounded-full">Toutes</span>
20
23
  </h2>
21
-
22
- <!-- Migration Selector -->
23
- <div class="flex flex-col sm:flex-row gap-2 items-start sm:items-center">
24
- <span class="text-sm font-medium text-gray-700">Migrations :</span>
25
- <div class="flex gap-2 flex-wrap">
26
- <label class="flex items-center gap-1 px-3 py-1.5 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition-colors">
27
- <input
28
- type="checkbox"
29
- data-migration-select="to18"
30
- class="w-4 h-4 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
31
- checked
32
- />
33
- <span class="text-sm font-medium text-gray-700">To 18</span>
34
- </label>
35
- <label class="flex items-center gap-1 px-3 py-1.5 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition-colors">
36
- <input
37
- type="checkbox"
38
- data-migration-select="to19"
39
- class="w-4 h-4 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
40
- checked
41
- />
42
- <span class="text-sm font-medium text-gray-700">To 19</span>
43
- </label>
44
- <label class="flex items-center gap-1 px-3 py-1.5 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition-colors">
45
- <input
46
- type="checkbox"
47
- data-migration-select="to20"
48
- class="w-4 h-4 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
49
- checked
50
- />
51
- <span class="text-sm font-medium text-gray-700">To 20</span>
52
- </label>
53
- <button
54
- data-migration-select-all
55
- class="px-3 py-1.5 bg-blue-100 text-blue-700 text-sm font-semibold rounded-lg hover:bg-blue-200 transition-colors"
56
- >
57
- Toutes
58
- </button>
59
- </div>
60
- </div>
61
24
  </div>
62
25
 
63
26
  <!-- KPIs -->
@@ -50,7 +50,7 @@ function renderGuideRuleCard(rule, matches) {
50
50
  <div class="flex items-center flex-wrap gap-2">
51
51
  ${(0, shared_1.renderBadge)(rule.risk_level.toUpperCase(), riskColor)}
52
52
  ${(0, shared_1.renderBadge)(rule.category, 'blue')}
53
- ${rule.auto_fixable ? (0, shared_1.renderBadge)('Auto-fixable', 'green') : ''}
53
+ ${rule.isAutoFixable ? (0, shared_1.renderBadge)('Auto-fixable', 'green') : ''}
54
54
  </div>
55
55
  </div>
56
56
  </div>
@@ -67,7 +67,7 @@ function renderModalHeader(rule, riskColor) {
67
67
  <div class="flex items-center space-x-2">
68
68
  ${(0, shared_1.renderBadge)(rule.risk_level.toUpperCase(), riskColor)}
69
69
  ${(0, shared_1.renderBadge)(rule.category, 'blue')}
70
- ${rule.auto_fixable ? (0, shared_1.renderBadge)('Auto-fixable', 'green') : ''}
70
+ ${rule.isAutoFixable ? (0, shared_1.renderBadge)('Auto-fixable', 'green') : ''}
71
71
  </div>
72
72
  </div>
73
73
  <button data-modal-close class="text-gray-400 hover:text-gray-600 text-3xl font-bold leading-none">
@@ -198,8 +198,6 @@ function renderAffectedFilesSection(matches) {
198
198
  function renderMatchItem(match) {
199
199
  const truncatedText = match.matchedText.substring(0, 100);
200
200
  const displayText = match.matchedText.length > 100 ? `${truncatedText}...` : truncatedText;
201
- // Formater le chemin pour VSCode (forward slashes, lowercase drive letter)
202
- const vscodePath = formatVSCodePath(match.filePath);
203
201
  return `
204
202
  <li class="text-sm">
205
203
  <div class="flex items-start justify-between">
@@ -208,7 +206,10 @@ function renderMatchItem(match) {
208
206
  <p class="text-gray-600 mt-1 ml-4 text-xs font-mono bg-white p-2 rounded">${(0, shared_1.escapeHtml)(displayText)}</p>
209
207
  </div>
210
208
  <a
211
- href="vscode://file/${vscodePath}:${match.lineNumber}"
209
+ href="#"
210
+ data-vscode-open
211
+ data-relative-path="${(0, shared_1.escapeHtml)(match.filePath)}"
212
+ data-line-number="${match.lineNumber}"
212
213
  class="px-3 py-1.5 text-xs bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium shadow-sm"
213
214
  title="Ouvrir dans VSCode à la ligne ${match.lineNumber}"
214
215
  >
@@ -218,22 +219,6 @@ function renderMatchItem(match) {
218
219
  </li>
219
220
  `;
220
221
  }
221
- /**
222
- * Formate un chemin Windows pour VSCode URI
223
- * VSCode nécessite: forward slashes + lowercase drive letter
224
- * Exemple: C:\Users\file.ts -> c:/Users/file.ts
225
- */
226
- function formatVSCodePath(filePath) {
227
- // Remplacer backslashes par forward slashes
228
- let formatted = filePath.replace(/\\/g, '/');
229
- // Convertir la lettre de lecteur en minuscule (C: -> c:)
230
- // Format: "C:/path" ou "C:\path" -> "c:/path"
231
- const driveLetterMatch = formatted.match(/^([A-Z]):/);
232
- if (driveLetterMatch) {
233
- formatted = driveLetterMatch[1].toLowerCase() + formatted.substring(1);
234
- }
235
- return formatted;
236
- }
237
222
  /**
238
223
  * Section Métadonnées
239
224
  * Exportée pour réutilisation dans guide-rule-card.template.ts
@@ -257,7 +242,7 @@ function renderMetadataSection(rule) {
257
242
  </div>
258
243
  <div>
259
244
  <span class="font-semibold text-gray-700">Auto-fixable :</span>
260
- <span class="ml-2 text-gray-600">${rule.auto_fixable ? '✅ Oui' : '❌ Non'}</span>
245
+ <span class="ml-2 text-gray-600">${rule.isAutoFixable ? '✅ Oui' : '❌ Non'}</span>
261
246
  </div>
262
247
  </div>
263
248
  </section>
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /**
3
+ * Template Unified Settings Panel - Réglages migrations + priorités
4
+ * Regroupement des filtres de migrations et priorités dans un seul bloc
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.renderUnifiedSettingsPanel = renderUnifiedSettingsPanel;
8
+ /**
9
+ * Génère le panel de réglages unifié
10
+ */
11
+ function renderUnifiedSettingsPanel() {
12
+ return `
13
+ <div class="bg-white rounded-2xl shadow-xl p-6 mb-8">
14
+ <!-- Header avec titre et badge global -->
15
+ <div class="flex items-center justify-between mb-6">
16
+ <h2 class="text-2xl font-bold text-gray-800 flex items-center">
17
+ ⚙️ Réglages de Filtrage
18
+ <span data-total-filters-count class="ml-3 px-3 py-1.5 bg-green-100 text-green-700 text-sm font-semibold rounded-full">
19
+ 6/6 actifs
20
+ </span>
21
+ </h2>
22
+ </div>
23
+
24
+ <!-- Grid 2 colonnes : Migrations | Priorités -->
25
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
26
+ <!-- Section Migrations -->
27
+ <div class="bg-gradient-to-br from-blue-50 to-blue-100 rounded-xl p-6">
28
+ <div class="flex items-center justify-between mb-4">
29
+ <h3 class="text-lg font-bold text-blue-900 flex items-center">
30
+ 🔄 Migrations
31
+ <span data-migration-count class="ml-2 px-2 py-1 bg-green-100 text-green-700 text-xs font-semibold rounded-full">Toutes</span>
32
+ </h3>
33
+ <button
34
+ data-migration-select-all
35
+ class="px-3 py-1.5 bg-blue-100 text-blue-700 text-sm font-semibold rounded-lg hover:bg-blue-200 transition-colors focus:ring-2 focus:ring-blue-500"
36
+ aria-label="Sélectionner toutes les migrations"
37
+ >
38
+ Toutes
39
+ </button>
40
+ </div>
41
+
42
+ <div class="space-y-3">
43
+ <label class="flex items-center gap-3 px-4 py-3 bg-white rounded-lg cursor-pointer hover:bg-blue-50 transition-colors border border-blue-200">
44
+ <input
45
+ type="checkbox"
46
+ data-migration-select="to18"
47
+ class="w-5 h-5 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
48
+ checked
49
+ aria-label="Migration vers Angular 18"
50
+ />
51
+ <span class="text-base font-medium text-gray-800">Angular 17 → 18</span>
52
+ </label>
53
+
54
+ <label class="flex items-center gap-3 px-4 py-3 bg-white rounded-lg cursor-pointer hover:bg-blue-50 transition-colors border border-blue-200">
55
+ <input
56
+ type="checkbox"
57
+ data-migration-select="to19"
58
+ class="w-5 h-5 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
59
+ checked
60
+ aria-label="Migration vers Angular 19"
61
+ />
62
+ <span class="text-base font-medium text-gray-800">Angular 18 → 19</span>
63
+ </label>
64
+
65
+ <label class="flex items-center gap-3 px-4 py-3 bg-white rounded-lg cursor-pointer hover:bg-blue-50 transition-colors border border-blue-200">
66
+ <input
67
+ type="checkbox"
68
+ data-migration-select="to20"
69
+ class="w-5 h-5 text-blue-600 rounded focus:ring-2 focus:ring-blue-500"
70
+ checked
71
+ aria-label="Migration vers Angular 20"
72
+ />
73
+ <span class="text-base font-medium text-gray-800">Angular 19 → 20</span>
74
+ </label>
75
+ </div>
76
+ </div>
77
+
78
+ <!-- Section Priorités -->
79
+ <div class="bg-gradient-to-br from-purple-50 to-purple-100 rounded-xl p-6">
80
+ <div class="flex items-center justify-between mb-4">
81
+ <h3 class="text-lg font-bold text-purple-900 flex items-center">
82
+ 🎯 Priorités
83
+ <span data-priority-count class="ml-2 px-2 py-1 bg-green-100 text-green-700 text-xs font-semibold rounded-full">Toutes</span>
84
+ </h3>
85
+ <button
86
+ data-priority-select-all
87
+ class="px-3 py-1.5 bg-purple-100 text-purple-700 text-sm font-semibold rounded-lg hover:bg-purple-200 transition-colors focus:ring-2 focus:ring-purple-500"
88
+ aria-label="Sélectionner toutes les priorités"
89
+ >
90
+ Toutes
91
+ </button>
92
+ </div>
93
+
94
+ <div class="space-y-3">
95
+ <label class="flex items-center gap-3 px-4 py-3 bg-white rounded-lg cursor-pointer hover:bg-purple-50 transition-colors border border-purple-200">
96
+ <input
97
+ type="checkbox"
98
+ data-priority-select="obligatoire"
99
+ class="w-5 h-5 text-purple-600 rounded focus:ring-2 focus:ring-purple-500"
100
+ checked
101
+ aria-label="Règles obligatoires"
102
+ />
103
+ <div class="flex items-center gap-2">
104
+ <span class="text-2xl">🔴</span>
105
+ <span class="text-base font-medium text-gray-800">Obligatoire</span>
106
+ </div>
107
+ </label>
108
+
109
+ <label class="flex items-center gap-3 px-4 py-3 bg-white rounded-lg cursor-pointer hover:bg-purple-50 transition-colors border border-purple-200">
110
+ <input
111
+ type="checkbox"
112
+ data-priority-select="recommande"
113
+ class="w-5 h-5 text-purple-600 rounded focus:ring-2 focus:ring-purple-500"
114
+ checked
115
+ aria-label="Règles recommandées"
116
+ />
117
+ <div class="flex items-center gap-2">
118
+ <span class="text-2xl">🟡</span>
119
+ <span class="text-base font-medium text-gray-800">Recommandé</span>
120
+ </div>
121
+ </label>
122
+
123
+ <label class="flex items-center gap-3 px-4 py-3 bg-white rounded-lg cursor-pointer hover:bg-purple-50 transition-colors border border-purple-200">
124
+ <input
125
+ type="checkbox"
126
+ data-priority-select="optionnelle"
127
+ class="w-5 h-5 text-purple-600 rounded focus:ring-2 focus:ring-purple-500"
128
+ checked
129
+ aria-label="Règles optionnelles"
130
+ />
131
+ <div class="flex items-center gap-2">
132
+ <span class="text-2xl">🟢</span>
133
+ <span class="text-base font-medium text-gray-800">Optionnel</span>
134
+ </div>
135
+ </label>
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ <!-- Info Box -->
141
+ <div class="mt-6 p-4 bg-gray-50 rounded-lg border border-gray-200">
142
+ <p class="text-sm text-gray-700">
143
+ <strong>ℹ️ Info :</strong> Les filtres s'appliquent à l'ensemble du rapport (timelines, gantt, diagrammes et totaux).
144
+ Au moins 1 migration et 1 priorité doivent rester sélectionnées.
145
+ </p>
146
+ </div>
147
+ </div>
148
+ `;
149
+ }