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.
- package/dist/src/pipeline/confidence.d.ts +70 -0
- package/dist/src/pipeline/confidence.d.ts.map +1 -0
- package/dist/src/pipeline/confidence.js +198 -0
- package/dist/src/pipeline/graph.d.ts +58 -0
- package/dist/src/pipeline/graph.d.ts.map +1 -0
- package/dist/src/pipeline/graph.js +199 -0
- package/dist/src/pipeline/index.d.ts +24 -0
- package/dist/src/pipeline/index.d.ts.map +1 -0
- package/dist/src/pipeline/index.js +41 -0
- package/dist/src/pipeline/orchestrator.d.ts +42 -0
- package/dist/src/pipeline/orchestrator.d.ts.map +1 -0
- package/dist/src/pipeline/orchestrator.js +115 -0
- package/dist/src/pipeline/stageInterface.d.ts +45 -0
- package/dist/src/pipeline/stageInterface.d.ts.map +1 -0
- package/dist/src/pipeline/stageInterface.js +17 -0
- package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts +38 -0
- package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts.map +1 -0
- package/dist/src/pipeline/stages/ast/abstractLayerTraversal.js +203 -0
- package/dist/src/pipeline/stages/ast/astStage.d.ts +19 -0
- package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -0
- package/dist/src/pipeline/stages/ast/astStage.js +238 -0
- package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts +23 -0
- package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts.map +1 -0
- package/dist/src/pipeline/stages/ast/crossFileResolver.js +183 -0
- package/dist/src/pipeline/stages/ast/graphBuilder.d.ts +15 -0
- package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -0
- package/dist/src/pipeline/stages/ast/graphBuilder.js +268 -0
- package/dist/src/pipeline/stages/ast/importResolver.d.ts +22 -0
- package/dist/src/pipeline/stages/ast/importResolver.d.ts.map +1 -0
- package/dist/src/pipeline/stages/ast/importResolver.js +186 -0
- package/dist/src/pipeline/stages/ast/types.d.ts +85 -0
- package/dist/src/pipeline/stages/ast/types.d.ts.map +1 -0
- package/dist/src/pipeline/stages/ast/types.js +5 -0
- package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts +25 -0
- package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts.map +1 -0
- package/dist/src/pipeline/stages/dast/conflictEmitter.js +90 -0
- package/dist/src/pipeline/stages/dast/dastStage.d.ts +17 -0
- package/dist/src/pipeline/stages/dast/dastStage.d.ts.map +1 -0
- package/dist/src/pipeline/stages/dast/dastStage.js +203 -0
- package/dist/src/pipeline/stages/dast/types.d.ts +49 -0
- package/dist/src/pipeline/stages/dast/types.d.ts.map +1 -0
- package/dist/src/pipeline/stages/dast/types.js +9 -0
- package/dist/src/pipeline/stages/iast/iastStage.d.ts +17 -0
- package/dist/src/pipeline/stages/iast/iastStage.d.ts.map +1 -0
- package/dist/src/pipeline/stages/iast/iastStage.js +191 -0
- package/dist/src/pipeline/stages/iast/types.d.ts +48 -0
- package/dist/src/pipeline/stages/iast/types.d.ts.map +1 -0
- package/dist/src/pipeline/stages/iast/types.js +8 -0
- package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +17 -0
- package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -0
- package/dist/src/pipeline/stages/merge/conflictDetector.js +60 -0
- package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts +15 -0
- package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -0
- package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +141 -0
- package/dist/src/pipeline/stages/merge/mergeRules.d.ts +39 -0
- package/dist/src/pipeline/stages/merge/mergeRules.d.ts.map +1 -0
- package/dist/src/pipeline/stages/merge/mergeRules.js +90 -0
- package/dist/src/pipeline/stages/merge/mergeStage.d.ts +20 -0
- package/dist/src/pipeline/stages/merge/mergeStage.d.ts.map +1 -0
- package/dist/src/pipeline/stages/merge/mergeStage.js +145 -0
- package/dist/src/pipeline/stages/merge/summaryComputer.d.ts +11 -0
- package/dist/src/pipeline/stages/merge/summaryComputer.d.ts.map +1 -0
- package/dist/src/pipeline/stages/merge/summaryComputer.js +46 -0
- package/dist/src/pipeline/stages/sca/ciDetector.d.ts +15 -0
- package/dist/src/pipeline/stages/sca/ciDetector.d.ts.map +1 -0
- package/dist/src/pipeline/stages/sca/ciDetector.js +87 -0
- package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts +31 -0
- package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts.map +1 -0
- package/dist/src/pipeline/stages/sca/dependencyClassification.js +296 -0
- package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts +25 -0
- package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts.map +1 -0
- package/dist/src/pipeline/stages/sca/dependencyDetector.js +416 -0
- package/dist/src/pipeline/stages/sca/scaStage.d.ts +21 -0
- package/dist/src/pipeline/stages/sca/scaStage.d.ts.map +1 -0
- package/dist/src/pipeline/stages/sca/scaStage.js +208 -0
- package/dist/src/pipeline/stages/sca/types.d.ts +61 -0
- package/dist/src/pipeline/stages/sca/types.d.ts.map +1 -0
- package/dist/src/pipeline/stages/sca/types.js +9 -0
- package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts +19 -0
- package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -0
- package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +118 -0
- package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts +20 -0
- package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts.map +1 -0
- package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +238 -0
- package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts +22 -0
- package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts.map +1 -0
- package/dist/src/pipeline/stages/tia/testEndpointMapper.js +134 -0
- package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts +16 -0
- package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -0
- package/dist/src/pipeline/stages/tia/testLayerClassifier.js +191 -0
- package/dist/src/pipeline/stages/tia/tiaStage.d.ts +20 -0
- package/dist/src/pipeline/stages/tia/tiaStage.d.ts.map +1 -0
- package/dist/src/pipeline/stages/tia/tiaStage.js +215 -0
- package/dist/src/pipeline/stages/tia/types.d.ts +52 -0
- package/dist/src/pipeline/stages/tia/types.d.ts.map +1 -0
- package/dist/src/pipeline/stages/tia/types.js +5 -0
- package/dist/src/pipeline/types.d.ts +128 -0
- package/dist/src/pipeline/types.d.ts.map +1 -0
- package/dist/src/pipeline/types.js +9 -0
- 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"}
|