api-tests-coverage 1.0.16 → 1.0.17

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 (56) hide show
  1. package/dist/dashboard/dist/index.html +1 -1
  2. package/dist/src/discovery/fileClassifier.d.ts.map +1 -1
  3. package/dist/src/discovery/fileClassifier.js +15 -16
  4. package/dist/src/discovery/projectDiscovery.d.ts.map +1 -1
  5. package/dist/src/discovery/projectDiscovery.js +4 -1
  6. package/dist/src/languages/java/semanticBuilder.d.ts.map +1 -1
  7. package/dist/src/languages/java/semanticBuilder.js +69 -12
  8. package/dist/src/languages/javascript/angularDetector.d.ts.map +1 -1
  9. package/dist/src/languages/javascript/angularDetector.js +50 -17
  10. package/dist/src/languages/javascript/assertionResolver.js +6 -4
  11. package/dist/src/languages/javascript/hapiDetector.d.ts.map +1 -1
  12. package/dist/src/languages/javascript/hapiDetector.js +48 -5
  13. package/dist/src/languages/javascript/vueDetector.d.ts +2 -0
  14. package/dist/src/languages/javascript/vueDetector.d.ts.map +1 -1
  15. package/dist/src/languages/javascript/vueDetector.js +22 -0
  16. package/dist/src/languages/python/index.d.ts +1 -1
  17. package/dist/src/languages/python/index.d.ts.map +1 -1
  18. package/dist/src/languages/python/index.js +33 -3
  19. package/dist/src/pipeline/confidence.d.ts +6 -1
  20. package/dist/src/pipeline/confidence.d.ts.map +1 -1
  21. package/dist/src/pipeline/confidence.js +8 -3
  22. package/dist/src/pipeline/graph.d.ts.map +1 -1
  23. package/dist/src/pipeline/graph.js +16 -4
  24. package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -1
  25. package/dist/src/pipeline/stages/ast/astStage.js +46 -2
  26. package/dist/src/pipeline/stages/ast/baseUrlComposer.d.ts.map +1 -1
  27. package/dist/src/pipeline/stages/ast/baseUrlComposer.js +18 -4
  28. package/dist/src/pipeline/stages/ast/crossFileResolver.js +29 -0
  29. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -1
  30. package/dist/src/pipeline/stages/ast/graphBuilder.js +81 -0
  31. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.d.ts +3 -1
  32. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.d.ts.map +1 -1
  33. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.js +34 -14
  34. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.d.ts.map +1 -1
  35. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.js +22 -3
  36. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.d.ts.map +1 -1
  37. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.js +104 -28
  38. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.d.ts.map +1 -1
  39. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.js +56 -0
  40. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.d.ts.map +1 -1
  41. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.js +43 -18
  42. package/dist/src/pipeline/stages/ast/rulesEnforcer.d.ts.map +1 -1
  43. package/dist/src/pipeline/stages/ast/rulesEnforcer.js +336 -45
  44. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +2 -0
  45. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -1
  46. package/dist/src/pipeline/stages/merge/conflictDetector.js +54 -2
  47. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -1
  48. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +67 -3
  49. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -1
  50. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +8 -1
  51. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +8 -4
  52. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -1
  53. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +36 -10
  54. package/dist/src/pipeline/types.d.ts +1 -1
  55. package/dist/src/pipeline/types.d.ts.map +1 -1
  56. package/package.json +3 -3
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>API Coverage Analyzer Dashboard</title>
8
- <script type="module" crossorigin src="/assets/index-D3sRJga7.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-D3_88Gr5.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-D_begBP0.css">
10
10
  </head>
11
11
  <body>
