api-tests-coverage 1.0.16 → 1.0.18

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 (135) hide show
  1. package/dist/dashboard/dist/assets/_basePickBy-CYB1KXah.js +1 -0
  2. package/dist/dashboard/dist/assets/_baseUniq-Bwm426M6.js +1 -0
  3. package/dist/dashboard/dist/assets/arc-B7p8x22e.js +1 -0
  4. package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-wVr1_uNB.js +36 -0
  5. package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-BBXc88fn.js +122 -0
  6. package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-BsgzPfQ3.js +10 -0
  7. package/dist/dashboard/dist/assets/channel-psxgcQ_j.js +1 -0
  8. package/dist/dashboard/dist/assets/chunk-4BX2VUAB-BF8loPLD.js +1 -0
  9. package/dist/dashboard/dist/assets/chunk-55IACEB6-C3HNF-UF.js +1 -0
  10. package/dist/dashboard/dist/assets/chunk-B4BG7PRW-wQ6TCEMq.js +165 -0
  11. package/dist/dashboard/dist/assets/chunk-DI55MBZ5-B7xHuqZu.js +220 -0
  12. package/dist/dashboard/dist/assets/chunk-FMBD7UC4-K3PC79JF.js +15 -0
  13. package/dist/dashboard/dist/assets/chunk-QN33PNHL-CmeZ1h1Z.js +1 -0
  14. package/dist/dashboard/dist/assets/chunk-QZHKN3VN-Cyg7Km90.js +1 -0
  15. package/dist/dashboard/dist/assets/chunk-TZMSLE5B-C8KNXDi7.js +1 -0
  16. package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-AMwn99HP.js +1 -0
  17. package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-AMwn99HP.js +1 -0
  18. package/dist/dashboard/dist/assets/clone-KEkbvJY9.js +1 -0
  19. package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-YL9kFxCl.js +1 -0
  20. package/dist/dashboard/dist/assets/dagre-6UL2VRFP-NZWnQN_Y.js +4 -0
  21. package/dist/dashboard/dist/assets/diagram-PSM6KHXK-DGtyS7lD.js +24 -0
  22. package/dist/dashboard/dist/assets/diagram-QEK2KX5R-CSCGZUfr.js +43 -0
  23. package/dist/dashboard/dist/assets/diagram-S2PKOQOG-DdqZVGN1.js +24 -0
  24. package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-Dhb_VQMS.js +60 -0
  25. package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-gKUH-GJ2.js +162 -0
  26. package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-Dm_lLo9y.js +267 -0
  27. package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-DM9AW1aP.js +65 -0
  28. package/dist/dashboard/dist/assets/graph-Clj85F2M.js +1 -0
  29. package/dist/dashboard/dist/assets/index-CqEIqNus.js +781 -0
  30. package/dist/dashboard/dist/assets/index-xecKLQ58.css +1 -0
  31. package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-BMp4C5wf.js +2 -0
  32. package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-BC0GSZ7W.js +139 -0
  33. package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-D6aRd_q1.js +89 -0
  34. package/dist/dashboard/dist/assets/layout-BbJNDkTr.js +1 -0
  35. package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-B93XW27v.js +68 -0
  36. package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-9G1tEuaq.js +30 -0
  37. package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-jDtdB4Ws.js +7 -0
  38. package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-WIJ0qiJG.js +64 -0
  39. package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-Cb4WB9UB.js +10 -0
  40. package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-BqGJWVUS.js +145 -0
  41. package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-0Wd-KmOv.js +1 -0
  42. package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-BlwaoFEG.js +1 -0
  43. package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-CAmQOjBu.js +61 -0
  44. package/dist/dashboard/dist/assets/treemap-GDKQZRPO-CRP-WvE-.js +162 -0
  45. package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-5DoR2_q5.js +7 -0
  46. package/dist/dashboard/dist/index.html +2 -2
  47. package/dist/src/config/defaultConfig.d.ts.map +1 -1
  48. package/dist/src/config/defaultConfig.js +37 -0
  49. package/dist/src/config/types.d.ts +42 -0
  50. package/dist/src/config/types.d.ts.map +1 -1
  51. package/dist/src/config/validateConfig.d.ts.map +1 -1
  52. package/dist/src/config/validateConfig.js +3 -0
  53. package/dist/src/discovery/fileClassifier.d.ts.map +1 -1
  54. package/dist/src/discovery/fileClassifier.js +15 -16
  55. package/dist/src/discovery/projectDiscovery.d.ts.map +1 -1
  56. package/dist/src/discovery/projectDiscovery.js +4 -1
  57. package/dist/src/generation/ai-flow-exporter.d.ts +7 -0
  58. package/dist/src/generation/ai-flow-exporter.d.ts.map +1 -0
  59. package/dist/src/generation/ai-flow-exporter.js +260 -0
  60. package/dist/src/generation/context-builder.d.ts +16 -0
  61. package/dist/src/generation/context-builder.d.ts.map +1 -0
  62. package/dist/src/generation/context-builder.js +170 -0
  63. package/dist/src/generation/engine.d.ts +19 -0
  64. package/dist/src/generation/engine.d.ts.map +1 -0
  65. package/dist/src/generation/engine.js +204 -0
  66. package/dist/src/generation/file-router.d.ts +8 -0
  67. package/dist/src/generation/file-router.d.ts.map +1 -0
  68. package/dist/src/generation/file-router.js +98 -0
  69. package/dist/src/generation/gap-extractor.d.ts +7 -0
  70. package/dist/src/generation/gap-extractor.d.ts.map +1 -0
  71. package/dist/src/generation/gap-extractor.js +291 -0
  72. package/dist/src/generation/index.d.ts +9 -0
  73. package/dist/src/generation/index.d.ts.map +1 -0
  74. package/dist/src/generation/index.js +15 -0
  75. package/dist/src/generation/quality-scorer.d.ts +15 -0
  76. package/dist/src/generation/quality-scorer.d.ts.map +1 -0
  77. package/dist/src/generation/quality-scorer.js +273 -0
  78. package/dist/src/generation/template-renderer.d.ts +12 -0
  79. package/dist/src/generation/template-renderer.d.ts.map +1 -0
  80. package/dist/src/generation/template-renderer.js +546 -0
  81. package/dist/src/generation/types.d.ts +269 -0
  82. package/dist/src/generation/types.d.ts.map +1 -0
  83. package/dist/src/generation/types.js +6 -0
  84. package/dist/src/index.js +113 -0
  85. package/dist/src/languages/java/semanticBuilder.d.ts.map +1 -1
  86. package/dist/src/languages/java/semanticBuilder.js +69 -12
  87. package/dist/src/languages/javascript/angularDetector.d.ts.map +1 -1
  88. package/dist/src/languages/javascript/angularDetector.js +50 -17
  89. package/dist/src/languages/javascript/assertionResolver.js +6 -4
  90. package/dist/src/languages/javascript/hapiDetector.d.ts.map +1 -1
  91. package/dist/src/languages/javascript/hapiDetector.js +48 -5
  92. package/dist/src/languages/javascript/vueDetector.d.ts +2 -0
  93. package/dist/src/languages/javascript/vueDetector.d.ts.map +1 -1
  94. package/dist/src/languages/javascript/vueDetector.js +22 -0
  95. package/dist/src/languages/python/index.d.ts +1 -1
  96. package/dist/src/languages/python/index.d.ts.map +1 -1
  97. package/dist/src/languages/python/index.js +33 -3
  98. package/dist/src/pipeline/confidence.d.ts +6 -1
  99. package/dist/src/pipeline/confidence.d.ts.map +1 -1
  100. package/dist/src/pipeline/confidence.js +8 -3
  101. package/dist/src/pipeline/graph.d.ts.map +1 -1
  102. package/dist/src/pipeline/graph.js +16 -4
  103. package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -1
  104. package/dist/src/pipeline/stages/ast/astStage.js +46 -2
  105. package/dist/src/pipeline/stages/ast/baseUrlComposer.d.ts.map +1 -1
  106. package/dist/src/pipeline/stages/ast/baseUrlComposer.js +18 -4
  107. package/dist/src/pipeline/stages/ast/crossFileResolver.js +29 -0
  108. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -1
  109. package/dist/src/pipeline/stages/ast/graphBuilder.js +81 -0
  110. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.d.ts +3 -1
  111. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.d.ts.map +1 -1
  112. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.js +34 -14
  113. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.d.ts.map +1 -1
  114. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.js +22 -3
  115. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.d.ts.map +1 -1
  116. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.js +104 -28
  117. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.d.ts.map +1 -1
  118. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.js +56 -0
  119. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.d.ts.map +1 -1
  120. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.js +43 -18
  121. package/dist/src/pipeline/stages/ast/rulesEnforcer.d.ts.map +1 -1
  122. package/dist/src/pipeline/stages/ast/rulesEnforcer.js +336 -45
  123. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +2 -0
  124. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -1
  125. package/dist/src/pipeline/stages/merge/conflictDetector.js +54 -2
  126. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -1
  127. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +67 -3
  128. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -1
  129. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +8 -1
  130. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +8 -4
  131. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -1
  132. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +36 -10
  133. package/dist/src/pipeline/types.d.ts +1 -1
  134. package/dist/src/pipeline/types.d.ts.map +1 -1
  135. package/package.json +3 -3
