@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.
- package/LICENSE +96 -0
- package/README.fr.md +359 -0
- package/README.md +360 -0
- package/SECURITY.md +187 -0
- package/dist/client.bundle.js +357 -0
- package/dist/src/core/app-analyzer.js +134 -0
- package/dist/src/core/ast/matchers/html/html-attribute-matcher.js +86 -0
- package/dist/src/core/ast/matchers/html/html-component-matcher.js +40 -0
- package/dist/src/core/ast/matchers/html/html-element-matcher.js +54 -0
- package/dist/src/core/ast/matchers/html/html-parser.js +58 -0
- package/dist/src/core/ast/matchers/html/html-pipe-matcher.js +95 -0
- package/dist/src/core/ast/matchers/html/html-text-matcher.js +53 -0
- package/dist/src/core/ast/matchers/html/index.js +118 -0
- package/dist/src/core/ast/matchers/index.js +377 -0
- package/dist/src/core/ast/matchers/ts/collection-matcher.js +51 -0
- package/dist/src/core/ast/matchers/ts/context-matcher.js +275 -0
- package/dist/src/core/ast/matchers/ts/decorator-matcher.js +465 -0
- package/dist/src/core/ast/matchers/ts/expression-matcher.js +237 -0
- package/dist/src/core/ast/matchers/ts/file-matcher.js +97 -0
- package/dist/src/core/ast/matchers/ts/hierarchy-matcher.js +172 -0
- package/dist/src/core/ast/matchers/ts/import-matcher.js +39 -0
- package/dist/src/core/ast/matchers/ts/index.js +53 -0
- package/dist/src/core/ast/matchers/ts/node-matcher.js +156 -0
- package/dist/src/core/ast/matchers/ts/symbol-matcher.js +281 -0
- package/dist/src/core/ast/matchers/ts/type-matcher.js +207 -0
- package/dist/src/core/ast/matchers/utils/matcher-helpers.js +37 -0
- package/dist/src/core/ast/scanner-ast.js +444 -0
- package/dist/src/core/project-detector.js +196 -0
- package/dist/src/core/project-strategy/index.js +9 -0
- package/dist/src/core/project-strategy/nx-strategy.js +130 -0
- package/dist/src/core/project-strategy/project-strategy.interface.js +2 -0
- package/dist/src/core/project-strategy/standalone-strategy.js +74 -0
- package/dist/src/core/project-strategy/strategy-factory.js +15 -0
- package/dist/src/core/rules-loader.js +89 -0
- package/dist/src/core/scan-reporter.js +316 -0
- package/dist/src/core/scanner-delta.js +339 -0
- package/dist/src/core/scanner-orchestrator.js +266 -0
- package/dist/src/core/scanner-regex.js +298 -0
- package/dist/src/core/workload/calculator.js +82 -0
- package/dist/src/core/workload/constants.js +15 -0
- package/dist/src/core/workload/grouping.js +18 -0
- package/dist/src/core/workload/hierarchy-calculator.js +127 -0
- package/dist/src/core/workload/index.js +11 -0
- package/dist/src/core/workload/metadata.js +20 -0
- package/dist/src/core/workload/special-workload.js +101 -0
- package/dist/src/core/workload/target-resolver.js +34 -0
- package/dist/src/data/angular-migration-rules.json +2337 -0
- package/dist/src/data/markdown/angular-migration-17-18.md +408 -0
- package/dist/src/data/markdown/angular-migration-18-19.md +600 -0
- package/dist/src/data/markdown/angular-migration-19-20.md +521 -0
- package/dist/src/data/rules/rearchitecture/rearchitecture-rules.json +66 -0
- package/dist/src/data/rules/to18/rules-18-obligatoire.json +374 -0
- package/dist/src/data/rules/to18/rules-18-optionnelle.json +188 -0
- package/dist/src/data/rules/to18/rules-18-recommande.json +218 -0
- package/dist/src/data/rules/to19/rules-19-obligatoire.json +348 -0
- package/dist/src/data/rules/to19/rules-19-optionnelle.json +223 -0
- package/dist/src/data/rules/to19/rules-19-recommande.json +200 -0
- package/dist/src/data/rules/to20/rules-20-obligatoire.json +556 -0
- package/dist/src/data/rules/to20/rules-20-optionnelle.json +190 -0
- package/dist/src/data/rules/to20/rules-20-recommande.json +151 -0
- package/dist/src/index.js +161 -0
- package/dist/src/models/chip-config.js +45 -0
- package/dist/src/models/interfaces/app-details.interface.js +2 -0
- package/dist/src/models/interfaces/ast-interfaces.js +5 -0
- package/dist/src/models/interfaces/ast-pattern.interface.js +2 -0
- package/dist/src/models/interfaces/client-interfaces.js +6 -0
- package/dist/src/models/interfaces/detection-stats.interface.js +2 -0
- package/dist/src/models/interfaces/html-match.interface.js +2 -0
- package/dist/src/models/interfaces/html-report-data.interface.js +2 -0
- package/dist/src/models/interfaces/lib-details.interface.js +2 -0
- package/dist/src/models/interfaces/migration-rules.interface.js +2 -0
- package/dist/src/models/interfaces/parsed-args.interface.js +2 -0
- package/dist/src/models/interfaces/project-info.interface.js +2 -0
- package/dist/src/models/interfaces/project-overview-data.interface.js +2 -0
- package/dist/src/models/interfaces/rule-match.interface.js +2 -0
- package/dist/src/models/interfaces/rule.interface.js +2 -0
- package/dist/src/models/interfaces/rules-by-priority.interface.js +2 -0
- package/dist/src/models/interfaces/scanner-comparison.interface.js +2 -0
- package/dist/src/models/interfaces/special-workload.interface.js +2 -0
- package/dist/src/models/interfaces/workload-report.interface.js +2 -0
- package/dist/src/models/types/build-block-blob.type.js +2 -0
- package/dist/src/models/types/migration-version.type.js +2 -0
- package/dist/src/models/types/project-type.type.js +2 -0
- package/dist/src/models/types/risk-level.type.js +2 -0
- package/dist/src/models/types/rule-category.type.js +2 -0
- package/dist/src/models/types/rule-priority.type.js +2 -0
- package/dist/src/models/types/rule-workload-type.type.js +2 -0
- package/dist/src/templates/landing/applications-analyzed.template.js +18 -0
- package/dist/src/templates/landing/card-app-info.template.js +63 -0
- package/dist/src/templates/landing/card-lib-info.template.js +67 -0
- package/dist/src/templates/landing/libs-analyzed.template.js +22 -0
- package/dist/src/templates/landing/nx-summary.template.js +115 -0
- package/dist/src/templates/landing/project-overview.template.js +27 -0
- package/dist/src/templates/page/index-page.template.js +95 -0
- package/dist/src/templates/page/main.template.js +83 -0
- package/dist/src/templates/page/migration-guide.template.js +175 -0
- package/dist/src/templates/page/workload-report.template.js +53 -0
- package/dist/src/templates/workload/dashboard.template.js +184 -0
- package/dist/src/templates/workload/filters-panel.template.js +215 -0
- package/dist/src/templates/workload/guide-rule-card.template.js +107 -0
- package/dist/src/templates/workload/hierarchy-nx.template.js +104 -0
- package/dist/src/templates/workload/hierarchy-shared.js +163 -0
- package/dist/src/templates/workload/hierarchy-standalone.template.js +36 -0
- package/dist/src/templates/workload/hierarchy.template.js +35 -0
- package/dist/src/templates/workload/rule-modal.template.js +280 -0
- package/dist/src/utils/core/args-parser.js +123 -0
- package/dist/src/utils/core/array-helpers.js +18 -0
- package/dist/src/utils/core/ast-helpers.js +99 -0
- package/dist/src/utils/core/file-helpers.js +109 -0
- package/dist/src/utils/core/html-helpers.js +36 -0
- package/dist/src/utils/core/index.js +28 -0
- package/dist/src/utils/core/logger.js +38 -0
- package/dist/src/utils/core/rule-helpers.js +15 -0
- package/dist/src/utils/core/workload-formatter.js +6 -0
- package/dist/src/utils/shared/array-helpers.js +25 -0
- package/dist/src/utils/shared/date-helpers.js +109 -0
- package/dist/src/utils/shared/html-helpers.js +37 -0
- package/dist/src/utils/shared/index.js +25 -0
- package/dist/src/utils/shared/rule-helpers.js +20 -0
- package/dist/src/utils/shared/time-formatters.js +76 -0
- package/dist/styles.css +2 -0
- package/package.json +107 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.NxStrategy = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
/**
|
|
40
|
+
* Stratégie pour projets Nx Monorepo
|
|
41
|
+
* - Structure apps/ et libs/
|
|
42
|
+
* - Routines globales séparées des targets apps/libs
|
|
43
|
+
* - Target "monorepo" pour règles de routine
|
|
44
|
+
*/
|
|
45
|
+
class NxStrategy {
|
|
46
|
+
getTargetPath(projectInfo, targetName) {
|
|
47
|
+
// Essayer d'abord apps/, puis libs/
|
|
48
|
+
const appPath = path.join(projectInfo.path, 'apps', targetName);
|
|
49
|
+
const libPath = path.join(projectInfo.path, 'libs', targetName);
|
|
50
|
+
if (fs.existsSync(appPath)) {
|
|
51
|
+
return appPath;
|
|
52
|
+
}
|
|
53
|
+
return libPath;
|
|
54
|
+
}
|
|
55
|
+
getTargetType(projectInfo, targetName) {
|
|
56
|
+
// Si targetName === projectInfo.name ET projet a plusieurs apps/libs → target "monorepo"
|
|
57
|
+
const hasMultipleTargets = (projectInfo.apps?.length || 0) + (projectInfo.libs?.length || 0) > 1;
|
|
58
|
+
if (hasMultipleTargets && targetName === projectInfo.name) {
|
|
59
|
+
return 'monorepo';
|
|
60
|
+
}
|
|
61
|
+
// Vérifier dans les apps
|
|
62
|
+
if (projectInfo.apps?.some(app => app.name === targetName)) {
|
|
63
|
+
return 'app';
|
|
64
|
+
}
|
|
65
|
+
// Vérifier dans les libs
|
|
66
|
+
if (projectInfo.libs?.some(lib => lib.name === targetName)) {
|
|
67
|
+
return 'lib';
|
|
68
|
+
}
|
|
69
|
+
// Par défaut app
|
|
70
|
+
return 'app';
|
|
71
|
+
}
|
|
72
|
+
extractTargetFromFilePath(filePath, projectInfo) {
|
|
73
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
74
|
+
// Nx monorepo : apps/XXX ou libs/XXX (ou libs/groupe/XXX pour structure groupée)
|
|
75
|
+
const appsMatch = normalizedPath.match(/^apps\/([^\/]+)/);
|
|
76
|
+
if (appsMatch)
|
|
77
|
+
return appsMatch[1];
|
|
78
|
+
// Support libs groupées : libs/apis/git-platform → "apis/git-platform"
|
|
79
|
+
const libsMatch = normalizedPath.match(/^libs\/(.*?)(?:\/|$)/);
|
|
80
|
+
if (libsMatch) {
|
|
81
|
+
// Extraire tout le chemin après libs/ jusqu'au premier fichier
|
|
82
|
+
const fullLibPath = normalizedPath.substring(5); // Enlever "libs/"
|
|
83
|
+
// Trouver la lib complète en cherchant dans projectInfo.libs
|
|
84
|
+
const matchingLib = projectInfo.libs?.find(lib => fullLibPath.startsWith(lib.name));
|
|
85
|
+
if (matchingLib) {
|
|
86
|
+
return matchingLib.name; // Ex: "apis/git-platform"
|
|
87
|
+
}
|
|
88
|
+
// Fallback : prendre premier segment (ancien comportement)
|
|
89
|
+
return libsMatch[1];
|
|
90
|
+
}
|
|
91
|
+
// Si le chemin ne correspond pas à apps/ ou libs/, c'est un fichier global (ex: package.json)
|
|
92
|
+
// Pour Nx monorepo, ces règles de routine vont dans le target "monorepo" (nom du projet)
|
|
93
|
+
return projectInfo.name;
|
|
94
|
+
}
|
|
95
|
+
shouldFilterRoutinesFromTarget(targetName, projectInfo) {
|
|
96
|
+
// Nx avec plusieurs targets : filtrer routines des apps/libs normaux
|
|
97
|
+
// Les routines vont dans le target "monorepo"
|
|
98
|
+
const hasMultipleTargets = (projectInfo.apps?.length || 0) + (projectInfo.libs?.length || 0) > 1;
|
|
99
|
+
const isMonorepoTarget = hasMultipleTargets && targetName === projectInfo.name;
|
|
100
|
+
// Filtrer routines pour apps/libs normaux, PAS pour target monorepo
|
|
101
|
+
return hasMultipleTargets && !isMonorepoTarget;
|
|
102
|
+
}
|
|
103
|
+
shouldDisplayMonorepoTarget(target) {
|
|
104
|
+
// Ne pas afficher target MONOREPO s'il contient SEULEMENT des routines
|
|
105
|
+
if (target.targetType !== 'monorepo') {
|
|
106
|
+
return true; // Toujours afficher apps/libs normaux
|
|
107
|
+
}
|
|
108
|
+
// Vérifier si target monorepo contient des règles non-routine
|
|
109
|
+
for (const migration of target.migrations) {
|
|
110
|
+
for (const priority of migration.priorities) {
|
|
111
|
+
for (const rule of priority.rules) {
|
|
112
|
+
if (rule.type !== 'routine') {
|
|
113
|
+
return true; // A au moins une règle non-routine
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Target monorepo ne contient QUE des routines → ne pas afficher
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
getTargetsList(projectInfo) {
|
|
122
|
+
const apps = projectInfo.apps || [];
|
|
123
|
+
const libs = projectInfo.libs || [];
|
|
124
|
+
return [...apps, ...libs];
|
|
125
|
+
}
|
|
126
|
+
isMultiTarget(projectInfo) {
|
|
127
|
+
return ((projectInfo.apps?.length || 0) + (projectInfo.libs?.length || 0)) > 1;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.NxStrategy = NxStrategy;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.StandaloneStrategy = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
/**
|
|
39
|
+
* Stratégie pour projets Angular Standalone
|
|
40
|
+
* - Structure src/ unique
|
|
41
|
+
* - Pas de séparation apps/libs
|
|
42
|
+
* - Routines intégrées au target principal
|
|
43
|
+
*/
|
|
44
|
+
class StandaloneStrategy {
|
|
45
|
+
getTargetPath(projectInfo, targetName) {
|
|
46
|
+
// Projet standalone : toujours src/
|
|
47
|
+
return path.join(projectInfo.path, 'src');
|
|
48
|
+
}
|
|
49
|
+
getTargetType(projectInfo, targetName) {
|
|
50
|
+
// Projet standalone : toujours 'app'
|
|
51
|
+
return 'app';
|
|
52
|
+
}
|
|
53
|
+
extractTargetFromFilePath(filePath, projectInfo) {
|
|
54
|
+
// Projet standalone : tout va dans le projet principal
|
|
55
|
+
return projectInfo.name;
|
|
56
|
+
}
|
|
57
|
+
shouldFilterRoutinesFromTarget(targetName, projectInfo) {
|
|
58
|
+
// Standalone : pas de filtrage, routines incluses dans le target principal
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
shouldDisplayMonorepoTarget(target) {
|
|
62
|
+
// Standalone : pas de target monorepo, N/A
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
getTargetsList(projectInfo) {
|
|
66
|
+
// Standalone : un seul target (le projet lui-même)
|
|
67
|
+
return projectInfo.apps || [{ name: projectInfo.name }];
|
|
68
|
+
}
|
|
69
|
+
isMultiTarget(projectInfo) {
|
|
70
|
+
// Standalone : toujours false
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.StandaloneStrategy = StandaloneStrategy;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createProjectStrategy = createProjectStrategy;
|
|
4
|
+
const nx_strategy_1 = require("./nx-strategy");
|
|
5
|
+
const standalone_strategy_1 = require("./standalone-strategy");
|
|
6
|
+
/**
|
|
7
|
+
* Factory pour créer la stratégie appropriée selon le type de projet
|
|
8
|
+
*/
|
|
9
|
+
function createProjectStrategy(projectInfo) {
|
|
10
|
+
if (projectInfo.type === 'nx-monorepo') {
|
|
11
|
+
return new nx_strategy_1.NxStrategy();
|
|
12
|
+
}
|
|
13
|
+
// 'angular-standalone' ou 'unknown' → Stratégie standalone par défaut
|
|
14
|
+
return new standalone_strategy_1.StandaloneStrategy();
|
|
15
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadMigrationRules = loadMigrationRules;
|
|
37
|
+
exports.getRulesForMigration = getRulesForMigration;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const core_1 = require("../utils/core");
|
|
41
|
+
/**
|
|
42
|
+
* Charge les règles de migration depuis la nouvelle architecture
|
|
43
|
+
* Lit tous les fichiers JSON dans src/data/rules/to{18,19,20}/
|
|
44
|
+
*/
|
|
45
|
+
function loadMigrationRules() {
|
|
46
|
+
const rulesDir = path.join(__dirname, '..', 'data', 'rules');
|
|
47
|
+
if (!fs.existsSync(rulesDir)) {
|
|
48
|
+
throw new Error(`Répertoire des règles introuvable: ${rulesDir}`);
|
|
49
|
+
}
|
|
50
|
+
const migrations = {
|
|
51
|
+
'to18': { obligatoire: [], recommande: [], optionnelle: [] },
|
|
52
|
+
'to19': { obligatoire: [], recommande: [], optionnelle: [] },
|
|
53
|
+
'to20': { obligatoire: [], recommande: [], optionnelle: [] }
|
|
54
|
+
};
|
|
55
|
+
// Charger les règles pour chaque migration
|
|
56
|
+
const migrationDirs = ['to18', 'to19', 'to20'];
|
|
57
|
+
for (const dir of migrationDirs) {
|
|
58
|
+
const migrationDir = path.join(rulesDir, dir);
|
|
59
|
+
if (!fs.existsSync(migrationDir))
|
|
60
|
+
continue;
|
|
61
|
+
// Charger chaque fichier de priorité
|
|
62
|
+
for (const priority of ['obligatoire', 'recommande', 'optionnelle']) {
|
|
63
|
+
const filename = `rules-${dir.replace('to', '')}-${priority}.json`;
|
|
64
|
+
const filePath = path.join(migrationDir, filename);
|
|
65
|
+
if (fs.existsSync(filePath)) {
|
|
66
|
+
try {
|
|
67
|
+
const rules = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
68
|
+
migrations[dir][priority] = rules;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
core_1.logger.warning(`Erreur lors du chargement de ${filePath}: ${error}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return migrations;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Charge les règles pour une migration spécifique (17→18, 18→19, 19→20)
|
|
80
|
+
*/
|
|
81
|
+
function getRulesForMigration(migration) {
|
|
82
|
+
const allRules = loadMigrationRules();
|
|
83
|
+
const migrationRules = allRules[migration];
|
|
84
|
+
return [
|
|
85
|
+
...migrationRules.obligatoire,
|
|
86
|
+
...migrationRules.recommande,
|
|
87
|
+
...migrationRules.optionnelle
|
|
88
|
+
];
|
|
89
|
+
}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logScanStart = logScanStart;
|
|
4
|
+
exports.logTargetStart = logTargetStart;
|
|
5
|
+
exports.logTargetComplete = logTargetComplete;
|
|
6
|
+
exports.logScanProgress = logScanProgress;
|
|
7
|
+
exports.logMethodStats = logMethodStats;
|
|
8
|
+
exports.logWorkloadReport = logWorkloadReport;
|
|
9
|
+
exports.logTopRules = logTopRules;
|
|
10
|
+
exports.logScanComplete = logScanComplete;
|
|
11
|
+
exports.logScannerInfo = logScannerInfo;
|
|
12
|
+
exports.logSpecialRulesInfo = logSpecialRulesInfo;
|
|
13
|
+
exports.logFilesDetected = logFilesDetected;
|
|
14
|
+
const core_1 = require("../utils/core");
|
|
15
|
+
const core_2 = require("../utils/core");
|
|
16
|
+
const project_strategy_1 = require("./project-strategy");
|
|
17
|
+
/**
|
|
18
|
+
* Reporter centralisé pour afficher la progression et les résultats du scan
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Affiche la bannière de démarrage du scan
|
|
22
|
+
*/
|
|
23
|
+
function logScanStart(projectInfo, scannerType, rules) {
|
|
24
|
+
core_1.logger.blank();
|
|
25
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
26
|
+
core_1.logger.info(' ANGULAR MIGRATION PLANIFICATOR');
|
|
27
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
28
|
+
core_1.logger.blank();
|
|
29
|
+
core_1.logger.step(`Analyse du projet: ${projectInfo.name}`);
|
|
30
|
+
core_1.logger.info(`Scanner: ${scannerType.toUpperCase()}`);
|
|
31
|
+
core_1.logger.success(`Projet détecté: ${projectInfo.name}`);
|
|
32
|
+
core_1.logger.info(`Type: ${projectInfo.type}`);
|
|
33
|
+
if (projectInfo.angularVersion) {
|
|
34
|
+
core_1.logger.info(`Version Angular: ${projectInfo.angularVersion}`);
|
|
35
|
+
}
|
|
36
|
+
if (projectInfo.apps && projectInfo.apps.length > 0) {
|
|
37
|
+
const appNames = projectInfo.apps.map(a => a.name).join(', ');
|
|
38
|
+
core_1.logger.info(`Applications: ${projectInfo.apps.length} (${appNames})`);
|
|
39
|
+
}
|
|
40
|
+
if (projectInfo.libs && projectInfo.libs.length > 0) {
|
|
41
|
+
const libCount = projectInfo.libs.length;
|
|
42
|
+
const libNames = projectInfo.libs.slice(0, 3).join(', ');
|
|
43
|
+
const moreText = libCount > 3 ? `, +${libCount - 3}` : '';
|
|
44
|
+
core_1.logger.info(`Librairies: ${libCount} (${libNames}${moreText})`);
|
|
45
|
+
}
|
|
46
|
+
core_1.logger.blank();
|
|
47
|
+
// Info sur les règles chargées
|
|
48
|
+
const migrations = new Set(rules.map(r => {
|
|
49
|
+
if (r.key.includes('_18_'))
|
|
50
|
+
return 'to18';
|
|
51
|
+
if (r.key.includes('_19_'))
|
|
52
|
+
return 'to19';
|
|
53
|
+
if (r.key.includes('_20_'))
|
|
54
|
+
return 'to20';
|
|
55
|
+
return 'unknown';
|
|
56
|
+
}));
|
|
57
|
+
const migrationList = Array.from(migrations).filter(m => m !== 'unknown').map(m => m.replace('to', '')).join(', ');
|
|
58
|
+
core_1.logger.step(`Chargement des règles (${migrationList})...`);
|
|
59
|
+
core_1.logger.success(`${rules.length} règles chargées`);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Affiche le début du scan d'un target
|
|
63
|
+
*/
|
|
64
|
+
function logTargetStart(targetName, targetType) {
|
|
65
|
+
core_1.logger.blank();
|
|
66
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
67
|
+
core_1.logger.info(` SCAN: ${targetName.toUpperCase()} (${targetType})`);
|
|
68
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
69
|
+
core_1.logger.blank();
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Affiche la fin du scan d'un target avec statistiques
|
|
73
|
+
*/
|
|
74
|
+
function logTargetComplete(targetName, matches, duration) {
|
|
75
|
+
const uniqueRules = new Set(matches.map(m => m.ruleKey)).size;
|
|
76
|
+
const durationText = duration ? ` en ${(duration / 1000).toFixed(2)}s` : '';
|
|
77
|
+
core_1.logger.blank();
|
|
78
|
+
core_1.logger.success(`Target ${targetName}: ${matches.length} occurrences (${uniqueRules} règles actives)${durationText}`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Affiche la progression du scan AST par batch
|
|
82
|
+
*/
|
|
83
|
+
function logScanProgress(current, total, message) {
|
|
84
|
+
const progress = Math.round((current / total) * 100);
|
|
85
|
+
const spinner = getSpinner(current);
|
|
86
|
+
const extraMsg = message ? ` - ${message}` : '';
|
|
87
|
+
core_1.logger.debug(` Progression: ${progress}% (${current}/${total})${extraMsg} ${spinner}`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Affiche les statistiques de détection par méthode (AST vs Regex)
|
|
91
|
+
*/
|
|
92
|
+
function logMethodStats(astCount, regexCount, astRulesCount, regexRulesCount) {
|
|
93
|
+
const total = astCount + regexCount;
|
|
94
|
+
const astPercent = total > 0 ? ((astCount / total) * 100).toFixed(1) : '0.0';
|
|
95
|
+
const regexPercent = total > 0 ? ((regexCount / total) * 100).toFixed(1) : '0.0';
|
|
96
|
+
core_1.logger.blank();
|
|
97
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
98
|
+
core_1.logger.info(' RAPPORT DE DÉTECTION PAR MÉTHODE');
|
|
99
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
100
|
+
core_1.logger.blank();
|
|
101
|
+
core_1.logger.info(`Total occurrences: ${total}`);
|
|
102
|
+
core_1.logger.info(` • AST: ${astCount} (${astPercent}%)`);
|
|
103
|
+
core_1.logger.info(` • Regex: ${regexCount} (${regexPercent}%)`);
|
|
104
|
+
core_1.logger.blank();
|
|
105
|
+
core_1.logger.info(`Règles actives: ${astRulesCount + regexRulesCount}`);
|
|
106
|
+
core_1.logger.info(` • Avec AST: ${astRulesCount}`);
|
|
107
|
+
core_1.logger.info(` • Regex fallback: ${regexRulesCount}`);
|
|
108
|
+
core_1.logger.blank();
|
|
109
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Affiche le rapport hiérarchique de charge de travail
|
|
113
|
+
*/
|
|
114
|
+
function logWorkloadReport(report) {
|
|
115
|
+
core_1.logger.blank();
|
|
116
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
117
|
+
core_1.logger.info(' RAPPORT DE CHARGE DE TRAVAIL');
|
|
118
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
119
|
+
core_1.logger.blank();
|
|
120
|
+
core_1.logger.info(`📊 Charge totale estimée: ${(0, core_2.formatWorkloadTime)(report.totalTime)}`);
|
|
121
|
+
// Créer la stratégie pour déterminer l'affichage
|
|
122
|
+
const strategy = (0, project_strategy_1.createProjectStrategy)(report.projectInfo);
|
|
123
|
+
const isMultiTarget = strategy.isMultiTarget(report.projectInfo);
|
|
124
|
+
// Afficher résumé des routines pour monorepo multi-target
|
|
125
|
+
if (isMultiTarget && report.stats.totalRoutineRules > 0) {
|
|
126
|
+
const routineRules = collectRoutineRules(report);
|
|
127
|
+
if (routineRules.length > 0) {
|
|
128
|
+
core_1.logger.blank();
|
|
129
|
+
core_1.logger.info(`🔧 Règles de routine (${routineRules.length}) - Tâches globales monorepo:`);
|
|
130
|
+
for (const routine of routineRules) {
|
|
131
|
+
const timeStr = (0, core_2.formatWorkloadTime)(routine.totalTime).padEnd(15);
|
|
132
|
+
core_1.logger.debug(` • [ROUTINE] ${timeStr} → ${routine.ruleSummary}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
core_1.logger.blank();
|
|
137
|
+
for (const target of report.targets) {
|
|
138
|
+
// Pour multi-target (Nx) : skip l'affichage des targets qui ne doivent pas être affichés
|
|
139
|
+
if (isMultiTarget && !strategy.shouldDisplayMonorepoTarget(target)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
let targetIcon;
|
|
143
|
+
if (target.targetType === 'app') {
|
|
144
|
+
targetIcon = '📦 APP';
|
|
145
|
+
}
|
|
146
|
+
else if (target.targetType === 'lib') {
|
|
147
|
+
targetIcon = '📚 LIB';
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
targetIcon = '🏗️ MONOREPO';
|
|
151
|
+
}
|
|
152
|
+
core_1.logger.info(`${targetIcon}: ${target.targetName} (${(0, core_2.formatWorkloadTime)(target.totalTime)})`);
|
|
153
|
+
core_1.logger.blank();
|
|
154
|
+
for (const migration of target.migrations) {
|
|
155
|
+
core_1.logger.info(` 🔄 ${migration.migration.toUpperCase()} (${(0, core_2.formatWorkloadTime)(migration.totalTime)})`);
|
|
156
|
+
for (const priority of migration.priorities) {
|
|
157
|
+
const priorityIcon = getPriorityIcon(priority.priority);
|
|
158
|
+
const rulesCount = priority.rules.length;
|
|
159
|
+
core_1.logger.info(` ${priorityIcon} ${priority.priority.toUpperCase()} (${(0, core_2.formatWorkloadTime)(priority.totalTime)}) - ${rulesCount} règles`);
|
|
160
|
+
// Afficher top 5 règles par priorité
|
|
161
|
+
const topRules = priority.rules.slice(0, 5);
|
|
162
|
+
for (const rule of topRules) {
|
|
163
|
+
let displayStr;
|
|
164
|
+
if (rule.type === 'routine') {
|
|
165
|
+
// Règle de routine : charge unique
|
|
166
|
+
const timeStr = (0, core_2.formatWorkloadTime)(rule.totalTime).padEnd(15);
|
|
167
|
+
displayStr = `[ROUTINE] 1 × ${timeStr} → ${rule.ruleSummary}`;
|
|
168
|
+
}
|
|
169
|
+
else if (rule.type === 'combined') {
|
|
170
|
+
// Règle combinée : AST + fichiers
|
|
171
|
+
const timeStr = (0, core_2.formatWorkloadTime)(rule.totalTime).padEnd(15);
|
|
172
|
+
if (rule.specialWorkloadFiles === 0) {
|
|
173
|
+
// Cas spécial : règle avec special_workload mais 0 fichiers trouvés
|
|
174
|
+
const countStr = `${rule.baseOccurrences}`.padStart(3);
|
|
175
|
+
displayStr = `[SPECIAL] ${countStr} × ${timeStr} → ${rule.ruleSummary}`;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
displayStr = `[SPECIAL] ${rule.baseOccurrences} occ. + ${rule.specialWorkloadFiles} fichiers = ${timeStr} → ${rule.ruleSummary}`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (rule.type === 'special') {
|
|
182
|
+
// Règle special seulement (pas d'occurrences AST)
|
|
183
|
+
const timeStr = (0, core_2.formatWorkloadTime)(rule.totalTime).padEnd(15);
|
|
184
|
+
displayStr = `[SPECIAL] ${rule.specialWorkloadFiles} fichiers × ${timeStr} → ${rule.ruleSummary}`;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
// Règle standard (AST/Regex)
|
|
188
|
+
const countStr = `${rule.occurrences}`.padStart(3);
|
|
189
|
+
const timeStr = (0, core_2.formatWorkloadTime)(rule.totalTime).padEnd(15);
|
|
190
|
+
displayStr = `${countStr} × ${timeStr} → ${rule.ruleSummary}`;
|
|
191
|
+
}
|
|
192
|
+
core_1.logger.debug(` ${displayStr}`);
|
|
193
|
+
}
|
|
194
|
+
if (priority.rules.length > 5) {
|
|
195
|
+
core_1.logger.debug(` ... et ${priority.rules.length - 5} règles supplémentaires`);
|
|
196
|
+
}
|
|
197
|
+
core_1.logger.blank();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
core_1.logger.info('═══════════════════════════════════════════════════════════');
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Affiche le top N des règles les plus fréquentes
|
|
205
|
+
*/
|
|
206
|
+
function logTopRules(matches, topN = 10) {
|
|
207
|
+
if (matches.length === 0) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
core_1.logger.blank();
|
|
211
|
+
core_1.logger.step(`Top ${topN} règles les plus fréquentes:`);
|
|
212
|
+
const ruleCount = new Map();
|
|
213
|
+
for (const match of matches) {
|
|
214
|
+
const existing = ruleCount.get(match.ruleKey);
|
|
215
|
+
if (existing) {
|
|
216
|
+
existing.count++;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
ruleCount.set(match.ruleKey, { summary: match.ruleSummary, count: 1 });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const topRules = Array.from(ruleCount.entries())
|
|
223
|
+
.sort((a, b) => b[1].count - a[1].count)
|
|
224
|
+
.slice(0, topN);
|
|
225
|
+
for (const [index, [ruleKey, data]] of topRules.entries()) {
|
|
226
|
+
core_1.logger.debug(` ${index + 1}. ${data.summary}: ${data.count} occurrences`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Affiche la fin du scan global avec statistiques enrichies
|
|
231
|
+
*/
|
|
232
|
+
function logScanComplete(totalDuration, totalMatches, routineCount, specialWorkloadFilesCount) {
|
|
233
|
+
core_1.logger.blank();
|
|
234
|
+
if (totalDuration) {
|
|
235
|
+
core_1.logger.success(`Analyse terminée en ${(totalDuration / 1000).toFixed(2)}s`);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
core_1.logger.success('Analyse terminée');
|
|
239
|
+
}
|
|
240
|
+
if (totalMatches !== undefined) {
|
|
241
|
+
core_1.logger.success(` • Occurrences détectées (AST/Regex): ${totalMatches}`);
|
|
242
|
+
}
|
|
243
|
+
if (specialWorkloadFilesCount && specialWorkloadFilesCount > 0) {
|
|
244
|
+
core_1.logger.success(` • Fichiers comptés (special_workload): ${specialWorkloadFilesCount}`);
|
|
245
|
+
}
|
|
246
|
+
if (routineCount && routineCount > 0) {
|
|
247
|
+
core_1.logger.success(` • Tâches de routine identifiées: ${routineCount}`);
|
|
248
|
+
}
|
|
249
|
+
core_1.logger.blank();
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Affiche les informations sur le scanner utilisé
|
|
253
|
+
*/
|
|
254
|
+
function logScannerInfo(astRulesCount, regexRulesCount) {
|
|
255
|
+
core_1.logger.info(`Scanner: ${astRulesCount} règles AST, ${regexRulesCount} règles Regex (fallback)`);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Affiche les compteurs de règles spéciales (special_workload et routines)
|
|
259
|
+
*/
|
|
260
|
+
function logSpecialRulesInfo(specialWorkloadCount, routineCount) {
|
|
261
|
+
if (specialWorkloadCount > 0) {
|
|
262
|
+
core_1.logger.info(`📦 ${specialWorkloadCount} règle(s) avec special_workload détectée(s)`);
|
|
263
|
+
}
|
|
264
|
+
if (routineCount > 0) {
|
|
265
|
+
core_1.logger.info(`🔧 ${routineCount} règle(s) de routine détectée(s)`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Affiche les fichiers détectés
|
|
270
|
+
*/
|
|
271
|
+
function logFilesDetected(fileType, count) {
|
|
272
|
+
core_1.logger.info(`Fichiers ${fileType}: ${count} détectés`);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Retourne l'icône correspondant à une priorité
|
|
276
|
+
*/
|
|
277
|
+
function getPriorityIcon(priority) {
|
|
278
|
+
switch (priority) {
|
|
279
|
+
case 'obligatoire':
|
|
280
|
+
return '🔴';
|
|
281
|
+
case 'recommande':
|
|
282
|
+
return '🟡';
|
|
283
|
+
case 'optionnelle':
|
|
284
|
+
return '🟢';
|
|
285
|
+
default:
|
|
286
|
+
return '⚪';
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Retourne un caractère de spinner pour animer la progression
|
|
291
|
+
*/
|
|
292
|
+
function getSpinner(step) {
|
|
293
|
+
const spinners = ['⣷', '⣯', '⣟', '⡿', '⢿', '⣻', '⣽', '⣾'];
|
|
294
|
+
return spinners[step % spinners.length];
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Collecte toutes les règles de routine depuis le rapport (parcours hiérarchique)
|
|
298
|
+
*/
|
|
299
|
+
function collectRoutineRules(report) {
|
|
300
|
+
const routineRules = [];
|
|
301
|
+
for (const target of report.targets) {
|
|
302
|
+
for (const migration of target.migrations) {
|
|
303
|
+
for (const priority of migration.priorities) {
|
|
304
|
+
for (const rule of priority.rules) {
|
|
305
|
+
if (rule.type === 'routine') {
|
|
306
|
+
routineRules.push({
|
|
307
|
+
ruleSummary: rule.ruleSummary,
|
|
308
|
+
totalTime: rule.totalTime
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return routineRules;
|
|
316
|
+
}
|