api-tests-coverage 1.0.12 → 1.0.14

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 (150) hide show
  1. package/dist/dashboard/dist/assets/_basePickBy-CErN2e4K.js +1 -0
  2. package/dist/dashboard/dist/assets/_baseUniq-DzHorfx6.js +1 -0
  3. package/dist/dashboard/dist/assets/arc-g03p1JXB.js +1 -0
  4. package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-CLCqS7Lv.js +36 -0
  5. package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-V4vxrfzX.js +122 -0
  6. package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-Bs4R4b6P.js +10 -0
  7. package/dist/dashboard/dist/assets/channel-BSnIwwuG.js +1 -0
  8. package/dist/dashboard/dist/assets/chunk-4BX2VUAB-oleArqPu.js +1 -0
  9. package/dist/dashboard/dist/assets/chunk-55IACEB6-BIFhHB94.js +1 -0
  10. package/dist/dashboard/dist/assets/chunk-B4BG7PRW-BChq1Wly.js +165 -0
  11. package/dist/dashboard/dist/assets/chunk-DI55MBZ5-D7eiRvhB.js +220 -0
  12. package/dist/dashboard/dist/assets/chunk-FMBD7UC4-BgEzYy_c.js +15 -0
  13. package/dist/dashboard/dist/assets/chunk-QN33PNHL-BNX7uRa_.js +1 -0
  14. package/dist/dashboard/dist/assets/chunk-QZHKN3VN-mq-zucvn.js +1 -0
  15. package/dist/dashboard/dist/assets/chunk-TZMSLE5B-DGTVcqTS.js +1 -0
  16. package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-Be0F7AG8.js +1 -0
  17. package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-Be0F7AG8.js +1 -0
  18. package/dist/dashboard/dist/assets/clone-B5PF81Z3.js +1 -0
  19. package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-xVw-THr_.js +1 -0
  20. package/dist/dashboard/dist/assets/dagre-6UL2VRFP-Bjadb8g_.js +4 -0
  21. package/dist/dashboard/dist/assets/diagram-PSM6KHXK-BPFtplp4.js +24 -0
  22. package/dist/dashboard/dist/assets/diagram-QEK2KX5R-CYxueP7U.js +43 -0
  23. package/dist/dashboard/dist/assets/diagram-S2PKOQOG-CRUXUQeh.js +24 -0
  24. package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-DvI8ycM6.js +60 -0
  25. package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-BAHshMEg.js +162 -0
  26. package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-BS4JnN-M.js +267 -0
  27. package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-Uz3nRdju.js +65 -0
  28. package/dist/dashboard/dist/assets/graph-Cwn7jgQS.js +1 -0
  29. package/dist/dashboard/dist/assets/index-D3_88Gr5.js +777 -0
  30. package/dist/dashboard/dist/assets/index-D_begBP0.css +1 -0
  31. package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-HLwGZBHJ.js +2 -0
  32. package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-CFgbI9OH.js +139 -0
  33. package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-D3u5Ov-5.js +89 -0
  34. package/dist/dashboard/dist/assets/layout-DgtRACDS.js +1 -0
  35. package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-BJ5xCmsL.js +68 -0
  36. package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-BIOVbZG_.js +30 -0
  37. package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-Crgu5WqK.js +7 -0
  38. package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-ClNSNeYe.js +64 -0
  39. package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-VcdyPlVE.js +10 -0
  40. package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-97qjzqIO.js +145 -0
  41. package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-BWqoDymf.js +1 -0
  42. package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-K_qkvHaB.js +1 -0
  43. package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-DR6HNny6.js +61 -0
  44. package/dist/dashboard/dist/assets/treemap-GDKQZRPO-MpQr6tee.js +162 -0
  45. package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-bS40I4IT.js +7 -0
  46. package/dist/dashboard/dist/index.html +2 -2
  47. package/dist/src/ast/astAnalysisOrchestrator.d.ts +28 -0
  48. package/dist/src/ast/astAnalysisOrchestrator.d.ts.map +1 -1
  49. package/dist/src/ast/astAnalysisOrchestrator.js +97 -27
  50. package/dist/src/languages/javascript/httpInteractionExtractor.js +10 -4
  51. package/dist/src/pipeline/confidence.d.ts +70 -0
  52. package/dist/src/pipeline/confidence.d.ts.map +1 -0
  53. package/dist/src/pipeline/confidence.js +198 -0
  54. package/dist/src/pipeline/graph.d.ts +58 -0
  55. package/dist/src/pipeline/graph.d.ts.map +1 -0
  56. package/dist/src/pipeline/graph.js +199 -0
  57. package/dist/src/pipeline/index.d.ts +24 -0
  58. package/dist/src/pipeline/index.d.ts.map +1 -0
  59. package/dist/src/pipeline/index.js +41 -0
  60. package/dist/src/pipeline/orchestrator.d.ts +42 -0
  61. package/dist/src/pipeline/orchestrator.d.ts.map +1 -0
  62. package/dist/src/pipeline/orchestrator.js +115 -0
  63. package/dist/src/pipeline/stageInterface.d.ts +45 -0
  64. package/dist/src/pipeline/stageInterface.d.ts.map +1 -0
  65. package/dist/src/pipeline/stageInterface.js +17 -0
  66. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts +38 -0
  67. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts.map +1 -0
  68. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.js +203 -0
  69. package/dist/src/pipeline/stages/ast/astStage.d.ts +19 -0
  70. package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -0
  71. package/dist/src/pipeline/stages/ast/astStage.js +238 -0
  72. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts +23 -0
  73. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts.map +1 -0
  74. package/dist/src/pipeline/stages/ast/crossFileResolver.js +183 -0
  75. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts +15 -0
  76. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -0
  77. package/dist/src/pipeline/stages/ast/graphBuilder.js +268 -0
  78. package/dist/src/pipeline/stages/ast/importResolver.d.ts +22 -0
  79. package/dist/src/pipeline/stages/ast/importResolver.d.ts.map +1 -0
  80. package/dist/src/pipeline/stages/ast/importResolver.js +186 -0
  81. package/dist/src/pipeline/stages/ast/types.d.ts +85 -0
  82. package/dist/src/pipeline/stages/ast/types.d.ts.map +1 -0
  83. package/dist/src/pipeline/stages/ast/types.js +5 -0
  84. package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts +25 -0
  85. package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts.map +1 -0
  86. package/dist/src/pipeline/stages/dast/conflictEmitter.js +90 -0
  87. package/dist/src/pipeline/stages/dast/dastStage.d.ts +17 -0
  88. package/dist/src/pipeline/stages/dast/dastStage.d.ts.map +1 -0
  89. package/dist/src/pipeline/stages/dast/dastStage.js +203 -0
  90. package/dist/src/pipeline/stages/dast/types.d.ts +49 -0
  91. package/dist/src/pipeline/stages/dast/types.d.ts.map +1 -0
  92. package/dist/src/pipeline/stages/dast/types.js +9 -0
  93. package/dist/src/pipeline/stages/iast/iastStage.d.ts +17 -0
  94. package/dist/src/pipeline/stages/iast/iastStage.d.ts.map +1 -0
  95. package/dist/src/pipeline/stages/iast/iastStage.js +191 -0
  96. package/dist/src/pipeline/stages/iast/types.d.ts +48 -0
  97. package/dist/src/pipeline/stages/iast/types.d.ts.map +1 -0
  98. package/dist/src/pipeline/stages/iast/types.js +8 -0
  99. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +17 -0
  100. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -0
  101. package/dist/src/pipeline/stages/merge/conflictDetector.js +60 -0
  102. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts +15 -0
  103. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -0
  104. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +141 -0
  105. package/dist/src/pipeline/stages/merge/mergeRules.d.ts +39 -0
  106. package/dist/src/pipeline/stages/merge/mergeRules.d.ts.map +1 -0
  107. package/dist/src/pipeline/stages/merge/mergeRules.js +90 -0
  108. package/dist/src/pipeline/stages/merge/mergeStage.d.ts +20 -0
  109. package/dist/src/pipeline/stages/merge/mergeStage.d.ts.map +1 -0
  110. package/dist/src/pipeline/stages/merge/mergeStage.js +145 -0
  111. package/dist/src/pipeline/stages/merge/summaryComputer.d.ts +11 -0
  112. package/dist/src/pipeline/stages/merge/summaryComputer.d.ts.map +1 -0
  113. package/dist/src/pipeline/stages/merge/summaryComputer.js +46 -0
  114. package/dist/src/pipeline/stages/sca/ciDetector.d.ts +15 -0
  115. package/dist/src/pipeline/stages/sca/ciDetector.d.ts.map +1 -0
  116. package/dist/src/pipeline/stages/sca/ciDetector.js +87 -0
  117. package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts +31 -0
  118. package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts.map +1 -0
  119. package/dist/src/pipeline/stages/sca/dependencyClassification.js +296 -0
  120. package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts +25 -0
  121. package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts.map +1 -0
  122. package/dist/src/pipeline/stages/sca/dependencyDetector.js +416 -0
  123. package/dist/src/pipeline/stages/sca/scaStage.d.ts +21 -0
  124. package/dist/src/pipeline/stages/sca/scaStage.d.ts.map +1 -0
  125. package/dist/src/pipeline/stages/sca/scaStage.js +208 -0
  126. package/dist/src/pipeline/stages/sca/types.d.ts +61 -0
  127. package/dist/src/pipeline/stages/sca/types.d.ts.map +1 -0
  128. package/dist/src/pipeline/stages/sca/types.js +9 -0
  129. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts +19 -0
  130. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -0
  131. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +118 -0
  132. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts +20 -0
  133. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts.map +1 -0
  134. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +238 -0
  135. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts +22 -0
  136. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts.map +1 -0
  137. package/dist/src/pipeline/stages/tia/testEndpointMapper.js +134 -0
  138. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts +16 -0
  139. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -0
  140. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +191 -0
  141. package/dist/src/pipeline/stages/tia/tiaStage.d.ts +20 -0
  142. package/dist/src/pipeline/stages/tia/tiaStage.d.ts.map +1 -0
  143. package/dist/src/pipeline/stages/tia/tiaStage.js +215 -0
  144. package/dist/src/pipeline/stages/tia/types.d.ts +52 -0
  145. package/dist/src/pipeline/stages/tia/types.d.ts.map +1 -0
  146. package/dist/src/pipeline/stages/tia/types.js +5 -0
  147. package/dist/src/pipeline/types.d.ts +128 -0
  148. package/dist/src/pipeline/types.d.ts.map +1 -0
  149. package/dist/src/pipeline/types.js +9 -0
  150. package/package.json +1 -1
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ /**
3
+ * Abstract layer traversal — resolves inherited assertions, imported helpers,
4
+ * fixture injections, and page objects across the inheritance chain.
5
+ *
6
+ * Implements the spec's abstract layer resolution with a configurable depth cap
7
+ * (default 5, RULE-05). When the cap is reached, resolution is marked as 'partial'.
8
+ * Cycles are detected and broken (RULE-15).
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.traverseInheritanceChain = traverseInheritanceChain;
12
+ exports.resolveImportedHelper = resolveImportedHelper;
13
+ exports.resolveFixtureInjection = resolveFixtureInjection;
14
+ /**
15
+ * Traverse the inheritance chain starting from a test class to resolve
16
+ * assertions, HTTP calls, and helper references from base classes.
17
+ *
18
+ * @param className - The test class/suite to start from
19
+ * @param table - The cross-file symbol table
20
+ * @param depthCap - Maximum traversal depth (RULE-05: default 5)
21
+ */
22
+ function traverseInheritanceChain(className, table, depthCap = 5) {
23
+ const visited = new Set();
24
+ const resolvedAssertions = [];
25
+ const resolvedHttpCalls = [];
26
+ const unresolvedChain = [];
27
+ let maxDepth = 0;
28
+ let cycleDetected = false;
29
+ function traverse(name, depth) {
30
+ var _a;
31
+ if (depth > depthCap) {
32
+ unresolvedChain.push(`${name} (depth cap ${depthCap} reached)`);
33
+ return;
34
+ }
35
+ if (visited.has(name)) {
36
+ cycleDetected = true;
37
+ unresolvedChain.push(`${name} (cycle detected)`);
38
+ return;
39
+ }
40
+ visited.add(name);
41
+ maxDepth = Math.max(maxDepth, depth);
42
+ // Find the class declaration
43
+ const classDecl = table.classes.get(name);
44
+ if (!classDecl) {
45
+ if (depth > 0) {
46
+ unresolvedChain.push(`${name} (class not found)`);
47
+ }
48
+ return;
49
+ }
50
+ // Get the semantic model for this class's file
51
+ const model = table.models.get(classDecl.filePath);
52
+ if (!model) {
53
+ unresolvedChain.push(`${name} (model not found for ${classDecl.filePath})`);
54
+ return;
55
+ }
56
+ // Collect assertions from this class's model
57
+ for (const assertion of model.assertions) {
58
+ resolvedAssertions.push(assertion);
59
+ }
60
+ // Collect HTTP calls from this class's functions
61
+ for (const methodName of classDecl.methods) {
62
+ const func = (_a = model.functions.get(methodName)) !== null && _a !== void 0 ? _a : model.functions.get(`${name}.${methodName}`);
63
+ if (func) {
64
+ resolvedHttpCalls.push(...func.bodyHttpCalls);
65
+ }
66
+ }
67
+ // Recurse into base class
68
+ if (classDecl.extendsClass) {
69
+ traverse(classDecl.extendsClass, depth + 1);
70
+ }
71
+ }
72
+ traverse(className, 0);
73
+ const resolution = unresolvedChain.length > 0 ? 'partial' : 'full';
74
+ const assertionSource = maxDepth === 0
75
+ ? 'direct'
76
+ : resolvedAssertions.length > 0
77
+ ? 'inherited'
78
+ : 'unresolved';
79
+ return {
80
+ resolvedAssertions,
81
+ resolvedHttpCalls,
82
+ assertionSource,
83
+ traversalDepth: maxDepth,
84
+ resolution,
85
+ unresolvedChain: unresolvedChain.length > 0 ? unresolvedChain : undefined,
86
+ cycleDetected,
87
+ };
88
+ }
89
+ /**
90
+ * Resolve an imported helper function by following the import chain.
91
+ *
92
+ * @param functionName - The helper function to resolve
93
+ * @param fromFile - The file importing the helper
94
+ * @param table - The cross-file symbol table
95
+ * @param depthCap - Maximum traversal depth
96
+ */
97
+ function resolveImportedHelper(functionName, fromFile, table, depthCap = 5) {
98
+ const visited = new Set();
99
+ const resolvedAssertions = [];
100
+ const resolvedHttpCalls = [];
101
+ const unresolvedChain = [];
102
+ let maxDepth = 0;
103
+ let cycleDetected = false;
104
+ function resolve(funcName, file, depth) {
105
+ var _a;
106
+ if (depth > depthCap) {
107
+ unresolvedChain.push(`${funcName} in ${file} (depth cap reached)`);
108
+ return;
109
+ }
110
+ const key = `${file}::${funcName}`;
111
+ if (visited.has(key)) {
112
+ cycleDetected = true;
113
+ unresolvedChain.push(`${funcName} in ${file} (cycle detected)`);
114
+ return;
115
+ }
116
+ visited.add(key);
117
+ maxDepth = Math.max(maxDepth, depth);
118
+ const model = table.models.get(file);
119
+ if (!model) {
120
+ unresolvedChain.push(`${funcName} (model not found for ${file})`);
121
+ return;
122
+ }
123
+ // Find the function in the model
124
+ const func = model.functions.get(funcName);
125
+ if (!func) {
126
+ // Try imported files
127
+ const importedFiles = (_a = table.importGraph.get(file)) !== null && _a !== void 0 ? _a : [];
128
+ for (const importedFile of importedFiles) {
129
+ const importedModel = table.models.get(importedFile);
130
+ if (importedModel === null || importedModel === void 0 ? void 0 : importedModel.functions.has(funcName)) {
131
+ resolve(funcName, importedFile, depth + 1);
132
+ return;
133
+ }
134
+ }
135
+ unresolvedChain.push(`${funcName} (function not found in ${file})`);
136
+ return;
137
+ }
138
+ // Collect HTTP calls from this function
139
+ resolvedHttpCalls.push(...func.bodyHttpCalls);
140
+ // Collect any assertions from the model that relate to this function
141
+ for (const assertion of model.assertions) {
142
+ resolvedAssertions.push(assertion);
143
+ }
144
+ // Follow called functions recursively
145
+ for (const calledFunc of func.calledFunctions) {
146
+ resolve(calledFunc, file, depth + 1);
147
+ }
148
+ }
149
+ resolve(functionName, fromFile, 0);
150
+ const resolution = unresolvedChain.length > 0 ? 'partial' : 'full';
151
+ const assertionSource = resolvedAssertions.length > 0 ? 'helper' : 'unresolved';
152
+ return {
153
+ resolvedAssertions,
154
+ resolvedHttpCalls,
155
+ assertionSource,
156
+ traversalDepth: maxDepth,
157
+ resolution,
158
+ unresolvedChain: unresolvedChain.length > 0 ? unresolvedChain : undefined,
159
+ cycleDetected,
160
+ };
161
+ }
162
+ /**
163
+ * Resolve fixture-injected assertions and HTTP calls.
164
+ * Traces @BeforeEach/beforeEach/pytest fixtures/@Autowired patterns.
165
+ *
166
+ * @param fixtureName - The fixture function name
167
+ * @param table - The cross-file symbol table
168
+ * @param depthCap - Maximum traversal depth
169
+ */
170
+ function resolveFixtureInjection(fixtureName, table, depthCap = 5) {
171
+ const resolvedAssertions = [];
172
+ const resolvedHttpCalls = [];
173
+ const unresolvedChain = [];
174
+ let maxDepth = 0;
175
+ let found = false;
176
+ // Search all models for the fixture function
177
+ for (const [filePath, model] of table.models) {
178
+ const func = model.functions.get(fixtureName);
179
+ if (!func)
180
+ continue;
181
+ found = true;
182
+ maxDepth = 1;
183
+ // Collect HTTP calls from the fixture
184
+ resolvedHttpCalls.push(...func.bodyHttpCalls);
185
+ // Check if fixture has assertions
186
+ for (const assertion of model.assertions) {
187
+ resolvedAssertions.push(assertion);
188
+ }
189
+ break; // Use first match
190
+ }
191
+ if (!found) {
192
+ unresolvedChain.push(`${fixtureName} (fixture not found)`);
193
+ }
194
+ return {
195
+ resolvedAssertions,
196
+ resolvedHttpCalls,
197
+ assertionSource: found ? 'fixture' : 'unresolved',
198
+ traversalDepth: maxDepth,
199
+ resolution: found ? 'full' : 'partial',
200
+ unresolvedChain: unresolvedChain.length > 0 ? unresolvedChain : undefined,
201
+ cycleDetected: false,
202
+ };
203
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * AST Stage — Stage 2 of the coverage pipeline.
3
+ *
4
+ * Wraps the existing AST analysis orchestrator and extends it with:
5
+ * - Multi-file analysis: parses all discovered files and builds a cross-file symbol table
6
+ * - Abstract layer traversal: resolves inherited assertions, helpers, fixtures
7
+ * - Graph building: converts analysis results into GraphNode[] and GraphEdge[]
8
+ *
9
+ * The AST stage reads the SCA output (from context.stageOutputs) to determine
10
+ * which languages and frameworks are present, enabling targeted analysis heuristics.
11
+ */
12
+ import type { PipelineStage, PipelineContext } from '../../stageInterface';
13
+ import type { AstStageOutput } from './types';
14
+ export declare class AstStage implements PipelineStage<AstStageOutput> {
15
+ readonly name: "ast";
16
+ readonly optional = false;
17
+ execute(context: PipelineContext): Promise<AstStageOutput>;
18
+ }
19
+ //# sourceMappingURL=astStage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"astStage.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/astStage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAkB9C,qBAAa,QAAS,YAAW,aAAa,CAAC,cAAc,CAAC;IAC5D,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAC/B,QAAQ,CAAC,QAAQ,SAAS;IAEpB,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;CAyKjE"}
@@ -0,0 +1,238 @@
1
+ "use strict";
2
+ /**
3
+ * AST Stage — Stage 2 of the coverage pipeline.
4
+ *
5
+ * Wraps the existing AST analysis orchestrator and extends it with:
6
+ * - Multi-file analysis: parses all discovered files and builds a cross-file symbol table
7
+ * - Abstract layer traversal: resolves inherited assertions, helpers, fixtures
8
+ * - Graph building: converts analysis results into GraphNode[] and GraphEdge[]
9
+ *
10
+ * The AST stage reads the SCA output (from context.stageOutputs) to determine
11
+ * which languages and frameworks are present, enabling targeted analysis heuristics.
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.AstStage = void 0;
48
+ const astAnalysisOrchestrator_1 = require("../../../ast/astAnalysisOrchestrator");
49
+ const crossFileResolver_1 = require("./crossFileResolver");
50
+ const abstractLayerTraversal_1 = require("./abstractLayerTraversal");
51
+ const graphBuilder_1 = require("./graphBuilder");
52
+ const fileClassifier_1 = require("../../../discovery/fileClassifier");
53
+ const projectDiscovery_1 = require("../../../discovery/projectDiscovery");
54
+ const parserRegistry_1 = require("../../../ast/parserRegistry");
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ class AstStage {
58
+ constructor() {
59
+ this.name = 'ast';
60
+ this.optional = false;
61
+ }
62
+ async execute(context) {
63
+ var _a;
64
+ const startTime = Date.now();
65
+ const filesScanned = [];
66
+ const filesSkipped = [];
67
+ // Ensure all language analyzers are registered
68
+ (0, astAnalysisOrchestrator_1.registerAllAnalyzers)();
69
+ // Get SCA output for language/framework context
70
+ const scaOutput = context.stageOutputs.get('sca');
71
+ // Build analysis context
72
+ const analysisContext = (0, astAnalysisOrchestrator_1.buildAnalysisContext)(context.config.astConfig);
73
+ // Discover all files
74
+ const artifacts = (0, projectDiscovery_1.discoverProject)({ rootDir: context.projectRoot });
75
+ const allSourceFiles = [
76
+ ...artifacts.testFiles,
77
+ ...artifacts.serviceFiles,
78
+ ];
79
+ // Phase 1: Parse all files and build semantic models
80
+ const models = new Map();
81
+ const interactionsMap = new Map();
82
+ for (const filePath of allSourceFiles) {
83
+ // Enforce per-file timeout (RULE-16)
84
+ const fileStart = Date.now();
85
+ let content;
86
+ try {
87
+ content = fs.readFileSync(filePath, 'utf-8');
88
+ }
89
+ catch (err) {
90
+ filesSkipped.push({ file: filePath, reason: 'read-error' });
91
+ continue;
92
+ }
93
+ // Detect language from file extension
94
+ const language = detectLanguage(filePath, scaOutput);
95
+ if (!language) {
96
+ filesSkipped.push({ file: filePath, reason: 'unsupported-language' });
97
+ continue;
98
+ }
99
+ // Check timeout
100
+ if (Date.now() - fileStart > context.config.fileTimeoutMs) {
101
+ filesSkipped.push({ file: filePath, reason: 'timeout' });
102
+ continue;
103
+ }
104
+ try {
105
+ // Use existing AST analysis
106
+ const result = (0, astAnalysisOrchestrator_1.analyzeFileDetailed)(content, filePath, language, analysisContext);
107
+ interactionsMap.set(filePath, result.interactions);
108
+ // Build semantic model if we have an analyzer
109
+ const analyzer = (0, parserRegistry_1.getAnalyzer)(language, analysisContext.astConfig);
110
+ if (analyzer) {
111
+ const parsed = analyzer.parse(filePath, content);
112
+ if (!parsed.parseError) {
113
+ const model = analyzer.buildSemanticModel(parsed, analysisContext);
114
+ models.set(filePath, model);
115
+ }
116
+ else {
117
+ // RULE-02: File not skipped on parse error — we already have fallback interactions
118
+ filesSkipped.push({ file: filePath, reason: 'parse-error' });
119
+ }
120
+ }
121
+ filesScanned.push(filePath);
122
+ }
123
+ catch (err) {
124
+ // RULE-02: Never skip a file entirely on error
125
+ filesSkipped.push({
126
+ file: filePath,
127
+ reason: `analysis-error: ${err instanceof Error ? err.message : String(err)}`,
128
+ });
129
+ }
130
+ }
131
+ // Phase 2: Build cross-file symbol table
132
+ const crossFileTable = (0, crossFileResolver_1.buildCrossFileSymbolTable)(models, context.projectRoot);
133
+ // Phase 3: Run abstract layer traversal for test files
134
+ const traversalResults = new Map();
135
+ const depthCap = context.config.traversalDepthCap;
136
+ for (const [filePath] of models) {
137
+ const basename = path.basename(filePath);
138
+ if (!(0, fileClassifier_1.isTestFile)(basename))
139
+ continue;
140
+ // Try inheritance chain traversal for classes in this test file
141
+ for (const [className, classDecl] of crossFileTable.classes) {
142
+ if (classDecl.filePath === filePath && classDecl.extendsClass) {
143
+ const result = (0, abstractLayerTraversal_1.traverseInheritanceChain)(className, crossFileTable, depthCap);
144
+ traversalResults.set(filePath, result);
145
+ break; // One traversal result per test file
146
+ }
147
+ }
148
+ // If no inheritance found, try resolving imported helpers
149
+ if (!traversalResults.has(filePath)) {
150
+ const model = models.get(filePath);
151
+ if (model) {
152
+ for (const [funcName, func] of model.functions) {
153
+ for (const calledFunc of func.calledFunctions) {
154
+ // Check if this is an imported function
155
+ const importedFiles = (_a = crossFileTable.importGraph.get(filePath)) !== null && _a !== void 0 ? _a : [];
156
+ for (const importedFile of importedFiles) {
157
+ const importedModel = models.get(importedFile);
158
+ if (importedModel === null || importedModel === void 0 ? void 0 : importedModel.functions.has(calledFunc)) {
159
+ const result = (0, abstractLayerTraversal_1.resolveImportedHelper)(calledFunc, importedFile, crossFileTable, depthCap);
160
+ if (result.resolvedAssertions.length > 0 || result.resolvedHttpCalls.length > 0) {
161
+ traversalResults.set(filePath, result);
162
+ }
163
+ break;
164
+ }
165
+ }
166
+ if (traversalResults.has(filePath))
167
+ break;
168
+ }
169
+ if (traversalResults.has(filePath))
170
+ break;
171
+ }
172
+ }
173
+ }
174
+ }
175
+ // Phase 4: Build graph nodes and edges
176
+ const { nodes, edges } = (0, graphBuilder_1.buildAstGraph)(models, crossFileTable, traversalResults, interactionsMap);
177
+ // Add nodes and edges to the context graph
178
+ for (const node of nodes) {
179
+ if (!context.graph.hasNode(node.id)) {
180
+ context.graph.addNode(node);
181
+ }
182
+ }
183
+ for (const edge of edges) {
184
+ if (!context.graph.hasEdge(edge.id)) {
185
+ context.graph.addEdge(edge);
186
+ }
187
+ }
188
+ // Record diagnostics (RULE-12)
189
+ const diagnostics = {
190
+ stageName: 'ast',
191
+ filesScanned,
192
+ filesSkipped,
193
+ durationMs: Date.now() - startTime,
194
+ metadata: {
195
+ totalModels: models.size,
196
+ totalInteractions: Array.from(interactionsMap.values()).reduce((sum, arr) => sum + arr.length, 0),
197
+ totalClasses: crossFileTable.classes.size,
198
+ totalExportedSymbols: crossFileTable.exportedSymbols.size,
199
+ traversalResultCount: traversalResults.size,
200
+ graphNodesAdded: nodes.length,
201
+ graphEdgesAdded: edges.length,
202
+ },
203
+ };
204
+ context.diagnostics.set('ast', diagnostics);
205
+ // Build output
206
+ const output = {
207
+ models,
208
+ crossFileTable,
209
+ traversalResults,
210
+ analyzedFiles: filesScanned,
211
+ skippedFiles: filesSkipped,
212
+ };
213
+ context.stageOutputs.set('ast', output);
214
+ return output;
215
+ }
216
+ }
217
+ exports.AstStage = AstStage;
218
+ /**
219
+ * Detect the language of a file from its extension.
220
+ */
221
+ function detectLanguage(filePath, scaOutput) {
222
+ const ext = path.extname(filePath).toLowerCase();
223
+ const extensionMap = {
224
+ '.ts': 'typescript',
225
+ '.tsx': 'typescript',
226
+ '.js': 'javascript',
227
+ '.jsx': 'javascript',
228
+ '.mjs': 'javascript',
229
+ '.cjs': 'javascript',
230
+ '.java': 'java',
231
+ '.kt': 'kotlin',
232
+ '.kts': 'kotlin',
233
+ '.py': 'python',
234
+ '.rb': 'ruby',
235
+ '.feature': 'cucumber',
236
+ };
237
+ return extensionMap[ext];
238
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Cross-file resolver — builds a multi-file symbol table from all parsed semantic models.
3
+ *
4
+ * Aggregates per-file symbol tables, export declarations, class declarations,
5
+ * and import graphs into a unified `CrossFileSymbolTable` that enables
6
+ * cross-file constant resolution, inheritance chain traversal, and
7
+ * import-based helper resolution.
8
+ */
9
+ import type { SemanticModel } from '../../../ast/astTypes';
10
+ import type { CrossFileSymbolTable } from './types';
11
+ /**
12
+ * Build a cross-file symbol table from all parsed semantic models.
13
+ *
14
+ * @param models - Map of filePath → SemanticModel
15
+ * @param projectRoot - The project root directory
16
+ */
17
+ export declare function buildCrossFileSymbolTable(models: Map<string, SemanticModel>, projectRoot: string): CrossFileSymbolTable;
18
+ /**
19
+ * Resolve a symbol name using the cross-file symbol table.
20
+ * Tries: direct lookup, qualified lookup (filePath::name), and import-chain following.
21
+ */
22
+ export declare function resolveSymbolCrossFile(symbolName: string, fromFile: string, table: CrossFileSymbolTable): string | undefined;
23
+ //# sourceMappingURL=crossFileResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crossFileResolver.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/crossFileResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAuC,MAAM,uBAAuB,CAAC;AAChG,OAAO,KAAK,EAAE,oBAAoB,EAAuC,MAAM,SAAS,CAAC;AAGzF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAClC,WAAW,EAAE,MAAM,GAClB,oBAAoB,CAuDtB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,oBAAoB,GAC1B,MAAM,GAAG,SAAS,CA4BpB"}
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ /**
3
+ * Cross-file resolver — builds a multi-file symbol table from all parsed semantic models.
4
+ *
5
+ * Aggregates per-file symbol tables, export declarations, class declarations,
6
+ * and import graphs into a unified `CrossFileSymbolTable` that enables
7
+ * cross-file constant resolution, inheritance chain traversal, and
8
+ * import-based helper resolution.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.buildCrossFileSymbolTable = buildCrossFileSymbolTable;
12
+ exports.resolveSymbolCrossFile = resolveSymbolCrossFile;
13
+ const importResolver_1 = require("./importResolver");
14
+ /**
15
+ * Build a cross-file symbol table from all parsed semantic models.
16
+ *
17
+ * @param models - Map of filePath → SemanticModel
18
+ * @param projectRoot - The project root directory
19
+ */
20
+ function buildCrossFileSymbolTable(models, projectRoot) {
21
+ const exportedSymbols = new Map();
22
+ const classes = new Map();
23
+ const importGraph = new Map();
24
+ // Pass 1: Collect all exported symbols and class declarations
25
+ for (const [filePath, model] of models) {
26
+ // Collect constants as exported symbols
27
+ for (const [name, symbol] of model.constants) {
28
+ if (symbol.value !== undefined) {
29
+ exportedSymbols.set(`${filePath}::${name}`, { filePath, value: symbol.value });
30
+ // Also register as global name for simple lookups
31
+ if (!exportedSymbols.has(name)) {
32
+ exportedSymbols.set(name, { filePath, value: symbol.value });
33
+ }
34
+ }
35
+ }
36
+ // Collect local variables that are const-like with string values
37
+ for (const [name, symbol] of model.localVariables) {
38
+ if (symbol.kind === 'const' && symbol.value !== undefined) {
39
+ exportedSymbols.set(`${filePath}::${name}`, { filePath, value: symbol.value });
40
+ }
41
+ }
42
+ // Collect enum members as exported symbols
43
+ for (const [enumName, members] of model.enums) {
44
+ for (const [memberName, value] of members) {
45
+ const qualifiedName = `${enumName}.${memberName}`;
46
+ exportedSymbols.set(`${filePath}::${qualifiedName}`, { filePath, value });
47
+ if (!exportedSymbols.has(qualifiedName)) {
48
+ exportedSymbols.set(qualifiedName, { filePath, value });
49
+ }
50
+ }
51
+ }
52
+ // Extract class declarations from functions (heuristic: capitalize name + has methods)
53
+ extractClassDeclarations(filePath, model, classes);
54
+ }
55
+ // Pass 2: Build import graph
56
+ for (const [filePath, model] of models) {
57
+ const imports = extractImportsFromModel(filePath, model, projectRoot);
58
+ const resolvedPaths = [];
59
+ for (const imp of imports) {
60
+ if (imp.resolvedPath) {
61
+ resolvedPaths.push(imp.resolvedPath);
62
+ }
63
+ }
64
+ importGraph.set(filePath, resolvedPaths);
65
+ }
66
+ return { models, exportedSymbols, classes, importGraph };
67
+ }
68
+ /**
69
+ * Resolve a symbol name using the cross-file symbol table.
70
+ * Tries: direct lookup, qualified lookup (filePath::name), and import-chain following.
71
+ */
72
+ function resolveSymbolCrossFile(symbolName, fromFile, table) {
73
+ var _a;
74
+ // Try qualified lookup for the current file
75
+ const qualified = table.exportedSymbols.get(`${fromFile}::${symbolName}`);
76
+ if (qualified)
77
+ return qualified.value;
78
+ // Try global lookup
79
+ const global = table.exportedSymbols.get(symbolName);
80
+ if (global)
81
+ return global.value;
82
+ // Try following imports from the current file
83
+ const importedFiles = (_a = table.importGraph.get(fromFile)) !== null && _a !== void 0 ? _a : [];
84
+ for (const importedFile of importedFiles) {
85
+ const fromImported = table.exportedSymbols.get(`${importedFile}::${symbolName}`);
86
+ if (fromImported)
87
+ return fromImported.value;
88
+ }
89
+ // Try dotted name resolution (e.g. "Config.BASE_URL")
90
+ const dotParts = symbolName.split('.');
91
+ if (dotParts.length >= 2) {
92
+ // Try each possible combination
93
+ for (const [key, entry] of table.exportedSymbols) {
94
+ if (key.endsWith(`::${symbolName}`) || key === symbolName) {
95
+ return entry.value;
96
+ }
97
+ }
98
+ }
99
+ return undefined;
100
+ }
101
+ /**
102
+ * Extract import declarations from a semantic model.
103
+ * This is a heuristic extraction — real import extraction would come from the AST.
104
+ */
105
+ function extractImportsFromModel(filePath, model, projectRoot) {
106
+ const imports = [];
107
+ // Use functions' calledFunctions to infer cross-file references
108
+ for (const [, func] of model.functions) {
109
+ for (const calledName of func.calledFunctions) {
110
+ // If the function name contains a dot, it might be an import reference
111
+ const dotIndex = calledName.indexOf('.');
112
+ if (dotIndex > 0) {
113
+ const modulePart = calledName.substring(0, dotIndex);
114
+ const resolvedPath = (0, importResolver_1.resolveImportPath)(`./${modulePart}`, filePath, projectRoot, model.language);
115
+ if (resolvedPath) {
116
+ imports.push({
117
+ source: modulePart,
118
+ resolvedPath,
119
+ importedNames: [calledName.substring(dotIndex + 1)],
120
+ isDefault: false,
121
+ });
122
+ }
123
+ }
124
+ }
125
+ }
126
+ return imports;
127
+ }
128
+ /**
129
+ * Extract class declarations from a semantic model (heuristic).
130
+ *
131
+ * Looks for functions that follow class patterns:
132
+ * - Capitalized names
133
+ * - Constructor patterns
134
+ * - Extends/implements annotations
135
+ */
136
+ function extractClassDeclarations(filePath, model, classes) {
137
+ const classMethods = new Map();
138
+ for (const [name, func] of model.functions) {
139
+ // Look for constructor patterns to detect class names
140
+ if (name === 'constructor' || name.startsWith('__init__'))
141
+ continue;
142
+ // Methods prefixed with "ClassName." or "ClassName#"
143
+ const dotIndex = name.indexOf('.');
144
+ const hashIndex = name.indexOf('#');
145
+ const separator = dotIndex >= 0 ? dotIndex : hashIndex;
146
+ if (separator > 0) {
147
+ const className = name.substring(0, separator);
148
+ const methodName = name.substring(separator + 1);
149
+ if (!classMethods.has(className)) {
150
+ classMethods.set(className, []);
151
+ }
152
+ classMethods.get(className).push(methodName);
153
+ }
154
+ // Check annotations for class membership
155
+ if (func.annotations) {
156
+ for (const ann of func.annotations) {
157
+ // Spring/Java annotations like @Controller, @Service, @RestController
158
+ if (ann.match(/^@(Controller|Service|Repository|Component|RestController|SpringBootTest)/)) {
159
+ const className = extractClassNameFromAnnotation(name, func);
160
+ if (className && !classMethods.has(className)) {
161
+ classMethods.set(className, []);
162
+ }
163
+ }
164
+ }
165
+ }
166
+ }
167
+ // Convert to ClassDeclaration objects
168
+ for (const [className, methods] of classMethods) {
169
+ if (!classes.has(className)) {
170
+ classes.set(className, {
171
+ name: className,
172
+ methods,
173
+ filePath,
174
+ });
175
+ }
176
+ }
177
+ }
178
+ function extractClassNameFromAnnotation(functionName, _func) {
179
+ const dotIndex = functionName.indexOf('.');
180
+ if (dotIndex > 0)
181
+ return functionName.substring(0, dotIndex);
182
+ return undefined;
183
+ }