@@ -1 +1 @@
1
- {"version":3,"file":"fileClassifier.d.ts","sourceRoot":"","sources":["../../../src/discovery/fileClassifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,MAAM,YAAY,GACpB,eAAe,GACf,cAAc,GACd,WAAW,GACX,eAAe,GACf,WAAW,GACX,aAAa,GACb,kBAAkB,GAClB,eAAe,GACf,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;IACvB,4DAA4D;IAC5D,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,4DAA4D;AAC5D,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,YAAY,CAGjE,CAAC;AAkEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CA4E7D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAEnE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAEhF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAapD"}
1
+ {"version":3,"file":"fileClassifier.d.ts","sourceRoot":"","sources":["../../../src/discovery/fileClassifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,MAAM,YAAY,GACpB,eAAe,GACf,cAAc,GACd,WAAW,GACX,eAAe,GACf,WAAW,GACX,aAAa,GACb,kBAAkB,GAClB,eAAe,GACf,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;IACvB,4DAA4D;IAC5D,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,4DAA4D;AAC5D,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,YAAY,CAGjE,CAAC;AA0EH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAkE7D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAEnE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAEhF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAapD"}
@@ -96,16 +96,25 @@ const CONFIG_BASENAMES = new Set([
96
96
  '.eslintrc.yaml',
97
97
  '.eslintrc.yml',
98
98
  ]);
99
- /** Extensions mapped directly to a category */
100
- const EXTENSION_MAP = {
101
- '.feature': 'bdd_scenarios',
102
- };
103
99
  /** Glob-style path-segment patterns for security reports */
104
100
  const SECURITY_REPORT_DIRS = ['zap', 'trivy', 'semgrep'];
105
101
  /** Glob-style path-segment patterns for performance artifacts */
106
102
  const PERFORMANCE_DIRS = ['jmeter', 'k6', 'gatling', 'locust'];
107
- /** Extensions for contract files */
108
- const CONTRACT_EXTENSIONS = new Set(['.pact.json']);
103
+ /** Source code file extensions for service code classification */
104
+ const SERVICE_CODE_EXTS = new Set([
105
+ '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
106
+ '.java', '.kt', '.kts',
107
+ '.py',
108
+ '.rb',
109
+ '.go',
110
+ '.cs',
111
+ '.cpp', '.cc', '.h',
112
+ '.rs',
113
+ '.php',
114
+ '.graphql', '.graphqls',
115
+ '.vue',
116
+ '.xml',
117
+ ]);
109
118
  // ─── Core classifier ─────────────────────────────────────────────────────────
110
119
  /**
111
120
  * Classify a single file path into a `FileCategory`.
@@ -173,16 +182,6 @@ function classifyFile(filePath) {
173
182
  return make(filePath, 'test_code');
174
183
  }
175
184
  // 9. Service code by extension
176
- const SERVICE_CODE_EXTS = new Set([
177
- '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
178
- '.java', '.kt', '.kts',
179
- '.py',
180
- '.rb',
181
- '.go',
182
- '.cs',
183
- '.cpp', '.cc', '.h',
184
- '.rs',
185
- ]);
186
185
  if (SERVICE_CODE_EXTS.has(ext)) {
187
186
  return make(filePath, 'service_code');
188
187
  }
@@ -1 +1 @@
1
- {"version":3,"file":"projectDiscovery.d.ts","sourceRoot":"","sources":["../../../src/discovery/projectDiscovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAgB,cAAc,EAAgB,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAuB,oBAAoB,EAAoB,MAAM,qBAAqB,CAAC;AAElG,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAIlF,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,YAAY,GACZ,YAAY,GACZ,IAAI,GACJ,QAAQ,CAAC;AAEb,MAAM,MAAM,iBAAiB,GAEzB,OAAO,GACP,QAAQ,GACR,aAAa,GAEb,QAAQ,GACR,UAAU,GAEV,OAAO,GACP,UAAU,GAEV,MAAM,GACN,OAAO,GACP,SAAS,GACT,YAAY,GAEZ,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,mBAAmB;IAClC,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,yCAAyC;IACzC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,oDAAoD;IACpD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,qCAAqC;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,kCAAkC;IAClC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,uDAAuD;IACvD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,iCAAiC;IACjC,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gCAAgC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qCAAqC;IACrC,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,+BAA+B;IAC/B,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,0EAA0E;IAC1E,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,8EAA8E;IAC9E,eAAe,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,mBAAmB,EAAE,UAAU,GAAG,aAAa,GAAG,iBAAiB,GAAG,WAAW,GAAG,YAAY,GAAG,eAAe,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC,CAAC;CACpL;AAED,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAiHD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,mBAAmB,CAkFnF"}
1
+ {"version":3,"file":"projectDiscovery.d.ts","sourceRoot":"","sources":["../../../src/discovery/projectDiscovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAgB,cAAc,EAAgB,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAuB,oBAAoB,EAAoB,MAAM,qBAAqB,CAAC;AAElG,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAIlF,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,YAAY,GACZ,YAAY,GACZ,IAAI,GACJ,QAAQ,CAAC;AAEb,MAAM,MAAM,iBAAiB,GAEzB,OAAO,GACP,QAAQ,GACR,aAAa,GAEb,QAAQ,GACR,UAAU,GAEV,OAAO,GACP,UAAU,GAEV,MAAM,GACN,OAAO,GACP,SAAS,GACT,YAAY,GAEZ,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,mBAAmB;IAClC,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,yCAAyC;IACzC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,oDAAoD;IACpD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,qCAAqC;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,kCAAkC;IAClC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,uDAAuD;IACvD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,iCAAiC;IACjC,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gCAAgC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qCAAqC;IACrC,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,+BAA+B;IAC/B,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,0EAA0E;IAC1E,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,8EAA8E;IAC9E,eAAe,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,mBAAmB,EAAE,UAAU,GAAG,aAAa,GAAG,iBAAiB,GAAG,WAAW,GAAG,YAAY,GAAG,eAAe,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC,CAAC;CACpL;AAED,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAgHD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,mBAAmB,CAkFnF"}
@@ -81,7 +81,6 @@ const BUILD_FILE_LANGUAGE_MAP = {
81
81
  'pyproject.toml': ['python'],
82
82
  'Gemfile': ['ruby'],
83
83
  'go.mod': ['go'],
84
- '*.csproj': ['csharp'],
85
84
  };
86
85
  const EXTENSION_LANGUAGE_MAP = {
87
86
  '.java': 'java',
@@ -250,6 +249,10 @@ function detectLanguages(filePaths) {
250
249
  if (byBuild) {
251
250
  byBuild.forEach((lang) => found.add(lang));
252
251
  }
252
+ // Check for .csproj files (basename varies, so match by extension)
253
+ if (basename.endsWith('.csproj')) {
254
+ found.add('csharp');
255
+ }
253
256
  // Check extension mapping
254
257
  const byExt = EXTENSION_LANGUAGE_MAP[ext];
255
258
  if (byExt) {
@@ -1 +1 @@
1
- {"version":3,"file":"semanticBuilder.d.ts","sourceRoot":"","sources":["../../../../src/languages/java/semanticBuilder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAEV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,OAAO,EACR,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAKL,KAAK,MAAM,EACZ,MAAM,2BAA2B,CAAC;AAOnC,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GACX;IAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,CAmErF;AAID,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACrC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAqC/B;AAID,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EACtC,GAAG,EAAE,gBAAgB,EAAE,GACtB,IAAI,CA6DN;AAID,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAyBvE;AAID,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CAa3E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAa3D"}
1
+ {"version":3,"file":"semanticBuilder.d.ts","sourceRoot":"","sources":["../../../../src/languages/java/semanticBuilder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAEV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,OAAO,EACR,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAKL,KAAK,MAAM,EACZ,MAAM,2BAA2B,CAAC;AAOnC,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GACX;IAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,CAmErF;AAID,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACrC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAwC/B;AAID,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EACtC,GAAG,EAAE,gBAAgB,EAAE,GACtB,IAAI,CA+EN;AAID,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAyBvE;AAID,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CAa3E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAa3D"}
@@ -97,6 +97,8 @@ function extractJavaFunctions(root, constants) {
97
97
  continue;
98
98
  const annotations = extractAnnotationNames(method);
99
99
  const block = (_e = (_d = method.childForFieldName) === null || _d === void 0 ? void 0 : _d.call(method, 'body')) !== null && _e !== void 0 ? _e : (0, treeSitterUtils_1.firstChildOfType)(method, 'block');
100
+ // Extract method parameters
101
+ const parameters = extractMethodParameters(method);
100
102
  const bodyHttpCalls = [];
101
103
  const calledFunctions = [];
102
104
  let returnValue;
@@ -109,7 +111,7 @@ function extractJavaFunctions(root, constants) {
109
111
  const cucumberPattern = extractCucumberPattern(annotations, method);
110
112
  graph.set(name, {
111
113
  name,
112
- parameters: [],
114
+ parameters,
113
115
  bodyHttpCalls,
114
116
  calledFunctions,
115
117
  returnValue,
@@ -121,14 +123,44 @@ function extractJavaFunctions(root, constants) {
121
123
  }
122
124
  // ─── HTTP call extraction ─────────────────────────────────────────────────────
123
125
  function extractJavaHttpCalls(block, constants, out) {
124
- var _a, _b, _c, _d, _e, _f, _g;
126
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
125
127
  const methodInvocations = (0, treeSitterUtils_1.findNodes)(block, ['method_invocation']);
126
128
  for (const invoc of methodInvocations) {
127
129
  const methodName = (_e = (_c = (_b = (_a = invoc.childForFieldName) === null || _a === void 0 ? void 0 : _a.call(invoc, 'name')) === null || _b === void 0 ? void 0 : _b.text) !== null && _c !== void 0 ? _c : (_d = firstChildNamed(invoc, 'identifier')) === null || _d === void 0 ? void 0 : _d.text) !== null && _e !== void 0 ? _e : '';
128
130
  const lowerMethod = methodName.toLowerCase();
131
+ // MockMvc: perform(get("/path")) — extract the inner HTTP method call
132
+ if (lowerMethod === 'perform') {
133
+ const argList = (_g = (_f = invoc.childForFieldName) === null || _f === void 0 ? void 0 : _f.call(invoc, 'arguments')) !== null && _g !== void 0 ? _g : (0, treeSitterUtils_1.firstChildOfType)(invoc, 'argument_list');
134
+ if (!argList)
135
+ continue;
136
+ // The argument to perform() is a method invocation like get("/path") or post("/path")
137
+ const innerInvocations = (0, treeSitterUtils_1.findNodes)(argList, ['method_invocation']);
138
+ for (const innerInvoc of innerInvocations) {
139
+ const innerMethodName = (_m = (_k = (_j = (_h = innerInvoc.childForFieldName) === null || _h === void 0 ? void 0 : _h.call(innerInvoc, 'name')) === null || _j === void 0 ? void 0 : _j.text) !== null && _k !== void 0 ? _k : (_l = firstChildNamed(innerInvoc, 'identifier')) === null || _l === void 0 ? void 0 : _l.text) !== null && _m !== void 0 ? _m : '';
140
+ const innerLower = innerMethodName.toLowerCase();
141
+ if (!HTTP_METHODS.has(innerLower))
142
+ continue;
143
+ const innerArgList = (_p = (_o = innerInvoc.childForFieldName) === null || _o === void 0 ? void 0 : _o.call(innerInvoc, 'arguments')) !== null && _p !== void 0 ? _p : (0, treeSitterUtils_1.firstChildOfType)(innerInvoc, 'argument_list');
144
+ if (!innerArgList)
145
+ continue;
146
+ const innerStringArg = findFirstStringInArgList(innerArgList, constants);
147
+ if (!innerStringArg)
148
+ continue;
149
+ const normalizedPath = innerStringArg.value.startsWith('/') ? (0, resolvePaths_1.normalizePathToTemplate)(innerStringArg.value) : undefined;
150
+ out.push({
151
+ method: innerLower.toUpperCase(),
152
+ rawPathArg: (_q = innerStringArg.varName) !== null && _q !== void 0 ? _q : innerStringArg.value,
153
+ resolvedPath: innerStringArg.value,
154
+ normalizedPath,
155
+ resolutionType: innerStringArg.isDirect ? 'direct' : 'constant',
156
+ confidence: innerStringArg.isDirect ? 'high' : 'medium',
157
+ });
158
+ }
159
+ continue;
160
+ }
129
161
  if (!HTTP_METHODS.has(lowerMethod))
130
162
  continue;
131
- const argList = (_g = (_f = invoc.childForFieldName) === null || _f === void 0 ? void 0 : _f.call(invoc, 'arguments')) !== null && _g !== void 0 ? _g : (0, treeSitterUtils_1.firstChildOfType)(invoc, 'argument_list');
163
+ const argList = (_s = (_r = invoc.childForFieldName) === null || _r === void 0 ? void 0 : _r.call(invoc, 'arguments')) !== null && _s !== void 0 ? _s : (0, treeSitterUtils_1.firstChildOfType)(invoc, 'argument_list');
132
164
  if (!argList)
133
165
  continue;
134
166
  // Extract the first string argument (path)
@@ -138,15 +170,6 @@ function extractJavaHttpCalls(block, constants, out) {
138
170
  const { value: path, isDirect, varName } = firstStringArg;
139
171
  // Try to detect the HTTP method from context
140
172
  let httpMethod = lowerMethod.toUpperCase();
141
- // RestAssured: .when().get("/path") or .given().get("/path")
142
- // The method name IS the HTTP method in RestAssured style
143
- if (!HTTP_METHODS.has(lowerMethod))
144
- continue;
145
- // MockMvc: perform(get("/path")) — perform wraps a method call
146
- if (lowerMethod === 'perform') {
147
- // The arg is another method invocation
148
- continue; // Handled when we process the inner get/post
149
- }
150
173
  if (lowerMethod === 'request') {
151
174
  // generic request(method, path) — try to get HTTP method from first arg
152
175
  const stringArgs = findAllStringsInArgList(argList, constants);
@@ -224,6 +247,40 @@ function extractJavaFlowRefs(root) {
224
247
  return refs;
225
248
  }
226
249
  // ─── Helpers ──────────────────────────────────────────────────────────────────
250
+ /**
251
+ * Extract method parameters with their annotations (e.g. @RequestParam, @PathVariable, @RequestBody).
252
+ */
253
+ function extractMethodParameters(method) {
254
+ var _a;
255
+ const params = [];
256
+ const formalParams = (0, treeSitterUtils_1.firstChildOfType)(method, 'formal_parameters');
257
+ if (!formalParams)
258
+ return params;
259
+ const paramNodes = (0, treeSitterUtils_1.findNodes)(formalParams, ['formal_parameter', 'spread_parameter']);
260
+ for (const paramNode of paramNodes) {
261
+ const paramAnnotations = [];
262
+ (0, treeSitterUtils_1.walkTree)(paramNode, (n) => {
263
+ var _a;
264
+ if (n.type === 'annotation' || n.type === 'marker_annotation') {
265
+ const nameNode = (0, treeSitterUtils_1.firstChildOfType)(n, 'identifier');
266
+ if (nameNode)
267
+ paramAnnotations.push('@' + ((_a = nameNode.text) !== null && _a !== void 0 ? _a : ''));
268
+ }
269
+ });
270
+ const nameNode = firstChildNamed(paramNode, 'identifier');
271
+ const name = (_a = nameNode === null || nameNode === void 0 ? void 0 : nameNode.text) !== null && _a !== void 0 ? _a : '';
272
+ if (!name)
273
+ continue;
274
+ // Include annotation prefix for annotated params (Spring @RequestParam, @PathVariable, etc.)
275
+ if (paramAnnotations.length > 0) {
276
+ params.push(`${paramAnnotations.join(' ')} ${name}`);
277
+ }
278
+ else {
279
+ params.push(name);
280
+ }
281
+ }
282
+ return params;
283
+ }
227
284
  function extractModifierTexts(node) {
228
285
  const modifiers = [];
229
286
  (0, treeSitterUtils_1.walkTree)(node, (n) => {
@@ -1 +1 @@
1
- {"version":3,"file":"angularDetector.d.ts","sourceRoot":"","sources":["../../../../src/languages/javascript/angularDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,KAAK,EAAE,aAAa,GAAG,WAAW,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC;IACnC,SAAS,EAAE,aAAa,GAAG,kBAAkB,GAAG,eAAe,GAAG,SAAS,GAAG,UAAU,CAAC;IACzF,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B,EAAE,OAAO,CAAC;IACrC,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,EAAE,CAyC9F;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAuChG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAyCxF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAgCpG;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAY7F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEhE"}
1
+ {"version":3,"file":"angularDetector.d.ts","sourceRoot":"","sources":["../../../../src/languages/javascript/angularDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,KAAK,EAAE,aAAa,GAAG,WAAW,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC;IACnC,SAAS,EAAE,aAAa,GAAG,kBAAkB,GAAG,eAAe,GAAG,SAAS,GAAG,UAAU,CAAC;IACzF,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B,EAAE,OAAO,CAAC;IACrC,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,EAAE,CAyC9F;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA2EhG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAyCxF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAgCpG;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAY7F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEhE"}
@@ -68,33 +68,66 @@ function detectAngularInjections(sourceText, filePath) {
68
68
  const injections = [];
69
69
  const lines = sourceText.split('\n');
70
70
  let currentClass = '';
71
+ let currentConstHost = '';
72
+ let inConstructorParams = false;
71
73
  for (let i = 0; i < lines.length; i++) {
72
74
  const line = lines[i];
73
75
  // Track current class
74
76
  const classMatch = line.match(/class\s+(\w+)/);
75
77
  if (classMatch)
76
78
  currentClass = classMatch[1];
79
+ // Track current const/export const assignment as potential host for inject() outside class.
80
+ // Only update when the line is NOT itself an inject() call (e.g. skip `const x = inject(Y)`).
81
+ if (!currentClass) {
82
+ const constHostMatch = line.match(/(?:export\s+)?(?:const|let)\s+(\w+)\s*(?::\s*\S+)?\s*=/);
83
+ if (constHostMatch && !line.match(/=\s*inject\s*\(/)) {
84
+ currentConstHost = constHostMatch[1];
85
+ }
86
+ }
87
+ // Track constructor parameter block boundaries
88
+ if (/\bconstructor\s*\(/.test(line)) {
89
+ inConstructorParams = true;
90
+ }
91
+ if (inConstructorParams && line.includes(')')) {
92
+ // Process this line (it's still inside the constructor params), then close
93
+ // We'll close after checking for injections below
94
+ }
77
95
  // Constructor injection: constructor(private http: HttpClient)
78
- const ctorMatch = line.match(/(?:private|protected|public|readonly)\s+(\w+)\s*:\s*(\w+)/);
79
- if (ctorMatch && currentClass) {
80
- injections.push({
81
- consumerClass: currentClass,
82
- serviceClass: ctorMatch[2],
83
- style: 'constructor',
84
- sourceFile: filePath,
85
- line: i + 1,
86
- });
96
+ // Only match visibility-modified parameters when inside a constructor(...) block
97
+ if (inConstructorParams) {
98
+ const ctorParamPattern = /(?:private|protected|public|readonly)\s+(\w+)\s*:\s*(\w+)/g;
99
+ let ctorMatch;
100
+ while ((ctorMatch = ctorParamPattern.exec(line)) !== null) {
101
+ if (currentClass) {
102
+ injections.push({
103
+ consumerClass: currentClass,
104
+ serviceClass: ctorMatch[2],
105
+ style: 'constructor',
106
+ sourceFile: filePath,
107
+ line: i + 1,
108
+ });
109
+ }
110
+ }
111
+ }
112
+ // Close the constructor param block after processing (handles closing paren on same line)
113
+ if (inConstructorParams && line.includes(')')) {
114
+ inConstructorParams = false;
87
115
  }
88
116
  // Functional inject: inject(HttpClient)
89
117
  const injectMatch = line.match(/(\w+)\s*=\s*inject\s*\(\s*(\w+)\s*\)/);
90
- if (injectMatch && currentClass) {
91
- injections.push({
92
- consumerClass: currentClass,
93
- serviceClass: injectMatch[2],
94
- style: 'inject-fn',
95
- sourceFile: filePath,
96
- line: i + 1,
97
- });
118
+ if (injectMatch) {
119
+ // Use the enclosing class, or fall back to the enclosing const/export const host
120
+ // (e.g. functional guards/interceptors: `export const authGuard: CanActivateFn = ...`)
121
+ const hostName = currentClass || currentConstHost;
122
+ if (hostName) {
123
+ injections.push({
124
+ consumerClass: hostName,
125
+ serviceClass: injectMatch[2],
126
+ style: 'inject-fn',
127
+ sourceFile: filePath,
128
+ line: i + 1,
129
+ });
130
+ }
98
131
  }
99
132
  }
100
133
  return injections;
@@ -66,8 +66,8 @@ function tryExtractAssertion(callNode) {
66
66
  if (!subject)
67
67
  return null;
68
68
  const methodName = (_j = (_h = (_g = callee.property) === null || _g === void 0 ? void 0 : _g.name) === null || _h === void 0 ? void 0 : _h.toLowerCase()) !== null && _j !== void 0 ? _j : '';
69
- const assertionType = classifyAssertionMethod(methodName);
70
- const { variable } = classifyExpectSubject(subject);
69
+ const { variable, assertionType: subjectType } = classifyExpectSubject(subject);
70
+ const assertionType = classifyAssertionMethod(methodName, subjectType);
71
71
  return { assertionType, subjectVariable: variable, line: (_l = (_k = callNode.loc) === null || _k === void 0 ? void 0 : _k.start) === null || _l === void 0 ? void 0 : _l.line };
72
72
  }
73
73
  }
@@ -132,13 +132,15 @@ function classifyExpectSubject(subject) {
132
132
  }
133
133
  return { variable: undefined, assertionType: 'body-field' };
134
134
  }
135
- function classifyAssertionMethod(methodName) {
135
+ function classifyAssertionMethod(methodName, subjectType) {
136
136
  if (methodName === 'tobe' ||
137
137
  methodName === 'toequal' ||
138
138
  methodName === 'tostrictequal' ||
139
139
  methodName === 'tobetruthy' ||
140
140
  methodName === 'tobefalsy') {
141
- return 'status-code'; // Could be either, default to status-code
141
+ // These methods are ambiguous use subject context to decide.
142
+ // Only classify as status-code when the subject involves status.
143
+ return subjectType === 'status-code' ? 'status-code' : 'body-field';
142
144
  }
143
145
  if (methodName === 'tohaveproperty' || methodName === 'tocontain' || methodName === 'tomatch') {
144
146
  return 'body-field';
@@ -1 +1 @@
1
- {"version":3,"file":"hapiDetector.d.ts","sourceRoot":"","sources":["../../../../src/languages/javascript/hapiDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,KAAK,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkBD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAuFlF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAmBtF"}
1
+ {"version":3,"file":"hapiDetector.d.ts","sourceRoot":"","sources":["../../../../src/languages/javascript/hapiDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,KAAK,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkBD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CA6HlF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAmBtF"}
@@ -30,7 +30,7 @@ const BOOM_STATUS_MAP = {
30
30
  * Detect HapiJS route definitions from source text.
31
31
  */
32
32
  function detectHapiRoutes(sourceText, filePath) {
33
- var _a, _b;
33
+ var _a, _b, _c, _d;
34
34
  const routes = [];
35
35
  const lines = sourceText.split('\n');
36
36
  for (let i = 0; i < lines.length; i++) {
@@ -55,7 +55,7 @@ function detectHapiRoutes(sourceText, filePath) {
55
55
  if (authSimple) {
56
56
  auth = { strategy: authSimple[1], mode: 'required' };
57
57
  }
58
- // auth: { mode: 'try' } or auth: { mode: 'optional' }
58
+ // auth: { mode: 'try' } or auth: { mode: 'optional' } — single-line case
59
59
  const authMode = nearLine.match(/(?:auth|mode)\s*:\s*[{]?\s*mode\s*:\s*['"](\w+)['"]/);
60
60
  if (authMode) {
61
61
  auth = {
@@ -63,6 +63,19 @@ function detectHapiRoutes(sourceText, filePath) {
63
63
  mode: authMode[1] === 'try' || authMode[1] === 'optional' ? 'optional' : 'required',
64
64
  };
65
65
  }
66
+ else if (/auth\s*:\s*\{/.test(nearLine) || /auth\s*\{/.test(nearLine)) {
67
+ // Multi-line auth object: scan the next 5 lines for mode: 'try' / 'optional'
68
+ for (let m = j + 1; m < Math.min(j + 6, lines.length); m++) {
69
+ const modeMatch = lines[m].match(/mode\s*:\s*['"](\w+)['"]/);
70
+ if (modeMatch) {
71
+ auth = {
72
+ strategy: auth === null || auth === void 0 ? void 0 : auth.strategy,
73
+ mode: modeMatch[1] === 'try' || modeMatch[1] === 'optional' ? 'optional' : 'required',
74
+ };
75
+ break;
76
+ }
77
+ }
78
+ }
66
79
  // auth: false
67
80
  if (/auth\s*:\s*false/.test(nearLine)) {
68
81
  auth = undefined; // Public route
@@ -74,8 +87,9 @@ function detectHapiRoutes(sourceText, filePath) {
74
87
  // Scan validation block
75
88
  for (let k = j; k < Math.min(j + 15, lines.length); k++) {
76
89
  const valLine = lines[k];
77
- // query: { ... }
90
+ // query: { ... } — extract Joi fields from same line and subsequent lines
78
91
  if (/query\s*:/.test(valLine)) {
92
+ // Same-line extraction
79
93
  const paramMatch = valLine.match(/(\w+)\s*:\s*Joi\./g);
80
94
  if (paramMatch) {
81
95
  for (const pm of paramMatch) {
@@ -84,17 +98,46 @@ function detectHapiRoutes(sourceText, filePath) {
84
98
  queryParams.push(name);
85
99
  }
86
100
  }
101
+ // Multi-line extraction: scan subsequent lines for fieldName: Joi. patterns
102
+ for (let q = k + 1; q < Math.min(k + 16, lines.length); q++) {
103
+ const subLine = lines[q];
104
+ if (/}\s*[),]/.test(subLine) || /]\s*,/.test(subLine))
105
+ break;
106
+ const fieldMatch = subLine.match(/(\w+)\s*:\s*Joi\./g);
107
+ if (fieldMatch) {
108
+ for (const fm of fieldMatch) {
109
+ const name = (_b = fm.match(/(\w+)\s*:/)) === null || _b === void 0 ? void 0 : _b[1];
110
+ if (name && !queryParams.includes(name))
111
+ queryParams.push(name);
112
+ }
113
+ }
114
+ }
87
115
  }
88
- // payload: { ... }
116
+ // payload: { ... } — extract Joi fields from same line and subsequent lines
89
117
  if (/payload\s*:/.test(valLine)) {
118
+ // Same-line extraction
90
119
  const paramMatch = valLine.match(/(\w+)\s*:\s*Joi\./g);
91
120
  if (paramMatch) {
92
121
  for (const pm of paramMatch) {
93
- const name = (_b = pm.match(/(\w+)\s*:/)) === null || _b === void 0 ? void 0 : _b[1];
122
+ const name = (_c = pm.match(/(\w+)\s*:/)) === null || _c === void 0 ? void 0 : _c[1];
94
123
  if (name)
95
124
  payloadParams.push(name);
96
125
  }
97
126
  }
127
+ // Multi-line extraction: scan subsequent lines for fieldName: Joi. patterns
128
+ for (let q = k + 1; q < Math.min(k + 16, lines.length); q++) {
129
+ const subLine = lines[q];
130
+ if (/}\s*[),]/.test(subLine) || /]\s*,/.test(subLine))
131
+ break;
132
+ const fieldMatch = subLine.match(/(\w+)\s*:\s*Joi\./g);
133
+ if (fieldMatch) {
134
+ for (const fm of fieldMatch) {
135
+ const name = (_d = fm.match(/(\w+)\s*:/)) === null || _d === void 0 ? void 0 : _d[1];
136
+ if (name && !payloadParams.includes(name))
137
+ payloadParams.push(name);
138
+ }
139
+ }
140
+ }
98
141
  }
99
142
  }
100
143
  if (queryParams.length > 0 || payloadParams.length > 0) {
@@ -9,6 +9,8 @@
9
9
  */
10
10
  export interface VueApiCall {
11
11
  actionName?: string;
12
+ /** Resolved string value when actionName is a constant (e.g., FETCH_ARTICLES → 'fetchArticles') */
13
+ resolvedName?: string;
12
14
  method: string;
13
15
  urlPattern: string;
14
16
  baseUrl?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"vueDetector.d.ts","sourceRoot":"","sources":["../../../../src/languages/javascript/vueDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAO/F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CA4CpF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAkBzF"}
1
+ {"version":3,"file":"vueDetector.d.ts","sourceRoot":"","sources":["../../../../src/languages/javascript/vueDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mGAAmG;IACnG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAO/F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAoEpF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAkBzF"}
@@ -29,7 +29,20 @@ function detectAxiosBaseUrl(sourceText, filePath) {
29
29
  function detectVuexActions(sourceText, filePath) {
30
30
  const calls = [];
31
31
  const lines = sourceText.split('\n');
32
+ // Pass 1: Build a map of constant name → string value.
33
+ // Matches patterns like:
34
+ // const FETCH_ARTICLES = 'fetchArticles'
35
+ // export const FETCH_ARTICLES = "fetchArticles"
36
+ const constantMap = new Map();
37
+ for (const line of lines) {
38
+ const constMatch = line.match(/(?:export\s+)?const\s+([A-Z_][A-Z0-9_]*)\s*=\s*['"]([^'"]+)['"]/);
39
+ if (constMatch) {
40
+ constantMap.set(constMatch[1], constMatch[2]);
41
+ }
42
+ }
43
+ // Pass 2: Detect action definitions and their API calls.
32
44
  let currentAction = '';
45
+ let currentResolvedName;
33
46
  for (let i = 0; i < lines.length; i++) {
34
47
  const line = lines[i];
35
48
  // Vuex action definition: [ACTION_NAME]({ commit }, payload) {
@@ -37,6 +50,13 @@ function detectVuexActions(sourceText, filePath) {
37
50
  const actionMatch = line.match(/(?:\[(\w+)\]|(\w+))\s*\(\s*\{\s*(?:commit|dispatch|state|getters|rootState)/);
38
51
  if (actionMatch) {
39
52
  currentAction = actionMatch[1] || actionMatch[2] || '';
53
+ // If using bracket syntax with a constant, resolve to its string value
54
+ if (actionMatch[1] && constantMap.has(actionMatch[1])) {
55
+ currentResolvedName = constantMap.get(actionMatch[1]);
56
+ }
57
+ else {
58
+ currentResolvedName = undefined;
59
+ }
40
60
  continue;
41
61
  }
42
62
  // ApiService.get/post/put/delete('resource')
@@ -44,6 +64,7 @@ function detectVuexActions(sourceText, filePath) {
44
64
  if (apiServiceMatch) {
45
65
  calls.push({
46
66
  actionName: currentAction || undefined,
67
+ resolvedName: currentResolvedName,
47
68
  method: apiServiceMatch[1].toUpperCase(),
48
69
  urlPattern: apiServiceMatch[2],
49
70
  sourceFile: filePath,
@@ -56,6 +77,7 @@ function detectVuexActions(sourceText, filePath) {
56
77
  if (axiosMatch) {
57
78
  calls.push({
58
79
  actionName: currentAction || undefined,
80
+ resolvedName: currentResolvedName,
59
81
  method: axiosMatch[1].toUpperCase(),
60
82
  urlPattern: axiosMatch[2],
61
83
  sourceFile: filePath,
@@ -10,7 +10,7 @@ export declare class PythonAnalyzer implements LanguageAnalyzer {
10
10
  extractHttpInteractions(model: SemanticModel, _ctx: AnalysisContext): ResolvedHttpInteraction[];
11
11
  extractAssertions(model: SemanticModel): SemanticAssertion[];
12
12
  extractBusinessRuleRefs(model: SemanticModel): BusinessRuleRef[];
13
- extractFlowRefs(_model: SemanticModel): FlowRef[];
13
+ extractFlowRefs(model: SemanticModel): FlowRef[];
14
14
  }
15
15
  /**
16
16
  * Classify JWT/auth security from decorator information.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/languages/python/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EAIb,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,OAAO,EACP,eAAe,EAEf,aAAa,EAEb,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAkC5B,qBAAa,cAAe,YAAW,gBAAgB;IACrD,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAY;IAEhD,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB;IAc1D,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,eAAe,GAAG,aAAa;IA6BtF,uBAAuB,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,GAAG,uBAAuB,EAAE;IAwB/F,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,iBAAiB,EAAE;IAG5D,uBAAuB,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,EAAE;IAGhE,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,EAAE;CAGlD;AA2WD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,sBAAsB,GAAG,SAAS,CAarG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/languages/python/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EAIb,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,OAAO,EACP,eAAe,EAEf,aAAa,EAEb,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAmC5B,qBAAa,cAAe,YAAW,gBAAgB;IACrD,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAY;IAEhD,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB;IAc1D,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,eAAe,GAAG,aAAa;IA4CtF,uBAAuB,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,GAAG,uBAAuB,EAAE;IAwB/F,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,iBAAiB,EAAE;IAG5D,uBAAuB,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,EAAE;IAGhE,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,EAAE;CAqBjD;AA2WD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,sBAAsB,GAAG,SAAS,CAarG"}
@@ -8,6 +8,7 @@ exports.classifyFlaskSecurity = classifyFlaskSecurity;
8
8
  const parserRegistry_1 = require("../../ast/parserRegistry");
9
9
  const treeSitterUtils_1 = require("../shared/treeSitterUtils");
10
10
  const resolvePaths_1 = require("../../coverage/deep-analysis/resolvePaths");
11
+ const testPatternDetector_1 = require("./testPatternDetector");
11
12
  // ─── Parser ───────────────────────────────────────────────────────────────────
12
13
  let cachedParser = undefined;
13
14
  let parserLoaded = false;
@@ -45,7 +46,7 @@ class PythonAnalyzer {
45
46
  }
46
47
  }
47
48
  buildSemanticModel(parsed, _context) {
48
- var _a, _b;
49
+ var _a, _b, _c, _d;
49
50
  const root = (_b = (_a = parsed.ast) === null || _a === void 0 ? void 0 : _a.rootNode) !== null && _b !== void 0 ? _b : parsed.ast;
50
51
  if (!root)
51
52
  return emptyModel(parsed.filePath);
@@ -56,6 +57,20 @@ class PythonAnalyzer {
56
57
  // Feature 27: Flask/FastAPI pattern detection
57
58
  const decoratorStacks = extractFlaskDecoratorStacks(root, parsed.filePath);
58
59
  const routeRegistrations = extractFlaskRouteRegistrations(root, parsed.filePath);
60
+ // Feature 27: webtest API call detection
61
+ const sourceText = (_d = (_c = root.text) !== null && _c !== void 0 ? _c : parsed.content) !== null && _d !== void 0 ? _d : '';
62
+ const webtestCalls = (0, testPatternDetector_1.detectWebtestCalls)(sourceText, parsed.filePath);
63
+ if (webtestCalls.length > 0) {
64
+ const httpCalls = (0, testPatternDetector_1.webtestCallsToHttpCalls)(webtestCalls);
65
+ // Merge webtest HTTP calls into the functions map under a synthetic entry
66
+ const webtestFunc = {
67
+ name: '__webtest_calls__',
68
+ parameters: [],
69
+ bodyHttpCalls: httpCalls,
70
+ calledFunctions: [],
71
+ };
72
+ functions.set('__webtest_calls__', webtestFunc);
73
+ }
59
74
  return {
60
75
  filePath: parsed.filePath,
61
76
  language: 'python',
@@ -103,8 +118,23 @@ class PythonAnalyzer {
103
118
  extractBusinessRuleRefs(model) {
104
119
  return model.businessRuleRefs;
105
120
  }
106
- extractFlowRefs(_model) {
107
- return [];
121
+ extractFlowRefs(model) {
122
+ // Feature 27: Resolve pytest fixture chains
123
+ const refs = [...model.flowRefs];
124
+ // Use function parameter names to discover fixture dependencies
125
+ // In pytest, function parameters that aren't built-in fixtures are fixture references
126
+ const builtinFixtures = new Set([
127
+ 'request', 'tmp_path', 'tmpdir', 'capsys', 'capfd', 'monkeypatch',
128
+ 'pytestconfig', 'recwarn', 'caplog', 'cache', 'self',
129
+ ]);
130
+ for (const [funcName, func] of model.functions) {
131
+ for (const param of func.parameters) {
132
+ if (param && !builtinFixtures.has(param)) {
133
+ refs.push({ flowId: `fixture:${param}`, source: 'tag' });
134
+ }
135
+ }
136
+ }
137
+ return refs;
108
138
  }
109
139
  }
110
140
  exports.PythonAnalyzer = PythonAnalyzer;
@@ -65,6 +65,11 @@ export declare function hasPartialResolution(graph: CoverageKnowledgeGraph, path
65
65
  /**
66
66
  * Build a ConfidenceEvidence object from a coverage path in the graph.
67
67
  * Inspects the nodes and their source stages to determine what evidence exists.
68
+ *
69
+ * Optional `iastConfirmed` and `dastConfirmed` flags allow the caller to
70
+ * inject runtime confirmation state that may not be discoverable by walking
71
+ * `pathNodeIds` alone (e.g. when IAST/DAST nodes are not directly on the
72
+ * endpoint→test path in the graph).
68
73
  */
69
- export declare function buildConfidenceEvidence(graph: CoverageKnowledgeGraph, pathNodeIds: string[], isStaticOnlyMode: boolean): ConfidenceEvidence;
74
+ export declare function buildConfidenceEvidence(graph: CoverageKnowledgeGraph, pathNodeIds: string[], isStaticOnlyMode: boolean, iastConfirmed?: boolean, dastConfirmed?: boolean): ConfidenceEvidence;
70
75
  //# sourceMappingURL=confidence.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"confidence.d.ts","sourceRoot":"","sources":["../../../src/pipeline/confidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAa,MAAM,SAAS,CAAC;AACjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,kBAAkB,CAwBtF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,kBAAkB,EAC7B,QAAQ,EAAE,kBAAkB,GAC3B,kBAAkB,CAoBpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,kBAAkB,CAGlF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,kBAAkB,GAC3B,kBAAkB,CAIpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,kBAAkB,EACrB,CAAC,EAAE,kBAAkB,GACpB,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,kBAAkB,CAS9E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,sBAAsB,EAC7B,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAMT;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,sBAAsB,EAC7B,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAMT;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,sBAAsB,EAC7B,WAAW,EAAE,MAAM,EAAE,EACrB,gBAAgB,EAAE,OAAO,GACxB,kBAAkB,CA6CpB"}
1
+ {"version":3,"file":"confidence.d.ts","sourceRoot":"","sources":["../../../src/pipeline/confidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAa,MAAM,SAAS,CAAC;AACjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,kBAAkB,CAwBtF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,kBAAkB,EAC7B,QAAQ,EAAE,kBAAkB,GAC3B,kBAAkB,CAoBpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,kBAAkB,CAGlF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,kBAAkB,GAC3B,kBAAkB,CAIpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,kBAAkB,EACrB,CAAC,EAAE,kBAAkB,GACpB,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,kBAAkB,CAS9E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,sBAAsB,EAC7B,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAMT;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,sBAAsB,EAC7B,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAMT;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,sBAAsB,EAC7B,WAAW,EAAE,MAAM,EAAE,EACrB,gBAAgB,EAAE,OAAO,EACzB,aAAa,CAAC,EAAE,OAAO,EACvB,aAAa,CAAC,EAAE,OAAO,GACtB,kBAAkB,CA6CpB"}