weavatrix 0.3.14 → 1.1.0

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 (306) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +132 -200
  3. package/bin/native/darwin-arm64/weavatrix +0 -0
  4. package/bin/native/darwin-x64/weavatrix +0 -0
  5. package/bin/native/linux-arm64/weavatrix +0 -0
  6. package/bin/native/linux-x64/weavatrix +0 -0
  7. package/bin/native/win32-arm64/weavatrix.exe +0 -0
  8. package/bin/native/win32-x64/weavatrix.exe +0 -0
  9. package/bin/resolve-binary.mjs +73 -0
  10. package/bin/run-native.mjs +26 -0
  11. package/bin/weavatrix-mcp.mjs +7 -6
  12. package/bin/weavatrix.mjs +5 -0
  13. package/package.json +10 -67
  14. package/server.json +38 -0
  15. package/skill/SKILL.md +62 -374
  16. package/skill/agents/openai.yaml +4 -0
  17. package/skill/references/tool-routing.md +45 -0
  18. package/SECURITY.md +0 -101
  19. package/docs/adr/0001-v0.3-offline-online-split.md +0 -60
  20. package/docs/agent-task-benchmark.md +0 -58
  21. package/docs/releases/v0.2.19.md +0 -33
  22. package/docs/releases/v0.3.0.md +0 -43
  23. package/docs/releases/v0.3.1.md +0 -30
  24. package/docs/releases/v0.3.10.md +0 -76
  25. package/docs/releases/v0.3.11.md +0 -55
  26. package/docs/releases/v0.3.12.md +0 -44
  27. package/docs/releases/v0.3.13.md +0 -34
  28. package/docs/releases/v0.3.14.md +0 -37
  29. package/docs/releases/v0.3.2.md +0 -15
  30. package/docs/releases/v0.3.3.md +0 -25
  31. package/docs/releases/v0.3.4.md +0 -40
  32. package/docs/releases/v0.3.5.md +0 -50
  33. package/docs/releases/v0.3.6.md +0 -44
  34. package/docs/releases/v0.3.7.md +0 -37
  35. package/docs/releases/v0.3.8.md +0 -21
  36. package/docs/releases/v0.3.9.md +0 -36
  37. package/scripts/run-agent-task-benchmark.mjs +0 -118
  38. package/src/analysis/allowed-test-runner.js +0 -70
  39. package/src/analysis/architecture/contract-graph.js +0 -119
  40. package/src/analysis/architecture/contract-schema.js +0 -110
  41. package/src/analysis/architecture/contract-storage.js +0 -35
  42. package/src/analysis/architecture/contract-verification.js +0 -168
  43. package/src/analysis/architecture-contract.js +0 -16
  44. package/src/analysis/audit-debt.js +0 -94
  45. package/src/analysis/audit-extensions.js +0 -60
  46. package/src/analysis/cargo-dependency-evidence.js +0 -108
  47. package/src/analysis/cargo-manifests.js +0 -81
  48. package/src/analysis/change-classification/diff-parser.js +0 -103
  49. package/src/analysis/change-classification/options.js +0 -40
  50. package/src/analysis/change-classification/symbol-classifier.js +0 -177
  51. package/src/analysis/change-classification.js +0 -188
  52. package/src/analysis/coverage-reports-tarpaulin.js +0 -112
  53. package/src/analysis/coverage-reports.js +0 -246
  54. package/src/analysis/cycle-route.js +0 -14
  55. package/src/analysis/data-flow-evidence.js +0 -114
  56. package/src/analysis/dead-check.js +0 -300
  57. package/src/analysis/dead-code-review/candidates.js +0 -194
  58. package/src/analysis/dead-code-review/policy.js +0 -23
  59. package/src/analysis/dead-code-review.js +0 -119
  60. package/src/analysis/dep-check-ecosystems.js +0 -205
  61. package/src/analysis/dep-check.js +0 -290
  62. package/src/analysis/dep-rules.js +0 -10
  63. package/src/analysis/dependency/conventions.js +0 -16
  64. package/src/analysis/dependency/scoped-dependencies.js +0 -51
  65. package/src/analysis/dependency/source-references.js +0 -21
  66. package/src/analysis/duplicate-groups.js +0 -104
  67. package/src/analysis/duplicates-worker.js +0 -11
  68. package/src/analysis/duplicates.compute.js +0 -269
  69. package/src/analysis/duplicates.js +0 -15
  70. package/src/analysis/duplicates.run.js +0 -52
  71. package/src/analysis/duplicates.tokenize.js +0 -199
  72. package/src/analysis/endpoints/common.js +0 -79
  73. package/src/analysis/endpoints/extract.js +0 -120
  74. package/src/analysis/endpoints/inventory.js +0 -84
  75. package/src/analysis/endpoints/mounts.js +0 -129
  76. package/src/analysis/endpoints-java.js +0 -260
  77. package/src/analysis/endpoints-rust.js +0 -124
  78. package/src/analysis/endpoints.js +0 -3
  79. package/src/analysis/findings.js +0 -70
  80. package/src/analysis/git-history/analytics.js +0 -177
  81. package/src/analysis/git-history/collector.js +0 -67
  82. package/src/analysis/git-history/options.js +0 -66
  83. package/src/analysis/git-history.js +0 -143
  84. package/src/analysis/git-ref-graph.js +0 -76
  85. package/src/analysis/go-dependency-evidence.js +0 -62
  86. package/src/analysis/graph-analysis.aggregate.js +0 -296
  87. package/src/analysis/graph-analysis.edges.js +0 -24
  88. package/src/analysis/graph-analysis.js +0 -7
  89. package/src/analysis/graph-analysis.refs.js +0 -202
  90. package/src/analysis/graph-analysis.summaries.js +0 -65
  91. package/src/analysis/health-capabilities.js +0 -83
  92. package/src/analysis/hot-path-review.js +0 -266
  93. package/src/analysis/http-contract-wrappers.js +0 -241
  94. package/src/analysis/http-contracts/analysis.js +0 -179
  95. package/src/analysis/http-contracts/client-call-detection.js +0 -82
  96. package/src/analysis/http-contracts/client-call-parser.js +0 -273
  97. package/src/analysis/http-contracts/graph-context.js +0 -143
  98. package/src/analysis/http-contracts/matching.js +0 -61
  99. package/src/analysis/http-contracts/shared.js +0 -85
  100. package/src/analysis/http-contracts.js +0 -6
  101. package/src/analysis/internal-audit/dependency-health.js +0 -113
  102. package/src/analysis/internal-audit/python-manifests.js +0 -78
  103. package/src/analysis/internal-audit/repo-files.js +0 -50
  104. package/src/analysis/internal-audit/supply-chain.js +0 -149
  105. package/src/analysis/internal-audit.collect.js +0 -213
  106. package/src/analysis/internal-audit.js +0 -9
  107. package/src/analysis/internal-audit.reach.js +0 -201
  108. package/src/analysis/internal-audit.run.js +0 -256
  109. package/src/analysis/java-source.js +0 -36
  110. package/src/analysis/jvm-artifact-index.js +0 -87
  111. package/src/analysis/jvm-dependency-evidence.js +0 -138
  112. package/src/analysis/jvm-manifests.js +0 -114
  113. package/src/analysis/manifests.js +0 -123
  114. package/src/analysis/package-reachability.js +0 -39
  115. package/src/analysis/source-complexity.ast.js +0 -97
  116. package/src/analysis/source-complexity.constants.js +0 -55
  117. package/src/analysis/source-complexity.js +0 -14
  118. package/src/analysis/source-complexity.report.js +0 -81
  119. package/src/analysis/source-complexity.walk.js +0 -228
  120. package/src/analysis/source-correctness/retry-patterns.js +0 -93
  121. package/src/analysis/source-correctness.js +0 -222
  122. package/src/analysis/static-test-reachability.js +0 -150
  123. package/src/analysis/structure/dependency-graph.js +0 -151
  124. package/src/analysis/structure/findings.js +0 -162
  125. package/src/analysis/task-retrieval.js +0 -107
  126. package/src/analysis/transport-contracts.js +0 -224
  127. package/src/analysis/transport-runtime-evidence.js +0 -155
  128. package/src/analysis-kit.mjs +0 -17
  129. package/src/bounds.js +0 -4
  130. package/src/build-graph.js +0 -209
  131. package/src/child-env.js +0 -7
  132. package/src/config.js +0 -5
  133. package/src/extension/local-services.mjs +0 -75
  134. package/src/git-exec.js +0 -67
  135. package/src/graph/build-worker.js +0 -49
  136. package/src/graph/builder/go-receiver-resolution.js +0 -112
  137. package/src/graph/builder/js/dynamic-import.js +0 -26
  138. package/src/graph/builder/js/queries.js +0 -48
  139. package/src/graph/builder/lang-csharp.js +0 -40
  140. package/src/graph/builder/lang-css.js +0 -29
  141. package/src/graph/builder/lang-go.js +0 -140
  142. package/src/graph/builder/lang-html.js +0 -29
  143. package/src/graph/builder/lang-java-calls.js +0 -142
  144. package/src/graph/builder/lang-java.js +0 -215
  145. package/src/graph/builder/lang-js.js +0 -291
  146. package/src/graph/builder/lang-python.js +0 -235
  147. package/src/graph/builder/lang-rust-calls.js +0 -63
  148. package/src/graph/builder/lang-rust.js +0 -299
  149. package/src/graph/builder/lang-solidity.js +0 -126
  150. package/src/graph/builder/lang-sql.js +0 -263
  151. package/src/graph/builder/pass2-resolution.js +0 -81
  152. package/src/graph/builder/spec-pkg.js +0 -87
  153. package/src/graph/community.js +0 -27
  154. package/src/graph/edge-provenance.js +0 -31
  155. package/src/graph/file-lock.js +0 -69
  156. package/src/graph/freshness-probe.js +0 -142
  157. package/src/graph/graph-filter.js +0 -63
  158. package/src/graph/incremental-refresh.js +0 -235
  159. package/src/graph/internal-builder.barrels.js +0 -235
  160. package/src/graph/internal-builder.build.js +0 -300
  161. package/src/graph/internal-builder.java.js +0 -33
  162. package/src/graph/internal-builder.js +0 -12
  163. package/src/graph/internal-builder.langs.js +0 -157
  164. package/src/graph/internal-builder.pass2.js +0 -163
  165. package/src/graph/internal-builder.resolvers.js +0 -286
  166. package/src/graph/layout.js +0 -51
  167. package/src/graph/node-id.js +0 -7
  168. package/src/graph/parser-artifact-boundary.js +0 -55
  169. package/src/graph/relations.js +0 -4
  170. package/src/graph/repo-registry.js +0 -124
  171. package/src/graph/resolvers/rust.js +0 -117
  172. package/src/infra/infra-items.js +0 -255
  173. package/src/infra/infra-registry.js +0 -184
  174. package/src/infra/infra.detect.js +0 -119
  175. package/src/infra/infra.js +0 -38
  176. package/src/infra/infra.match.js +0 -102
  177. package/src/infra/infra.scan.js +0 -93
  178. package/src/mcp/actions/graph-lifecycle.mjs +0 -148
  179. package/src/mcp/architecture-bootstrap.mjs +0 -168
  180. package/src/mcp/architecture-starter.mjs +0 -234
  181. package/src/mcp/catalog.mjs +0 -233
  182. package/src/mcp/company-contract-page.mjs +0 -142
  183. package/src/mcp/company-contract-reconcile.mjs +0 -87
  184. package/src/mcp/company-contract-verdict.mjs +0 -42
  185. package/src/mcp/evidence/bun-lock-graph.mjs +0 -209
  186. package/src/mcp/evidence/duplicate-member-order.mjs +0 -8
  187. package/src/mcp/evidence/package-graph-common.mjs +0 -115
  188. package/src/mcp/evidence/package-lock-graph.mjs +0 -92
  189. package/src/mcp/evidence-snapshot.architecture.mjs +0 -80
  190. package/src/mcp/evidence-snapshot.common.mjs +0 -158
  191. package/src/mcp/evidence-snapshot.duplicates.mjs +0 -213
  192. package/src/mcp/evidence-snapshot.health.mjs +0 -102
  193. package/src/mcp/evidence-snapshot.inventory.mjs +0 -148
  194. package/src/mcp/evidence-snapshot.mjs +0 -50
  195. package/src/mcp/evidence-snapshot.package-graph.mjs +0 -34
  196. package/src/mcp/evidence-snapshot.structure.mjs +0 -84
  197. package/src/mcp/extension-api.mjs +0 -77
  198. package/src/mcp/git-output.mjs +0 -7
  199. package/src/mcp/graph/context-core.mjs +0 -111
  200. package/src/mcp/graph/context-seeds.mjs +0 -207
  201. package/src/mcp/graph/context-state.mjs +0 -85
  202. package/src/mcp/graph/reverse-reach.mjs +0 -42
  203. package/src/mcp/graph/tools-core.mjs +0 -143
  204. package/src/mcp/graph/tools-query.mjs +0 -276
  205. package/src/mcp/graph-context.mjs +0 -5
  206. package/src/mcp/graph-diff.mjs +0 -218
  207. package/src/mcp/health/audit-format.mjs +0 -199
  208. package/src/mcp/health/audit.mjs +0 -199
  209. package/src/mcp/health/dead-code.mjs +0 -110
  210. package/src/mcp/health/duplicates.mjs +0 -121
  211. package/src/mcp/health/endpoints.mjs +0 -71
  212. package/src/mcp/health/structure.mjs +0 -220
  213. package/src/mcp/runtime-version.mjs +0 -31
  214. package/src/mcp/server/auto-refresh.mjs +0 -66
  215. package/src/mcp/server/runtime-config.mjs +0 -43
  216. package/src/mcp/server/shutdown.mjs +0 -40
  217. package/src/mcp/staleness-notice.mjs +0 -20
  218. package/src/mcp/sync/evidence-architecture.mjs +0 -54
  219. package/src/mcp/sync/evidence-common.mjs +0 -88
  220. package/src/mcp/sync/evidence-duplicates.mjs +0 -97
  221. package/src/mcp/sync/evidence-health.mjs +0 -56
  222. package/src/mcp/sync/evidence-packages.mjs +0 -95
  223. package/src/mcp/sync/payload-common.mjs +0 -97
  224. package/src/mcp/sync/payload-v2.mjs +0 -54
  225. package/src/mcp/sync/payload-v3.mjs +0 -79
  226. package/src/mcp/sync-evidence.mjs +0 -23
  227. package/src/mcp/sync-payload.mjs +0 -70
  228. package/src/mcp/tool-result.mjs +0 -54
  229. package/src/mcp/tools-actions.mjs +0 -11
  230. package/src/mcp/tools-architecture.mjs +0 -177
  231. package/src/mcp/tools-company.mjs +0 -251
  232. package/src/mcp/tools-context.mjs +0 -222
  233. package/src/mcp/tools-endpoints.mjs +0 -207
  234. package/src/mcp/tools-graph-hubs.mjs +0 -78
  235. package/src/mcp/tools-graph.mjs +0 -17
  236. package/src/mcp/tools-health.mjs +0 -24
  237. package/src/mcp/tools-history.mjs +0 -28
  238. package/src/mcp/tools-impact-change.mjs +0 -220
  239. package/src/mcp/tools-impact-precision.mjs +0 -89
  240. package/src/mcp/tools-impact.mjs +0 -169
  241. package/src/mcp/tools-source.mjs +0 -238
  242. package/src/mcp/tools-verified-change.mjs +0 -200
  243. package/src/mcp-rg.mjs +0 -50
  244. package/src/mcp-runtime.mjs +0 -2
  245. package/src/mcp-server.mjs +0 -298
  246. package/src/mcp-source-tools.mjs +0 -163
  247. package/src/path-classification.js +0 -226
  248. package/src/path-ignore.js +0 -69
  249. package/src/precision/lsp-client/constants.js +0 -12
  250. package/src/precision/lsp-client/environment.js +0 -20
  251. package/src/precision/lsp-client/errors.js +0 -15
  252. package/src/precision/lsp-client/lifecycle.js +0 -114
  253. package/src/precision/lsp-client/message-parser.js +0 -81
  254. package/src/precision/lsp-client/protocol.js +0 -212
  255. package/src/precision/lsp-client/registry.js +0 -59
  256. package/src/precision/lsp-client/repo-uri.js +0 -60
  257. package/src/precision/lsp-client/stdio-client.js +0 -140
  258. package/src/precision/lsp-client.js +0 -10
  259. package/src/precision/lsp-overlay/budget-policy.js +0 -78
  260. package/src/precision/lsp-overlay/build.js +0 -261
  261. package/src/precision/lsp-overlay/contract.js +0 -61
  262. package/src/precision/lsp-overlay/reference-results.js +0 -108
  263. package/src/precision/lsp-overlay/semantic-inputs.js +0 -62
  264. package/src/precision/lsp-overlay/source-session.js +0 -142
  265. package/src/precision/lsp-overlay/store.js +0 -150
  266. package/src/precision/lsp-overlay/target-index.js +0 -152
  267. package/src/precision/lsp-overlay/target-query.js +0 -55
  268. package/src/precision/lsp-overlay.js +0 -11
  269. package/src/precision/symbol-query.js +0 -224
  270. package/src/precision/typescript-lsp-provider.js +0 -12
  271. package/src/precision/typescript-provider/client.js +0 -89
  272. package/src/precision/typescript-provider/discovery.js +0 -124
  273. package/src/precision/typescript-provider/isolated-runtime.js +0 -39
  274. package/src/precision/typescript-provider/project-host.js +0 -254
  275. package/src/precision/typescript-provider/project-safety.js +0 -166
  276. package/src/precision/typescript-provider/reference-usage.js +0 -53
  277. package/src/process.js +0 -95
  278. package/src/repo-path.js +0 -53
  279. package/src/scan/discover.inventory.js +0 -78
  280. package/src/scan/discover.js +0 -5
  281. package/src/scan/discover.list.js +0 -79
  282. package/src/scan/discover.stack.js +0 -227
  283. package/src/scan/search.core.js +0 -24
  284. package/src/scan/search.git.js +0 -102
  285. package/src/scan/search.js +0 -9
  286. package/src/scan/search.node.js +0 -83
  287. package/src/scan/search.preview.js +0 -49
  288. package/src/scan/search.rg.js +0 -145
  289. package/src/security/advisory-store.js +0 -172
  290. package/src/security/installed-jvm-rust.js +0 -46
  291. package/src/security/installed.js +0 -280
  292. package/src/security/malware-file-heuristics.js +0 -121
  293. package/src/security/malware-heuristics.exclusions.js +0 -134
  294. package/src/security/malware-heuristics.js +0 -15
  295. package/src/security/malware-heuristics.roots.js +0 -145
  296. package/src/security/malware-heuristics.scan.js +0 -89
  297. package/src/security/malware-heuristics.sweep.js +0 -122
  298. package/src/security/malware-scoring.js +0 -105
  299. package/src/security/match.js +0 -85
  300. package/src/security/registry-sig.classify.js +0 -137
  301. package/src/security/registry-sig.js +0 -18
  302. package/src/security/registry-sig.rules.js +0 -192
  303. package/src/security/rust-advisory-report.js +0 -60
  304. package/src/security/typosquat.js +0 -81
  305. package/src/util.js +0 -40
  306. package/src/version.js +0 -7