@@ -60,6 +60,28 @@ function buildAstGraph(models, crossFileTable, traversalResults, interactions) {
60
60
  addedEdgeIds.add(edge.id);
61
61
  edges.push(edge);
62
62
  }
63
+ /**
64
+ * Ensure a node exists in the graph. If the node ID is not yet present,
65
+ * create a stub node flagged as cross-file-unresolved (spec §2.3).
66
+ * Confidence on stub nodes is capped at 'low'.
67
+ */
68
+ function ensureNodeExists(nodeId, missingFilePath, nodeType) {
69
+ if (addedNodeIds.has(nodeId))
70
+ return nodeId;
71
+ addNode({
72
+ id: nodeId,
73
+ type: nodeType,
74
+ label: `[unresolved] ${path.basename(missingFilePath)}`,
75
+ sourceStage: 'ast',
76
+ filePath: missingFilePath,
77
+ metadata: {
78
+ resolution: 'cross-file-unresolved',
79
+ confidence: 'low',
80
+ diagnostic: `Cross-file resolution failed: file "${missingFilePath}" was not found in parsed models`,
81
+ },
82
+ });
83
+ return nodeId;
84
+ }
63
85
  // 1. Create file nodes for every parsed file
64
86
  for (const [filePath, model] of models) {
65
87
  const basename = path.basename(filePath);
@@ -241,6 +263,65 @@ function buildAstGraph(models, crossFileTable, traversalResults, interactions) {
241
263
  });
