api-tests-coverage 1.0.18 → 1.0.20

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 (55) hide show
  1. package/README.md +7 -3
  2. package/dist/dashboard/dist/assets/_basePickBy-DUQHbXda.js +1 -0
  3. package/dist/dashboard/dist/assets/_baseUniq-Ct8XEXnH.js +1 -0
  4. package/dist/dashboard/dist/assets/arc-CjFGY63A.js +1 -0
  5. package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-Boahc5dR.js +36 -0
  6. package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-CavSRNuP.js +122 -0
  7. package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-w18S5AEN.js +10 -0
  8. package/dist/dashboard/dist/assets/channel-BgeGdqQG.js +1 -0
  9. package/dist/dashboard/dist/assets/chunk-4BX2VUAB-IN53WLTx.js +1 -0
  10. package/dist/dashboard/dist/assets/chunk-55IACEB6-kJkjQYxk.js +1 -0
  11. package/dist/dashboard/dist/assets/chunk-B4BG7PRW-B7YfMggR.js +165 -0
  12. package/dist/dashboard/dist/assets/chunk-DI55MBZ5-DfslhtXS.js +220 -0
  13. package/dist/dashboard/dist/assets/chunk-FMBD7UC4-BBMfQbw1.js +15 -0
  14. package/dist/dashboard/dist/assets/chunk-QN33PNHL-DFgUs0T8.js +1 -0
  15. package/dist/dashboard/dist/assets/chunk-QZHKN3VN-DKgOcPif.js +1 -0
  16. package/dist/dashboard/dist/assets/chunk-TZMSLE5B-BoJFBewj.js +1 -0
  17. package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-CM6Qs-Qs.js +1 -0
  18. package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-CM6Qs-Qs.js +1 -0
  19. package/dist/dashboard/dist/assets/clone-DEYRVSAn.js +1 -0
  20. package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-DMGRGhwB.js +1 -0
  21. package/dist/dashboard/dist/assets/dagre-6UL2VRFP-CJT7lofP.js +4 -0
  22. package/dist/dashboard/dist/assets/diagram-PSM6KHXK-DtE0cTIs.js +24 -0
  23. package/dist/dashboard/dist/assets/diagram-QEK2KX5R-BHyZd544.js +43 -0
  24. package/dist/dashboard/dist/assets/diagram-S2PKOQOG-qvXlTDud.js +24 -0
  25. package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-D0MbudeO.js +60 -0
  26. package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-DRAD4OG7.js +162 -0
  27. package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-DK_45K6s.js +267 -0
  28. package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-DYrdM8tK.js +65 -0
  29. package/dist/dashboard/dist/assets/graph-CD7-npU0.js +1 -0
  30. package/dist/dashboard/dist/assets/index-DbUdNJca.js +781 -0
  31. package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-DyT5Fs8R.js +2 -0
  32. package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-nYZBlgTD.js +139 -0
  33. package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-COTfX74l.js +89 -0
  34. package/dist/dashboard/dist/assets/layout-6njVG9Ld.js +1 -0
  35. package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-CkyYtMaD.js +68 -0
  36. package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-uWFQFMEe.js +30 -0
  37. package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-i3-JTN3e.js +7 -0
  38. package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-Dw260IiT.js +64 -0
  39. package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-LR8T4Hv0.js +10 -0
  40. package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-DBqchhlr.js +145 -0
  41. package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-Bl16d4W5.js +1 -0
  42. package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-B05ygO34.js +1 -0
  43. package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-D6JNee_P.js +61 -0
  44. package/dist/dashboard/dist/assets/treemap-GDKQZRPO-CCvvSJBX.js +162 -0
  45. package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-B72UwDAP.js +7 -0
  46. package/dist/dashboard/dist/index.html +1 -1
  47. package/dist/src/index.js +141 -3
  48. package/dist/src/inference/businessRuleInference.d.ts.map +1 -1
  49. package/dist/src/inference/businessRuleInference.js +95 -0
  50. package/dist/src/inference/integrationFlowInference.d.ts +11 -1
  51. package/dist/src/inference/integrationFlowInference.d.ts.map +1 -1
  52. package/dist/src/inference/integrationFlowInference.js +49 -2
  53. package/dist/src/inference/routeInference.d.ts.map +1 -1
  54. package/dist/src/inference/routeInference.js +54 -8
  55. package/package.json +1 -1