@@ -1,120 +0,0 @@
1
- import { extractRustEndpoints } from "../endpoints-rust.js";
2
- import { extractSpringEndpoints } from "../endpoints-java.js";
3
- import { HTTP_METHODS, cleanPath, handlerName, handlerReference, lineAt, looksLikePath, maskComments } from "./common.js";
4
-
5
- const HTTP_CLIENT_CALLER = /^(axios|https?|fetch|ky|got|superagent|needle|undici|xhr|\$http|http[Cc]lient|api[Cc]lient|rest[Cc]lient)$/;
6
- const OPENAPI_BLOCK = /\boperationId\b|\bresponses\s*:|\brequestBody\b|\bschemaRef\b|\boperation\s*\(|\bsummary\s*:/;
7
-
8
- export function nextRoutePath(file) {
9
- const parts = String(file || "").replace(/\\/g, "/").split("/").filter(Boolean);
10
- if (!/^route\.[cm]?[jt]s$/i.test(parts.at(-1) || "")) return "";
11
- const appAt = parts.lastIndexOf("app");
12
- if (appAt < 0) return "";
13
- const route = [];
14
- for (let segment of parts.slice(appAt + 1, -1)) {
15
- if (!segment || /^\([^)]*\)$/.test(segment) || segment.startsWith("@")) continue;
16
- segment = segment.replace(/^\((?:\.{1,3})\)/, "");
17
- let match;
18
- if ((match = /^\[\[\.\.\.([^\]]+)\]\]$/.exec(segment))) segment = `*${match[1]}?`;
19
- else if ((match = /^\[\.\.\.([^\]]+)\]$/.exec(segment))) segment = `*${match[1]}`;
20
- else if ((match = /^\[([^\]]+)\]$/.exec(segment))) segment = `:${match[1]}`;
21
- if (segment) route.push(segment);
22
- }
23
- return `/${route.join("/")}`;
24
- }
25
-
26
- export function extractEndpointsFromText(text, file) {
27
- const out = [];
28
- const py = /\.py$/i.test(file), rust = /\.rs$/i.test(file), java = /\.java$/i.test(file);
29
- const scanText = maskComments(text, { hashComments: py });
30
- const add = (method, path, expr, index) => {
31
- const normalizedPath = cleanPath(path);
32
- const normalizedMethod = String(method || "ANY").toUpperCase();
33
- if (!looksLikePath(normalizedPath) || !HTTP_METHODS.has(normalizedMethod)) return;
34
- const handler = handlerName(expr);
35
- const handlerRef = handlerReference(expr);
36
- out.push({ method: normalizedMethod, path: normalizedPath, handler, ...(handlerRef ? { handlerRef } : {}), file, line: lineAt(text, index) });
37
- };
38
-
39
- const nextPath = nextRoutePath(file);
40
- if (nextPath) {
41
- const seen = new Set();
42
- const direct = /\bexport\s+(?:(?:async|declare)\s+)*(?:function\s+|(?:const|let|var)\s+)(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;
43
- let match;
44
- while ((match = direct.exec(scanText))) {
45
- const method = match[1].toUpperCase();
46
- if (!seen.has(method)) { seen.add(method); add(method, nextPath, method, match.index); }
47
- }
48
- const lists = /\bexport\s*\{([^}]+)\}/g;
49
- while ((match = lists.exec(scanText))) {
50
- for (const item of match[1].split(",")) {
51
- const methodMatch = /^\s*([A-Za-z_$][\w$]*)(?:\s+as\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS))?\s*$/.exec(item);
52
- if (!methodMatch || (!methodMatch[2] && !HTTP_METHODS.has(methodMatch[1]))) continue;
53
- const method = String(methodMatch[2] || methodMatch[1]).toUpperCase();
54
- if (HTTP_METHODS.has(method) && !seen.has(method)) { seen.add(method); add(method, nextPath, methodMatch[1], match.index); }
55
- }
56
- }
57
- }
58
-
59
- if (rust) extractRustEndpoints(scanText, add);
60
- if (java) {
61
- out.push(...extractSpringEndpoints(scanText, file));
62
- return out;
63
- }
64
-
65
- const objKey = /(["'`])(\/[^"'`]*)\1\s*:\s*(\{)?/g;
66
- let match;
67
- while ((match = objKey.exec(scanText))) {
68
- const path = match[2], keyIndex = match.index;
69
- if (match[3]) {
70
- let cursor = objKey.lastIndex, depth = 1;
71
- const start = cursor;
72
- while (cursor < scanText.length && depth > 0) {
73
- if (scanText[cursor] === "{") depth++;
74
- else if (scanText[cursor] === "}") depth--;
75
- cursor++;
76
- }
77
- const body = scanText.slice(start, cursor - 1);
78
- objKey.lastIndex = cursor;
79
- if (OPENAPI_BLOCK.test(body)) continue;
80
- const methodEntry = /\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b\s*:\s*([^,\n}]+)/gi;
81
- let entry;
82
- while ((entry = methodEntry.exec(body))) add(entry[1], path, entry[2], keyIndex);
83
- } else {
84
- const expression = /^([^,\n}]+)/.exec(scanText.slice(objKey.lastIndex, objKey.lastIndex + 200));
85
- if (expression && !/^\s*(?:\{|["'`\[]|[-+]?\d|true\b|false\b|null\b|undefined\b)/i.test(expression[1])) add("ANY", path, expression[1], keyIndex);
86
- }
87
- }
88
-
89
- const call = /(?<!@)\b([\w$]+)\s*\.\s*(get|post|put|patch|delete|head|options|all)\s*\(\s*(["'`])(\/[^"'`]*)\3\s*(?:,\s*([\s\S]{0,160}?))?\)/gi;
90
- while ((match = call.exec(scanText))) {
91
- const handler = String(match[5] || "").trim();
92
- if (!HTTP_CLIENT_CALLER.test(match[1]) && handler && handler[0] !== "{") add(match[2], match[4], match[5], match.index);
93
- }
94
-
95
- // Bare node:http servers commonly dispatch through request-method and URL-pathname guards rather
96
- // than a router API. Keep the extraction bounded to files that actually construct an HTTP server;
97
- // test assertions and arbitrary `object.method` comparisons are not enough to create endpoints.
98
- if (!py && /\bcreateServer\s*\(|\b(?:node:)?https?\b/.test(scanText)) {
99
- const guardedRoute = /\bif\s*\(([\s\S]{0,600}?)\)\s*(?:\{|return\b)/g;
100
- while ((match = guardedRoute.exec(scanText))) {
101
- const condition = match[1];
102
- const methodMatch = /\b[A-Za-z_$][\w$]*\.method\s*={2,3}\s*(["'`])(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|TRACE|CONNECT)\1/i.exec(condition);
103
- const pathMatch = /\b[A-Za-z_$][\w$]*\.pathname\s*={2,3}\s*(["'`])(\/[^"'`]*)\1/i.exec(condition);
104
- if (methodMatch && pathMatch) add(methodMatch[2], pathMatch[2], "", match.index);
105
- }
106
- }
107
-
108
- const go = /\.\s*(?:HandleFunc|Handle)\s*\(\s*(["'`])(\/[^"'`]*)\1\s*,\s*([\s\S]{0,120}?)\)/g;
109
- while ((match = go.exec(scanText))) add("ANY", match[2], match[3], match.index);
110
-
111
- if (py || /\.(?:[cm]?[jt]sx?)$/i.test(file)) {
112
- const decorator = /@[\w$]*\.?\s*(get|post|put|patch|delete|head|options)\s*\(\s*(["'`])(\/[^"'`]*)\2/gi;
113
- while ((match = decorator.exec(scanText))) {
114
- const after = scanText.slice(decorator.lastIndex, decorator.lastIndex + 200);
115
- const fn = /\b(?:def|async\s+def|function|const|export\s+function)\s+([A-Za-z_$][\w$]*)/.exec(after);
116
- add(match[1], match[3], fn ? fn[1] : "", match.index);
117
- }
118
- }
119
- return out;
120
- }
@@ -1,84 +0,0 @@
1
- import { safeRead } from "../../util.js";
2
- import { createRepoBoundary } from "../../repo-path.js";
3
- import { MAX_ENDPOINT_FILES, MAX_ENDPOINTS, normalizedFile } from "./common.js";
4
- import { extractEndpointsFromText, nextRoutePath } from "./extract.js";
5
- import { joinEndpointPath, mountedBasePaths } from "./mounts.js";
6
-
7
- const normParamKey = (path) => String(path).replace(/\{([^/}]+)\}/g, ":$1");
8
- const sortEndpoints = (left, right) => left.path.localeCompare(right.path) || left.method.localeCompare(right.method);
9
-
10
- function preferEndpoint(candidate, current) {
11
- if (Boolean(candidate.handler) !== Boolean(current.handler)) return Boolean(candidate.handler);
12
- return Number(candidate.path.includes("{")) < Number(current.path.includes("{"));
13
- }
14
-
15
- export function analyzeEndpointInventory(repoPath, codeFiles) {
16
- const files = (codeFiles || []).slice(0, MAX_ENDPOINT_FILES);
17
- const byKey = new Map();
18
- const declarations = new Map();
19
- const boundary = createRepoBoundary(repoPath);
20
- const sources = new Map();
21
- const eligibleFiles = [];
22
- for (const file of files) {
23
- const relative = normalizedFile(file.path || file);
24
- if (!/\.(?:[cm]?[jt]sx?|py|go|rs|java)$/i.test(relative)) continue;
25
- const resolved = boundary.resolve(relative);
26
- if (!resolved.ok) continue;
27
- sources.set(relative, safeRead(resolved.path) || "");
28
- eligibleFiles.push(relative);
29
- }
30
- const mountAnalysis = mountedBasePaths(eligibleFiles, sources);
31
- let truncated = false;
32
- for (const relative of eligibleFiles) {
33
- const text = sources.get(relative);
34
- const routeSignal = /["'`]\/|\.(?:get|post|put|patch|delete)\s*\(|HandleFunc|@\w*\.?(?:get|post|put|patch|delete)|@(?:[\w$]+\.)*(?:Request|Get|Post|Put|Patch|Delete)Mapping\b/i;
35
- if (!text || (!nextRoutePath(relative) && !routeSignal.test(text))) continue;
36
- for (const declaration of extractEndpointsFromText(text, relative)) {
37
- const declarationKey = `${declaration.file}\0${declaration.line}\0${declaration.method}\0${normParamKey(declaration.path)}`;
38
- if (!declarations.has(declarationKey)) declarations.set(declarationKey, declaration);
39
- const bases = mountAnalysis.paths.get(relative) || [{ path: "", chain: [] }];
40
- for (const base of bases) {
41
- const path = base.path ? joinEndpointPath(base.path, declaration.path) : declaration.path;
42
- const endpoint = {
43
- ...declaration,
44
- declaredPath: declaration.path,
45
- path,
46
- mountState: base.chain.length ? "COMPOSED_STATIC" : "DECLARED_LOCAL",
47
- confidence: base.chain.length ? "high" : "medium",
48
- mountChain: base.chain,
49
- ...(base.path ? { localPath: declaration.path } : {}),
50
- };
51
- const key = `${endpoint.method} ${normParamKey(endpoint.path)}`;
52
- const current = byKey.get(key);
53
- if (!current || preferEndpoint(endpoint, current)) byKey.set(key, endpoint);
54
- if (byKey.size >= MAX_ENDPOINTS) { truncated = true; break; }
55
- }
56
- if (truncated) break;
57
- }
58
- if (truncated) break;
59
- }
60
- const endpoints = [...byKey.values()].sort(sortEndpoints);
61
- const composed = endpoints.filter((endpoint) => endpoint.mountChain.length).length;
62
- return {
63
- endpoints,
64
- declarations: [...declarations.values()].sort(sortEndpoints),
65
- mounts: mountAnalysis.mounts,
66
- stats: {
67
- scannedFiles: eligibleFiles.length,
68
- declaredRoutes: declarations.size,
69
- emittedRoutes: endpoints.length,
70
- reachableRoutes: composed,
71
- reachableStaticRoutes: composed,
72
- composedRoutes: composed,
73
- localRoutes: endpoints.length - composed,
74
- localDeclarations: endpoints.length - composed,
75
- staticMounts: mountAnalysis.mounts.length,
76
- truncated,
77
- maxEndpoints: MAX_ENDPOINTS,
78
- },
79
- };
80
- }
81
-
82
- export function detectEndpoints(repoPath, codeFiles) {
83
- return analyzeEndpointInventory(repoPath, codeFiles).endpoints;
84
- }
@@ -1,129 +0,0 @@
1
- import { posix } from "node:path";
2
- import { cleanPath, lineAt, maskComments } from "./common.js";
3
-
4
- const JS_ROUTE_EXTENSIONS = [".js", ".ts", ".tsx", ".jsx", ".cjs", ".mjs"];
5
-
6
- function importBindings(text) {
7
- const bindings = new Map();
8
- const add = (name, specifier) => {
9
- if (/^[A-Za-z_$][\w$]*$/.test(name || "") && typeof specifier === "string") bindings.set(name, specifier);
10
- };
11
- let match;
12
- const direct = /\bimport\s+([A-Za-z_$][\w$]*)\s*(?:,\s*\{[^}]*\})?\s+from\s*(["'`])([^"'`]+)\2/g;
13
- while ((match = direct.exec(text))) add(match[1], match[3]);
14
- const namespace = /\bimport\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*(["'`])([^"'`]+)\2/g;
15
- while ((match = namespace.exec(text))) add(match[1], match[3]);
16
- const named = /\bimport\s*\{([^}]+)\}\s*from\s*(["'`])([^"'`]+)\2/g;
17
- while ((match = named.exec(text))) {
18
- for (const item of match[1].split(",")) {
19
- const binding = /^\s*[A-Za-z_$][\w$]*(?:\s+as\s+([A-Za-z_$][\w$]*))?\s*$/.exec(item);
20
- if (binding) add(binding[1] || item.trim(), match[3]);
21
- }
22
- }
23
- const commonJs = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*require\s*\(\s*(["'`])([^"'`]+)\2\s*\)/g;
24
- while ((match = commonJs.exec(text))) add(match[1], match[3]);
25
- return bindings;
26
- }
27
-
28
- function resolveImportedFile(importer, specifier, availableFiles) {
29
- if (!specifier?.startsWith(".")) return null;
30
- const base = posix.normalize(posix.join(posix.dirname(importer), specifier));
31
- const candidates = [base];
32
- if (!JS_ROUTE_EXTENSIONS.some((extension) => base.endsWith(extension))) {
33
- for (const extension of JS_ROUTE_EXTENSIONS) candidates.push(`${base}${extension}`);
34
- for (const extension of JS_ROUTE_EXTENSIONS) candidates.push(`${base}/index${extension}`);
35
- }
36
- return candidates.find((candidate) => availableFiles.has(candidate)) || null;
37
- }
38
-
39
- function callArguments(text, openParen) {
40
- let quote = "", escaped = false, depth = 0, start = openParen + 1;
41
- const args = [];
42
- for (let index = openParen; index < text.length; index++) {
43
- const char = text[index];
44
- if (quote) {
45
- if (escaped) escaped = false;
46
- else if (char === "\\") escaped = true;
47
- else if (char === quote) quote = "";
48
- continue;
49
- }
50
- if (char === '"' || char === "'" || char === "`") { quote = char; continue; }
51
- if (char === "(") { depth++; continue; }
52
- if (char === ")") {
53
- depth--;
54
- if (depth === 0) {
55
- args.push(text.slice(start, index).trim());
56
- return { args, end: index + 1 };
57
- }
58
- continue;
59
- }
60
- if (char === "," && depth === 1) {
61
- args.push(text.slice(start, index).trim());
62
- start = index + 1;
63
- }
64
- }
65
- return null;
66
- }
67
-
68
- function routerMounts(text, file, availableFiles) {
69
- const scanText = maskComments(text);
70
- const bindings = importBindings(scanText);
71
- const mounts = [];
72
- const useCall = /\b[A-Za-z_$][\w$]*\s*\.\s*use\s*\(/g;
73
- let match;
74
- while ((match = useCall.exec(scanText))) {
75
- const parsed = callArguments(scanText, scanText.indexOf("(", match.index));
76
- if (!parsed) continue;
77
- useCall.lastIndex = parsed.end;
78
- const args = parsed.args.filter(Boolean);
79
- if (!args.length) continue;
80
- const literal = /^(["'`])(\/[^"'`]*)\1$/.exec(args[0]);
81
- const mountPath = literal ? cleanPath(literal[2]) : "/";
82
- const identifier = /^([A-Za-z_$][\w$]*)(?:\.[A-Za-z_$][\w$]*)?$/.exec(args.at(-1) || "")?.[1];
83
- const child = resolveImportedFile(file, identifier ? bindings.get(identifier) : null, availableFiles);
84
- if (child && child !== file) mounts.push({ parent: file, child, path: mountPath, line: lineAt(text, match.index) });
85
- }
86
- return mounts;
87
- }
88
-
89
- export function joinEndpointPath(base, route) {
90
- const left = cleanPath(base || "/");
91
- const right = cleanPath(route || "/");
92
- if (left === "/") return right;
93
- if (right === "/") return left;
94
- return cleanPath(`${left}/${right.replace(/^\/+/, "")}`.replace(/\/{2,}/g, "/"));
95
- }
96
-
97
- export function mountedBasePaths(files, sources) {
98
- const incoming = new Map();
99
- const mounts = [];
100
- const available = new Set(files);
101
- for (const file of files) {
102
- for (const mount of routerMounts(sources.get(file) || "", file, available)) {
103
- mounts.push(mount);
104
- if (!incoming.has(mount.child)) incoming.set(mount.child, []);
105
- incoming.get(mount.child).push(mount);
106
- }
107
- }
108
- const cache = new Map();
109
- const resolve = (file, stack = new Set()) => {
110
- if (cache.has(file)) return cache.get(file);
111
- if (stack.has(file)) return [];
112
- const parents = incoming.get(file) || [];
113
- if (!parents.length) return [{ path: "", chain: [] }];
114
- const paths = [];
115
- for (const mount of parents) {
116
- for (const base of resolve(mount.parent, new Set(stack).add(file))) {
117
- const path = joinEndpointPath(base.path, mount.path);
118
- const key = `${path}\0${base.chain.map((item) => `${item.file}:${item.line}:${item.path}`).join("|")}\0${mount.parent}:${mount.line}:${mount.path}`;
119
- if (!paths.some((item) => item.key === key)) paths.push({ key, path, chain: [...base.chain, { file: mount.parent, line: mount.line, path: mount.path, child: mount.child }] });
120
- if (paths.length >= 32) break;
121
- }
122
- if (paths.length >= 32) break;
123
- }
124
- const result = paths.length ? paths.map(({ key: _key, ...item }) => item) : [{ path: "", chain: [] }];
125
- cache.set(file, result);
126
- return result;
127
- };
128
- return { paths: new Map(files.map((file) => [file, resolve(file)])), mounts };
129
- }
@@ -1,260 +0,0 @@
1
- // Spring MVC/WebFlux endpoint extraction. This stays source-only and deliberately resolves only
2
- // literal annotation paths: inventing values for constants would make an architecture inventory look
3
- // more complete than the evidence permits.
4
- import { maskJavaNonCode } from "./java-source.js";
5
- import { lineNumberAt } from "../util.js";
6
-
7
- const SPRING_MAPPING = /@(?:org\.springframework\.web\.bind\.annotation\.)?(RequestMapping|GetMapping|PostMapping|PutMapping|PatchMapping|DeleteMapping)\b/g;
8
- const SPRING_CONDITION = /@(?:org\.springframework\.boot\.autoconfigure\.condition\.)?(ConditionalOnExpression|ConditionalOnProperty)\b/g;
9
- const REQUEST_METHOD = /\bRequestMethod\s*\.\s*(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|TRACE)\b/g;
10
-
11
- const lineAt = lineNumberAt;
12
-
13
- function skipTrivia(text, start) {
14
- let i = start;
15
- while (i < text.length) {
16
- if (/\s/.test(text[i])) { i++; continue; }
17
- if (text.startsWith("//", i)) {
18
- const nl = text.indexOf("\n", i + 2);
19
- i = nl < 0 ? text.length : nl + 1;
20
- continue;
21
- }
22
- if (text.startsWith("/*", i)) {
23
- const end = text.indexOf("*/", i + 2);
24
- i = end < 0 ? text.length : end + 2;
25
- continue;
26
- }
27
- break;
28
- }
29
- return i;
30
- }
31
-
32
- function balancedEnd(text, start, open = "(", close = ")") {
33
- if (text[start] !== open) return start;
34
- let depth = 0;
35
- let quote = "";
36
- let escaped = false;
37
- for (let i = start; i < text.length; i++) {
38
- const ch = text[i];
39
- if (quote) {
40
- if (escaped) escaped = false;
41
- else if (ch === "\\") escaped = true;
42
- else if (ch === quote) quote = "";
43
- continue;
44
- }
45
- if (ch === '"' || ch === "'") { quote = ch; continue; }
46
- if (ch === open) depth++;
47
- else if (ch === close && --depth === 0) return i + 1;
48
- }
49
- return text.length;
50
- }
51
-
52
- function annotationInvocation(text, nameEnd) {
53
- const start = skipTrivia(text, nameEnd);
54
- if (text[start] !== "(") return { args: "", end: start };
55
- const end = balancedEnd(text, start);
56
- return { args: text.slice(start + 1, Math.max(start + 1, end - 1)), end };
57
- }
58
-
59
- function skipAnnotations(text, start) {
60
- let i = skipTrivia(text, start);
61
- while (text[i] === "@") {
62
- const name = /^@[A-Za-z_$][\w$]*(?:\s*\.\s*[A-Za-z_$][\w$]*)*/.exec(text.slice(i));
63
- if (!name) break;
64
- i += name[0].length;
65
- i = annotationInvocation(text, i).end;
66
- i = skipTrivia(text, i);
67
- }
68
- return i;
69
- }
70
-
71
- function stringLiterals(value) {
72
- const out = [];
73
- const re = /"((?:\\.|[^"\\])*)"/g;
74
- let match;
75
- while ((match = re.exec(String(value || "")))) {
76
- out.push(match[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\"));
77
- }
78
- return out;
79
- }
80
-
81
- function initializer(args, equalsAt) {
82
- let i = skipTrivia(args, equalsAt + 1);
83
- if (args[i] === "{") {
84
- const end = balancedEnd(args, i, "{", "}");
85
- return args.slice(i, end);
86
- }
87
- if (args[i] === '"') {
88
- let escaped = false;
89
- for (let end = i + 1; end < args.length; end++) {
90
- if (escaped) escaped = false;
91
- else if (args[end] === "\\") escaped = true;
92
- else if (args[end] === '"') return args.slice(i, end + 1);
93
- }
94
- }
95
- const comma = args.indexOf(",", i);
96
- return args.slice(i, comma < 0 ? args.length : comma);
97
- }
98
-
99
- function mappingPaths(args) {
100
- const source = String(args || "");
101
- const named = /\b(?:path|value)\s*=/g.exec(source);
102
- if (named) return stringLiterals(initializer(source, source.indexOf("=", named.index)));
103
- const leading = source.trimStart();
104
- if (!leading) return [""];
105
- if (leading[0] === '"' || leading[0] === "{") return stringLiterals(leading);
106
- // `method=`, `produces=` and friends do not specify a path, so they map the class/method root.
107
- if (/^(?:method|produces|consumes|headers|params|name)\s*=/.test(leading)) return [""];
108
- return []; // unresolved positional constant: do not invent a root route
109
- }
110
-
111
- function mappingMethods(name, args) {
112
- if (name !== "RequestMapping") return [name.replace(/Mapping$/, "").toUpperCase()];
113
- const methods = [];
114
- let match;
115
- REQUEST_METHOD.lastIndex = 0;
116
- while ((match = REQUEST_METHOD.exec(args))) if (!methods.includes(match[1])) methods.push(match[1]);
117
- return methods.length ? methods : ["ANY"];
118
- }
119
-
120
- function namedInitializer(args, name) {
121
- const source = String(args || "");
122
- const match = new RegExp(`\\b${name}\\s*=`).exec(source);
123
- return match ? initializer(source, source.indexOf("=", match.index)) : "";
124
- }
125
-
126
- function namedStrings(args, name) {
127
- return stringLiterals(namedInitializer(args, name));
128
- }
129
-
130
- function namedBoolean(args, name, fallback) {
131
- const value = namedInitializer(args, name).trim();
132
- if (/^true\b/i.test(value)) return true;
133
- if (/^false\b/i.test(value)) return false;
134
- return fallback;
135
- }
136
-
137
- function positionalStrings(args) {
138
- const source = String(args || "");
139
- const start = source.trimStart()[0];
140
- return start === '"' || start === "{" ? stringLiterals(initializer(source, -1)) : [];
141
- }
142
-
143
- function expressionDefaultActive(expression) {
144
- const value = String(expression || "").trim();
145
- if (/^(?:true|false)$/i.test(value)) return value.toLowerCase() === "true";
146
- const match = /^\$\{[^{}:]+:(true|false)\}$/i.exec(value);
147
- return match ? match[1].toLowerCase() === "true" : null;
148
- }
149
-
150
- function conditionMetadata(annotation, args) {
151
- if (annotation === "ConditionalOnExpression") {
152
- const expression = namedStrings(args, "value")[0] || stringLiterals(args)[0] || "";
153
- return {
154
- type: annotation,
155
- expression,
156
- defaultActive: expressionDefaultActive(expression),
157
- };
158
- }
159
- const namedProperties = [...namedStrings(args, "name"), ...namedStrings(args, "value")];
160
- const properties = [...new Set(namedProperties.length ? namedProperties : positionalStrings(args))];
161
- const matchIfMissing = namedBoolean(args, "matchIfMissing", false);
162
- return {
163
- type: annotation,
164
- prefix: namedStrings(args, "prefix")[0] || "",
165
- properties,
166
- havingValue: namedStrings(args, "havingValue")[0] || "",
167
- matchIfMissing,
168
- defaultActive: matchIfMissing,
169
- };
170
- }
171
-
172
- function joinPaths(prefix, path) {
173
- const left = String(prefix || "").trim().replace(/^\/+|\/+$/g, "");
174
- const right = String(path || "").trim().replace(/^\/+|\/+$/g, "");
175
- return `/${[left, right].filter(Boolean).join("/")}`.replace(/\/{2,}/g, "/");
176
- }
177
-
178
- function declarationAfter(text, start) {
179
- const declarationStart = skipAnnotations(text, start);
180
- const bounded = text.slice(declarationStart, declarationStart + 2_500);
181
- const terminators = [bounded.indexOf("{"), bounded.indexOf(";")].filter((i) => i >= 0);
182
- const end = terminators.length ? Math.min(...terminators) : bounded.length;
183
- const head = bounded.slice(0, end);
184
- const classMatch = /\b(class|interface|record|enum)\s+([A-Za-z_$][\w$]*)/.exec(head);
185
- if (classMatch) {
186
- const open = bounded.indexOf("{");
187
- const bodyOpen = open < 0 ? -1 : declarationStart + open;
188
- return { kind: "class", name: classMatch[2], start: declarationStart, bodyOpen, bodyClose: bodyOpen < 0 ? text.length : balancedEnd(text, bodyOpen, "{", "}") };
189
- }
190
- const methodMatch = /\b([A-Za-z_$][\w$]*)\s*\(/.exec(head);
191
- return methodMatch ? { kind: "method", name: methodMatch[1], start: declarationStart } : { kind: "unknown", name: "", start: declarationStart };
192
- }
193
-
194
- export function extractSpringEndpoints(text, file) {
195
- if (!/\.java$/i.test(file)) return [];
196
- const code = maskJavaNonCode(text);
197
- if (!/@(?:[\w$]+\.)*(?:Request|Get|Post|Put|Patch|Delete)Mapping\b/.test(code)) return [];
198
- const mappings = [];
199
- let match;
200
- SPRING_MAPPING.lastIndex = 0;
201
- while ((match = SPRING_MAPPING.exec(code))) {
202
- const invocation = annotationInvocation(text, SPRING_MAPPING.lastIndex);
203
- const declaration = declarationAfter(code, invocation.end);
204
- mappings.push({
205
- annotation: match[1],
206
- args: invocation.args,
207
- index: match.index,
208
- line: lineAt(text, match.index),
209
- declaration,
210
- });
211
- SPRING_MAPPING.lastIndex = Math.max(SPRING_MAPPING.lastIndex, invocation.end);
212
- }
213
- const conditions = [];
214
- SPRING_CONDITION.lastIndex = 0;
215
- while ((match = SPRING_CONDITION.exec(code))) {
216
- const invocation = annotationInvocation(text, SPRING_CONDITION.lastIndex);
217
- const declaration = declarationAfter(code, invocation.end);
218
- conditions.push({
219
- index: match.index,
220
- line: lineAt(text, match.index),
221
- declaration,
222
- ...conditionMetadata(match[1], invocation.args),
223
- });
224
- SPRING_CONDITION.lastIndex = Math.max(SPRING_CONDITION.lastIndex, invocation.end);
225
- }
226
-
227
- const classMappings = mappings
228
- .filter((item) => item.declaration.kind === "class")
229
- .map((item) => ({ ...item, paths: mappingPaths(item.args) }));
230
- const out = [];
231
- for (const item of mappings) {
232
- if (item.declaration.kind !== "method") continue;
233
- const owner = classMappings
234
- .filter((candidate) => candidate.declaration.bodyOpen >= 0
235
- && item.index > candidate.declaration.bodyOpen
236
- && item.index < candidate.declaration.bodyClose)
237
- .sort((a, b) => b.declaration.bodyOpen - a.declaration.bodyOpen)[0];
238
- if (owner && !owner.paths.length) continue; // unresolved class prefix makes the full route unknowable
239
- const prefixes = owner?.paths?.length ? owner.paths : [""];
240
- const paths = mappingPaths(item.args);
241
- if (!paths.length) continue; // literal path was requested but could not be resolved
242
- const activationConditions = conditions.filter((condition) => condition.declaration.start === item.declaration.start
243
- || (owner && condition.declaration.start === owner.declaration.start));
244
- const activation = activationConditions.length
245
- ? {
246
- conditional: true,
247
- defaultActive: activationConditions.some((condition) => condition.defaultActive === false)
248
- ? false
249
- : activationConditions.every((condition) => condition.defaultActive === true) ? true : null,
250
- conditions: activationConditions.map(({ declaration: _declaration, index: _index, ...condition }) => condition),
251
- }
252
- : {};
253
- for (const method of mappingMethods(item.annotation, item.args)) {
254
- for (const prefix of prefixes) for (const path of paths) {
255
- out.push({ method, path: joinPaths(prefix, path), handler: item.declaration.name, file, line: item.line, ...activation });
256
- }
257
- }
258
- }
259
- return out;
260
- }