242
264
  }
243
265
  }
266
+ // 7. Feature 27: Create router mount edges
267
+ for (const [filePath, mounts] of crossFileTable.routerMounts) {
268
+ const sourceId = `file:${filePath}`;
269
+ if (!addedNodeIds.has(sourceId))
270
+ continue;
271
+ for (const mount of mounts) {
272
+ const targetId = `file:${mount.targetModulePath}`;
273
+ // Create edge even if target not parsed (creates stub node for missing files)
274
+ addEdge({
275
+ id: `${sourceId}->mounts->${mount.prefix}:${mount.targetModulePath}`,
276
+ type: 'router-mount',
277
+ sourceNodeId: sourceId,
278
+ targetNodeId: ensureNodeExists(targetId, mount.targetModulePath, 'file'),
279
+ sourceStage: 'ast',
280
+ metadata: {
281
+ prefix: mount.prefix,
282
+ targetModule: mount.targetModulePath,
283
+ middlewareCount: mount.middleware.length,
284
+ },
285
+ });
286
+ }
287
+ }
288
+ // 8. Feature 27: Create injection chain edges
289
+ for (const [consumerFile, chains] of crossFileTable.injectionChains) {
290
+ for (const chain of chains) {
291
+ const consumerNodeId = `file:${chain.consumerFile}`;
292
+ const serviceNodeId = `file:${chain.serviceFile}`;
293
+ addEdge({
294
+ id: `${consumerNodeId}->injects->${chain.serviceClass}:${chain.serviceFile}`,
295
+ type: 'injects',
296
+ sourceNodeId: ensureNodeExists(consumerNodeId, chain.consumerFile, 'file'),
297
+ targetNodeId: ensureNodeExists(serviceNodeId, chain.serviceFile, 'file'),
298
+ sourceStage: 'ast',
299
+ metadata: {
300
+ consumerClass: chain.consumerClass,
301
+ serviceClass: chain.serviceClass,
302
+ injectionStyle: chain.injectionStyle,
303
+ },
304
+ });
305
+ }
306
+ }
307
+ // 9. Feature 27: Create interface implementation edges
308
+ for (const [ifaceFile, impls] of crossFileTable.interfaceImplementations) {
309
+ for (const impl of impls) {
310
+ const ifaceNodeId = `file:${impl.interfaceFile}`;
311
+ const implNodeId = `file:${impl.implFile}`;
312
+ addEdge({
313
+ id: `${implNodeId}->implements->${impl.interfaceName}:${impl.interfaceFile}`,
314
+ type: 'implements',
315
+ sourceNodeId: ensureNodeExists(implNodeId, impl.implFile, 'file'),
316
+ targetNodeId: ensureNodeExists(ifaceNodeId, impl.interfaceFile, 'file'),
317
+ sourceStage: 'ast',
318
+ metadata: {
319
+ interfaceName: impl.interfaceName,
320
+ implName: impl.implName,
321
+ },
322
+ });
323
+ }
324
+ }
244
325
  return { nodes, edges };
245
326
  }
246
327
  /**
@@ -7,7 +7,9 @@
7
7
  * Express auth.optional / credentialsRequired: false → { optional: true }
8
8
  * HapiJS auth: { mode: 'try' } → { optional: true }
9
9
  * Spring @PreAuthorize → { required: true }
10
- * Angular route guarddepends on guard type
10
+ * Slim PHP optionalAuth{ optional: true }, jwt/auth → { required: true }
11
+ * Angular canActivate:none → { optional: true } (interceptor-based)
12
+ * NestJS @UseGuards → { required: true }
11
13
  */
12
14
  import type { SecurityClassification } from '../../../ast/astTypes';
