api-tests-coverage 1.0.13 → 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 (100) hide show
  1. package/dist/src/pipeline/confidence.d.ts +70 -0
  2. package/dist/src/pipeline/confidence.d.ts.map +1 -0
  3. package/dist/src/pipeline/confidence.js +198 -0
  4. package/dist/src/pipeline/graph.d.ts +58 -0
  5. package/dist/src/pipeline/graph.d.ts.map +1 -0
  6. package/dist/src/pipeline/graph.js +199 -0
  7. package/dist/src/pipeline/index.d.ts +24 -0
  8. package/dist/src/pipeline/index.d.ts.map +1 -0
  9. package/dist/src/pipeline/index.js +41 -0
  10. package/dist/src/pipeline/orchestrator.d.ts +42 -0
  11. package/dist/src/pipeline/orchestrator.d.ts.map +1 -0
  12. package/dist/src/pipeline/orchestrator.js +115 -0
  13. package/dist/src/pipeline/stageInterface.d.ts +45 -0
  14. package/dist/src/pipeline/stageInterface.d.ts.map +1 -0
  15. package/dist/src/pipeline/stageInterface.js +17 -0
  16. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts +38 -0
  17. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts.map +1 -0
  18. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.js +203 -0
  19. package/dist/src/pipeline/stages/ast/astStage.d.ts +19 -0
  20. package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -0
  21. package/dist/src/pipeline/stages/ast/astStage.js +238 -0
  22. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts +23 -0
  23. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts.map +1 -0
  24. package/dist/src/pipeline/stages/ast/crossFileResolver.js +183 -0
  25. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts +15 -0
  26. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -0
  27. package/dist/src/pipeline/stages/ast/graphBuilder.js +268 -0
  28. package/dist/src/pipeline/stages/ast/importResolver.d.ts +22 -0
  29. package/dist/src/pipeline/stages/ast/importResolver.d.ts.map +1 -0
  30. package/dist/src/pipeline/stages/ast/importResolver.js +186 -0
  31. package/dist/src/pipeline/stages/ast/types.d.ts +85 -0
  32. package/dist/src/pipeline/stages/ast/types.d.ts.map +1 -0
  33. package/dist/src/pipeline/stages/ast/types.js +5 -0
  34. package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts +25 -0
  35. package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts.map +1 -0
  36. package/dist/src/pipeline/stages/dast/conflictEmitter.js +90 -0
  37. package/dist/src/pipeline/stages/dast/dastStage.d.ts +17 -0
  38. package/dist/src/pipeline/stages/dast/dastStage.d.ts.map +1 -0
  39. package/dist/src/pipeline/stages/dast/dastStage.js +203 -0
  40. package/dist/src/pipeline/stages/dast/types.d.ts +49 -0
  41. package/dist/src/pipeline/stages/dast/types.d.ts.map +1 -0
  42. package/dist/src/pipeline/stages/dast/types.js +9 -0
  43. package/dist/src/pipeline/stages/iast/iastStage.d.ts +17 -0
  44. package/dist/src/pipeline/stages/iast/iastStage.d.ts.map +1 -0
  45. package/dist/src/pipeline/stages/iast/iastStage.js +191 -0
  46. package/dist/src/pipeline/stages/iast/types.d.ts +48 -0
  47. package/dist/src/pipeline/stages/iast/types.d.ts.map +1 -0
  48. package/dist/src/pipeline/stages/iast/types.js +8 -0
  49. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +17 -0
  50. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -0
  51. package/dist/src/pipeline/stages/merge/conflictDetector.js +60 -0
  52. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts +15 -0
  53. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -0
  54. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +141 -0
  55. package/dist/src/pipeline/stages/merge/mergeRules.d.ts +39 -0
  56. package/dist/src/pipeline/stages/merge/mergeRules.d.ts.map +1 -0
  57. package/dist/src/pipeline/stages/merge/mergeRules.js +90 -0
  58. package/dist/src/pipeline/stages/merge/mergeStage.d.ts +20 -0
  59. package/dist/src/pipeline/stages/merge/mergeStage.d.ts.map +1 -0
  60. package/dist/src/pipeline/stages/merge/mergeStage.js +145 -0
  61. package/dist/src/pipeline/stages/merge/summaryComputer.d.ts +11 -0
  62. package/dist/src/pipeline/stages/merge/summaryComputer.d.ts.map +1 -0
  63. package/dist/src/pipeline/stages/merge/summaryComputer.js +46 -0
  64. package/dist/src/pipeline/stages/sca/ciDetector.d.ts +15 -0
  65. package/dist/src/pipeline/stages/sca/ciDetector.d.ts.map +1 -0
  66. package/dist/src/pipeline/stages/sca/ciDetector.js +87 -0
  67. package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts +31 -0
  68. package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts.map +1 -0
  69. package/dist/src/pipeline/stages/sca/dependencyClassification.js +296 -0
  70. package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts +25 -0
  71. package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts.map +1 -0
  72. package/dist/src/pipeline/stages/sca/dependencyDetector.js +416 -0
  73. package/dist/src/pipeline/stages/sca/scaStage.d.ts +21 -0
  74. package/dist/src/pipeline/stages/sca/scaStage.d.ts.map +1 -0
  75. package/dist/src/pipeline/stages/sca/scaStage.js +208 -0
  76. package/dist/src/pipeline/stages/sca/types.d.ts +61 -0
  77. package/dist/src/pipeline/stages/sca/types.d.ts.map +1 -0
  78. package/dist/src/pipeline/stages/sca/types.js +9 -0
  79. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts +19 -0
  80. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -0
  81. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +118 -0
  82. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts +20 -0
  83. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts.map +1 -0
  84. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +238 -0
  85. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts +22 -0
  86. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts.map +1 -0
  87. package/dist/src/pipeline/stages/tia/testEndpointMapper.js +134 -0
  88. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts +16 -0
  89. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -0
  90. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +191 -0
  91. package/dist/src/pipeline/stages/tia/tiaStage.d.ts +20 -0
  92. package/dist/src/pipeline/stages/tia/tiaStage.d.ts.map +1 -0
  93. package/dist/src/pipeline/stages/tia/tiaStage.js +215 -0
  94. package/dist/src/pipeline/stages/tia/types.d.ts +52 -0
  95. package/dist/src/pipeline/stages/tia/types.d.ts.map +1 -0
  96. package/dist/src/pipeline/stages/tia/types.js +5 -0
  97. package/dist/src/pipeline/types.d.ts +128 -0
  98. package/dist/src/pipeline/types.d.ts.map +1 -0
  99. package/dist/src/pipeline/types.js +9 -0
  100. package/package.json +1 -1
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+ /**
3
+ * Graph builder — converts SemanticModels, cross-file results, and traversal
4
+ * results into GraphNode[] and GraphEdge[] for the Coverage Knowledge Graph.
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.buildAstGraph = buildAstGraph;
41
+ const fileClassifier_1 = require("../../../discovery/fileClassifier");
42
+ const path = __importStar(require("path"));
43
+ /**
44
+ * Build graph nodes and edges from parsed semantic models and analysis results.
45
+ */
46
+ function buildAstGraph(models, crossFileTable, traversalResults, interactions) {
47
+ const nodes = [];
48
+ const edges = [];
49
+ const addedNodeIds = new Set();
50
+ const addedEdgeIds = new Set();
51
+ function addNode(node) {
52
+ if (addedNodeIds.has(node.id))
53
+ return;
54
+ addedNodeIds.add(node.id);
55
+ nodes.push(node);
56
+ }
57
+ function addEdge(edge) {
58
+ if (addedEdgeIds.has(edge.id))
59
+ return;
60
+ addedEdgeIds.add(edge.id);
61
+ edges.push(edge);
62
+ }
63
+ // 1. Create file nodes for every parsed file
64
+ for (const [filePath, model] of models) {
65
+ const basename = path.basename(filePath);
66
+ const isTest = (0, fileClassifier_1.isTestFile)(basename);
67
+ const fileNodeType = isTest ? 'test-file' : 'file';
68
+ addNode({
69
+ id: `file:${filePath}`,
70
+ type: fileNodeType,
71
+ label: basename,
72
+ sourceStage: 'ast',
73
+ filePath,
74
+ metadata: { language: model.language, isTestFile: isTest },
75
+ });
76
+ }
77
+ // 2. Create endpoint nodes from HTTP interactions
78
+ for (const [filePath, fileInteractions] of interactions) {
79
+ for (const interaction of fileInteractions) {
80
+ const endpointId = `endpoint:${interaction.method}:${interaction.path}`;
81
+ addNode({
82
+ id: endpointId,
83
+ type: 'endpoint',
84
+ label: `${interaction.method} ${interaction.path}`,
85
+ sourceStage: 'ast',
86
+ filePath: interaction.sourceFile,
87
+ metadata: {
88
+ method: interaction.method,
89
+ path: interaction.path,
90
+ normalizedPath: interaction.normalizedPath,
91
+ resolutionType: interaction.resolutionType,
92
+ confidence: interaction.confidence,
93
+ },
94
+ });
95
+ // Create 'tests' edge from test file to endpoint
96
+ const basename = path.basename(filePath);
97
+ if ((0, fileClassifier_1.isTestFile)(basename)) {
98
+ addEdge({
99
+ id: `file:${filePath}->tests->${endpointId}`,
100
+ type: 'tests',
101
+ sourceNodeId: `file:${filePath}`,
102
+ targetNodeId: endpointId,
103
+ sourceStage: 'ast',
104
+ metadata: {
105
+ resolutionType: interaction.resolutionType,
106
+ confidence: interaction.confidence,
107
+ },
108
+ });
109
+ }
110
+ // Create 'asserts' edge if assertion-linked
111
+ if (interaction.assertionLinked && interaction.assertionType && interaction.assertionType !== 'none') {
112
+ addEdge({
113
+ id: `file:${filePath}->asserts->${endpointId}`,
114
+ type: 'asserts',
115
+ sourceNodeId: `file:${filePath}`,
116
+ targetNodeId: endpointId,
117
+ sourceStage: 'ast',
118
+ metadata: { assertionType: interaction.assertionType },
119
+ });
120
+ }
121
+ }
122
+ }
123
+ // 3. Create function/class nodes from semantic models
124
+ for (const [filePath, model] of models) {
125
+ for (const [funcName, func] of model.functions) {
126
+ const funcNodeId = `function:${filePath}:${funcName}`;
127
+ addNode({
128
+ id: funcNodeId,
129
+ type: 'function',
130
+ label: funcName,
131
+ sourceStage: 'ast',
132
+ filePath,
133
+ metadata: {
134
+ parameters: func.parameters,
135
+ annotations: func.annotations,
136
+ httpCallCount: func.bodyHttpCalls.length,
137
+ calledFunctions: func.calledFunctions,
138
+ },
139
+ });
140
+ // Create 'calls' edges to other functions
141
+ for (const calledFunc of func.calledFunctions) {
142
+ // Try to find the called function in the same file or imported files
143
+ const targetFile = findFunctionFile(calledFunc, filePath, crossFileTable);
144
+ if (targetFile) {
145
+ const targetId = `function:${targetFile}:${calledFunc}`;
146
+ addEdge({
147
+ id: `${funcNodeId}->calls->${targetId}`,
148
+ type: 'calls',
149
+ sourceNodeId: funcNodeId,
150
+ targetNodeId: targetId,
151
+ sourceStage: 'ast',
152
+ metadata: {},
153
+ });
154
+ }
155
+ }
156
+ // Create edges from function to endpoints it defines (for controller methods)
157
+ for (const httpCall of func.bodyHttpCalls) {
158
+ if (httpCall.resolvedPath) {
159
+ const endpointId = `endpoint:${httpCall.method}:${httpCall.resolvedPath}`;
160
+ if (addedNodeIds.has(endpointId)) {
161
+ addEdge({
162
+ id: `${funcNodeId}->defines->${endpointId}`,
163
+ type: 'defines',
164
+ sourceNodeId: funcNodeId,
165
+ targetNodeId: endpointId,
166
+ sourceStage: 'ast',
167
+ metadata: {},
168
+ });
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ // 4. Create class nodes from cross-file table
175
+ for (const [className, classDecl] of crossFileTable.classes) {
176
+ const classNodeId = `class:${classDecl.filePath}:${className}`;
177
+ addNode({
178
+ id: classNodeId,
179
+ type: 'class',
180
+ label: className,
181
+ sourceStage: 'ast',
182
+ filePath: classDecl.filePath,
183
+ line: classDecl.line,
184
+ metadata: {
185
+ methods: classDecl.methods,
186
+ extendsClass: classDecl.extendsClass,
187
+ implementsInterfaces: classDecl.implementsInterfaces,
188
+ },
189
+ });
190
+ // Create 'extends' edge if there's a base class
191
+ if (classDecl.extendsClass) {
192
+ const baseDecl = crossFileTable.classes.get(classDecl.extendsClass);
193
+ if (baseDecl) {
194
+ const baseNodeId = `class:${baseDecl.filePath}:${classDecl.extendsClass}`;
195
+ addEdge({
196
+ id: `${classNodeId}->extends->${baseNodeId}`,
197
+ type: 'extends',
198
+ sourceNodeId: classNodeId,
199
+ targetNodeId: baseNodeId,
200
+ sourceStage: 'ast',
201
+ metadata: {},
202
+ });
203
+ }
204
+ }
205
+ }
206
+ // 5. Create assertion nodes from traversal results
207
+ for (const [filePath, result] of traversalResults) {
208
+ if (result.resolvedAssertions.length > 0) {
209
+ const assertionNodeId = `assertion:${filePath}`;
210
+ addNode({
211
+ id: assertionNodeId,
212
+ type: 'assertion',
213
+ label: `Assertions (${result.assertionSource})`,
214
+ sourceStage: 'ast',
215
+ filePath,
216
+ metadata: {
217
+ assertionSource: result.assertionSource,
218
+ assertionCount: result.resolvedAssertions.length,
219
+ traversalDepth: result.traversalDepth,
220
+ resolution: result.resolution,
221
+ },
222
+ });
223
+ }
224
+ }
225
+ // 6. Create import edges from the import graph
226
+ for (const [filePath, importedFiles] of crossFileTable.importGraph) {
227
+ const sourceId = `file:${filePath}`;
228
+ if (!addedNodeIds.has(sourceId))
229
+ continue;
230
+ for (const importedFile of importedFiles) {
231
+ const targetId = `file:${importedFile}`;
232
+ if (!addedNodeIds.has(targetId))
233
+ continue;
234
+ addEdge({
235
+ id: `${sourceId}->imports-helper->${targetId}`,
236
+ type: 'imports-helper',
237
+ sourceNodeId: sourceId,
238
+ targetNodeId: targetId,
239
+ sourceStage: 'ast',
240
+ metadata: {},
241
+ });
242
+ }
243
+ }
244
+ return { nodes, edges };
245
+ }
246
+ /**
247
+ * Find the file containing a function definition.
248
+ */
249
+ function findFunctionFile(funcName, fromFile, table) {
250
+ var _a;
251
+ // Check current file first
252
+ const currentModel = table.models.get(fromFile);
253
+ if (currentModel === null || currentModel === void 0 ? void 0 : currentModel.functions.has(funcName))
254
+ return fromFile;
255
+ // Check imported files
256
+ const importedFiles = (_a = table.importGraph.get(fromFile)) !== null && _a !== void 0 ? _a : [];
257
+ for (const importedFile of importedFiles) {
258
+ const model = table.models.get(importedFile);
259
+ if (model === null || model === void 0 ? void 0 : model.functions.has(funcName))
260
+ return importedFile;
261
+ }
262
+ // Search all models as fallback
263
+ for (const [filePath, model] of table.models) {
264
+ if (model.functions.has(funcName))
265
+ return filePath;
266
+ }
267
+ return undefined;
268
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Import resolver — resolves import paths to absolute file paths.
3
+ *
4
+ * Supports:
5
+ * - TypeScript/JavaScript: relative paths, index files, .ts/.js extension resolution
6
+ * - Java: package-based imports to file paths
7
+ * - Kotlin: same as Java
8
+ * - Python: relative and absolute module imports
9
+ * - Ruby: require/require_relative
10
+ */
11
+ import type { SupportedLanguage } from '../../../ast/astTypes';
12
+ /**
13
+ * Resolve an import source to an absolute file path.
14
+ *
15
+ * @param importSource - The import specifier (e.g. './utils', 'express', 'com.example.Service')
16
+ * @param fromFile - The absolute path of the file containing the import
17
+ * @param projectRoot - The project root directory
18
+ * @param language - The language of the importing file
19
+ * @returns The resolved absolute file path, or undefined if unresolvable
20
+ */
21
+ export declare function resolveImportPath(importSource: string, fromFile: string, projectRoot: string, language: SupportedLanguage): string | undefined;
22
+ //# sourceMappingURL=importResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importResolver.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/importResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,iBAAiB,GAC1B,MAAM,GAAG,SAAS,CAepB"}
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ /**
3
+ * Import resolver — resolves import paths to absolute file paths.
4
+ *
5
+ * Supports:
6
+ * - TypeScript/JavaScript: relative paths, index files, .ts/.js extension resolution
7
+ * - Java: package-based imports to file paths
8
+ * - Kotlin: same as Java
9
+ * - Python: relative and absolute module imports
10
+ * - Ruby: require/require_relative
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.resolveImportPath = resolveImportPath;
47
+ const path = __importStar(require("path"));
48
+ const fs = __importStar(require("fs"));
49
+ /**
50
+ * Resolve an import source to an absolute file path.
51
+ *
52
+ * @param importSource - The import specifier (e.g. './utils', 'express', 'com.example.Service')
53
+ * @param fromFile - The absolute path of the file containing the import
54
+ * @param projectRoot - The project root directory
55
+ * @param language - The language of the importing file
56
+ * @returns The resolved absolute file path, or undefined if unresolvable
57
+ */
58
+ function resolveImportPath(importSource, fromFile, projectRoot, language) {
59
+ switch (language) {
60
+ case 'typescript':
61
+ case 'javascript':
62
+ return resolveJsTsImport(importSource, fromFile, projectRoot);
63
+ case 'java':
64
+ case 'kotlin':
65
+ return resolveJavaKotlinImport(importSource, fromFile, projectRoot, language);
66
+ case 'python':
67
+ return resolvePythonImport(importSource, fromFile, projectRoot);
68
+ case 'ruby':
69
+ return resolveRubyImport(importSource, fromFile, projectRoot);
70
+ default:
71
+ return undefined;
72
+ }
73
+ }
74
+ // ─── JS/TS Import Resolution ─────────────────────────────────────────────────
75
+ const JS_TS_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
76
+ function resolveJsTsImport(importSource, fromFile, projectRoot) {
77
+ // Skip bare module specifiers (node_modules packages)
78
+ if (!importSource.startsWith('.') && !importSource.startsWith('/')) {
79
+ return undefined;
80
+ }
81
+ const fromDir = path.dirname(fromFile);
82
+ const basePath = path.resolve(fromDir, importSource);
83
+ // Try exact match first
84
+ if (existsAsFile(basePath))
85
+ return basePath;
86
+ // Try with extensions
87
+ for (const ext of JS_TS_EXTENSIONS) {
88
+ const withExt = basePath + ext;
89
+ if (existsAsFile(withExt))
90
+ return withExt;
91
+ }
92
+ // Try as directory with index file
93
+ for (const ext of JS_TS_EXTENSIONS) {
94
+ const indexFile = path.join(basePath, `index${ext}`);
95
+ if (existsAsFile(indexFile))
96
+ return indexFile;
97
+ }
98
+ return undefined;
99
+ }
100
+ // ─── Java/Kotlin Import Resolution ───────────────────────────────────────────
101
+ function resolveJavaKotlinImport(importSource, _fromFile, projectRoot, language) {
102
+ // Java import: com.example.service.UserService → src/main/java/com/example/service/UserService.java
103
+ // Handle wildcard imports: com.example.service.* → directory
104
+ const cleanImport = importSource.replace(/\.\*$/, '');
105
+ const pathParts = cleanImport.split('.');
106
+ const extensions = language === 'kotlin' ? ['.kt', '.kts', '.java'] : ['.java', '.kt'];
107
+ const sourceDirs = ['src/main/java', 'src/main/kotlin', 'src/test/java', 'src/test/kotlin', 'src'];
108
+ for (const sourceDir of sourceDirs) {
109
+ for (const ext of extensions) {
110
+ const filePath = path.join(projectRoot, sourceDir, ...pathParts) + ext;
111
+ if (existsAsFile(filePath))
112
+ return filePath;
113
+ }
114
+ }
115
+ return undefined;
116
+ }
117
+ // ─── Python Import Resolution ────────────────────────────────────────────────
118
+ function resolvePythonImport(importSource, fromFile, projectRoot) {
119
+ // Relative import: .utils or ..models
120
+ const dotMatch = /^(\.+)(.*)$/.exec(importSource);
121
+ if (dotMatch) {
122
+ const dots = dotMatch[1].length;
123
+ const rest = dotMatch[2];
124
+ let baseDir = path.dirname(fromFile);
125
+ for (let i = 1; i < dots; i++) {
126
+ baseDir = path.dirname(baseDir);
127
+ }
128
+ const parts = rest ? rest.split('.') : [];
129
+ return resolvePythonPath(path.join(baseDir, ...parts));
130
+ }
131
+ // Absolute import: package.module
132
+ const parts = importSource.split('.');
133
+ // Try from project root and common source directories
134
+ const searchDirs = [projectRoot, path.join(projectRoot, 'src'), path.join(projectRoot, 'tests')];
135
+ for (const dir of searchDirs) {
136
+ const result = resolvePythonPath(path.join(dir, ...parts));
137
+ if (result)
138
+ return result;
139
+ }
140
+ return undefined;
141
+ }
142
+ function resolvePythonPath(basePath) {
143
+ // Try as .py file
144
+ const asFile = basePath + '.py';
145
+ if (existsAsFile(asFile))
146
+ return asFile;
147
+ // Try as package (__init__.py)
148
+ const asPackage = path.join(basePath, '__init__.py');
149
+ if (existsAsFile(asPackage))
150
+ return asPackage;
151
+ return undefined;
152
+ }
153
+ // ─── Ruby Import Resolution ─────────────────────────────────────────────────
154
+ function resolveRubyImport(importSource, fromFile, projectRoot) {
155
+ // require_relative './utils' → relative to current file
156
+ // require 'app/models/user' → relative to project root / lib
157
+ if (importSource.startsWith('.')) {
158
+ const fromDir = path.dirname(fromFile);
159
+ const basePath = path.resolve(fromDir, importSource);
160
+ return tryRubyExtensions(basePath);
161
+ }
162
+ const searchDirs = [projectRoot, path.join(projectRoot, 'lib'), path.join(projectRoot, 'app')];
163
+ for (const dir of searchDirs) {
164
+ const result = tryRubyExtensions(path.join(dir, importSource));
165
+ if (result)
166
+ return result;
167
+ }
168
+ return undefined;
169
+ }
170
+ function tryRubyExtensions(basePath) {
171
+ if (existsAsFile(basePath))
172
+ return basePath;
173
+ const withRb = basePath + '.rb';
174
+ if (existsAsFile(withRb))
175
+ return withRb;
176
+ return undefined;
177
+ }
178
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
179
+ function existsAsFile(filePath) {
180
+ try {
181
+ return fs.statSync(filePath).isFile();
182
+ }
183
+ catch {
184
+ return false;
185
+ }
186
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * AST stage types — cross-file analysis, import resolution, and abstract layer traversal.
3
+ */
4
+ import type { SemanticModel, SemanticHttpCall, SemanticAssertion } from '../../../ast/astTypes';
5
+ import type { AssertionSource } from '../../types';
6
+ /**
7
+ * An import declaration extracted from a source file.
8
+ */
9
+ export interface ImportDeclaration {
10
+ /** The import source specifier (e.g. './utils', 'express', '@nestjs/common') */
11
+ source: string;
12
+ /** The resolved absolute file path (undefined if unresolvable) */
13
+ resolvedPath?: string;
14
+ /** Names imported (e.g. ['Router', 'Response'] or ['default']) */
15
+ importedNames: string[];
16
+ /** Whether this is a default import */
17
+ isDefault: boolean;
18
+ /** Line number in source file */
19
+ line?: number;
20
+ }
21
+ /**
22
+ * A class declaration extracted from a source file.
23
+ */
24
+ export interface ClassDeclaration {
25
+ name: string;
26
+ extendsClass?: string;
27
+ implementsInterfaces?: string[];
28
+ methods: string[];
29
+ filePath: string;
30
+ line?: number;
31
+ }
32
+ /**
33
+ * Multi-file symbol table aggregating all parsed file models.
34
+ */
35
+ export interface CrossFileSymbolTable {
36
+ /** All parsed semantic models keyed by file path */
37
+ models: Map<string, SemanticModel>;
38
+ /** Exported symbols: symbolName → { filePath, value } */
39
+ exportedSymbols: Map<string, {
40
+ filePath: string;
41
+ value: string;
42
+ }>;
43
+ /** All classes: className → declaration */
44
+ classes: Map<string, ClassDeclaration>;
45
+ /** Import graph: filePath → array of resolved import file paths */
46
+ importGraph: Map<string, string[]>;
47
+ }
48
+ /**
49
+ * Result of abstract layer traversal (inheritance, helpers, fixtures).
50
+ */
51
+ export interface TraversalResult {
52
+ /** Assertions resolved from base classes, helpers, or fixtures */
53
+ resolvedAssertions: SemanticAssertion[];
54
+ /** HTTP calls resolved from abstract layers */
55
+ resolvedHttpCalls: SemanticHttpCall[];
56
+ /** How the assertion was sourced */
57
+ assertionSource: AssertionSource;
58
+ /** How deep the traversal went */
59
+ traversalDepth: number;
60
+ /** Whether resolution is full or partial */
61
+ resolution: 'full' | 'partial';
62
+ /** Chain of unresolved references (for diagnostics) */
63
+ unresolvedChain?: string[];
64
+ /** Whether a cycle was detected during traversal */
65
+ cycleDetected: boolean;
66
+ }
67
+ /**
68
+ * Output of the AST pipeline stage.
69
+ */
70
+ export interface AstStageOutput {
71
+ /** All parsed semantic models */
72
+ models: Map<string, SemanticModel>;
73
+ /** Cross-file symbol table */
74
+ crossFileTable: CrossFileSymbolTable;
75
+ /** Traversal results per test file */
76
+ traversalResults: Map<string, TraversalResult>;
77
+ /** Files that were successfully analyzed */
78
+ analyzedFiles: string[];
79
+ /** Files that failed or were skipped */
80
+ skippedFiles: Array<{
81
+ file: string;
82
+ reason: string;
83
+ }>;
84
+ }
85
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAuC,MAAM,uBAAuB,CAAC;AACrI,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,aAAa,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACnC,yDAAyD;IACzD,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,2CAA2C;IAC3C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACvC,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,+CAA+C;IAC/C,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IACtC,oCAAoC;IACpC,eAAe,EAAE,eAAe,CAAC;IACjC,kCAAkC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACnC,8BAA8B;IAC9B,cAAc,EAAE,oBAAoB,CAAC;IACrC,sCAAsC;IACtC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC/C,4CAA4C;IAC5C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,wCAAwC;IACxC,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * AST stage types — cross-file analysis, import resolution, and abstract layer traversal.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,25 @@
1
+ /**
2
+ * DAST conflict emitter — detects conflicts between DAST probe results and
3
+ * AST-declared endpoints.
4
+ *
5
+ * Conflict rules from spec §7:
6
+ *
7
+ * | DAST Result | AST Declared | Conflict Type |
8
+ * |--------------------------|-----------------------|------------------------------------|
9
+ * | Not reachable | Endpoint exists | dast-unreachable |
10
+ * | Reachable, no auth check | @Secured present | security-annotation-not-enforced |
11
+ * | Returns 500 | No error handler | unhandled-server-error |
12
+ * | New endpoint found | Not in AST | undeclared-endpoint |
13
+ */
14
+ import type { ConflictNode } from '../../types';
15
+ import type { CoverageKnowledgeGraph } from '../../graph';
16
+ import type { DastProbeResult } from './types';
17
+ /**
18
+ * Emit conflicts by comparing DAST results with the AST-declared graph.
19
+ *
20
+ * @param results - DAST probe results
21
+ * @param graph - Current coverage knowledge graph
22
+ * @returns Array of conflict nodes to be added to the graph
23
+ */
24
+ export declare function emitDastConflicts(results: DastProbeResult[], graph: CoverageKnowledgeGraph): ConflictNode[];
25
+ //# sourceMappingURL=conflictEmitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflictEmitter.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/dast/conflictEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAkC,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,eAAe,EAAE,EAC1B,KAAK,EAAE,sBAAsB,GAC5B,YAAY,EAAE,CA0EhB"}