@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,156 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matchesNodeType = matchesNodeType;
4
+ exports.matchesName = matchesName;
5
+ exports.matchesPropertyName = matchesPropertyName;
6
+ exports.matchesFunctionName = matchesFunctionName;
7
+ exports.matchesValue = matchesValue;
8
+ exports.matchesOperatorKind = matchesOperatorKind;
9
+ exports.matchesModifiers = matchesModifiers;
10
+ exports.matchesExported = matchesExported;
11
+ exports.matchesValuePattern = matchesValuePattern;
12
+ exports.matchesText = matchesText;
13
+ const ts_morph_1 = require("ts-morph");
14
+ const matcher_helpers_1 = require("../utils/matcher-helpers");
15
+ /**
16
+ * Vérifie si le nœud correspond au type demandé
17
+ */
18
+ function matchesNodeType(node, nodeType) {
19
+ const nodeTypes = (0, matcher_helpers_1.ensureArray)(nodeType);
20
+ const nodeKindName = node.getKindName();
21
+ return nodeTypes.includes(nodeKindName);
22
+ }
23
+ /**
24
+ * Vérifie le nom du nœud (Identifier, Decorator, PropertyAccessExpression, PropertyAssignment, MethodDeclaration, etc.)
25
+ */
26
+ function matchesName(node, name) {
27
+ const names = (0, matcher_helpers_1.ensureArray)(name);
28
+ if (ts_morph_1.Node.isIdentifier(node)) {
29
+ return names.includes(node.getText());
30
+ }
31
+ if (ts_morph_1.Node.isDecorator(node)) {
32
+ const expression = node.getExpression();
33
+ if (ts_morph_1.Node.isCallExpression(expression)) {
34
+ const decoratorName = expression.getExpression().getText();
35
+ return names.includes(decoratorName);
36
+ }
37
+ return names.includes(expression.getText());
38
+ }
39
+ // Pour PropertyAccessExpression, vérifier le nom de la propriété
40
+ // Cela permet d'utiliser "name" comme alias de "propertyName"
41
+ if (ts_morph_1.Node.isPropertyAccessExpression(node)) {
42
+ return names.includes(node.getName());
43
+ }
44
+ // Pour PropertyAssignment (ex: { redirectTo: '/home' })
45
+ if (ts_morph_1.Node.isPropertyAssignment(node)) {
46
+ return names.includes(node.getName());
47
+ }
48
+ // Pour MethodDeclaration (ex: canActivate() { })
49
+ if (ts_morph_1.Node.isMethodDeclaration(node)) {
50
+ return names.includes(node.getName());
51
+ }
52
+ // Pour VariableDeclaration (ex: const serverRoutes: ServerRoute[] = [])
53
+ if (ts_morph_1.Node.isVariableDeclaration(node)) {
54
+ return names.includes(node.getName());
55
+ }
56
+ return false;
57
+ }
58
+ /**
59
+ * Vérifie le nom de propriété (PropertyAccessExpression)
60
+ */
61
+ function matchesPropertyName(node, propertyName) {
62
+ const propertyNames = (0, matcher_helpers_1.ensureArray)(propertyName);
63
+ if (ts_morph_1.Node.isPropertyAccessExpression(node)) {
64
+ const propName = node.getName();
65
+ return propertyNames.includes(propName);
66
+ }
67
+ return false;
68
+ }
69
+ /**
70
+ * Vérifie le nom de fonction (CallExpression)
71
+ */
72
+ function matchesFunctionName(node, functionName) {
73
+ const functionNames = (0, matcher_helpers_1.ensureArray)(functionName);
74
+ if (ts_morph_1.Node.isCallExpression(node)) {
75
+ const expression = node.getExpression();
76
+ const funcName = expression.getText().split('.').pop() || '';
77
+ return functionNames.includes(funcName);
78
+ }
79
+ return false;
80
+ }
81
+ /**
82
+ * Vérifie la valeur d'un nœud
83
+ */
84
+ function matchesValue(node, value) {
85
+ const nodeText = node.getText();
86
+ const expectedValue = (0, matcher_helpers_1.normalizeValue)(value);
87
+ return (0, matcher_helpers_1.matchesTextValue)(nodeText, expectedValue);
88
+ }
89
+ /**
90
+ * Vérifie le type d'opérateur (BinaryExpression)
91
+ */
92
+ function matchesOperatorKind(node, operatorKind) {
93
+ if (!ts_morph_1.Node.isBinaryExpression(node)) {
94
+ return false;
95
+ }
96
+ const operator = node.getOperatorToken();
97
+ return operator.getKindName() === operatorKind;
98
+ }
99
+ /**
100
+ * Vérifie les modificateurs (export, public, private, etc.)
101
+ */
102
+ function matchesModifiers(node, modifiers) {
103
+ if (!('getModifiers' in node) || typeof node.getModifiers !== 'function') {
104
+ return false;
105
+ }
106
+ const nodeModifiers = node.getModifiers().map((m) => m.getText());
107
+ return modifiers.every(mod => nodeModifiers.includes(mod));
108
+ }
109
+ /**
110
+ * Vérifie si le nœud est exporté
111
+ */
112
+ function matchesExported(node, shouldBeExported) {
113
+ // Pour VariableDeclaration, vérifier si le parent VariableStatement est exporté
114
+ if (ts_morph_1.Node.isVariableDeclaration(node)) {
115
+ const parent = node.getParent();
116
+ if (parent && ts_morph_1.Node.isVariableDeclarationList(parent)) {
117
+ const grandParent = parent.getParent();
118
+ if (grandParent && ts_morph_1.Node.isVariableStatement(grandParent)) {
119
+ const isExported = grandParent.isExported();
120
+ return isExported === shouldBeExported;
121
+ }
122
+ }
123
+ return false;
124
+ }
125
+ if (!('isExported' in node) || typeof node.isExported !== 'function') {
126
+ return false;
127
+ }
128
+ const isExported = node.isExported();
129
+ return isExported === shouldBeExported;
130
+ }
131
+ /**
132
+ * Vérifie un pattern de valeur avec regex
133
+ */
134
+ function matchesValuePattern(node, valuePattern) {
135
+ const nodeText = node.getText();
136
+ const regex = new RegExp(valuePattern);
137
+ return regex.test(nodeText);
138
+ }
139
+ /**
140
+ * Vérifie le texte d'un StringLiteral
141
+ */
142
+ function matchesText(node, textPattern) {
143
+ if (!ts_morph_1.Node.isStringLiteral(node)) {
144
+ return false;
145
+ }
146
+ const text = node.getLiteralValue();
147
+ // Si c'est une string simple, vérifier l'égalité exacte
148
+ if (typeof textPattern === 'string') {
149
+ return text === textPattern;
150
+ }
151
+ // Si c'est un objet avec startsWith
152
+ if (textPattern.startsWith) {
153
+ return text.startsWith(textPattern.startsWith);
154
+ }
155
+ return true;
156
+ }
@@ -0,0 +1,281 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveModuleSourceFile = resolveModuleSourceFile;
4
+ exports.matchesReferTo = matchesReferTo;
5
+ const ts_morph_1 = require("ts-morph");
6
+ const ast_helpers_1 = require("../../../../utils/core/ast-helpers");
7
+ /**
8
+ * Matcher pour la résolution de symboles cross-file (referTo)
9
+ * Utilise ts-morph getDefinitionNodes() pour suivre les références
10
+ */
11
+ /**
12
+ * Profondeur maximale pour suivre les références cross-file
13
+ * (ImportSpecifier → ExportSpecifier → ... → ClassDeclaration)
14
+ *
15
+ * Valeur recommandée: 10+ pour projets Nx complexes avec barrel exports multiples
16
+ * Exemple: libs/feature/index.ts → libs/feature/services/index.ts → service.ts
17
+ */
18
+ const MAX_REFERENCE_DEPTH = 20;
19
+ /**
20
+ * Résout un module specifier (chemin relatif ou absolu) vers un SourceFile
21
+ * Gère les chemins relatifs profonds que ts-morph en mémoire a du mal à résoudre
22
+ * @param moduleSpecifier - Chemin du module (ex: '../../../../libs/shared/services/user.service')
23
+ * @param fromFile - Fichier source qui fait l'import
24
+ * @returns SourceFile résolu ou undefined
25
+ */
26
+ function resolveModuleSourceFile(moduleSpecifier, fromFile) {
27
+ const project = fromFile.getProject();
28
+ // APPROCHE 1: Essayer getModuleSpecifierSourceFile (fonctionne pour chemins simples)
29
+ const directResolve = fromFile.getImportDeclarations()
30
+ .find(imp => imp.getModuleSpecifierValue() === moduleSpecifier)
31
+ ?.getModuleSpecifierSourceFile();
32
+ if (directResolve) {
33
+ return directResolve;
34
+ }
35
+ // APPROCHE 2: Résolution manuelle pour chemins relatifs (en mémoire)
36
+ if (moduleSpecifier.startsWith('.')) {
37
+ const fromPath = fromFile.getFilePath();
38
+ const parts = fromPath.split('/').filter(p => p);
39
+ // Retirer le fichier pour avoir le directory
40
+ parts.pop();
41
+ // Parser le module specifier
42
+ const moduleParts = moduleSpecifier.split('/');
43
+ // Naviguer selon les ../ et ./
44
+ for (const part of moduleParts) {
45
+ if (part === '..') {
46
+ parts.pop();
47
+ }
48
+ else if (part !== '.') {
49
+ parts.push(part);
50
+ }
51
+ }
52
+ // Reconstruire le chemin
53
+ const resolvedPath = '/' + parts.join('/');
54
+ // Essayer avec différentes extensions
55
+ const extensions = ['', '.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx'];
56
+ for (const ext of extensions) {
57
+ const pathWithExt = resolvedPath + ext;
58
+ const sourceFile = project.getSourceFile(pathWithExt);
59
+ if (sourceFile) {
60
+ return sourceFile;
61
+ }
62
+ }
63
+ // Dernière tentative: chercher par nom de fichier relatif
64
+ const allFiles = project.getSourceFiles();
65
+ const fileName = parts[parts.length - 1];
66
+ for (const file of allFiles) {
67
+ const filePath = file.getFilePath();
68
+ if (filePath.endsWith('/' + fileName + '.ts') ||
69
+ filePath.endsWith('/' + fileName + '.tsx') ||
70
+ filePath.endsWith('/' + fileName + '/index.ts')) {
71
+ // Vérifier que le chemin complet correspond
72
+ const filePathParts = filePath.split('/').filter(p => p);
73
+ let match = true;
74
+ for (let i = 0; i < parts.length && i < filePathParts.length; i++) {
75
+ if (parts[parts.length - 1 - i] !== filePathParts[filePathParts.length - 1 - i]) {
76
+ match = false;
77
+ break;
78
+ }
79
+ }
80
+ if (match) {
81
+ return file;
82
+ }
83
+ }
84
+ }
85
+ }
86
+ return undefined;
87
+ }
88
+ /**
89
+ * Résout récursivement un ImportSpecifier/ExportSpecifier vers sa déclaration finale
90
+ * Suit la chaîne: ImportSpecifier → ExportSpecifier → ... → ClassDeclaration
91
+ *
92
+ * @param node - Nœud de départ (ImportSpecifier ou ExportSpecifier)
93
+ * @param maxDepth - Profondeur maximale de récursion
94
+ * @returns Nœud final résolu ou le nœud d'origine si résolution impossible
95
+ */
96
+ function resolveSpecifierRecursively(node, maxDepth = MAX_REFERENCE_DEPTH) {
97
+ let targetNode = node;
98
+ let depth = 0;
99
+ while ((0, ast_helpers_1.isImportOrExportSpecifier)(targetNode) && depth < maxDepth) {
100
+ const nextNode = resolveSpecifierOneLevel(targetNode);
101
+ if (!nextNode)
102
+ break;
103
+ targetNode = nextNode;
104
+ depth++;
105
+ }
106
+ return targetNode;
107
+ }
108
+ /**
109
+ * Résout un ImportSpecifier/ExportSpecifier d'un niveau
110
+ * Essaie via getSymbol() d'abord, puis via navigation manuelle du module
111
+ *
112
+ * @param specifier - ImportSpecifier ou ExportSpecifier
113
+ * @returns Prochain nœud dans la chaîne ou undefined
114
+ */
115
+ function resolveSpecifierOneLevel(specifier) {
116
+ // APPROCHE 1: Via getSymbol() + getAliasedSymbol()
117
+ const symbol = specifier.getSymbol();
118
+ if (symbol) {
119
+ const aliasedSymbol = symbol.getAliasedSymbol() || symbol;
120
+ const declarations = aliasedSymbol.getDeclarations();
121
+ if (declarations.length > 0) {
122
+ return declarations[0];
123
+ }
124
+ }
125
+ // APPROCHE 2: Via navigation manuelle du module (barrel exports en mémoire)
126
+ const parentDecl = (0, ast_helpers_1.findImportOrExportDeclaration)(specifier);
127
+ if (!parentDecl)
128
+ return undefined;
129
+ const moduleInfo = (0, ast_helpers_1.extractModuleInfo)(parentDecl, specifier);
130
+ if (!moduleInfo)
131
+ return undefined;
132
+ const resolvedFile = resolveModuleSourceFile(moduleInfo.moduleSpecifier, moduleInfo.sourceFile);
133
+ if (!resolvedFile)
134
+ return undefined;
135
+ const exports = resolvedFile.getExportedDeclarations();
136
+ const exportedNodes = exports.get(moduleInfo.name);
137
+ return exportedNodes && exportedNodes.length > 0 ? exportedNodes[0] : undefined;
138
+ }
139
+ /**
140
+ * Vérifie si un nœud référence un symbole qui correspond au pattern referTo
141
+ * @param node Nœud à vérifier (généralement un Identifier dans un tableau providers)
142
+ * @param referToPattern Pattern de référence (decorator, propertyNotEqual, etc.)
143
+ * @returns true si le symbole référencé matche le pattern
144
+ */
145
+ function matchesReferTo(node, referToPattern) {
146
+ const identifierNode = extractIdentifierNode(node, referToPattern);
147
+ if (!identifierNode || !ts_morph_1.Node.isIdentifier(identifierNode))
148
+ return false;
149
+ const definitions = identifierNode.getDefinitionNodes();
150
+ if (definitions.length === 0)
151
+ return false;
152
+ return definitions.some((def) => matchesDefinition(def, referToPattern));
153
+ }
154
+ /**
155
+ * Extrait le nœud Identifier du nœud donné selon le pattern
156
+ * @param node - Nœud à analyser
157
+ * @param pattern - Pattern avec elementNodeType optionnel
158
+ * @returns Identifier ou undefined
159
+ */
160
+ function extractIdentifierNode(node, pattern) {
161
+ // Vérifier elementNodeType si spécifié
162
+ if (pattern.elementNodeType) {
163
+ const nodeTypes = Array.isArray(pattern.elementNodeType)
164
+ ? pattern.elementNodeType
165
+ : [pattern.elementNodeType];
166
+ const nodeKind = node.getKindName();
167
+ if (!nodeTypes.includes(nodeKind)) {
168
+ return undefined;
169
+ }
170
+ }
171
+ // Extraire l'identifier
172
+ if (ts_morph_1.Node.isIdentifier(node)) {
173
+ return node;
174
+ }
175
+ if (ts_morph_1.Node.isCallExpression(node)) {
176
+ const expression = node.getExpression();
177
+ if (ts_morph_1.Node.isIdentifier(expression)) {
178
+ return expression;
179
+ }
180
+ }
181
+ return undefined;
182
+ }
183
+ /**
184
+ * Vérifie si une définition matche le pattern referTo
185
+ * @param def - Définition à vérifier
186
+ * @param pattern - Pattern referTo
187
+ * @returns true si match
188
+ */
189
+ function matchesDefinition(def, pattern) {
190
+ const targetNode = resolveToClassDeclaration(def);
191
+ if (!targetNode)
192
+ return false;
193
+ return checkDecoratorMatch(targetNode, pattern);
194
+ }
195
+ /**
196
+ * Résout une définition vers sa ClassDeclaration
197
+ * Gère les ImportSpecifier/ExportSpecifier avec résolution cross-file
198
+ *
199
+ * @param def - Définition (peut être ImportSpecifier, ExportSpecifier ou ClassDeclaration)
200
+ * @returns ClassDeclaration ou undefined
201
+ */
202
+ function resolveToClassDeclaration(def) {
203
+ let targetNode = def;
204
+ // Si c'est un Import/ExportSpecifier, résoudre récursivement
205
+ if ((0, ast_helpers_1.isImportOrExportSpecifier)(def)) {
206
+ targetNode = resolveSpecifierRecursively(def);
207
+ }
208
+ return findParentClass(targetNode);
209
+ }
210
+ /**
211
+ * Vérifie si la ClassDeclaration a le bon décorateur avec les bonnes propriétés
212
+ * @param classDecl - ClassDeclaration à vérifier
213
+ * @param pattern - Pattern avec decorator et propertyNotEqual
214
+ * @returns true si match
215
+ */
216
+ function checkDecoratorMatch(classDecl, pattern) {
217
+ const decorators = classDecl.getDecorators();
218
+ const targetDecorator = decorators.find(dec => getDecoratorName(dec) === pattern.decorator);
219
+ if (!targetDecorator)
220
+ return false;
221
+ if (pattern.propertyNotEqual) {
222
+ return checkPropertyNotEqual(targetDecorator, pattern.propertyNotEqual);
223
+ }
224
+ return true;
225
+ }
226
+ /**
227
+ * Trouve la classe parente d'une définition
228
+ */
229
+ function findParentClass(def) {
230
+ if (ts_morph_1.Node.isClassDeclaration(def)) {
231
+ return def;
232
+ }
233
+ let current = def.getParent();
234
+ while (current && !ts_morph_1.Node.isClassDeclaration(current)) {
235
+ current = current.getParent();
236
+ }
237
+ return current;
238
+ }
239
+ /**
240
+ * Extrait le nom d'un décorateur
241
+ */
242
+ function getDecoratorName(decorator) {
243
+ const expr = decorator.getExpression();
244
+ if (ts_morph_1.Node.isCallExpression(expr)) {
245
+ return expr.getExpression().getText();
246
+ }
247
+ if (ts_morph_1.Node.isIdentifier(expr)) {
248
+ return expr.getText();
249
+ }
250
+ return undefined;
251
+ }
252
+ /**
253
+ * Vérifie si la propriété du décorateur ne correspond PAS à la valeur attendue
254
+ * @returns true si la propriété est absente OU différente de la valeur
255
+ */
256
+ function checkPropertyNotEqual(decorator, propertyNotEqual) {
257
+ const { key, value } = propertyNotEqual;
258
+ const expr = decorator.getExpression();
259
+ // Si le décorateur n'a pas d'arguments, pas de config = match (car != value)
260
+ if (ts_morph_1.Node.isIdentifier(expr)) {
261
+ return true;
262
+ }
263
+ if (!ts_morph_1.Node.isCallExpression(expr)) {
264
+ return false;
265
+ }
266
+ const args = expr.getArguments();
267
+ if (args.length === 0 || !ts_morph_1.Node.isObjectLiteralExpression(args[0])) {
268
+ return true;
269
+ }
270
+ const configObj = args[0];
271
+ const targetProp = configObj.getProperty(key);
272
+ if (!targetProp || !ts_morph_1.Node.isPropertyAssignment(targetProp)) {
273
+ return true;
274
+ }
275
+ const propValue = targetProp.getInitializer();
276
+ if (!propValue) {
277
+ return true;
278
+ }
279
+ const actualValue = propValue.getText().replace(/['"]/g, '');
280
+ return actualValue !== value;
281
+ }
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matchesType = matchesType;
4
+ exports.matchesReturnType = matchesReturnType;
5
+ exports.matchesInitializer = matchesInitializer;
6
+ exports.matchesObject = matchesObject;
7
+ exports.matchesProperty = matchesProperty;
8
+ const ts_morph_1 = require("ts-morph");
9
+ /**
10
+ * Vérifie le type TypeScript d'un nœud
11
+ */
12
+ function matchesType(node, typePattern) {
13
+ let typeNode;
14
+ if (ts_morph_1.Node.isPropertyDeclaration(node) || ts_morph_1.Node.isParameterDeclaration(node)) {
15
+ typeNode = node.getTypeNode();
16
+ }
17
+ else if (ts_morph_1.Node.isVariableDeclaration(node)) {
18
+ typeNode = node.getTypeNode();
19
+ }
20
+ if (!typeNode) {
21
+ return false;
22
+ }
23
+ const typeText = typeNode.getText();
24
+ // Vérifier string simple (comparaison exacte)
25
+ if (typeof typePattern === 'string') {
26
+ return typeText === typePattern;
27
+ }
28
+ // Vérifier containsAny
29
+ if (typeof typePattern === 'object' && typePattern.containsAny) {
30
+ return typePattern.containsAny.some((t) => typeText.includes(t));
31
+ }
32
+ // Vérifier union
33
+ if (typeof typePattern === 'object' && typePattern.union) {
34
+ if (ts_morph_1.Node.isUnionTypeNode(typeNode)) {
35
+ const types = typeNode.getTypeNodes().map(t => t.getText());
36
+ if (typePattern.union.contains) {
37
+ const hasAll = typePattern.union.contains.every((t) => types.includes(t));
38
+ if (!hasAll) {
39
+ return false;
40
+ }
41
+ }
42
+ if (typePattern.union.missing) {
43
+ const missingTypes = Array.isArray(typePattern.union.missing)
44
+ ? typePattern.union.missing
45
+ : [typePattern.union.missing];
46
+ const hasAny = missingTypes.some((t) => types.includes(t));
47
+ if (hasAny) {
48
+ return false;
49
+ }
50
+ }
51
+ return true;
52
+ }
53
+ return false;
54
+ }
55
+ // Vérifier type simple
56
+ if (typeof typePattern === 'string') {
57
+ return typeText === typePattern;
58
+ }
59
+ return false;
60
+ }
61
+ /**
62
+ * Vérifie le type de retour d'une fonction
63
+ */
64
+ function matchesReturnType(node, returnTypePattern) {
65
+ let returnTypeNode;
66
+ // Cas 1: FunctionDeclaration ou MethodDeclaration
67
+ if (ts_morph_1.Node.isFunctionDeclaration(node) || ts_morph_1.Node.isMethodDeclaration(node)) {
68
+ returnTypeNode = node.getReturnTypeNode();
69
+ }
70
+ // Cas 2: VariableDeclaration avec ArrowFunction initializer
71
+ else if (ts_morph_1.Node.isVariableDeclaration(node)) {
72
+ const initializer = node.getInitializer();
73
+ if (initializer && ts_morph_1.Node.isArrowFunction(initializer)) {
74
+ returnTypeNode = initializer.getReturnTypeNode();
75
+ }
76
+ }
77
+ // Cas 3: ArrowFunction directement
78
+ else if (ts_morph_1.Node.isArrowFunction(node)) {
79
+ returnTypeNode = node.getReturnTypeNode();
80
+ }
81
+ else {
82
+ return false;
83
+ }
84
+ // Si pas de returnType, vérifier si on attend 'missing'
85
+ if (!returnTypeNode) {
86
+ if (returnTypePattern.missing) {
87
+ return true;
88
+ }
89
+ if (returnTypePattern.union && returnTypePattern.union.missing) {
90
+ return true;
91
+ }
92
+ return false;
93
+ }
94
+ const fullTypeText = returnTypeNode.getText();
95
+ // Vérifier union
96
+ if (returnTypePattern.union) {
97
+ // Cas simplifié: vérifier contains ET missing sur le texte complet
98
+ if (returnTypePattern.union.contains) {
99
+ const hasAll = returnTypePattern.union.contains.every((t) => fullTypeText.includes(t));
100
+ if (!hasAll) {
101
+ return false;
102
+ }
103
+ }
104
+ if (returnTypePattern.union.missing) {
105
+ const missingTypes = Array.isArray(returnTypePattern.union.missing)
106
+ ? returnTypePattern.union.missing
107
+ : [returnTypePattern.union.missing];
108
+ const hasAny = missingTypes.some((t) => fullTypeText.includes(t));
109
+ if (hasAny) {
110
+ return false;
111
+ }
112
+ }
113
+ return true;
114
+ }
115
+ // Vérifier missing
116
+ if (returnTypePattern.missing) {
117
+ const missingTypes = Array.isArray(returnTypePattern.missing)
118
+ ? returnTypePattern.missing
119
+ : [returnTypePattern.missing];
120
+ const hasAny = missingTypes.some((t) => fullTypeText.includes(t));
121
+ return !hasAny;
122
+ }
123
+ return false;
124
+ }
125
+ /**
126
+ * Vérifie l'initializer d'une propriété ou variable
127
+ */
128
+ function matchesInitializer(node, initializerPattern, matchesAstPatternFn) {
129
+ let initializer;
130
+ if (ts_morph_1.Node.isPropertyDeclaration(node)) {
131
+ initializer = node.getInitializer();
132
+ }
133
+ else if (ts_morph_1.Node.isVariableDeclaration(node)) {
134
+ initializer = node.getInitializer();
135
+ }
136
+ else if (ts_morph_1.Node.isPropertyAssignment(node)) {
137
+ initializer = node.getInitializer();
138
+ }
139
+ if (!initializer) {
140
+ return false;
141
+ }
142
+ // Vérifier notWrappedIn
143
+ if (initializerPattern.notWrappedIn) {
144
+ if (ts_morph_1.Node.isCallExpression(initializer)) {
145
+ const funcName = initializer.getExpression().getText();
146
+ if (funcName === initializerPattern.notWrappedIn) {
147
+ return false;
148
+ }
149
+ }
150
+ }
151
+ // Vérifier le pattern de l'initializer
152
+ return matchesAstPatternFn(initializer, initializerPattern);
153
+ }
154
+ /**
155
+ * Vérifie si l'objet a une propriété spécifique
156
+ */
157
+ function matchesObject(node, objectPattern) {
158
+ // Vérifier type simple
159
+ if (typeof objectPattern === 'string') {
160
+ if (ts_morph_1.Node.isPropertyAccessExpression(node)) {
161
+ const expressionText = node.getExpression().getText();
162
+ // Accepter soit "pendingTasks" soit "this.pendingTasks" soit "obj.pendingTasks"
163
+ return expressionText === objectPattern || expressionText.endsWith('.' + objectPattern);
164
+ }
165
+ if (ts_morph_1.Node.isIdentifier(node)) {
166
+ return node.getText() === objectPattern;
167
+ }
168
+ return false;
169
+ }
170
+ // Vérifier object avec type
171
+ if (objectPattern.type) {
172
+ if (ts_morph_1.Node.isPropertyAccessExpression(node)) {
173
+ const expr = node.getExpression();
174
+ if (ts_morph_1.Node.isIdentifier(expr)) {
175
+ // Vérifier le type via le type checker de ts-morph
176
+ try {
177
+ const type = expr.getType();
178
+ const typeText = type.getText();
179
+ if (typeText.includes(objectPattern.type)) {
180
+ return true;
181
+ }
182
+ }
183
+ catch {
184
+ // Si l'analyse de type échoue, fallback sur le nom de variable
185
+ return true;
186
+ }
187
+ }
188
+ }
189
+ return false;
190
+ }
191
+ // Vérifier properties (avec checkObjectProperties si nécessaire)
192
+ if (objectPattern.properties) {
193
+ // Pour l'instant, retourner true si l'objet existe
194
+ // Une vérification plus précise nécessiterait checkObjectProperties
195
+ return true;
196
+ }
197
+ return false;
198
+ }
199
+ /**
200
+ * Vérifie la propriété d'un PropertyAccessExpression
201
+ */
202
+ function matchesProperty(node, property) {
203
+ if (!ts_morph_1.Node.isPropertyAccessExpression(node)) {
204
+ return false;
205
+ }
206
+ return node.getName() === property;
207
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /**
3
+ * Utilitaires partagés pour les matchers
4
+ * Évite la duplication de code (principe DRY)
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ensureArray = ensureArray;
8
+ exports.normalizeValue = normalizeValue;
9
+ exports.matchesTextValue = matchesTextValue;
10
+ /**
11
+ * Normalise une valeur en tableau
12
+ * @param value Valeur simple ou tableau
13
+ * @returns Tableau
14
+ */
15
+ function ensureArray(value) {
16
+ return Array.isArray(value) ? value : [value];
17
+ }
18
+ /**
19
+ * Normalise une valeur en tant que string
20
+ * @param value Valeur à normaliser
21
+ * @returns String normalisée
22
+ */
23
+ function normalizeValue(value) {
24
+ return String(value);
25
+ }
26
+ /**
27
+ * Vérifie si un texte correspond à une valeur (avec ou sans quotes)
28
+ * @param nodeText Texte du nœud
29
+ * @param expectedValue Valeur attendue
30
+ * @returns true si le texte correspond
31
+ */
32
+ function matchesTextValue(nodeText, expectedValue) {
33
+ return nodeText === expectedValue ||
34
+ nodeText === `'${expectedValue}'` ||
35
+ nodeText === `"${expectedValue}"` ||
36
+ nodeText === `${expectedValue}`;
37
+ }