13
15
  export interface AuthClassificationEntry {
@@ -1 +1 @@
1
- {"version":3,"file":"optionalAuthUnifier.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/optionalAuthUnifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,sBAAsB,CAAC;CACxC;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,sBAAsB,GAAG,SAAS,CAwCpC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,kBAAkB,GAAG,4BAA4B,CAAC;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,sBAAsB,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,EACzF,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC9B,eAAe,EAAE,CA0BnB"}
1
+ {"version":3,"file":"optionalAuthUnifier.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/optionalAuthUnifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,sBAAsB,CAAC;CACxC;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,sBAAsB,GAAG,SAAS,CA6DpC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,kBAAkB,GAAG,4BAA4B,CAAC;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,sBAAsB,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,EACzF,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC9B,eAAe,EAAE,CA0BnB"}
@@ -8,7 +8,9 @@
8
8
  * Express auth.optional / credentialsRequired: false → { optional: true }
9
9
  * HapiJS auth: { mode: 'try' } → { optional: true }
10
10
  * Spring @PreAuthorize → { required: true }
11
- * Angular route guarddepends on guard type
11
+ * Slim PHP optionalAuth{ optional: true }, jwt/auth → { required: true }
12
+ * Angular canActivate:none → { optional: true } (interceptor-based)
13
+ * NestJS @UseGuards → { required: true }
12
14
  */
13
15
  Object.defineProperty(exports, "__esModule", { value: true });
14
16
  exports.unifyAuthClassification = unifyAuthClassification;
@@ -18,36 +20,54 @@ exports.detectAuthCoverageGaps = detectAuthCoverageGaps;
18
20
  */
19
21
  function unifyAuthClassification(framework, pattern) {
20
22
  const key = `${framework}:${pattern}`.toLowerCase();
21
- // Flask patterns
22
- if (key.includes('flask:@jwt_required') || key.includes('flask:jwt_required')) {
23
+ // Flask patterns — use word-boundary regex to avoid matching e.g. "@jwt_required_custom"
24
+ if (/^flask:@?jwt_required\b/.test(key)) {
23
25
  return { type: 'jwt', required: true, optional: false, sourcePattern: pattern };
24
26
  }
25
- if (key.includes('flask:@jwt_optional') || key.includes('flask:jwt_optional')) {
27
+ if (/^flask:@?jwt_optional\b/.test(key)) {
26
28
  return { type: 'jwt', required: false, optional: true, sourcePattern: pattern };
27
29
  }
28
- if (key.includes('flask:@login_required') || key.includes('flask:login_required')) {
30
+ if (/^flask:@?login_required\b/.test(key)) {
29
31
  return { type: 'session', required: true, optional: false, sourcePattern: pattern };
30
32
  }
31
- // Express patterns
32
- if (key.includes('express:auth.required') || key.includes('express:credentialsrequired: true')) {
33
+ // Express patterns — use word-boundary regex for precise matching
34
+ if (/^express:auth\.required\b/.test(key) || /^express:credentialsrequired:\s*true\b/.test(key)) {
33
35
  return { type: 'jwt', required: true, optional: false, sourcePattern: pattern };
34
36
  }
35
- if (key.includes('express:auth.optional') || key.includes('express:credentialsrequired: false')) {
37
+ if (/^express:auth\.optional\b/.test(key) || /^express:credentialsrequired:\s*false\b/.test(key)) {
36
38
  return { type: 'jwt', required: false, optional: true, sourcePattern: pattern };
37
39
  }
38
- if (key.includes('express:passport.authenticate')) {
40
+ if (/^express:passport\.authenticate\b/.test(key)) {
39
41
  return { type: 'jwt', required: true, optional: false, sourcePattern: pattern };
40
42
  }
41
43
  // HapiJS patterns (framework may be 'hapi' or 'hapijs')
42
- const isHapi = key.startsWith('hapi:') || key.startsWith('hapijs:');
43
- if (isHapi && key.includes('auth') && key.includes('mode') && (key.includes('try') || key.includes('optional'))) {
44
+ const isHapi = /^hapi(?:js)?:/.test(key);
45
+ if (isHapi && /\bauth\b/.test(key) && /\bmode\b/.test(key) && (/\btry\b/.test(key) || /\boptional\b/.test(key))) {
44
46
  return { type: 'jwt', required: false, optional: true, sourcePattern: pattern };
45
47
  }
46
- if (isHapi && key.includes('auth') && !key.includes('false') && !key.includes('try') && !key.includes('optional')) {
48
+ if (isHapi && /\bauth\b/.test(key) && !/\bfalse\b/.test(key) && !/\btry\b/.test(key) && !/\boptional\b/.test(key)) {
47
49
  return { type: 'jwt', required: true, optional: false, sourcePattern: pattern };
48
50
  }
49
- // Spring patterns
50
- if (key.includes('spring:@preauthorize') || key.includes('spring:@secured')) {
51
+ // Spring patterns — include @RolesAllowed and @WithMockUser
52
+ if (/^spring:@?preauthorize\b/.test(key) || /^spring:@?secured\b/.test(key) || /^spring:@?rolesallowed\b/.test(key)) {
53
+ return { type: 'custom', required: true, optional: false, sourcePattern: pattern };
54
+ }
55
+ if (/^spring:@?withmockuser\b/.test(key)) {
56
+ return { type: 'custom', required: true, optional: false, sourcePattern: pattern };
57
+ }
58
+ // Slim PHP patterns — slim:optionalAuth is optional, slim:jwt or slim:auth is required
59
+ if (/^slim:optionalauth\b/.test(key)) {
60
+ return { type: 'jwt', required: false, optional: true, sourcePattern: pattern };
61
+ }
62
+ if (/^slim:(?:jwt|auth)\b/.test(key)) {
63
+ return { type: 'jwt', required: true, optional: false, sourcePattern: pattern };
64
+ }
65
+ // Angular patterns — canActivate:none (no guard) with interceptor tokens is optional
66
+ if (/^angular:canactivate:none\b/.test(key)) {
67
+ return { type: 'custom', required: false, optional: true, sourcePattern: pattern };
68
+ }
69
+ // NestJS patterns — @UseGuards is required auth
70
+ if (/^nestjs:@?useguards\b/.test(key)) {
51
71
  return { type: 'custom', required: true, optional: false, sourcePattern: pattern };
52
72
  }
53
73
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"angularInjectionResolver.d.ts","sourceRoot":"","sources":["../../../../../../src/pipeline/stages/ast/resolvers/angularInjectionResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAEpF,qBAAa,wBAAyB,YAAW,iBAAiB;IAChE,QAAQ,CAAC,IAAI,uBAAuB;IAEpC,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO;IAItD,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB;CA0CpE"}
1
+ {"version":3,"file":"angularInjectionResolver.d.ts","sourceRoot":"","sources":["../../../../../../src/pipeline/stages/ast/resolvers/angularInjectionResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAEpF,qBAAa,wBAAyB,YAAW,iBAAiB;IAChE,QAAQ,CAAC,IAAI,uBAAuB;IAEpC,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO;IAItD,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB;CAyCpE"}
@@ -24,9 +24,7 @@ class AngularInjectionResolver {
24
24
  const unresolvedRefs = [];
25
25
  // Build injection chains from class registry
26
26
  for (const [className, classInfo] of ctx.symbolTable.classes) {
27
- // If class implements interfaces, it may be a service
28
- if (!classInfo.implementsInterfaces)
29
- continue;
27
+ // Check any class that has a model Angular services typically don't implement interfaces
30
28
  // Look for classes that have methods making HTTP calls
31
29
  const model = ctx.symbolTable.models.get(classInfo.filePath);
32
30
  if (!model)
@@ -73,5 +71,26 @@ function findConsumers(serviceName, ctx) {
73
71
  }
74
72
  }
75
73
  }
74
+ // Fallback: search class registry for classes that might inject this service
75
+ // (constructor injection detected by parameter name matching)
76
+ for (const [className, classInfo] of ctx.symbolTable.classes) {
77
+ // Skip if already found as a consumer
78
+ if (consumers.some((c) => c.className === className && c.file === classInfo.filePath))
79
+ continue;
80
+ // Check if this class's model has the service name in its calledFunctions
81
+ const model = ctx.symbolTable.models.get(classInfo.filePath);
82
+ if (!model)
83
+ continue;
84
+ for (const [, func] of model.functions) {
85
+ if (func.calledFunctions.some((f) => f.includes(serviceName))) {
86
+ consumers.push({
87
+ className,
88
+ file: classInfo.filePath,
89
+ style: 'constructor',
90
+ });
91
+ break;
92
+ }
93
+ }
94
+ }
76
95
  return consumers;
77
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dddLayerResolver.d.ts","sourceRoot":"","sources":["../../../../../../src/pipeline/stages/ast/resolvers/dddLayerResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAEpF,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IAC3C,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,QAAQ,CAAC,IAAI,eAAe;IAE5B,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO;IAMtD,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB;CAqEpE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,sBAAsB,EAAE,CAgFrG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAiCrF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAcjG"}
1
+ {"version":3,"file":"dddLayerResolver.d.ts","sourceRoot":"","sources":["../../../../../../src/pipeline/stages/ast/resolvers/dddLayerResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAEpF,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IAC3C,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,QAAQ,CAAC,IAAI,eAAe;IAE5B,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO;IAMtD,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB;CA+JpE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,sBAAsB,EAAE,CAgFrG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAiCrF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAcjG"}
@@ -28,23 +28,80 @@ class DddLayerResolver {
28
28
  const repoInterfaces = [];
29
29
  const cqrsHandlers = [];
30
30
  const implementations = new Map();
31
- for (const [filePath, model] of ctx.symbolTable.models) {
32
- const sourceText = getSourceText(filePath, ctx);
33
- if (!sourceText)
31
+ // ----- Detect from class registry and semantic models -----
32
+ // 1. Detect repository interfaces from class registry
33
+ for (const [className, classDecl] of ctx.symbolTable.classes) {
34
+ const isRepoByName = /(?:Repository|Repo|Store|Gateway)$/.test(className);
35
+ const repoMethods = classDecl.methods.filter(m => /^(?:findBy\w+|find\w+|save|saveAll|delete|deleteById|existsBy\w+|countBy\w+|getBy\w+)$/.test(m));
36
+ if (isRepoByName && repoMethods.length > 0) {
37
+ repoInterfaces.push({
38
+ interfaceName: className,
39
+ methods: repoMethods,
40
+ sourceFile: classDecl.filePath,
41
+ line: classDecl.line,
42
+ });
43
+ }
44
+ else if (!isRepoByName && repoMethods.length >= 2) {
45
+ // Generic interface with enough repository-like methods
46
+ repoInterfaces.push({
47
+ interfaceName: className,
48
+ methods: repoMethods,
49
+ sourceFile: classDecl.filePath,
50
+ line: classDecl.line,
51
+ });
52
+ }
53
+ }
54
+ // 2. Detect CQRS handlers from class registry + semantic models
55
+ for (const [className, classDecl] of ctx.symbolTable.classes) {
56
+ const model = ctx.symbolTable.models.get(classDecl.filePath);
57
+ if (!model)
58
+ continue;
59
+ for (const methodName of classDecl.methods) {
60
+ if (methodName !== 'execute' && methodName !== 'handle' && methodName !== 'apply')
61
+ continue;
62
+ // Determine handler type from class name or method context
63
+ let handlerType = 'command';
64
+ if (/Query/.test(className))
65
+ handlerType = 'query';
66
+ else if (/Event/.test(className))
67
+ handlerType = 'event';
68
+ // Try to get parameter type from the function's annotations or the class name
69
+ const func = model.functions.get(methodName);
70
+ let parameterType = `${className.replace(/Handler$/, '')}`;
71
+ if (func === null || func === void 0 ? void 0 : func.annotations) {
72
+ // Check for annotations that hint at the command/query type
73
+ for (const ann of func.annotations) {
74
+ const typeMatch = ann.match(/(\w+(?:Command|Query|Event))/);
75
+ if (typeMatch) {
76
+ parameterType = typeMatch[1];
77
+ if (/Command$/.test(parameterType))
78
+ handlerType = 'command';
79
+ else if (/Query$/.test(parameterType))
80
+ handlerType = 'query';
81
+ else if (/Event$/.test(parameterType))
82
+ handlerType = 'event';
83
+ }
84
+ }
85
+ }
86
+ cqrsHandlers.push({
87
+ className,
88
+ handlerType,
89
+ handleMethodName: methodName,
90
+ parameterType,
91
+ sourceFile: classDecl.filePath,
92
+ line: classDecl.line,
93
+ });
94
+ }
95
+ }
96
+ // 3. Detect implements clauses from class registry (already parsed by tree-sitter)
97
+ for (const [className, classDecl] of ctx.symbolTable.classes) {
98
+ if (!classDecl.implementsInterfaces || classDecl.implementsInterfaces.length === 0)
34
99
  continue;
35
- // Detect repository interfaces
36
- const repos = detectRepositoryInterfaces(sourceText, filePath);
37
- repoInterfaces.push(...repos);
38
- // Detect CQRS handlers
39
- const handlers = detectCqrsHandlers(sourceText, filePath);
40
- cqrsHandlers.push(...handlers);
41
- // Detect implements clauses
42
- const impls = detectImplementsClauses(sourceText, filePath);
43
- for (const [ifaceName, implName] of impls) {
44
- if (!implementations.has(ifaceName)) {
45
- implementations.set(ifaceName, []);
100
+ for (const iface of classDecl.implementsInterfaces) {
101
+ if (!implementations.has(iface)) {
102
+ implementations.set(iface, []);
46
103
  }
47
- implementations.get(ifaceName).push(implName);
104
+ implementations.get(iface).push(className);
48
105
  }
49
106
  }
50
107
  // Map interface → implementation in symbolTable
@@ -72,6 +129,38 @@ class DddLayerResolver {
72
129
  }
73
130
  }
74
131
  }
132
+ // Write repository interfaces into symbolTable (Section 5.3)
133
+ for (const repo of repoInterfaces) {
134
+ const key = repo.sourceFile;
135
+ if (!ctx.symbolTable.interfaceImplementations.has(key)) {
136
+ ctx.symbolTable.interfaceImplementations.set(key, []);
137
+ }
138
+ const existing = ctx.symbolTable.interfaceImplementations.get(key);
139
+ const alreadyMapped = existing.some(e => e.interfaceName === repo.interfaceName);
140
+ if (!alreadyMapped) {
141
+ existing.push({
142
+ interfaceName: repo.interfaceName,
143
+ interfaceFile: repo.sourceFile,
144
+ implName: '',
145
+ implFile: '',
146
+ });
147
+ entriesAdded++;
148
+ }
149
+ }
150
+ // Write CQRS handlers as service-layer entries into symbolTable (Section 5.2)
151
+ for (const handler of cqrsHandlers) {
152
+ const key = handler.sourceFile;
153
+ if (!ctx.symbolTable.interfaceImplementations.has(key)) {
154
+ ctx.symbolTable.interfaceImplementations.set(key, []);
155
+ }
156
+ ctx.symbolTable.interfaceImplementations.get(key).push({
157
+ interfaceName: handler.parameterType,
158
+ interfaceFile: handler.sourceFile,
159
+ implName: handler.className,
160
+ implFile: handler.sourceFile,
161
+ });
162
+ entriesAdded++;
163
+ }
75
164
  if (repoInterfaces.length > 0) {
76
165
  diagnostics.push(`Found ${repoInterfaces.length} repository interface(s)`);
77
166
  }
@@ -211,19 +300,6 @@ function detectImplementsClauses(source, filePath) {
211
300
  }
212
301
  return impls;
213
302
  }
214
- function getSourceText(filePath, ctx) {
215
- // Try to get content from models (stored as raw source in semantic model)
216
- // For now, we scan from the model's functions and other extracted data
217
- // to detect patterns. In practice, we use regex on the raw source.
218
- // If the model has functions, we have some content available.
219
- const model = ctx.symbolTable.models.get(filePath);
220
- if (!model)
221
- return undefined;
222
- // We return a synthetic source text reconstructed from available data.
223
- // In a full implementation, we'd cache the raw source from the parse stage.
224
- // For now, return undefined to indicate we can't access raw source from the symbol table.
225
- return undefined;
226
- }
227
303
  function findFileForClass(className, ctx) {
228
304
  // Search through exported symbols and class registry
229
305
  const classInfo = ctx.symbolTable.classes.get(className);
@@ -1 +1 @@
1
- {"version":3,"file":"mybatisResolver.d.ts","sourceRoot":"","sources":["../../../../../../src/pipeline/stages/ast/resolvers/mybatisResolver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAEpF,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,qBAAa,eAAgB,YAAW,iBAAiB;IACvD,QAAQ,CAAC,IAAI,aAAa;IAE1B,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO;IAItD,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB;CAgEpE"}
1
+ {"version":3,"file":"mybatisResolver.d.ts","sourceRoot":"","sources":["../../../../../../src/pipeline/stages/ast/resolvers/mybatisResolver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAIpF,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,qBAAa,eAAgB,YAAW,iBAAiB;IACvD,QAAQ,CAAC,IAAI,aAAa;IAE1B,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO;IAItD,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB;CAmFpE"}
@@ -6,8 +6,43 @@
6
6
  * - @Mapper interface FQCN ↔ <mapper namespace="..."> in XML
7
7
  * - Interface method names ↔ <select id="...">, <insert id="...">, etc.
8
8
  */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
9
42
  Object.defineProperty(exports, "__esModule", { value: true });
10
43
  exports.MyBatisResolver = void 0;
44
+ const mybatisXmlParser_1 = require("../../../../languages/java/mybatisXmlParser");
45
+ const fs = __importStar(require("fs"));
11
46
  class MyBatisResolver {
12
47
  constructor() {
13
48
  this.name = 'mybatis';
@@ -41,6 +76,27 @@ class MyBatisResolver {
41
76
  mapperInterfaces.push({ name: className, file: classInfo.filePath });
42
77
  }
43
78
  }
79
+ // Parse XML mapper files from the project
80
+ for (const filePath of ctx.allSourceFiles) {
81
+ if (!filePath.endsWith('.xml'))
82
+ continue;
83
+ try {
84
+ const content = fs.readFileSync(filePath, 'utf-8');
85
+ if (!(0, mybatisXmlParser_1.isMyBatisMapperXml)(content))
86
+ continue;
87
+ const parsed = (0, mybatisXmlParser_1.parseMyBatisMapper)(content, filePath);
88
+ if (parsed) {
89
+ xmlMappers.push({
90
+ namespace: parsed.namespace,
91
+ file: filePath,
92
+ methods: parsed.queries.map((q) => q.id),
93
+ });
94
+ }
95
+ }
96
+ catch {
97
+ // Skip unreadable XML files
98
+ }
99
+ }
44
100
  // Match mapper interfaces to XML files by namespace suffix
45
101
  for (const xml of xmlMappers) {
46
102
  const simpleName = (_b = xml.namespace.split('.').pop()) !== null && _b !== void 0 ? _b : xml.namespace;
@@ -1 +1 @@
1
- {"version":3,"file":"vuexActionResolver.d.ts","sourceRoot":"","sources":["../../../../../../src/pipeline/stages/ast/resolvers/vuexActionResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAEpF,qBAAa,kBAAmB,YAAW,iBAAiB;IAC1D,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO;IAItD,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB;CAyCpE"}
1
+ {"version":3,"file":"vuexActionResolver.d.ts","sourceRoot":"","sources":["../../../../../../src/pipeline/stages/ast/resolvers/vuexActionResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAEpF,qBAAa,kBAAmB,YAAW,iBAAiB;IAC1D,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO;IAItD,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB;CAgEpE"}
@@ -21,33 +21,58 @@ class VuexActionResolver {
21
21
  let entriesAdded = 0;
22
22
  const diagnostics = [];
23
23
  const unresolvedRefs = [];
24
- // Look for Vuex store modules (files with actions that call APIs)
25
- // and link them to component dispatch calls
26
- let vuexStoreFiles = 0;
27
- let dispatchFiles = 0;
24
+ // Collect Vuex store files: files with functions that have API calls (actions)
25
+ const actionFiles = new Map(); // filePath → action function names
28
26
  for (const [filePath, model] of ctx.symbolTable.models) {
29
- // Check if file has functions that look like Vuex actions (call API services)
30
- let hasApiCalls = false;
31
- for (const [, func] of model.functions) {
27
+ const actionNames = [];
28
+ for (const [funcName, func] of model.functions) {
32
29
  if (func.bodyHttpCalls.length > 0) {
33
- hasApiCalls = true;
34
- break;
30
+ actionNames.push(funcName);
35
31
  }
36
32
  }
37
- if (hasApiCalls) {
38
- vuexStoreFiles++;
33
+ if (actionNames.length > 0) {
34
+ actionFiles.set(filePath, actionNames);
39
35
  }
40
- // Check if file dispatches to store
41
- if (model.functions.size > 0) {
42
- for (const [, func] of model.functions) {
43
- if (func.calledFunctions.some((f) => f.includes('dispatch'))) {
44
- dispatchFiles++;
36
+ }
37
+ // Find dispatch calls and link them to actions
38
+ for (const [filePath, model] of ctx.symbolTable.models) {
39
+ for (const [funcName, func] of model.functions) {
40
+ for (const calledFunc of func.calledFunctions) {
41
+ if (!calledFunc.includes('dispatch'))
42
+ continue;
43
+ // Try to match dispatched action name to a known action function
44
+ // dispatch('getArticles') → match to 'getArticles' action in a store file
45
+ // Extract the action name from the dispatch call if possible
46
+ // Since we only have function names from calledFunctions, look for action names
47
+ // across all store files
48
+ for (const [storeFile, actionNames] of actionFiles) {
49
+ if (storeFile === filePath)
50
+ continue; // Don't link a file to itself
51
+ for (const actionName of actionNames) {
52
+ // Check if the current file references this action name
53
+ if (func.calledFunctions.some((f) => f.includes(actionName))) {
54
+ if (!ctx.symbolTable.injectionChains.has(filePath)) {
55
+ ctx.symbolTable.injectionChains.set(filePath, []);
56
+ }
57
+ ctx.symbolTable.injectionChains.get(filePath).push({
58
+ consumerFile: filePath,
59
+ consumerClass: funcName,
60
+ serviceClass: actionName,
61
+ serviceFile: storeFile,
62
+ injectionStyle: 'property',
63
+ });
64
+ entriesAdded++;
65
+ }
66
+ }
45
67
  }
46
68
  }
47
69
  }
48
70
  }
49
- if (vuexStoreFiles > 0 || dispatchFiles > 0) {
50
- diagnostics.push(`Found ${vuexStoreFiles} Vuex store file(s), ${dispatchFiles} dispatch file(s)`);
71
+ if (actionFiles.size > 0) {
72
+ diagnostics.push(`Found ${actionFiles.size} Vuex store file(s) with actions`);
73
+ }
74
+ if (entriesAdded > 0) {
75
+ diagnostics.push(`Linked ${entriesAdded} Vuex dispatch→action chain(s)`);
51
76
  }
52
77
  return { entriesAdded, diagnostics, unresolvedRefs };
53
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rulesEnforcer.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/rulesEnforcer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAGpD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,oBAAoB,EACjC,WAAW,EAAE,MAAM,GAClB,sBAAsB,CAsDxB"}
1
+ {"version":3,"file":"rulesEnforcer.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/rulesEnforcer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAGpD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,oBAAoB,EACjC,WAAW,EAAE,MAAM,GAClB,sBAAsB,CA0BxB"}