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,170 @@
1
+ "use strict";
2
+ /**
3
+ * Feature 28 — ContextBuilder
4
+ * Assembles a GenerationContext from a DetectedGap and project discovery info.
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.buildContext = buildContext;
41
+ const path = __importStar(require("path"));
42
+ // ─── Path normalisation ───────────────────────────────────────────────────────
43
+ /**
44
+ * Convert an OpenAPI-style path (/api/articles/{slug}) to framework-native
45
+ * Express/supertest style (/api/articles/:slug).
46
+ */
47
+ function normalizePathParam(p) {
48
+ return p.replace(/\{([^}]+)\}/g, ':$1');
49
+ }
50
+ // ─── Fixture generation ───────────────────────────────────────────────────────
51
+ function buildValidPayload(params) {
52
+ const payload = {};
53
+ for (const p of params) {
54
+ if (p.in !== 'body')
55
+ continue;
56
+ const { name, schema } = p;
57
+ payload[name] = generateExampleValue(schema);
58
+ }
59
+ return payload;
60
+ }
61
+ function buildInvalidPayload(params) {
62
+ const payload = {};
63
+ for (const p of params) {
64
+ if (p.in !== 'body' || !p.required)
65
+ continue;
66
+ // Omit required fields to create invalid payload
67
+ }
68
+ return payload;
69
+ }
70
+ function buildPathParams(pathTemplate) {
71
+ var _a;
72
+ const params = {};
73
+ const matches = (_a = pathTemplate.match(/\{([^}]+)\}/g)) !== null && _a !== void 0 ? _a : [];
74
+ for (const m of matches) {
75
+ const name = m.slice(1, -1);
76
+ if (name.toLowerCase().includes('id')) {
77
+ params[name] = '1';
78
+ }
79
+ else if (name.toLowerCase().includes('slug')) {
80
+ params[name] = 'test-slug';
81
+ }
82
+ else {
83
+ params[name] = 'test-value';
84
+ }
85
+ }
86
+ return params;
87
+ }
88
+ function generateExampleValue(schema) {
89
+ if (schema.enum && schema.enum.length > 0)
90
+ return schema.enum[0];
91
+ switch (schema.type) {
92
+ case 'string':
93
+ if (schema.format === 'email')
94
+ return 'test@example.com';
95
+ if (schema.format === 'date')
96
+ return '2026-01-01';
97
+ if (schema.format === 'date-time')
98
+ return '2026-01-01T00:00:00Z';
99
+ if (schema.format === 'uri')
100
+ return 'https://example.com';
101
+ if (schema.minLength && schema.minLength > 0)
102
+ return 'a'.repeat(schema.minLength);
103
+ return 'test-value';
104
+ case 'number':
105
+ case 'integer':
106
+ if (schema.minimum !== undefined)
107
+ return schema.minimum;
108
+ return 1;
109
+ case 'boolean':
110
+ return true;
111
+ case 'array':
112
+ return [];
113
+ case 'object':
114
+ return {};
115
+ default:
116
+ return 'test-value';
117
+ }
118
+ }
119
+ // ─── Import prefix computation ────────────────────────────────────────────────
120
+ function computeImportPrefix(outputFilePath, projectRoot) {
121
+ const outDir = path.dirname(outputFilePath);
122
+ const rel = path.relative(outDir, path.join(projectRoot, 'src'));
123
+ return rel.startsWith('.') ? rel : `./${rel}`;
124
+ }
125
+ function buildContext(gap, outputFilePath, discovery) {
126
+ var _a, _b;
127
+ const importPrefix = computeImportPrefix(outputFilePath, discovery.projectRoot);
128
+ const params = (_a = gap.parameters) !== null && _a !== void 0 ? _a : [];
129
+ const responses = (_b = gap.responses) !== null && _b !== void 0 ? _b : [
130
+ { statusCode: 200, description: 'Success' },
131
+ { statusCode: 401, description: 'Unauthorized' },
132
+ { statusCode: 422, description: 'Unprocessable Entity' },
133
+ ];
134
+ return {
135
+ gap: {
136
+ id: gap.id,
137
+ type: gap.type,
138
+ priority: gap.priority,
139
+ riskScore: gap.riskScore,
140
+ },
141
+ endpoint: {
142
+ method: gap.endpoint.method,
143
+ path: gap.endpoint.path,
144
+ pathNormalized: normalizePathParam(gap.endpoint.path),
145
+ operationId: gap.endpoint.operationId,
146
+ summary: gap.endpoint.summary,
147
+ tags: gap.endpoint.tags,
148
+ auth: gap.endpoint.auth,
149
+ },
150
+ parameters: params,
151
+ responses,
152
+ fixtures: {
153
+ validPayload: buildValidPayload(params),
154
+ invalidPayload: buildInvalidPayload(params),
155
+ authToken: 'Bearer <your-test-token>',
156
+ pathParams: buildPathParams(gap.endpoint.path),
157
+ },
158
+ project: {
159
+ name: discovery.name,
160
+ language: discovery.language,
161
+ framework: discovery.framework,
162
+ testFramework: discovery.testFramework,
163
+ baseUrl: discovery.baseUrl,
164
+ importPrefix,
165
+ },
166
+ businessRule: gap.businessRule,
167
+ securityControl: gap.securityControl,
168
+ flow: gap.flow,
169
+ };
170
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Feature 28 — TestGenerationEngine
3
+ * Main orchestrator for the test generation pipeline.
4
+ *
5
+ * Pipeline:
6
+ * GapList → GapClassifier → ContextBuilder → TemplateRenderer → FileRouter → FileWriter
7
+ */
8
+ import type { GenerationOptions, GenerationResult } from './types';
9
+ export declare class TestGenerationEngine {
10
+ private opts;
11
+ private discovery;
12
+ constructor(opts: GenerationOptions);
13
+ run(): Promise<GenerationResult>;
14
+ private generateForGap;
15
+ private getTestTypes;
16
+ private writeFile;
17
+ }
18
+ export declare function generateTests(opts: GenerationOptions): Promise<GenerationResult>;
19
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/generation/engine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,KAAK,EAGV,iBAAiB,EACjB,gBAAgB,EAKjB,MAAM,SAAS,CAAC;AA6DjB,qBAAa,oBAAoB;IAGnB,OAAO,CAAC,IAAI;IAFxB,OAAO,CAAC,SAAS,CAAuB;gBAEpB,IAAI,EAAE,iBAAiB;IAQrC,GAAG,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAsDtC,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,SAAS;CAUlB;AAID,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGtF"}
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ /**
3
+ * Feature 28 — TestGenerationEngine
4
+ * Main orchestrator for the test generation pipeline.
5
+ *
6
+ * Pipeline:
7
+ * GapList → GapClassifier → ContextBuilder → TemplateRenderer → FileRouter → FileWriter
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.TestGenerationEngine = void 0;
44
+ exports.generateTests = generateTests;
45
+ const fs = __importStar(require("fs"));
46
+ const path = __importStar(require("path"));
47
+ const gap_extractor_1 = require("./gap-extractor");
48
+ const context_builder_1 = require("./context-builder");
49
+ const template_renderer_1 = require("./template-renderer");
50
+ const file_router_1 = require("./file-router");
51
+ // ─── Priority ordering ────────────────────────────────────────────────────────
52
+ const PRIORITY_VALUES = {
53
+ P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5,
54
+ };
55
+ function priorityGte(a, b) {
56
+ return PRIORITY_VALUES[a] <= PRIORITY_VALUES[b];
57
+ }
58
+ // ─── Gap → test type mapping (Section 1.1 of spec) ───────────────────────────
59
+ const GAP_GENERATOR_MAP = {
60
+ endpoint: ['unit', 'integration', 'cypress'],
61
+ parameter: ['unit', 'integration'],
62
+ error: ['unit', 'integration'],
63
+ business: ['unit', 'integration'],
64
+ integration: ['integration', 'cypress'],
65
+ security: ['security', 'unit'],
66
+ auth: ['unit', 'integration', 'security'],
67
+ };
68
+ // ─── Discovery info loader ────────────────────────────────────────────────────
69
+ function loadDiscoveryInfo(reportsDir) {
70
+ var _a, _b, _c, _d, _e, _f, _g;
71
+ const summaryPath = path.join(reportsDir, 'coverage-summary.json');
72
+ if (fs.existsSync(summaryPath)) {
73
+ try {
74
+ const summary = JSON.parse(fs.readFileSync(summaryPath, 'utf8'));
75
+ const di = (_a = summary.discoveryInfo) !== null && _a !== void 0 ? _a : {};
76
+ return {
77
+ name: (_d = (_b = di.name) !== null && _b !== void 0 ? _b : (_c = summary.project) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : 'my-api',
78
+ language: (_e = di.language) !== null && _e !== void 0 ? _e : 'typescript',
79
+ framework: (_f = di.framework) !== null && _f !== void 0 ? _f : 'express',
80
+ testFramework: (_g = di.testFramework) !== null && _g !== void 0 ? _g : 'jest',
81
+ baseUrl: 'http://localhost:3000',
82
+ projectRoot: process.cwd(),
83
+ appImportPath: di.appImportPath,
84
+ };
85
+ }
86
+ catch {
87
+ // Fall through to defaults
88
+ }
89
+ }
90
+ return {
91
+ name: 'my-api',
92
+ language: 'typescript',
93
+ framework: 'express',
94
+ testFramework: 'jest',
95
+ baseUrl: 'http://localhost:3000',
96
+ projectRoot: process.cwd(),
97
+ };
98
+ }
99
+ // ─── Engine ───────────────────────────────────────────────────────────────────
100
+ class TestGenerationEngine {
101
+ constructor(opts) {
102
+ this.opts = opts;
103
+ this.discovery = loadDiscoveryInfo(opts.reportsDir);
104
+ // Override detection with CLI options
105
+ if (opts.language)
106
+ this.discovery.language = opts.language;
107
+ if (opts.framework)
108
+ this.discovery.framework = opts.framework;
109
+ }
110
+ async run() {
111
+ var _a, _b;
112
+ const result = {
113
+ files: [],
114
+ dryRun: (_a = this.opts.dryRun) !== null && _a !== void 0 ? _a : false,
115
+ totalGaps: 0,
116
+ generatedCount: 0,
117
+ skippedCount: 0,
118
+ errors: [],
119
+ };
120
+ // 1. Extract gaps from reports
121
+ let gaps = (0, gap_extractor_1.extractGapsFromReports)(this.opts.reportsDir);
122
+ // 2. Filter by specific gap ID if requested
123
+ if (this.opts.gapId) {
124
+ gaps = gaps.filter(g => g.id === this.opts.gapId);
125
+ }
126
+ // 3. Filter by priority
127
+ const minPriority = (_b = this.opts.priority) !== null && _b !== void 0 ? _b : 'P1';
128
+ gaps = gaps.filter(g => priorityGte(g.priority, minPriority));
129
+ // 4. Filter by type
130
+ if (this.opts.types && this.opts.types.length > 0) {
131
+ gaps = gaps.filter(g => this.opts.types.includes(g.type));
132
+ }
133
+ // 5. Sort by priority (P0 first)
134
+ gaps = (0, file_router_1.sortGapsByPriority)(gaps);
135
+ result.totalGaps = gaps.length;
136
+ // 6. Generate files for each gap
137
+ for (const gap of gaps) {
138
+ try {
139
+ const generated = this.generateForGap(gap);
140
+ for (const file of generated) {
141
+ result.files.push(file);
142
+ if (!this.opts.dryRun) {
143
+ this.writeFile(file);
144
+ }
145
+ result.generatedCount++;
146
+ }
147
+ }
148
+ catch (err) {
149
+ result.errors.push({
150
+ gapId: gap.id,
151
+ message: err instanceof Error ? err.message : String(err),
152
+ });
153
+ }
154
+ }
155
+ return result;
156
+ }
157
+ generateForGap(gap) {
158
+ const files = [];
159
+ const testTypes = this.getTestTypes(gap);
160
+ const language = this.discovery.language;
161
+ const convention = 'kebab';
162
+ for (const testType of testTypes) {
163
+ const outputPath = (0, file_router_1.routeOutputFile)(gap, testType, this.opts.outDir, language, convention);
164
+ const ctx = (0, context_builder_1.buildContext)(gap, outputPath, this.discovery);
165
+ const content = (0, template_renderer_1.renderTemplate)(ctx, { language, testType });
166
+ files.push({
167
+ gapId: gap.id,
168
+ filePath: path.resolve(outputPath),
169
+ relativePath: outputPath,
170
+ content,
171
+ testType,
172
+ language,
173
+ framework: this.discovery.testFramework,
174
+ });
175
+ }
176
+ return files;
177
+ }
178
+ getTestTypes(gap) {
179
+ var _a;
180
+ let types = (_a = GAP_GENERATOR_MAP[gap.type]) !== null && _a !== void 0 ? _a : ['unit'];
181
+ // Apply exclusion flags
182
+ if (this.opts.noSecurity) {
183
+ types = types.filter(t => t !== 'security');
184
+ }
185
+ if (this.opts.noCypress) {
186
+ types = types.filter(t => t !== 'cypress');
187
+ }
188
+ return types;
189
+ }
190
+ writeFile(file) {
191
+ const dir = path.dirname(file.relativePath);
192
+ fs.mkdirSync(dir, { recursive: true });
193
+ if (fs.existsSync(file.relativePath) && !this.opts.overwrite) {
194
+ return;
195
+ }
196
+ fs.writeFileSync(file.relativePath, file.content, 'utf8');
197
+ }
198
+ }
199
+ exports.TestGenerationEngine = TestGenerationEngine;
200
+ // ─── Public API ───────────────────────────────────────────────────────────────
201
+ async function generateTests(opts) {
202
+ const engine = new TestGenerationEngine(opts);
203
+ return engine.run();
204
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Feature 28 — FileRouter
3
+ * Determines output file paths for generated test files.
4
+ */
5
+ import type { DetectedGap, TestType, FileNamingConvention } from './types';
6
+ export declare function routeOutputFile(gap: DetectedGap, testType: TestType, outDir: string, language: string, convention?: FileNamingConvention): string;
7
+ export declare function sortGapsByPriority(gaps: DetectedGap[]): DetectedGap[];
8
+ //# sourceMappingURL=file-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-router.d.ts","sourceRoot":"","sources":["../../../src/generation/file-router.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAyC3E,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,GAAE,oBAA8B,GACzC,MAAM,CAoBR;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAErE"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * Feature 28 — FileRouter
4
+ * Determines output file paths for generated test files.
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.routeOutputFile = routeOutputFile;
41
+ exports.sortGapsByPriority = sortGapsByPriority;
42
+ const path = __importStar(require("path"));
43
+ const PRIORITY_ORDER = { P0: 0, P1: 1, P2: 2, P3: 3, P4: 4, P5: 5 };
44
+ function toKebab(s) {
45
+ return s
46
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
47
+ .replace(/[^a-zA-Z0-9]+/g, '-')
48
+ .replace(/^-+|-+$/g, '')
49
+ .toLowerCase();
50
+ }
51
+ function toCamel(s) {
52
+ return toKebab(s)
53
+ .split('-')
54
+ .map((w, i) => (i === 0 ? w : w.charAt(0).toUpperCase() + w.slice(1)))
55
+ .join('');
56
+ }
57
+ function toSnake(s) {
58
+ return toKebab(s).replace(/-/g, '_');
59
+ }
60
+ function applyNaming(name, convention) {
61
+ switch (convention) {
62
+ case 'camelCase': return toCamel(name);
63
+ case 'snake_case': return toSnake(name);
64
+ case 'kebab':
65
+ default: return toKebab(name);
66
+ }
67
+ }
68
+ function pathToFileName(method, apiPath, convention) {
69
+ const parts = apiPath
70
+ .split('/')
71
+ .filter(Boolean)
72
+ .map(p => p.replace(/[{}]/g, '').replace(/[^a-zA-Z0-9]/g, '-'));
73
+ const base = [...parts, method.toLowerCase()].join('-');
74
+ return applyNaming(base, convention);
75
+ }
76
+ function routeOutputFile(gap, testType, outDir, language, convention = 'kebab') {
77
+ const method = gap.endpoint.method.toLowerCase();
78
+ const apiPath = gap.endpoint.path;
79
+ const baseName = pathToFileName(method, apiPath, convention);
80
+ switch (testType) {
81
+ case 'security':
82
+ return path.join(outDir, 'security', `${baseName}.security.test.ts`);
83
+ case 'cypress':
84
+ return path.join('cypress', 'e2e', 'generated', `${baseName}.cy.js`);
85
+ case 'integration':
86
+ if (gap.flow) {
87
+ const flowName = applyNaming(gap.flow.name, convention);
88
+ return path.join(outDir, 'flows', `${flowName}.flow.test.ts`);
89
+ }
90
+ return path.join(outDir, `${baseName}.integration.test.ts`);
91
+ case 'unit':
92
+ default:
93
+ return path.join(outDir, `${baseName}.test.ts`);
94
+ }
95
+ }
96
+ function sortGapsByPriority(gaps) {
97
+ return [...gaps].sort((a, b) => { var _a, _b; return ((_a = PRIORITY_ORDER[a.priority]) !== null && _a !== void 0 ? _a : 99) - ((_b = PRIORITY_ORDER[b.priority]) !== null && _b !== void 0 ? _b : 99); });
98
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Feature 28 — GapExtractor
3
+ * Reads coverage-summary.json (or coverage reports) and extracts DetectedGap objects.
4
+ */
5
+ import type { DetectedGap } from './types';
6
+ export declare function extractGapsFromReports(reportsDir: string): DetectedGap[];
7
+ //# sourceMappingURL=gap-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gap-extractor.d.ts","sourceRoot":"","sources":["../../../src/generation/gap-extractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAoC,MAAM,SAAS,CAAC;AA4D7E,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE,CAmLxE"}