@@ -80,7 +80,18 @@ const JSDOC_ROUTE_PATTERN = /@route\s+\{(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)
80
80
  * Used to gate the URL+method object-form scan so we only activate it in
81
81
  * files that actually make HTTP calls (avoids scanning every JS file).
82
82
  */
83
- const HTTP_CLIENT_SIGNAL = /\$http|\bfetch\s*\(|\baxios\b/;
83
+ const HTTP_CLIENT_SIGNAL = /\$http|\bfetch\s*\(|\baxios\b|\bsuperagent\b/;
84
+ /**
85
+ * Matches client-side HTTP method calls: requests.get('/path'), api.post('/path'), etc.
86
+ * Group 1 = HTTP method, Group 2 = path literal starting with /
87
+ * Also handles: superagent.get(`${base}/path`) → captures the static suffix
88
+ */
89
+ const HTTP_CLIENT_METHOD_CALL = /\b\w+\s*\.\s*(get|post|put|patch|delete|del|head|options)\s*\(\s*(?:[^'"`\n]*?\+\s*)?['"`](\/[^'"`?\n]+)/i;
90
+ /**
91
+ * Signals that this JS/TS file is a client-side HTTP service layer.
92
+ * Expands on HTTP_CLIENT_SIGNAL to include superagent and common wrapper patterns.
93
+ */
94
+ const HTTP_SERVICE_SIGNAL = /\bsuperagent\b|\brequests\s*\.\s*(?:get|post|put|delete|del)\b|\bapi\s*\.\s*(?:get|post|put|delete)\b/;
84
95
  /**
85
96
  * Matches a `url:` property that ends with a literal path segment starting
86
97
  * with `/`. Handles both bare and concatenated forms:
@@ -162,6 +173,8 @@ function inferRoutesFromFile(filePath) {
162
173
  // We only enable the object-form method+url scanner for such files to
163
174
  // avoid false positives in ordinary JS/TS source.
164
175
  const usesHttpClient = HTTP_CLIENT_SIGNAL.test(content);
176
+ // Pre-check: does this file use a client-side HTTP service wrapper (requests.*, api.*, etc.)?
177
+ const usesHttpServiceWrapper = HTTP_SERVICE_SIGNAL.test(content);
165
178
  for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
166
179
  const line = lines[lineIdx];
167
180
  // 1a. router.method('/path', ...) — all on one line
@@ -239,6 +252,21 @@ function inferRoutesFromFile(filePath) {
239
252
  }
240
253
  }
241
254
  }
255
+ // 6. Client-side HTTP method calls: requests.get('/path'), api.post('/path')
256
+ // Only activate for files that contain HTTP service signals to avoid false positives
257
+ if (usesHttpServiceWrapper) {
258
+ const clientCallMatch = line.match(HTTP_CLIENT_METHOD_CALL);
259
+ if (clientCallMatch) {
260
+ let httpMethod = clientCallMatch[1].toLowerCase();
261
+ // Normalize 'del' → 'delete'
262
+ if (httpMethod === 'del')
263
+ httpMethod = 'delete';
264
+ if (exports.HTTP_METHODS.includes(httpMethod)) {
265
+ const routePath = clientCallMatch[2].split('?')[0]; // strip query string
266
+ addRoute(httpMethod, routePath, lineIdx + 1, 'code');
267
+ }
268
+ }
269
+ }
242
270
  }
243
271
  return [...byKey.values()];
244
272
  }
@@ -400,7 +428,7 @@ function findNextMethodNameInJava(javaLines, fromLine) {
400
428
  * @blueprint.route('/articles/<slug>', methods=['PUT'])
401
429
  * @app.route('/tags') ← defaults to GET
402
430
  */
403
- const FLASK_ROUTE = /@(\w+)\.route\s*\(\s*['"]([^'"]+)['"](?:\s*,\s*methods\s*=\s*\[([^\]]+)\])?\s*\)/;
431
+ const FLASK_ROUTE = /@(\w+)\.route\s*\(\s*['"]([^'"]+)['"](?:[^\n]*?\bmethods\s*=\s*[\[(]([^\])\n]+)[\])])?/;
404
432
  /**
405
433
  * Matches FastAPI decorators.
406
434
  * @app.get('/articles')
@@ -419,6 +447,22 @@ const FLASK_BLUEPRINT_CTOR = /(\w+)\s*=\s*Blueprint\s*\(\s*['"][^'"]+['"](?:\s*,
419
447
  * router = APIRouter(prefix="/articles")
420
448
  */
421
449
  const FASTAPI_APIROUTER = /(\w+)\s*=\s*APIRouter\s*\([^)]*?prefix\s*=\s*['"]([^'"]+)['"]/;
450
+ /**
451
+ * Scan ahead for a Python `def function_name(` line following a decorator.
452
+ * Skips additional decorator lines and stops at the first non-decorator,
453
+ * non-blank, non-comment line that is not a def.
454
+ */
455
+ function findPythonHandlerFunction(lines, fromLine) {
456
+ for (let j = fromLine + 1; j < Math.min(fromLine + 6, lines.length); j++) {
457
+ const m = lines[j].match(/^def\s+(\w+)\s*\(/);
458
+ if (m)
459
+ return m[1];
460
+ // Skip decorator lines
461
+ if (!lines[j].trim().startsWith('@') && lines[j].trim().length > 0 && !lines[j].trim().startsWith('#'))
462
+ break;
463
+ }
464
+ return undefined;
465
+ }
422
466
  /**
423
467
  * Infer routes from a Python (Flask/FastAPI) source file.
424
468
  */
@@ -432,10 +476,10 @@ function inferRoutesFromPythonFile(filePath) {
432
476
  }
433
477
  const lines = content.split('\n');
434
478
  const byKey = new Map();
435
- const addRoute = (method, routePath, lineNumber) => {
479
+ const addRoute = (method, routePath, lineNumber, handlerFunction) => {
436
480
  const key = `${method}:${routePath}`;
437
481
  if (!byKey.has(key)) {
438
- byKey.set(key, { method, path: routePath, sourceFile: filePath, lineNumber, discoveredVia: 'code' });
482
+ byKey.set(key, { method, path: routePath, handlerFunction, sourceFile: filePath, lineNumber, discoveredVia: 'code' });
439
483
  }
440
484
  };
441
485
  // Pass 1: Detect blueprint/router prefix for the file
@@ -463,18 +507,19 @@ function inferRoutesFromPythonFile(filePath) {
463
507
  const fullPath = localPrefix + (routePath.startsWith('/') ? routePath : '/' + routePath);
464
508
  // Normalize Flask <param> to {param}
465
509
  const normalizedPath = fullPath.replace(/<(?:\w+:)?(\w+)>/g, '{$1}');
510
+ const handlerFn = findPythonHandlerFunction(lines, i);
466
511
  if (methodsList) {
467
- // Parse methods=['GET', 'POST'] → individual routes
512
+ // Parse methods=['GET', 'POST'] or methods=('GET', 'POST') → individual routes
468
513
  const methods = methodsList.replace(/['"]/g, '').split(',').map((m) => m.trim().toLowerCase());
469
514
  for (const m of methods) {
470
515
  if (exports.HTTP_METHODS.includes(m)) {
471
- addRoute(m, normalizedPath, i + 1);
516
+ addRoute(m, normalizedPath, i + 1, handlerFn);
472
517
  }
473
518
  }
474
519
  }
475
520
  else {
476
521
  // Default to GET
477
- addRoute('get', normalizedPath, i + 1);
522
+ addRoute('get', normalizedPath, i + 1, handlerFn);
478
523
  }
479
524
  continue;
480
525
  }
@@ -484,8 +529,9 @@ function inferRoutesFromPythonFile(filePath) {
484
529
  const httpMethod = fastapiMatch[2].toLowerCase();
485
530
  const routePath = fastapiMatch[3];
486
531
  const fullPath = localPrefix + (routePath.startsWith('/') ? routePath : '/' + routePath);
532
+ const handlerFn = findPythonHandlerFunction(lines, i);
487
533
  // FastAPI uses {param} natively
488
- addRoute(httpMethod, fullPath, i + 1);
534
+ addRoute(httpMethod, fullPath, i + 1, handlerFn);
489
535
  continue;
490
536
  }
491
537
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-tests-coverage",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "CLI and library to measure how thoroughly your test suite exercises your API surface area",
5
5
  "main": "dist/src/lib/index.js",
6
6
  "types": "dist/src/lib/index.d.ts",