api-tests-coverage 1.0.13 → 1.0.15

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,115 @@
1
+ "use strict";
2
+ /**
3
+ * Pipeline orchestrator — chains the 6 stages (SCA → AST → TIA → IAST → DAST → Merge)
4
+ * and executes them in sequence, threading the PipelineContext through each stage.
5
+ *
6
+ * Optional stages (IAST, DAST) are skipped gracefully when disabled or when
7
+ * their data files are missing. The orchestrator catches per-stage errors
8
+ * and records them in diagnostics (RULE-02: never skip a file entirely on error).
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.runPipeline = runPipeline;
12
+ exports.createPipelineContext = createPipelineContext;
13
+ const graph_1 = require("./graph");
14
+ const stageInterface_1 = require("./stageInterface");
15
+ const scaStage_1 = require("./stages/sca/scaStage");
16
+ const astStage_1 = require("./stages/ast/astStage");
17
+ const tiaStage_1 = require("./stages/tia/tiaStage");
18
+ const iastStage_1 = require("./stages/iast/iastStage");
19
+ const dastStage_1 = require("./stages/dast/dastStage");
20
+ const mergeStage_1 = require("./stages/merge/mergeStage");
21
+ /**
22
+ * Run the full 6-stage coverage pipeline.
23
+ *
24
+ * @param options - Pipeline run options
25
+ * @returns PipelineRunResult with the final output, context, and timing information
26
+ */
27
+ async function runPipeline(options) {
28
+ const startTime = Date.now();
29
+ // Build full config with defaults
30
+ const config = {
31
+ projectRoot: options.projectRoot,
32
+ ...stageInterface_1.DEFAULT_PIPELINE_CONFIG,
33
+ ...options.config,
34
+ };
35
+ // Initialize context
36
+ const context = {
37
+ projectRoot: options.projectRoot,
38
+ config,
39
+ graph: new graph_1.CoverageKnowledgeGraph(),
40
+ diagnostics: new Map(),
41
+ stageOutputs: new Map(),
42
+ };
43
+ // Build stage pipeline
44
+ const stages = [
45
+ new scaStage_1.ScaStage(),
46
+ new astStage_1.AstStage(),
47
+ new tiaStage_1.TiaStage(),
48
+ ];
49
+ // IAST and DAST are optional
50
+ if (config.enableIast) {
51
+ stages.push(new iastStage_1.IastStage());
52
+ }
53
+ if (config.enableDast) {
54
+ stages.push(new dastStage_1.DastStage());
55
+ }
56
+ // Merge is always last
57
+ stages.push(new mergeStage_1.MergeStage());
58
+ const stagesDurationMs = {};
59
+ // Execute stages in sequence
60
+ for (const stage of stages) {
61
+ const stageStart = Date.now();
62
+ if (!options.silent) {
63
+ // Log stage name — caller can capture stdout if needed
64
+ }
65
+ try {
66
+ await stage.execute(context);
67
+ }
68
+ catch (err) {
69
+ // Record error in diagnostics but don't fail the pipeline for optional stages
70
+ const errorMsg = err instanceof Error ? err.message : String(err);
71
+ if (!context.diagnostics.has(stage.name)) {
72
+ context.diagnostics.set(stage.name, {
73
+ stageName: stage.name,
74
+ filesScanned: [],
75
+ filesSkipped: [],
76
+ durationMs: Date.now() - stageStart,
77
+ metadata: { error: errorMsg, failed: true },
78
+ });
79
+ }
80
+ if (!stage.optional) {
81
+ throw new Error(`Pipeline stage '${stage.name}' failed: ${errorMsg}`);
82
+ }
83
+ // Optional stages are swallowed — continue pipeline
84
+ }
85
+ stagesDurationMs[stage.name] = Date.now() - stageStart;
86
+ }
87
+ // Get the merge output
88
+ const mergeOutput = context.stageOutputs.get('merge');
89
+ if (!mergeOutput) {
90
+ throw new Error('Pipeline merge stage did not produce output');
91
+ }
92
+ return {
93
+ output: mergeOutput,
94
+ context,
95
+ durationMs: Date.now() - startTime,
96
+ stagesDurationMs: stagesDurationMs,
97
+ };
98
+ }
99
+ /**
100
+ * Create a pipeline context for testing or manual usage.
101
+ */
102
+ function createPipelineContext(projectRoot, configOverrides) {
103
+ const config = {
104
+ projectRoot,
105
+ ...stageInterface_1.DEFAULT_PIPELINE_CONFIG,
106
+ ...configOverrides,
107
+ };
108
+ return {
109
+ projectRoot,
110
+ config,
111
+ graph: new graph_1.CoverageKnowledgeGraph(),
112
+ diagnostics: new Map(),
113
+ stageOutputs: new Map(),
114
+ };
115
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Pipeline stage interface and execution context.
3
+ *
4
+ * Every stage in the 6-stage pipeline (SCA → AST → TIA → IAST → DAST → Merge)
5
+ * implements `PipelineStage`. The `PipelineContext` is threaded through all
6
+ * stages and accumulates the knowledge graph, diagnostics, and stage outputs.
7
+ */
8
+ import type { CoverageKnowledgeGraph } from './graph';
9
+ import type { StageName, StageDiagnostics } from './types';
10
+ import type { AstAnalysisConfig } from '../config/types';
11
+ export interface PipelineConfig {
12
+ projectRoot: string;
13
+ enableIast: boolean;
14
+ enableDast: boolean;
15
+ /** DAST probing rate limit in requests/second. Default: 10. (RULE-17) */
16
+ dastRateLimit: number;
17
+ /** Abstract layer traversal depth cap. Default: 5. (RULE-05) */
18
+ traversalDepthCap: number;
19
+ /** Per-file timeout in ms. Default: 30000. (RULE-16) */
20
+ fileTimeoutMs: number;
21
+ /** Path to IAST events file. Default: 'iast-events.json' in project root. */
22
+ iastEventsPath?: string;
23
+ /** Path to DAST results file. Default: 'dast-results.json' in project root. */
24
+ dastResultsPath?: string;
25
+ /** Existing AST analysis config (passed through to analyzers). */
26
+ astConfig?: AstAnalysisConfig;
27
+ }
28
+ export declare const DEFAULT_PIPELINE_CONFIG: Omit<PipelineConfig, 'projectRoot'>;
29
+ export interface PipelineContext {
30
+ projectRoot: string;
31
+ config: PipelineConfig;
32
+ graph: CoverageKnowledgeGraph;
33
+ diagnostics: Map<StageName, StageDiagnostics>;
34
+ /** Accumulated output from each completed stage. */
35
+ stageOutputs: Map<StageName, unknown>;
36
+ }
37
+ export interface PipelineStage<TOutput = unknown> {
38
+ /** Stage identifier. */
39
+ readonly name: StageName;
40
+ /** If true, the pipeline continues even if this stage is skipped or fails. */
41
+ readonly optional: boolean;
42
+ /** Execute the stage, enriching the context's graph and diagnostics. */
43
+ execute(context: PipelineContext): Promise<TOutput>;
44
+ }
45
+ //# sourceMappingURL=stageInterface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stageInterface.d.ts","sourceRoot":"","sources":["../../../src/pipeline/stageInterface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAIzD,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,SAAS,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,eAAO,MAAM,uBAAuB,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,CAMvE,CAAC;AAIF,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,sBAAsB,CAAC;IAC9B,WAAW,EAAE,GAAG,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAC9C,oDAAoD;IACpD,YAAY,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;CACvC;AAID,MAAM,WAAW,aAAa,CAAC,OAAO,GAAG,OAAO;IAC9C,wBAAwB;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,wEAAwE;IACxE,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrD"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ /**
3
+ * Pipeline stage interface and execution context.
4
+ *
5
+ * Every stage in the 6-stage pipeline (SCA → AST → TIA → IAST → DAST → Merge)
6
+ * implements `PipelineStage`. The `PipelineContext` is threaded through all
7
+ * stages and accumulates the knowledge graph, diagnostics, and stage outputs.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.DEFAULT_PIPELINE_CONFIG = void 0;
11
+ exports.DEFAULT_PIPELINE_CONFIG = {
12
+ enableIast: false,
13
+ enableDast: false,
14
+ dastRateLimit: 10,
15
+ traversalDepthCap: 5,
16
+ fileTimeoutMs: 30000,
17
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Abstract layer traversal — resolves inherited assertions, imported helpers,
3
+ * fixture injections, and page objects across the inheritance chain.
4
+ *
5
+ * Implements the spec's abstract layer resolution with a configurable depth cap
6
+ * (default 5, RULE-05). When the cap is reached, resolution is marked as 'partial'.
7
+ * Cycles are detected and broken (RULE-15).
8
+ */
9
+ import type { CrossFileSymbolTable } from './types';
10
+ import type { TraversalResult } from './types';
11
+ /**
12
+ * Traverse the inheritance chain starting from a test class to resolve
13
+ * assertions, HTTP calls, and helper references from base classes.
14
+ *
15
+ * @param className - The test class/suite to start from
16
+ * @param table - The cross-file symbol table
17
+ * @param depthCap - Maximum traversal depth (RULE-05: default 5)
18
+ */
19
+ export declare function traverseInheritanceChain(className: string, table: CrossFileSymbolTable, depthCap?: number): TraversalResult;
20
+ /**
21
+ * Resolve an imported helper function by following the import chain.
22
+ *
23
+ * @param functionName - The helper function to resolve
24
+ * @param fromFile - The file importing the helper
25
+ * @param table - The cross-file symbol table
26
+ * @param depthCap - Maximum traversal depth
27
+ */
28
+ export declare function resolveImportedHelper(functionName: string, fromFile: string, table: CrossFileSymbolTable, depthCap?: number): TraversalResult;
29
+ /**
30
+ * Resolve fixture-injected assertions and HTTP calls.
31
+ * Traces @BeforeEach/beforeEach/pytest fixtures/@Autowired patterns.
32
+ *
33
+ * @param fixtureName - The fixture function name
34
+ * @param table - The cross-file symbol table
35
+ * @param depthCap - Maximum traversal depth
36
+ */
37
+ export declare function resolveFixtureInjection(fixtureName: string, table: CrossFileSymbolTable, depthCap?: number): TraversalResult;
38
+ //# sourceMappingURL=abstractLayerTraversal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abstractLayerTraversal.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/abstractLayerTraversal.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,GAAE,MAAU,GACnB,eAAe,CA4EjB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,GAAE,MAAU,GACnB,eAAe,CA2EjB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,GAAE,MAAU,GACnB,eAAe,CAuCjB"}
@@ -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"}