@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,237 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matchesExpression = matchesExpression;
4
+ exports.matchesArguments = matchesArguments;
5
+ exports.matchesLeft = matchesLeft;
6
+ exports.matchesRight = matchesRight;
7
+ exports.matchesChainContains = matchesChainContains;
8
+ exports.matchesBody = matchesBody;
9
+ const ts_morph_1 = require("ts-morph");
10
+ const decorator_matcher_1 = require("./decorator-matcher");
11
+ /**
12
+ * Vérifie l'expression d'un nœud (CallExpression, PropertyAccessExpression, etc.)
13
+ * Supporte l'imbrication : expression.expression.expression etc.
14
+ */
15
+ function matchesExpression(node, expressionPattern, matchesAstPatternFn) {
16
+ let expression;
17
+ if (ts_morph_1.Node.isCallExpression(node)) {
18
+ expression = node.getExpression();
19
+ }
20
+ else if (ts_morph_1.Node.isPropertyAccessExpression(node)) {
21
+ expression = node.getExpression();
22
+ }
23
+ else if (ts_morph_1.Node.isDecorator(node)) {
24
+ expression = node.getExpression();
25
+ }
26
+ else if (ts_morph_1.Node.isNonNullExpression(node)) {
27
+ expression = node.getExpression();
28
+ }
29
+ else if (ts_morph_1.Node.isNewExpression(node)) {
30
+ expression = node.getExpression();
31
+ }
32
+ if (!expression) {
33
+ return false;
34
+ }
35
+ // Si expressionPattern est une string, vérifier que l'expression est un Identifier avec ce nom
36
+ if (typeof expressionPattern === 'string') {
37
+ if (ts_morph_1.Node.isIdentifier(expression)) {
38
+ return expression.getText() === expressionPattern;
39
+ }
40
+ return false;
41
+ }
42
+ return matchesAstPatternFn(expression, expressionPattern);
43
+ }
44
+ /**
45
+ * Vérifie les arguments d'un CallExpression
46
+ */
47
+ function matchesArguments(node, argumentsPattern, matchesAstPatternFn) {
48
+ if (!ts_morph_1.Node.isCallExpression(node)) {
49
+ return false;
50
+ }
51
+ const args = node.getArguments();
52
+ // Vérifier contains
53
+ if (argumentsPattern.contains) {
54
+ const hasMatch = args.some(arg => matchesAstPatternFn(arg, argumentsPattern.contains));
55
+ if (!hasMatch) {
56
+ return false;
57
+ }
58
+ }
59
+ // Vérifier containsAny
60
+ if (argumentsPattern.containsAny) {
61
+ const hasMatch = args.some(arg => argumentsPattern.containsAny.some((pattern) => matchesAstPatternFn(arg, pattern)));
62
+ if (!hasMatch) {
63
+ return false;
64
+ }
65
+ }
66
+ // Vérifier containsCall
67
+ if (argumentsPattern.containsCall) {
68
+ const hasCall = args.some(arg => {
69
+ if (!ts_morph_1.Node.isCallExpression(arg)) {
70
+ return false;
71
+ }
72
+ // Vérifier le nom de la fonction
73
+ if (argumentsPattern.containsCall.functionName) {
74
+ const funcName = arg.getExpression().getText().split('.').pop() || '';
75
+ if (funcName !== argumentsPattern.containsCall.functionName) {
76
+ return false;
77
+ }
78
+ }
79
+ // Vérifier l'objet passé en argument
80
+ if (argumentsPattern.containsCall.object && argumentsPattern.containsCall.object.properties) {
81
+ const callArgs = arg.getArguments();
82
+ // Si des propriétés sont définies avec missing: true
83
+ const hasAnyMissing = Object.values(argumentsPattern.containsCall.object.properties).some((prop) => prop.missing === true);
84
+ if (hasAnyMissing) {
85
+ // Vérifier que l'appel n'a PAS d'objet ou que l'objet n'a PAS la propriété
86
+ if (callArgs.length === 0) {
87
+ // Pas d'arguments = propriété manquante
88
+ return true;
89
+ }
90
+ if (ts_morph_1.Node.isObjectLiteralExpression(callArgs[0])) {
91
+ // Vérifier que les propriétés "missing" sont bien absentes
92
+ return (0, decorator_matcher_1.checkObjectProperties)(callArgs[0], argumentsPattern.containsCall.object.properties);
93
+ }
94
+ // Pas un objet littéral = propriété manquante
95
+ return true;
96
+ }
97
+ // Vérification normale (exists, valeurs spécifiques)
98
+ if (callArgs.length > 0 && ts_morph_1.Node.isObjectLiteralExpression(callArgs[0])) {
99
+ return (0, decorator_matcher_1.checkObjectProperties)(callArgs[0], argumentsPattern.containsCall.object.properties);
100
+ }
101
+ return false;
102
+ }
103
+ return true;
104
+ });
105
+ if (!hasCall) {
106
+ return false;
107
+ }
108
+ }
109
+ // Vérifier properties (sur les arguments objets - par défaut le 1er, sinon chercher dans tous)
110
+ if (argumentsPattern.properties) {
111
+ // Chercher dans tous les arguments pour trouver un ObjectLiteralExpression
112
+ for (const arg of args) {
113
+ if (ts_morph_1.Node.isObjectLiteralExpression(arg)) {
114
+ const result = (0, decorator_matcher_1.checkObjectProperties)(arg, argumentsPattern.properties);
115
+ // Si on trouve un objet qui matche (ou qui ne matche pas les missing), on retourne le résultat
116
+ if (result || Object.values(argumentsPattern.properties).some((p) => p && typeof p === 'object' && p.missing)) {
117
+ return result;
118
+ }
119
+ }
120
+ }
121
+ // Aucun objet trouvé - si on cherche des "missing", c'est un match (l'objet n'existe pas du tout)
122
+ if (Object.values(argumentsPattern.properties).some((p) => p && typeof p === 'object' && p.missing)) {
123
+ return true;
124
+ }
125
+ return false;
126
+ }
127
+ // Vérifier count
128
+ if (argumentsPattern.count !== undefined) {
129
+ if (args.length !== argumentsPattern.count) {
130
+ return false;
131
+ }
132
+ }
133
+ // Vérifier secondArgument
134
+ if (argumentsPattern.secondArgument) {
135
+ if (argumentsPattern.secondArgument.missing) {
136
+ if (args.length >= 2) {
137
+ return false;
138
+ }
139
+ }
140
+ }
141
+ // Vérifier missing (vérifier que l'argument nommé n'est PAS présent)
142
+ if (argumentsPattern.missing) {
143
+ const missingName = argumentsPattern.missing;
144
+ // Vérifier si un argument est un CallExpression avec ce nom de fonction
145
+ const hasMatchingCall = args.some(arg => {
146
+ if (ts_morph_1.Node.isCallExpression(arg)) {
147
+ const funcName = arg.getExpression().getText().split('.').pop() || '';
148
+ return funcName === missingName;
149
+ }
150
+ // Vérifier aussi si c'est un Identifier simple
151
+ if (ts_morph_1.Node.isIdentifier(arg)) {
152
+ return arg.getText() === missingName;
153
+ }
154
+ return false;
155
+ });
156
+ // Si on trouve l'argument "missing", le pattern ne matche PAS
157
+ if (hasMatchingCall) {
158
+ return false;
159
+ }
160
+ }
161
+ return true;
162
+ }
163
+ /**
164
+ * Vérifie la partie gauche d'une BinaryExpression
165
+ */
166
+ function matchesLeft(node, leftPattern, matchesAstPatternFn) {
167
+ if (!ts_morph_1.Node.isBinaryExpression(node)) {
168
+ return false;
169
+ }
170
+ const left = node.getLeft();
171
+ return matchesAstPatternFn(left, leftPattern);
172
+ }
173
+ /**
174
+ * Vérifie la partie droite d'une BinaryExpression
175
+ */
176
+ function matchesRight(node, rightPattern) {
177
+ if (!ts_morph_1.Node.isBinaryExpression(node)) {
178
+ return false;
179
+ }
180
+ const right = node.getRight();
181
+ // Vérifier value
182
+ if (rightPattern.value !== undefined) {
183
+ const rightValue = right.getText();
184
+ const expectedValue = String(rightPattern.value);
185
+ return rightValue === expectedValue ||
186
+ rightValue === `'${expectedValue}'` ||
187
+ rightValue === `"${expectedValue}"`;
188
+ }
189
+ return true;
190
+ }
191
+ /**
192
+ * Vérifie une chaîne de propriétés (ex: a.b.c.pipe().subscribe())
193
+ */
194
+ function matchesChainContains(node, chainPatterns, matchesAstPatternFn) {
195
+ if (!ts_morph_1.Node.isPropertyAccessExpression(node)) {
196
+ return false;
197
+ }
198
+ let current = node;
199
+ let patternIndex = chainPatterns.length - 1;
200
+ while (patternIndex >= 0 && ts_morph_1.Node.isPropertyAccessExpression(current)) {
201
+ if (!matchesAstPatternFn(current, chainPatterns[patternIndex])) {
202
+ return false;
203
+ }
204
+ patternIndex--;
205
+ current = current.getExpression();
206
+ }
207
+ return patternIndex < 0;
208
+ }
209
+ /**
210
+ * Vérifie le corps d'une fonction
211
+ */
212
+ function matchesBody(node, bodyPattern, matchesAstPatternFn) {
213
+ let body;
214
+ if (ts_morph_1.Node.isFunctionDeclaration(node)) {
215
+ body = node.getBody();
216
+ }
217
+ else if (ts_morph_1.Node.isMethodDeclaration(node)) {
218
+ body = node.getBody();
219
+ }
220
+ else if (ts_morph_1.Node.isArrowFunction(node)) {
221
+ body = node.getBody();
222
+ }
223
+ if (!body) {
224
+ return false;
225
+ }
226
+ // Vérifier contains
227
+ if (bodyPattern.contains) {
228
+ let hasMatch = false;
229
+ body.forEachDescendant((child) => {
230
+ if (matchesAstPatternFn(child, bodyPattern.contains)) {
231
+ hasMatch = true;
232
+ }
233
+ });
234
+ return hasMatch;
235
+ }
236
+ return true;
237
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matchesInFilePattern = matchesInFilePattern;
4
+ exports.matchesTestSetup = matchesTestSetup;
5
+ const ts_morph_1 = require("ts-morph");
6
+ /**
7
+ * Vérifie si un fichier correspond au pattern inFile
8
+ * @param filePath Chemin relatif du fichier
9
+ * @param inFilePattern Pattern de fichier (string, objet tsconfig, objet avec exclude, etc.)
10
+ */
11
+ function matchesInFilePattern(filePath, inFilePattern) {
12
+ // Si c'est un pattern de type "*.spec.ts" ou "angular.json"
13
+ if (typeof inFilePattern === 'string') {
14
+ // Normaliser le chemin (remplacer \ par /)
15
+ const normalizedPath = filePath.replace(/\\/g, '/');
16
+ // Convertir le pattern glob en regex
17
+ const regexPattern = inFilePattern
18
+ .replace(/\./g, '\\.')
19
+ .replace(/\*/g, '.*');
20
+ const regex = new RegExp(regexPattern + '$');
21
+ // Tester le chemin complet ET juste le nom de fichier
22
+ const fileName = normalizedPath.split('/').pop() || '';
23
+ return regex.test(normalizedPath) || regex.test(fileName);
24
+ }
25
+ // Si c'est un objet avec exclude (ex: { exclude: "*.spec.ts" })
26
+ if (typeof inFilePattern === 'object' && inFilePattern.exclude) {
27
+ // Normaliser le chemin (remplacer \ par /)
28
+ const normalizedPath = filePath.replace(/\\/g, '/');
29
+ // Convertir le pattern glob en regex
30
+ const excludePattern = inFilePattern.exclude;
31
+ const regexPattern = excludePattern
32
+ .replace(/\./g, '\\.')
33
+ .replace(/\*/g, '.*');
34
+ const regex = new RegExp(regexPattern + '$');
35
+ // Tester le chemin complet ET juste le nom de fichier
36
+ const fileName = normalizedPath.split('/').pop() || '';
37
+ const isExcluded = regex.test(normalizedPath) || regex.test(fileName);
38
+ // Retourner l'inverse : si exclu, retourner false
39
+ return !isExcluded;
40
+ }
41
+ // Si c'est un objet de configuration (ex: { tsconfig: {...} })
42
+ if (typeof inFilePattern === 'object' && inFilePattern.tsconfig) {
43
+ // Pour les patterns tsconfig complexes (ex: host_bindings_type_checking)
44
+ // On vérifie si le fichier devrait être concerné
45
+ // Cette vérification nécessite de lire tsconfig.json, ce qui est coûteux
46
+ // Règle spécifique: host_bindings_type_checking concerne tous les fichiers .ts
47
+ if (inFilePattern.tsconfig.angularCompilerOptions) {
48
+ return filePath.endsWith('.ts') && !filePath.endsWith('.spec.ts');
49
+ }
50
+ // Par défaut, matcher tous les fichiers pour ne pas bloquer l'analyse
51
+ return true;
52
+ }
53
+ return true;
54
+ }
55
+ /**
56
+ * Vérifie si le setup de test correspond au pattern testSetup
57
+ * @param sourceFile Fichier source TypeScript
58
+ * @param testSetupPattern Pattern de setup de test (providers, etc.)
59
+ */
60
+ function matchesTestSetup(sourceFile, testSetupPattern) {
61
+ // Vérifier si ErrorHandler est manquant dans les providers du TestBed
62
+ if (testSetupPattern.providers && testSetupPattern.providers.missing) {
63
+ const missingProvider = testSetupPattern.providers.missing;
64
+ let hasProvider = false;
65
+ // Chercher tous les appels à TestBed.configureTestingModule
66
+ sourceFile.forEachDescendant((node) => {
67
+ if (ts_morph_1.Node.isCallExpression(node)) {
68
+ const expression = node.getExpression();
69
+ if (ts_morph_1.Node.isPropertyAccessExpression(expression)) {
70
+ const objectText = expression.getExpression().getText();
71
+ const propertyText = expression.getName();
72
+ if (objectText === 'TestBed' && propertyText === 'configureTestingModule') {
73
+ // Analyser les arguments pour trouver providers
74
+ const args = node.getArguments();
75
+ if (args.length > 0 && ts_morph_1.Node.isObjectLiteralExpression(args[0])) {
76
+ const configObj = args[0];
77
+ const providersProperty = configObj.getProperty('providers');
78
+ if (providersProperty && ts_morph_1.Node.isPropertyAssignment(providersProperty)) {
79
+ const providersValue = providersProperty.getInitializer();
80
+ if (providersValue) {
81
+ const providersText = providersValue.getText();
82
+ if (providersText.includes(missingProvider)) {
83
+ hasProvider = true;
84
+ }
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ });
92
+ // Si le pattern demande "missing: ErrorHandler" et qu'on l'a trouvé, retourner false
93
+ // Sinon, retourner true (le provider est bien manquant)
94
+ return !hasProvider;
95
+ }
96
+ return true;
97
+ }
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matchesParent = matchesParent;
4
+ exports.matchesInClass = matchesInClass;
5
+ exports.matchesAncestor = matchesAncestor;
6
+ exports.matchesImplements = matchesImplements;
7
+ exports.matchesImplementsGeneric = matchesImplementsGeneric;
8
+ const ts_morph_1 = require("ts-morph");
9
+ const matcher_helpers_1 = require("../utils/matcher-helpers");
10
+ /**
11
+ * Vérifie le parent d'un nœud
12
+ * Note: matchesAstPattern sera importé depuis index.ts pour éviter les dépendances circulaires
13
+ */
14
+ function matchesParent(node, parentPattern, matchesAstPatternFn) {
15
+ const parent = node.getParent();
16
+ if (!parent) {
17
+ return false;
18
+ }
19
+ // Vérifier notNodeType et notFunctionName : chercher dans TOUS les ancêtres (pas juste parent immédiat)
20
+ if (parentPattern.notNodeType || parentPattern.notFunctionName) {
21
+ let current = node.getParent();
22
+ while (current) {
23
+ // Vérifier notNodeType
24
+ if (parentPattern.notNodeType && current.getKindName() === parentPattern.notNodeType) {
25
+ // Vérifier notFunctionName si spécifié
26
+ if (parentPattern.notFunctionName && ts_morph_1.Node.isCallExpression(current)) {
27
+ const funcName = current.getExpression().getText().split('.').pop() || '';
28
+ if (funcName === parentPattern.notFunctionName) {
29
+ return false; // Trouvé le pattern à exclure
30
+ }
31
+ }
32
+ else if (!parentPattern.notFunctionName) {
33
+ return false; // notNodeType seul trouvé
34
+ }
35
+ }
36
+ current = current.getParent();
37
+ }
38
+ }
39
+ // D'abord vérifier le nodeType du parent
40
+ if (parentPattern.nodeType) {
41
+ const parentNodeTypes = (0, matcher_helpers_1.ensureArray)(parentPattern.nodeType);
42
+ // Si name est spécifié, chercher dans les ancêtres une VariableDeclaration qui matche
43
+ if (parentPattern.name) {
44
+ let current = node.getParent();
45
+ while (current) {
46
+ const currentKind = current.getKindName();
47
+ if (parentNodeTypes.includes(currentKind)) {
48
+ // Vérifier si ce nœud a le nom recherché
49
+ if (ts_morph_1.Node.isVariableDeclaration(current)) {
50
+ const varName = current.getName();
51
+ const expectedNames = (0, matcher_helpers_1.ensureArray)(parentPattern.name);
52
+ if (expectedNames.includes(varName)) {
53
+ return true;
54
+ }
55
+ }
56
+ else if (ts_morph_1.Node.isVariableStatement(current)) {
57
+ // Pour VariableStatement, vérifier les déclarations
58
+ const declarations = current.getDeclarations();
59
+ const expectedNames = (0, matcher_helpers_1.ensureArray)(parentPattern.name);
60
+ const hasMatchingName = declarations.some(decl => expectedNames.includes(decl.getName()));
61
+ if (hasMatchingName) {
62
+ return true;
63
+ }
64
+ }
65
+ }
66
+ current = current.getParent();
67
+ }
68
+ return false;
69
+ }
70
+ // Si pas de name, vérifier seulement le nodeType du parent immédiat
71
+ const parentKind = parent.getKindName();
72
+ if (!parentNodeTypes.includes(parentKind)) {
73
+ return false;
74
+ }
75
+ }
76
+ // Vérifier initializer (pour PropertyDeclaration) APRÈS avoir vérifié le nodeType
77
+ if (parentPattern.initializer && ts_morph_1.Node.isPropertyDeclaration(parent)) {
78
+ const initializer = parent.getInitializer();
79
+ if (!initializer) {
80
+ return false;
81
+ }
82
+ // Vérifier récursivement l'initializer
83
+ if (!matchesAstPatternFn(initializer, parentPattern.initializer)) {
84
+ return false;
85
+ }
86
+ // Si l'initializer matche, on retourne true (pas besoin de vérifier tout le parent)
87
+ return true;
88
+ }
89
+ return matchesAstPatternFn(parent, parentPattern);
90
+ }
91
+ /**
92
+ * Vérifie si le nœud est dans une classe avec les décorateurs spécifiés
93
+ */
94
+ function matchesInClass(node, classPattern, matchesAstPatternFn) {
95
+ let current = node.getParent();
96
+ while (current) {
97
+ if (ts_morph_1.Node.isClassDeclaration(current)) {
98
+ // Vérifier hasDecorator
99
+ if (classPattern.hasDecorator) {
100
+ const decorators = current.getDecorators();
101
+ const decoratorNames = decorators.map(d => {
102
+ const expr = d.getExpression();
103
+ if (ts_morph_1.Node.isCallExpression(expr)) {
104
+ return expr.getExpression().getText();
105
+ }
106
+ return expr.getText();
107
+ });
108
+ const hasRequiredDecorator = classPattern.hasDecorator.some((name) => decoratorNames.includes(name));
109
+ if (!hasRequiredDecorator) {
110
+ return false;
111
+ }
112
+ }
113
+ return matchesAstPatternFn(current, classPattern);
114
+ }
115
+ current = current.getParent();
116
+ }
117
+ return false;
118
+ }
119
+ /**
120
+ * Vérifie un ancêtre dans l'arbre AST
121
+ */
122
+ function matchesAncestor(node, ancestorPattern, matchesAstPatternFn) {
123
+ let current = node.getParent();
124
+ while (current) {
125
+ if (matchesAstPatternFn(current, ancestorPattern)) {
126
+ return true;
127
+ }
128
+ current = current.getParent();
129
+ }
130
+ return false;
131
+ }
132
+ /**
133
+ * Vérifie si le nœud implémente une interface
134
+ */
135
+ function matchesImplements(node, interfaceName) {
136
+ if (!ts_morph_1.Node.isClassDeclaration(node)) {
137
+ return false;
138
+ }
139
+ const implementsClauses = node.getImplements();
140
+ return implementsClauses.some(clause => {
141
+ const text = clause.getText();
142
+ // Matcher l'interface avec ou sans génériques (ex: "Resolve" matche "Resolve<User>")
143
+ return text === interfaceName || text.startsWith(interfaceName + '<');
144
+ });
145
+ }
146
+ /**
147
+ * Vérifie si le nœud implémente une interface générique manquante
148
+ */
149
+ function matchesImplementsGeneric(node, implementsGenericPattern) {
150
+ if (!ts_morph_1.Node.isClassDeclaration(node)) {
151
+ return false;
152
+ }
153
+ const implementsClauses = node.getImplements();
154
+ if (implementsGenericPattern.missing) {
155
+ const missingType = implementsGenericPattern.missing;
156
+ // Vérifier qu'aucune clause implements ne contient le type manquant dans ses génériques
157
+ const hasGeneric = implementsClauses.some(clause => {
158
+ const text = clause.getText();
159
+ // Vérifier si le type manquant est présent dans la partie générique (entre < et >)
160
+ const genericMatch = text.match(/<([^>]+)>/);
161
+ if (genericMatch) {
162
+ const genericsText = genericMatch[1];
163
+ // Vérifier si le type manquant apparaît dans les génériques (avec ou sans espaces)
164
+ return genericsText.includes(missingType);
165
+ }
166
+ return false;
167
+ });
168
+ // On veut que le type soit absent, donc on retourne true si hasGeneric est false
169
+ return !hasGeneric;
170
+ }
171
+ return true;
172
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.matchesModuleSpecifier = matchesModuleSpecifier;
4
+ exports.matchesNamedImports = matchesNamedImports;
5
+ const ts_morph_1 = require("ts-morph");
6
+ /**
7
+ * Vérifie le module specifier d'une ImportDeclaration
8
+ */
9
+ function matchesModuleSpecifier(node, moduleSpecifier) {
10
+ if (!ts_morph_1.Node.isImportDeclaration(node)) {
11
+ return false;
12
+ }
13
+ const moduleSpec = node.getModuleSpecifierValue();
14
+ return moduleSpec === moduleSpecifier;
15
+ }
16
+ /**
17
+ * Vérifie les named imports (contains, containsAny)
18
+ */
19
+ function matchesNamedImports(node, namedImports) {
20
+ if (!ts_morph_1.Node.isImportDeclaration(node)) {
21
+ return false;
22
+ }
23
+ const importClause = node.getImportClause();
24
+ if (!importClause) {
25
+ return false;
26
+ }
27
+ const namedBindings = importClause.getNamedBindings();
28
+ if (!namedBindings || !ts_morph_1.Node.isNamedImports(namedBindings)) {
29
+ return false;
30
+ }
31
+ const importNames = namedBindings.getElements().map(el => el.getName());
32
+ if (namedImports.contains) {
33
+ return importNames.includes(namedImports.contains);
34
+ }
35
+ if (namedImports.containsAny) {
36
+ return namedImports.containsAny.some(name => importNames.includes(name));
37
+ }
38
+ return false;
39
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * Index centralisé des matchers TypeScript AST
4
+ * Regroupe tous les matchers pour analyse de code TypeScript
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.clearContextCaches = exports.FileMatcher = exports.CollectionMatcher = exports.TypeMatcher = exports.ExpressionMatcher = exports.HierarchyMatcher = exports.DecoratorMatcher = exports.ImportMatcher = exports.ContextMatcher = exports.NodeMatcher = void 0;
41
+ // Export all TypeScript matchers
42
+ exports.NodeMatcher = __importStar(require("./node-matcher"));
43
+ exports.ContextMatcher = __importStar(require("./context-matcher"));
44
+ exports.ImportMatcher = __importStar(require("./import-matcher"));
45
+ exports.DecoratorMatcher = __importStar(require("./decorator-matcher"));
46
+ exports.HierarchyMatcher = __importStar(require("./hierarchy-matcher"));
47
+ exports.ExpressionMatcher = __importStar(require("./expression-matcher"));
48
+ exports.TypeMatcher = __importStar(require("./type-matcher"));
49
+ exports.CollectionMatcher = __importStar(require("./collection-matcher"));
50
+ exports.FileMatcher = __importStar(require("./file-matcher"));
51
+ // Export clearContextCaches pour gestion mémoire
52
+ var context_matcher_1 = require("./context-matcher");
53
+ Object.defineProperty(exports, "clearContextCaches", { enumerable: true, get: function () { return context_matcher_1.clearContextCaches; } });