api-tests-coverage 1.0.16 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/dashboard/dist/assets/_basePickBy-CYB1KXah.js +1 -0
  2. package/dist/dashboard/dist/assets/_baseUniq-Bwm426M6.js +1 -0
  3. package/dist/dashboard/dist/assets/arc-B7p8x22e.js +1 -0
  4. package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-wVr1_uNB.js +36 -0
  5. package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-BBXc88fn.js +122 -0
  6. package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-BsgzPfQ3.js +10 -0
  7. package/dist/dashboard/dist/assets/channel-psxgcQ_j.js +1 -0
  8. package/dist/dashboard/dist/assets/chunk-4BX2VUAB-BF8loPLD.js +1 -0
  9. package/dist/dashboard/dist/assets/chunk-55IACEB6-C3HNF-UF.js +1 -0
  10. package/dist/dashboard/dist/assets/chunk-B4BG7PRW-wQ6TCEMq.js +165 -0
  11. package/dist/dashboard/dist/assets/chunk-DI55MBZ5-B7xHuqZu.js +220 -0
  12. package/dist/dashboard/dist/assets/chunk-FMBD7UC4-K3PC79JF.js +15 -0
  13. package/dist/dashboard/dist/assets/chunk-QN33PNHL-CmeZ1h1Z.js +1 -0
  14. package/dist/dashboard/dist/assets/chunk-QZHKN3VN-Cyg7Km90.js +1 -0
  15. package/dist/dashboard/dist/assets/chunk-TZMSLE5B-C8KNXDi7.js +1 -0
  16. package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-AMwn99HP.js +1 -0
  17. package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-AMwn99HP.js +1 -0
  18. package/dist/dashboard/dist/assets/clone-KEkbvJY9.js +1 -0
  19. package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-YL9kFxCl.js +1 -0
  20. package/dist/dashboard/dist/assets/dagre-6UL2VRFP-NZWnQN_Y.js +4 -0
  21. package/dist/dashboard/dist/assets/diagram-PSM6KHXK-DGtyS7lD.js +24 -0
  22. package/dist/dashboard/dist/assets/diagram-QEK2KX5R-CSCGZUfr.js +43 -0
  23. package/dist/dashboard/dist/assets/diagram-S2PKOQOG-DdqZVGN1.js +24 -0
  24. package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-Dhb_VQMS.js +60 -0
  25. package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-gKUH-GJ2.js +162 -0
  26. package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-Dm_lLo9y.js +267 -0
  27. package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-DM9AW1aP.js +65 -0
  28. package/dist/dashboard/dist/assets/graph-Clj85F2M.js +1 -0
  29. package/dist/dashboard/dist/assets/index-CqEIqNus.js +781 -0
  30. package/dist/dashboard/dist/assets/index-xecKLQ58.css +1 -0
  31. package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-BMp4C5wf.js +2 -0
  32. package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-BC0GSZ7W.js +139 -0
  33. package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-D6aRd_q1.js +89 -0
  34. package/dist/dashboard/dist/assets/layout-BbJNDkTr.js +1 -0
  35. package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-B93XW27v.js +68 -0
  36. package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-9G1tEuaq.js +30 -0
  37. package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-jDtdB4Ws.js +7 -0
  38. package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-WIJ0qiJG.js +64 -0
  39. package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-Cb4WB9UB.js +10 -0
  40. package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-BqGJWVUS.js +145 -0
  41. package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-0Wd-KmOv.js +1 -0
  42. package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-BlwaoFEG.js +1 -0
  43. package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-CAmQOjBu.js +61 -0
  44. package/dist/dashboard/dist/assets/treemap-GDKQZRPO-CRP-WvE-.js +162 -0
  45. package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-5DoR2_q5.js +7 -0
  46. package/dist/dashboard/dist/index.html +2 -2
  47. package/dist/src/config/defaultConfig.d.ts.map +1 -1
  48. package/dist/src/config/defaultConfig.js +37 -0
  49. package/dist/src/config/types.d.ts +42 -0
  50. package/dist/src/config/types.d.ts.map +1 -1
  51. package/dist/src/config/validateConfig.d.ts.map +1 -1
  52. package/dist/src/config/validateConfig.js +3 -0
  53. package/dist/src/discovery/fileClassifier.d.ts.map +1 -1
  54. package/dist/src/discovery/fileClassifier.js +15 -16
  55. package/dist/src/discovery/projectDiscovery.d.ts.map +1 -1
  56. package/dist/src/discovery/projectDiscovery.js +4 -1
  57. package/dist/src/generation/ai-flow-exporter.d.ts +7 -0
  58. package/dist/src/generation/ai-flow-exporter.d.ts.map +1 -0
  59. package/dist/src/generation/ai-flow-exporter.js +260 -0
  60. package/dist/src/generation/context-builder.d.ts +16 -0
  61. package/dist/src/generation/context-builder.d.ts.map +1 -0
  62. package/dist/src/generation/context-builder.js +170 -0
  63. package/dist/src/generation/engine.d.ts +19 -0
  64. package/dist/src/generation/engine.d.ts.map +1 -0
  65. package/dist/src/generation/engine.js +204 -0
  66. package/dist/src/generation/file-router.d.ts +8 -0
  67. package/dist/src/generation/file-router.d.ts.map +1 -0
  68. package/dist/src/generation/file-router.js +98 -0
  69. package/dist/src/generation/gap-extractor.d.ts +7 -0
  70. package/dist/src/generation/gap-extractor.d.ts.map +1 -0
  71. package/dist/src/generation/gap-extractor.js +291 -0
  72. package/dist/src/generation/index.d.ts +9 -0
  73. package/dist/src/generation/index.d.ts.map +1 -0
  74. package/dist/src/generation/index.js +15 -0
  75. package/dist/src/generation/quality-scorer.d.ts +15 -0
  76. package/dist/src/generation/quality-scorer.d.ts.map +1 -0
  77. package/dist/src/generation/quality-scorer.js +273 -0
  78. package/dist/src/generation/template-renderer.d.ts +12 -0
  79. package/dist/src/generation/template-renderer.d.ts.map +1 -0
  80. package/dist/src/generation/template-renderer.js +546 -0
  81. package/dist/src/generation/types.d.ts +269 -0
  82. package/dist/src/generation/types.d.ts.map +1 -0
  83. package/dist/src/generation/types.js +6 -0
  84. package/dist/src/index.js +113 -0
  85. package/dist/src/languages/java/semanticBuilder.d.ts.map +1 -1
  86. package/dist/src/languages/java/semanticBuilder.js +69 -12
  87. package/dist/src/languages/javascript/angularDetector.d.ts.map +1 -1
  88. package/dist/src/languages/javascript/angularDetector.js +50 -17
  89. package/dist/src/languages/javascript/assertionResolver.js +6 -4
  90. package/dist/src/languages/javascript/hapiDetector.d.ts.map +1 -1
  91. package/dist/src/languages/javascript/hapiDetector.js +48 -5
  92. package/dist/src/languages/javascript/vueDetector.d.ts +2 -0
  93. package/dist/src/languages/javascript/vueDetector.d.ts.map +1 -1
  94. package/dist/src/languages/javascript/vueDetector.js +22 -0
  95. package/dist/src/languages/python/index.d.ts +1 -1
  96. package/dist/src/languages/python/index.d.ts.map +1 -1
  97. package/dist/src/languages/python/index.js +33 -3
  98. package/dist/src/pipeline/confidence.d.ts +6 -1
  99. package/dist/src/pipeline/confidence.d.ts.map +1 -1
  100. package/dist/src/pipeline/confidence.js +8 -3
  101. package/dist/src/pipeline/graph.d.ts.map +1 -1
  102. package/dist/src/pipeline/graph.js +16 -4
  103. package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -1
  104. package/dist/src/pipeline/stages/ast/astStage.js +46 -2
  105. package/dist/src/pipeline/stages/ast/baseUrlComposer.d.ts.map +1 -1
  106. package/dist/src/pipeline/stages/ast/baseUrlComposer.js +18 -4
  107. package/dist/src/pipeline/stages/ast/crossFileResolver.js +29 -0
  108. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -1
  109. package/dist/src/pipeline/stages/ast/graphBuilder.js +81 -0
  110. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.d.ts +3 -1
  111. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.d.ts.map +1 -1
  112. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.js +34 -14
  113. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.d.ts.map +1 -1
  114. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.js +22 -3
  115. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.d.ts.map +1 -1
  116. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.js +104 -28
  117. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.d.ts.map +1 -1
  118. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.js +56 -0
  119. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.d.ts.map +1 -1
  120. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.js +43 -18
  121. package/dist/src/pipeline/stages/ast/rulesEnforcer.d.ts.map +1 -1
  122. package/dist/src/pipeline/stages/ast/rulesEnforcer.js +336 -45
  123. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +2 -0
  124. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -1
  125. package/dist/src/pipeline/stages/merge/conflictDetector.js +54 -2
  126. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -1
  127. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +67 -3
  128. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -1
  129. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +8 -1
  130. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +8 -4
  131. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -1
  132. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +36 -10
  133. package/dist/src/pipeline/types.d.ts +1 -1
  134. package/dist/src/pipeline/types.d.ts.map +1 -1
  135. package/package.json +3 -3
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ /**
3
+ * Feature 28 — GapExtractor
4
+ * Reads coverage-summary.json (or coverage reports) and extracts DetectedGap objects.
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.extractGapsFromReports = extractGapsFromReports;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ // ─── Priority logic ───────────────────────────────────────────────────────────
44
+ function computePriority(type, authRequired, riskScore) {
45
+ if (type === 'security' || (type === 'auth' && authRequired))
46
+ return 'P0';
47
+ if (type === 'endpoint')
48
+ return 'P1';
49
+ if (type === 'error')
50
+ return 'P2';
51
+ if (type === 'business')
52
+ return 'P3';
53
+ if (type === 'parameter')
54
+ return 'P4';
55
+ if (type === 'integration')
56
+ return 'P5';
57
+ return 'P3';
58
+ }
59
+ function buildGapId(type, method, apiPath, condition) {
60
+ return `${type}:${method.toUpperCase()}:${apiPath}:${condition}`;
61
+ }
62
+ // ─── Summary JSON reader ──────────────────────────────────────────────────────
63
+ function readJson(filePath) {
64
+ if (!fs.existsSync(filePath))
65
+ return null;
66
+ try {
67
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ // ─── Public API ───────────────────────────────────────────────────────────────
74
+ function extractGapsFromReports(reportsDir) {
75
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24;
76
+ const gaps = [];
77
+ // Try coverage-summary.json first
78
+ const summaryPath = path.join(reportsDir, 'coverage-summary.json');
79
+ const summary = readJson(summaryPath);
80
+ if (!summary) {
81
+ // Return synthetic sample gaps for smoke-test / dry-run mode
82
+ return buildSampleGaps();
83
+ }
84
+ // ── Endpoint gaps ─────────────────────────────────────────────────────────
85
+ const endpointItems = (_c = (_b = (_a = summary.details) === null || _a === void 0 ? void 0 : _a.endpoint) === null || _b === void 0 ? void 0 : _b.items) !== null && _c !== void 0 ? _c : [];
86
+ for (const item of endpointItems) {
87
+ if (item.covered)
88
+ continue;
89
+ const method = ((_d = item.method) !== null && _d !== void 0 ? _d : 'GET').toUpperCase();
90
+ const apiPath = (_e = item.path) !== null && _e !== void 0 ? _e : '/unknown';
91
+ const authRequired = (_f = item.authRequired) !== null && _f !== void 0 ? _f : false;
92
+ const authOptional = (_g = item.authOptional) !== null && _g !== void 0 ? _g : false;
93
+ const riskScore = authRequired ? 85 : 60;
94
+ gaps.push({
95
+ id: buildGapId('endpoint', method, apiPath, 'uncovered'),
96
+ type: 'endpoint',
97
+ priority: computePriority('endpoint', authRequired, riskScore),
98
+ riskScore,
99
+ endpoint: {
100
+ method,
101
+ path: apiPath,
102
+ operationId: item.operationId,
103
+ tags: item.tags,
104
+ auth: {
105
+ required: authRequired,
106
+ optional: authOptional,
107
+ type: authRequired ? 'jwt' : undefined,
108
+ headerName: authRequired ? 'Authorization' : undefined,
109
+ scheme: authRequired ? 'Bearer' : undefined,
110
+ },
111
+ },
112
+ responses: [
113
+ { statusCode: 200, description: 'Success' },
114
+ ...(authRequired ? [{ statusCode: 401, description: 'Unauthorized' }] : []),
115
+ { statusCode: 422, description: 'Unprocessable Entity' },
116
+ ],
117
+ });
118
+ }
119
+ // ── Security gaps ─────────────────────────────────────────────────────────
120
+ const securityItems = (_k = (_j = (_h = summary.details) === null || _h === void 0 ? void 0 : _h.security) === null || _j === void 0 ? void 0 : _j.items) !== null && _k !== void 0 ? _k : [];
121
+ for (const item of securityItems) {
122
+ if (item.covered)
123
+ continue;
124
+ const parts = ((_l = item.endpoint) !== null && _l !== void 0 ? _l : 'GET /unknown').split(' ');
125
+ const method = ((_m = parts[0]) !== null && _m !== void 0 ? _m : 'GET').toUpperCase();
126
+ const apiPath = (_o = parts[1]) !== null && _o !== void 0 ? _o : '/unknown';
127
+ gaps.push({
128
+ id: buildGapId('security', method, apiPath, (_p = item.controlType) !== null && _p !== void 0 ? _p : 'auth-bypass'),
129
+ type: 'security',
130
+ priority: 'P0',
131
+ riskScore: 95,
132
+ endpoint: {
133
+ method,
134
+ path: apiPath,
135
+ auth: { required: true, optional: false, type: 'jwt', headerName: 'Authorization', scheme: 'Bearer' },
136
+ },
137
+ securityControl: {
138
+ type: (_q = item.controlType) !== null && _q !== void 0 ? _q : 'auth-bypass',
139
+ description: `Security control not tested for ${item.endpoint}`,
140
+ attackVector: 'Missing auth validation test',
141
+ expectedStatusCode: 401,
142
+ },
143
+ });
144
+ }
145
+ // ── Error gaps ────────────────────────────────────────────────────────────
146
+ const errorItems = (_t = (_s = (_r = summary.details) === null || _r === void 0 ? void 0 : _r.error) === null || _s === void 0 ? void 0 : _s.items) !== null && _t !== void 0 ? _t : [];
147
+ for (const item of errorItems) {
148
+ if (item.covered)
149
+ continue;
150
+ const parts = ((_u = item.endpoint) !== null && _u !== void 0 ? _u : 'GET /unknown').split(' ');
151
+ const method = ((_v = parts[0]) !== null && _v !== void 0 ? _v : 'GET').toUpperCase();
152
+ const apiPath = (_w = parts[1]) !== null && _w !== void 0 ? _w : '/unknown';
153
+ const statusCode = (_x = item.statusCode) !== null && _x !== void 0 ? _x : 500;
154
+ gaps.push({
155
+ id: buildGapId('error', method, apiPath, String(statusCode)),
156
+ type: 'error',
157
+ priority: 'P2',
158
+ riskScore: 65,
159
+ endpoint: {
160
+ method,
161
+ path: apiPath,
162
+ auth: { required: false, optional: false },
163
+ },
164
+ responses: [{ statusCode, description: `Error ${statusCode} not tested` }],
165
+ });
166
+ }
167
+ // ── Business rule gaps ────────────────────────────────────────────────────
168
+ const businessItems = (_0 = (_z = (_y = summary.details) === null || _y === void 0 ? void 0 : _y.business) === null || _z === void 0 ? void 0 : _z.items) !== null && _0 !== void 0 ? _0 : [];
169
+ for (const item of businessItems) {
170
+ if (item.covered)
171
+ continue;
172
+ const parts = ((_1 = item.endpoint) !== null && _1 !== void 0 ? _1 : 'GET /unknown').split(' ');
173
+ const method = ((_2 = parts[0]) !== null && _2 !== void 0 ? _2 : 'GET').toUpperCase();
174
+ const apiPath = (_3 = parts[1]) !== null && _3 !== void 0 ? _3 : '/unknown';
175
+ gaps.push({
176
+ id: buildGapId('business', method, apiPath, (_4 = item.ruleId) !== null && _4 !== void 0 ? _4 : 'business-rule'),
177
+ type: 'business',
178
+ priority: 'P3',
179
+ riskScore: 55,
180
+ endpoint: {
181
+ method,
182
+ path: apiPath,
183
+ auth: { required: false, optional: false },
184
+ },
185
+ businessRule: {
186
+ id: (_5 = item.ruleId) !== null && _5 !== void 0 ? _5 : 'rule-1',
187
+ description: (_6 = item.description) !== null && _6 !== void 0 ? _6 : 'Business rule not covered',
188
+ condition: 'When condition is met',
189
+ acceptanceCriteria: ['Expected behavior is verified'],
190
+ },
191
+ });
192
+ }
193
+ // ── Integration flow gaps ─────────────────────────────────────────────────
194
+ const integrationItems = (_9 = (_8 = (_7 = summary.details) === null || _7 === void 0 ? void 0 : _7.integration) === null || _8 === void 0 ? void 0 : _8.items) !== null && _9 !== void 0 ? _9 : [];
195
+ for (const item of integrationItems) {
196
+ if (item.covered)
197
+ continue;
198
+ gaps.push({
199
+ id: `integration:${(_10 = item.flowId) !== null && _10 !== void 0 ? _10 : 'flow'}:step-${(_11 = item.missingStepIndex) !== null && _11 !== void 0 ? _11 : 0}-missing`,
200
+ type: 'integration',
201
+ priority: 'P5',
202
+ riskScore: 45,
203
+ endpoint: {
204
+ method: 'GET',
205
+ path: '/unknown',
206
+ auth: { required: false, optional: false },
207
+ },
208
+ flow: {
209
+ id: (_12 = item.flowId) !== null && _12 !== void 0 ? _12 : 'flow-1',
210
+ name: (_13 = item.name) !== null && _13 !== void 0 ? _13 : 'Integration Flow',
211
+ steps: (_14 = item.steps) !== null && _14 !== void 0 ? _14 : [],
212
+ missingStepIndex: (_15 = item.missingStepIndex) !== null && _15 !== void 0 ? _15 : 0,
213
+ },
214
+ });
215
+ }
216
+ // ── Parameter gaps ────────────────────────────────────────────────────────
217
+ const parameterItems = (_18 = (_17 = (_16 = summary.details) === null || _16 === void 0 ? void 0 : _16.parameter) === null || _17 === void 0 ? void 0 : _17.items) !== null && _18 !== void 0 ? _18 : [];
218
+ for (const item of parameterItems) {
219
+ const parts = ((_19 = item.endpoint) !== null && _19 !== void 0 ? _19 : 'GET /unknown').split(' ');
220
+ const method = ((_20 = parts[0]) !== null && _20 !== void 0 ? _20 : 'GET').toUpperCase();
221
+ const apiPath = (_21 = parts[1]) !== null && _21 !== void 0 ? _21 : '/unknown';
222
+ const paramName = (_22 = item.parameter) !== null && _22 !== void 0 ? _22 : 'param';
223
+ const missingCases = ((_23 = item.missingCases) !== null && _23 !== void 0 ? _23 : ['boundary-min']);
224
+ const condition = (_24 = missingCases[0]) !== null && _24 !== void 0 ? _24 : 'boundary';
225
+ gaps.push({
226
+ id: buildGapId('parameter', method, apiPath, `${paramName}:${condition}`),
227
+ type: 'parameter',
228
+ priority: 'P4',
229
+ riskScore: 40,
230
+ endpoint: {
231
+ method,
232
+ path: apiPath,
233
+ auth: { required: false, optional: false },
234
+ },
235
+ parameters: [{
236
+ name: paramName,
237
+ in: 'query',
238
+ required: false,
239
+ schema: { type: 'string' },
240
+ missingCases,
241
+ }],
242
+ });
243
+ }
244
+ return gaps;
245
+ }
246
+ /** Build a minimal set of synthetic gaps for smoke-test / dry-run mode */
247
+ function buildSampleGaps() {
248
+ return [
249
+ {
250
+ id: 'endpoint:POST:/api/articles:uncovered',
251
+ type: 'endpoint',
252
+ priority: 'P1',
253
+ riskScore: 85,
254
+ endpoint: {
255
+ method: 'POST',
256
+ path: '/api/articles',
257
+ operationId: 'createArticle',
258
+ summary: 'Create Article',
259
+ auth: { required: true, optional: false, type: 'jwt', headerName: 'Authorization', scheme: 'Bearer' },
260
+ },
261
+ parameters: [
262
+ {
263
+ name: 'title',
264
+ in: 'body',
265
+ required: true,
266
+ schema: { type: 'string', minLength: 1 },
267
+ missingCases: ['missing-required'],
268
+ },
269
+ {
270
+ name: 'body',
271
+ in: 'body',
272
+ required: true,
273
+ schema: { type: 'string' },
274
+ missingCases: ['missing-required'],
275
+ },
276
+ {
277
+ name: 'description',
278
+ in: 'body',
279
+ required: true,
280
+ schema: { type: 'string' },
281
+ missingCases: ['missing-required'],
282
+ },
283
+ ],
284
+ responses: [
285
+ { statusCode: 201, description: 'Created' },
286
+ { statusCode: 401, description: 'Unauthorized' },
287
+ { statusCode: 422, description: 'Unprocessable Entity' },
288
+ ],
289
+ },
290
+ ];
291
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Feature 28 — Test Generation & Quality Intelligence Engine
3
+ * Public API exports
4
+ */
5
+ export { TestGenerationEngine, generateTests } from './engine';
6
+ export { scoreTests, scoreFile } from './quality-scorer';
7
+ export { exportAiFlows } from './ai-flow-exporter';
8
+ export type { DetectedGap, GeneratedFile, GenerationResult, GenerationOptions, TestQualityReport, FileQualityScore, AiReadyFlows, AiFlowGap, AiFlowExporterOptions, GenerationConfig, TestQualityConfig, AiFlowsConfig, } from './types';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/generation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,GACd,MAAM,SAAS,CAAC"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * Feature 28 — Test Generation & Quality Intelligence Engine
4
+ * Public API exports
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.exportAiFlows = exports.scoreFile = exports.scoreTests = exports.generateTests = exports.TestGenerationEngine = void 0;
8
+ var engine_1 = require("./engine");
9
+ Object.defineProperty(exports, "TestGenerationEngine", { enumerable: true, get: function () { return engine_1.TestGenerationEngine; } });
10
+ Object.defineProperty(exports, "generateTests", { enumerable: true, get: function () { return engine_1.generateTests; } });
11
+ var quality_scorer_1 = require("./quality-scorer");
12
+ Object.defineProperty(exports, "scoreTests", { enumerable: true, get: function () { return quality_scorer_1.scoreTests; } });
13
+ Object.defineProperty(exports, "scoreFile", { enumerable: true, get: function () { return quality_scorer_1.scoreFile; } });
14
+ var ai_flow_exporter_1 = require("./ai-flow-exporter");
15
+ Object.defineProperty(exports, "exportAiFlows", { enumerable: true, get: function () { return ai_flow_exporter_1.exportAiFlows; } });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Feature 28 — QualityScorer
3
+ * Scores existing test files on 5 dimensions (0–100 total).
4
+ *
5
+ * Dimensions (20 pts each):
6
+ * 1. Assertion Depth
7
+ * 2. Negative Path Coverage
8
+ * 3. Auth Coverage
9
+ * 4. Boundary Coverage
10
+ * 5. Test Independence
11
+ */
12
+ import type { FileQualityScore, TestQualityReport, QualityScorerOptions } from './types';
13
+ export declare function scoreFile(filePath: string): FileQualityScore;
14
+ export declare function scoreTests(opts: QualityScorerOptions): Promise<TestQualityReport>;
15
+ //# sourceMappingURL=quality-scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-scorer.d.ts","sourceRoot":"","sources":["../../../src/generation/quality-scorer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EACV,gBAAgB,EAEhB,iBAAiB,EACjB,oBAAoB,EAErB,MAAM,SAAS,CAAC;AA8JjB,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAoB5D;AAID,wBAAsB,UAAU,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAsEvF"}
@@ -0,0 +1,273 @@
1
+ "use strict";
2
+ /**
3
+ * Feature 28 — QualityScorer
4
+ * Scores existing test files on 5 dimensions (0–100 total).
5
+ *
6
+ * Dimensions (20 pts each):
7
+ * 1. Assertion Depth
8
+ * 2. Negative Path Coverage
9
+ * 3. Auth Coverage
10
+ * 4. Boundary Coverage
11
+ * 5. Test Independence
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
47
+ return (mod && mod.__esModule) ? mod : { "default": mod };
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.scoreFile = scoreFile;
51
+ exports.scoreTests = scoreTests;
52
+ const fs = __importStar(require("fs"));
53
+ const path = __importStar(require("path"));
54
+ const fast_glob_1 = __importDefault(require("fast-glob"));
55
+ // ─── Assertion depth scoring ──────────────────────────────────────────────────
56
+ function scoreAssertionDepth(content) {
57
+ // +20 — specific field value assertions
58
+ if (/expect\([^)]+\)\.(toBe|toEqual|toStrictEqual|toContain|toHaveProperty)\(/.test(content)) {
59
+ // Check if it's a specific value (not just existence)
60
+ if (/\.toBe\([^)]{3,}\)/.test(content) || /\.toEqual\([^)]{3,}\)/.test(content)) {
61
+ return 20;
62
+ }
63
+ // toHaveProperty with a value
64
+ if (/\.toHaveProperty\('[^']+',/.test(content)) {
65
+ return 20;
66
+ }
67
+ return 15;
68
+ }
69
+ // +10 — only status code assertions
70
+ if (/expect\(response\.status\)\.toBe\(/.test(content) && !/expect\(response\.body\)/.test(content)) {
71
+ return 10;
72
+ }
73
+ // +5 — weak assertions
74
+ if (/\.toBeTruthy\(\)|\.toBeDefined\(\)/.test(content)) {
75
+ return 5;
76
+ }
77
+ // +15 — property existence checks
78
+ if (/\.toHaveProperty\(/.test(content)) {
79
+ return 15;
80
+ }
81
+ // +10 — has some assertions
82
+ if (/expect\(/.test(content)) {
83
+ return 10;
84
+ }
85
+ return 0;
86
+ }
87
+ // ─── Negative path coverage ───────────────────────────────────────────────────
88
+ function scoreNegativePathCoverage(content) {
89
+ const has4xx = /toBe\(4\d{2}\)|toBe\(401\)|toBe\(403\)|toBe\(404\)|toBe\(422\)|toBe\(400\)/.test(content);
90
+ const has5xx = /toBe\(5\d{2}\)|toBe\(500\)/.test(content);
91
+ const hasErrorPath = /error|invalid|fail|missing|unauthorized|forbidden|not.found/i.test(content);
92
+ if (has4xx && (has5xx || hasErrorPath))
93
+ return 20;
94
+ if (has4xx)
95
+ return 15;
96
+ if (hasErrorPath)
97
+ return 10;
98
+ return 0;
99
+ }
100
+ // ─── Auth coverage ────────────────────────────────────────────────────────────
101
+ function scoreAuthCoverage(content) {
102
+ const hasAuthTest = /401|403|Authorization|auth.*token|token.*auth/i.test(content);
103
+ const hasBothPaths = /401/.test(content) && /200|201/.test(content);
104
+ const hasOptionalAuth = /optional.*auth|without.*auth|with.*auth/i.test(content);
105
+ if (hasBothPaths && hasOptionalAuth)
106
+ return 20;
107
+ if (hasBothPaths)
108
+ return 15;
109
+ if (hasAuthTest)
110
+ return 10;
111
+ return 0;
112
+ }
113
+ // ─── Boundary coverage ────────────────────────────────────────────────────────
114
+ function scoreBoundaryCoverage(content) {
115
+ const hasBoundaryMax = /max|maximum|overflow|too.long|too.large/i.test(content);
116
+ const hasBoundaryMin = /min|minimum|empty|too.short|too.small/i.test(content);
117
+ const hasNullTest = /null|undefined|missing.*required/i.test(content);
118
+ if (hasBoundaryMax && hasBoundaryMin && hasNullTest)
119
+ return 20;
120
+ if ((hasBoundaryMax || hasBoundaryMin) && hasNullTest)
121
+ return 15;
122
+ if (hasBoundaryMax || hasBoundaryMin)
123
+ return 10;
124
+ if (hasNullTest)
125
+ return 8;
126
+ return 0;
127
+ }
128
+ // ─── Test independence ────────────────────────────────────────────────────────
129
+ function scoreTestIndependence(content) {
130
+ // Deduct points for ordered dependencies
131
+ const hasAfterEach = /afterEach|afterAll/.test(content);
132
+ const hasBeforeEach = /beforeEach/.test(content);
133
+ const hasSharedMutableState = /let\s+\w+\s*;/.test(content) && !/beforeAll/.test(content);
134
+ // Has cleanup
135
+ if (hasAfterEach)
136
+ return 20;
137
+ // Uses beforeEach for isolation (good pattern for unit tests)
138
+ if (hasBeforeEach && !hasSharedMutableState)
139
+ return 18;
140
+ // Shared mutable state without cleanup (risky for parallelism)
141
+ if (hasSharedMutableState)
142
+ return 10;
143
+ // Simple independent tests
144
+ return 15;
145
+ }
146
+ // ─── Issue detection ──────────────────────────────────────────────────────────
147
+ function detectIssues(content, dimensions) {
148
+ const issues = [];
149
+ if (dimensions.assertionDepth < 10) {
150
+ issues.push('No meaningful assertions found — tests may pass even if the endpoint is broken');
151
+ }
152
+ else if (dimensions.assertionDepth < 15) {
153
+ issues.push('Only status code assertions, no body validation');
154
+ }
155
+ if (dimensions.negativePathCoverage < 10) {
156
+ issues.push('No error path coverage — 4xx/5xx scenarios not tested');
157
+ }
158
+ if (dimensions.authCoverage < 10 && /Authorization|auth.*token/i.test(content)) {
159
+ issues.push('Auth coverage incomplete: only happy path tested, no 401 scenario');
160
+ }
161
+ else if (dimensions.authCoverage < 15) {
162
+ issues.push('Auth coverage incomplete: optional-auth path not tested');
163
+ }
164
+ if (dimensions.boundaryCoverage < 8) {
165
+ issues.push('No boundary tests found (min/max/null/empty values not tested)');
166
+ }
167
+ if (dimensions.testIndependence < 15) {
168
+ issues.push('Tests may have ordering dependencies — shared mutable state without cleanup');
169
+ }
170
+ return issues;
171
+ }
172
+ function detectStrengths(content, dimensions) {
173
+ const strengths = [];
174
+ if (dimensions.assertionDepth >= 18) {
175
+ strengths.push('Good assertion depth on response body fields');
176
+ }
177
+ if (dimensions.negativePathCoverage >= 18) {
178
+ strengths.push('All error scenarios covered');
179
+ }
180
+ if (dimensions.authCoverage >= 18) {
181
+ strengths.push('Both authenticated and unauthenticated paths tested');
182
+ }
183
+ if (dimensions.boundaryCoverage >= 18) {
184
+ strengths.push('Comprehensive boundary testing');
185
+ }
186
+ if (dimensions.testIndependence >= 18) {
187
+ strengths.push('Tests are well-isolated and independent');
188
+ }
189
+ return strengths;
190
+ }
191
+ // ─── File scorer ──────────────────────────────────────────────────────────────
192
+ function scoreFile(filePath) {
193
+ const content = fs.readFileSync(filePath, 'utf8');
194
+ const dimensions = {
195
+ assertionDepth: scoreAssertionDepth(content),
196
+ negativePathCoverage: scoreNegativePathCoverage(content),
197
+ authCoverage: scoreAuthCoverage(content),
198
+ boundaryCoverage: scoreBoundaryCoverage(content),
199
+ testIndependence: scoreTestIndependence(content),
200
+ };
201
+ const score = Object.values(dimensions).reduce((sum, v) => sum + v, 0);
202
+ return {
203
+ file: filePath,
204
+ score,
205
+ dimensions,
206
+ issues: detectIssues(content, dimensions),
207
+ strengths: detectStrengths(content, dimensions),
208
+ };
209
+ }
210
+ // ─── Report builder ───────────────────────────────────────────────────────────
211
+ async function scoreTests(opts) {
212
+ var _a, _b;
213
+ const testsGlob = (_a = opts.testsGlob) !== null && _a !== void 0 ? _a : 'tests/**/*.test.ts';
214
+ const reportsDir = (_b = opts.reportsDir) !== null && _b !== void 0 ? _b : 'reports';
215
+ const files = await (0, fast_glob_1.default)(testsGlob, { cwd: process.cwd(), absolute: true });
216
+ const byFile = [];
217
+ for (const file of files) {
218
+ try {
219
+ byFile.push(scoreFile(file));
220
+ }
221
+ catch {
222
+ // Skip unreadable files
223
+ }
224
+ }
225
+ const overallScore = byFile.length > 0
226
+ ? Math.round(byFile.reduce((sum, f) => sum + f.score, 0) / byFile.length)
227
+ : 0;
228
+ const sorted = [...byFile].sort((a, b) => a.score - b.score);
229
+ const lowestQualityFiles = sorted.slice(0, 3).map(f => path.relative(process.cwd(), f.file));
230
+ // Build high-risk + low-quality gaps (stub — would cross-reference with gap data)
231
+ const highestRiskLowQualityGaps = sorted
232
+ .filter(f => f.score < 60)
233
+ .slice(0, 5)
234
+ .map(f => {
235
+ var _a;
236
+ return ({
237
+ endpoint: path.relative(process.cwd(), f.file),
238
+ qualityScore: f.score,
239
+ riskScore: 70,
240
+ primaryIssue: (_a = f.issues[0]) !== null && _a !== void 0 ? _a : 'Low quality score',
241
+ });
242
+ });
243
+ const report = {
244
+ overallScore,
245
+ byFile: byFile.map(f => ({ ...f, file: path.relative(process.cwd(), f.file) })),
246
+ lowestQualityFiles,
247
+ highestRiskLowQualityGaps,
248
+ };
249
+ // Write output
250
+ fs.mkdirSync(reportsDir, { recursive: true });
251
+ const outputPath = path.join(reportsDir, 'test-quality.json');
252
+ fs.writeFileSync(outputPath, JSON.stringify(report, null, 2), 'utf8');
253
+ // Also update coverage-summary.json if present
254
+ const summaryPath = path.join(reportsDir, 'coverage-summary.json');
255
+ if (fs.existsSync(summaryPath)) {
256
+ try {
257
+ const summary = JSON.parse(fs.readFileSync(summaryPath, 'utf8'));
258
+ summary['testQuality'] = report;
259
+ fs.writeFileSync(summaryPath, JSON.stringify(summary, null, 2), 'utf8');
260
+ }
261
+ catch {
262
+ // Non-fatal
263
+ }
264
+ }
265
+ if (opts.failBelow && opts.failBelow > 0) {
266
+ const failing = byFile.filter(f => f.score < opts.failBelow);
267
+ if (failing.length > 0) {
268
+ throw new Error(`Quality gate failed: ${failing.length} test file(s) scored below ${opts.failBelow}.\n` +
269
+ failing.map(f => ` ${path.relative(process.cwd(), f.file)}: ${f.score}/100`).join('\n'));
270
+ }
271
+ }
272
+ return report;
273
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Feature 28 — TemplateRenderer
3
+ * Renders test scaffolds from GenerationContext.
4
+ * Uses string-based templates (no external dependency required).
5
+ */
6
+ import type { GenerationContext, TestType } from './types';
7
+ export interface RenderOptions {
8
+ language: string;
9
+ testType: TestType;
10
+ }
11
+ export declare function renderTemplate(ctx: GenerationContext, opts: RenderOptions): string;
12
+ //# sourceMappingURL=template-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../../src/generation/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAW,QAAQ,EAAE,MAAM,SAAS,CAAC;AAujBpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CA8BlF"}