mnehmos.trace.mcp 1.0.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 (339) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1662 -0
  3. package/dist/adapters/bootstrap.d.ts +29 -0
  4. package/dist/adapters/bootstrap.d.ts.map +1 -0
  5. package/dist/adapters/bootstrap.js +46 -0
  6. package/dist/adapters/bootstrap.js.map +1 -0
  7. package/dist/adapters/errors.d.ts +94 -0
  8. package/dist/adapters/errors.d.ts.map +1 -0
  9. package/dist/adapters/errors.js +107 -0
  10. package/dist/adapters/errors.js.map +1 -0
  11. package/dist/adapters/graphql/index.d.ts +9 -0
  12. package/dist/adapters/graphql/index.d.ts.map +1 -0
  13. package/dist/adapters/graphql/index.js +9 -0
  14. package/dist/adapters/graphql/index.js.map +1 -0
  15. package/dist/adapters/graphql/sdl-parser.d.ts +74 -0
  16. package/dist/adapters/graphql/sdl-parser.d.ts.map +1 -0
  17. package/dist/adapters/graphql/sdl-parser.js +559 -0
  18. package/dist/adapters/graphql/sdl-parser.js.map +1 -0
  19. package/dist/adapters/grpc/adapter.d.ts +76 -0
  20. package/dist/adapters/grpc/adapter.d.ts.map +1 -0
  21. package/dist/adapters/grpc/adapter.js +362 -0
  22. package/dist/adapters/grpc/adapter.js.map +1 -0
  23. package/dist/adapters/grpc/index.d.ts +10 -0
  24. package/dist/adapters/grpc/index.d.ts.map +1 -0
  25. package/dist/adapters/grpc/index.js +12 -0
  26. package/dist/adapters/grpc/index.js.map +1 -0
  27. package/dist/adapters/grpc/proto-parser.d.ts +76 -0
  28. package/dist/adapters/grpc/proto-parser.d.ts.map +1 -0
  29. package/dist/adapters/grpc/proto-parser.js +523 -0
  30. package/dist/adapters/grpc/proto-parser.js.map +1 -0
  31. package/dist/adapters/grpc/type-converter.d.ts +43 -0
  32. package/dist/adapters/grpc/type-converter.d.ts.map +1 -0
  33. package/dist/adapters/grpc/type-converter.js +270 -0
  34. package/dist/adapters/grpc/type-converter.js.map +1 -0
  35. package/dist/adapters/grpc/types.d.ts +85 -0
  36. package/dist/adapters/grpc/types.d.ts.map +1 -0
  37. package/dist/adapters/grpc/types.js +7 -0
  38. package/dist/adapters/grpc/types.js.map +1 -0
  39. package/dist/adapters/index.d.ts +39 -0
  40. package/dist/adapters/index.d.ts.map +1 -0
  41. package/dist/adapters/index.js +50 -0
  42. package/dist/adapters/index.js.map +1 -0
  43. package/dist/adapters/mcp.d.ts +23 -0
  44. package/dist/adapters/mcp.d.ts.map +1 -0
  45. package/dist/adapters/mcp.js +293 -0
  46. package/dist/adapters/mcp.js.map +1 -0
  47. package/dist/adapters/openapi/adapter.d.ts +213 -0
  48. package/dist/adapters/openapi/adapter.d.ts.map +1 -0
  49. package/dist/adapters/openapi/adapter.js +557 -0
  50. package/dist/adapters/openapi/adapter.js.map +1 -0
  51. package/dist/adapters/openapi/convert.d.ts +120 -0
  52. package/dist/adapters/openapi/convert.d.ts.map +1 -0
  53. package/dist/adapters/openapi/convert.js +363 -0
  54. package/dist/adapters/openapi/convert.js.map +1 -0
  55. package/dist/adapters/openapi/index.d.ts +39 -0
  56. package/dist/adapters/openapi/index.d.ts.map +1 -0
  57. package/dist/adapters/openapi/index.js +48 -0
  58. package/dist/adapters/openapi/index.js.map +1 -0
  59. package/dist/adapters/openapi/parser.d.ts +95 -0
  60. package/dist/adapters/openapi/parser.d.ts.map +1 -0
  61. package/dist/adapters/openapi/parser.js +171 -0
  62. package/dist/adapters/openapi/parser.js.map +1 -0
  63. package/dist/adapters/registry.d.ts +116 -0
  64. package/dist/adapters/registry.d.ts.map +1 -0
  65. package/dist/adapters/registry.js +246 -0
  66. package/dist/adapters/registry.js.map +1 -0
  67. package/dist/adapters/trpc/adapter.d.ts +159 -0
  68. package/dist/adapters/trpc/adapter.d.ts.map +1 -0
  69. package/dist/adapters/trpc/adapter.js +223 -0
  70. package/dist/adapters/trpc/adapter.js.map +1 -0
  71. package/dist/adapters/trpc/extractor.d.ts +218 -0
  72. package/dist/adapters/trpc/extractor.d.ts.map +1 -0
  73. package/dist/adapters/trpc/extractor.js +708 -0
  74. package/dist/adapters/trpc/extractor.js.map +1 -0
  75. package/dist/adapters/trpc/index.d.ts +31 -0
  76. package/dist/adapters/trpc/index.d.ts.map +1 -0
  77. package/dist/adapters/trpc/index.js +40 -0
  78. package/dist/adapters/trpc/index.js.map +1 -0
  79. package/dist/adapters/trpc/parser.d.ts +119 -0
  80. package/dist/adapters/trpc/parser.d.ts.map +1 -0
  81. package/dist/adapters/trpc/parser.js +128 -0
  82. package/dist/adapters/trpc/parser.js.map +1 -0
  83. package/dist/compare/index.d.ts +33 -0
  84. package/dist/compare/index.d.ts.map +1 -0
  85. package/dist/compare/index.js +261 -0
  86. package/dist/compare/index.js.map +1 -0
  87. package/dist/core/types.d.ts +188 -0
  88. package/dist/core/types.d.ts.map +1 -0
  89. package/dist/core/types.js +9 -0
  90. package/dist/core/types.js.map +1 -0
  91. package/dist/extract/index.d.ts +26 -0
  92. package/dist/extract/index.d.ts.map +1 -0
  93. package/dist/extract/index.js +44 -0
  94. package/dist/extract/index.js.map +1 -0
  95. package/dist/index.d.ts +9 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +674 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/languages/base.d.ts +57 -0
  100. package/dist/languages/base.d.ts.map +1 -0
  101. package/dist/languages/base.js +6 -0
  102. package/dist/languages/base.js.map +1 -0
  103. package/dist/languages/bootstrap.d.ts +10 -0
  104. package/dist/languages/bootstrap.d.ts.map +1 -0
  105. package/dist/languages/bootstrap.js +25 -0
  106. package/dist/languages/bootstrap.js.map +1 -0
  107. package/dist/languages/go/handlers/chi.d.ts +24 -0
  108. package/dist/languages/go/handlers/chi.d.ts.map +1 -0
  109. package/dist/languages/go/handlers/chi.js +205 -0
  110. package/dist/languages/go/handlers/chi.js.map +1 -0
  111. package/dist/languages/go/handlers/gin.d.ts +24 -0
  112. package/dist/languages/go/handlers/gin.d.ts.map +1 -0
  113. package/dist/languages/go/handlers/gin.js +156 -0
  114. package/dist/languages/go/handlers/gin.js.map +1 -0
  115. package/dist/languages/go/handlers/stdlib.d.ts +19 -0
  116. package/dist/languages/go/handlers/stdlib.d.ts.map +1 -0
  117. package/dist/languages/go/handlers/stdlib.js +112 -0
  118. package/dist/languages/go/handlers/stdlib.js.map +1 -0
  119. package/dist/languages/go/index.d.ts +18 -0
  120. package/dist/languages/go/index.d.ts.map +1 -0
  121. package/dist/languages/go/index.js +20 -0
  122. package/dist/languages/go/index.js.map +1 -0
  123. package/dist/languages/go/parser.d.ts +33 -0
  124. package/dist/languages/go/parser.d.ts.map +1 -0
  125. package/dist/languages/go/parser.js +95 -0
  126. package/dist/languages/go/parser.js.map +1 -0
  127. package/dist/languages/go/struct-extractor.d.ts +59 -0
  128. package/dist/languages/go/struct-extractor.d.ts.map +1 -0
  129. package/dist/languages/go/struct-extractor.js +483 -0
  130. package/dist/languages/go/struct-extractor.js.map +1 -0
  131. package/dist/languages/go/tag-parser.d.ts +62 -0
  132. package/dist/languages/go/tag-parser.d.ts.map +1 -0
  133. package/dist/languages/go/tag-parser.js +108 -0
  134. package/dist/languages/go/tag-parser.js.map +1 -0
  135. package/dist/languages/go/type-converter.d.ts +32 -0
  136. package/dist/languages/go/type-converter.d.ts.map +1 -0
  137. package/dist/languages/go/type-converter.js +226 -0
  138. package/dist/languages/go/type-converter.js.map +1 -0
  139. package/dist/languages/go/types.d.ts +153 -0
  140. package/dist/languages/go/types.d.ts.map +1 -0
  141. package/dist/languages/go/types.js +6 -0
  142. package/dist/languages/go/types.js.map +1 -0
  143. package/dist/languages/import-resolver.d.ts +645 -0
  144. package/dist/languages/import-resolver.d.ts.map +1 -0
  145. package/dist/languages/import-resolver.js +1278 -0
  146. package/dist/languages/import-resolver.js.map +1 -0
  147. package/dist/languages/index.d.ts +34 -0
  148. package/dist/languages/index.d.ts.map +1 -0
  149. package/dist/languages/index.js +93 -0
  150. package/dist/languages/index.js.map +1 -0
  151. package/dist/languages/json-schema.d.ts +40 -0
  152. package/dist/languages/json-schema.d.ts.map +1 -0
  153. package/dist/languages/json-schema.js +188 -0
  154. package/dist/languages/json-schema.js.map +1 -0
  155. package/dist/languages/python-ast/index.d.ts +8 -0
  156. package/dist/languages/python-ast/index.d.ts.map +1 -0
  157. package/dist/languages/python-ast/index.js +7 -0
  158. package/dist/languages/python-ast/index.js.map +1 -0
  159. package/dist/languages/python-ast/parser.d.ts +174 -0
  160. package/dist/languages/python-ast/parser.d.ts.map +1 -0
  161. package/dist/languages/python-ast/parser.js +1205 -0
  162. package/dist/languages/python-ast/parser.js.map +1 -0
  163. package/dist/languages/python-ast/type-resolver.d.ts +75 -0
  164. package/dist/languages/python-ast/type-resolver.d.ts.map +1 -0
  165. package/dist/languages/python-ast/type-resolver.js +421 -0
  166. package/dist/languages/python-ast/type-resolver.js.map +1 -0
  167. package/dist/languages/python-ast/types.d.ts +216 -0
  168. package/dist/languages/python-ast/types.d.ts.map +1 -0
  169. package/dist/languages/python-ast/types.js +6 -0
  170. package/dist/languages/python-ast/types.js.map +1 -0
  171. package/dist/languages/python.d.ts +55 -0
  172. package/dist/languages/python.d.ts.map +1 -0
  173. package/dist/languages/python.js +311 -0
  174. package/dist/languages/python.js.map +1 -0
  175. package/dist/languages/typescript.d.ts +272 -0
  176. package/dist/languages/typescript.d.ts.map +1 -0
  177. package/dist/languages/typescript.js +1381 -0
  178. package/dist/languages/typescript.js.map +1 -0
  179. package/dist/patterns/base.d.ts +146 -0
  180. package/dist/patterns/base.d.ts.map +1 -0
  181. package/dist/patterns/base.js +89 -0
  182. package/dist/patterns/base.js.map +1 -0
  183. package/dist/patterns/errors.d.ts +172 -0
  184. package/dist/patterns/errors.d.ts.map +1 -0
  185. package/dist/patterns/errors.js +185 -0
  186. package/dist/patterns/errors.js.map +1 -0
  187. package/dist/patterns/extractors.d.ts +170 -0
  188. package/dist/patterns/extractors.d.ts.map +1 -0
  189. package/dist/patterns/extractors.js +305 -0
  190. package/dist/patterns/extractors.js.map +1 -0
  191. package/dist/patterns/graphql/apollo-client.d.ts +80 -0
  192. package/dist/patterns/graphql/apollo-client.d.ts.map +1 -0
  193. package/dist/patterns/graphql/apollo-client.js +800 -0
  194. package/dist/patterns/graphql/apollo-client.js.map +1 -0
  195. package/dist/patterns/graphql/apollo-server.d.ts +55 -0
  196. package/dist/patterns/graphql/apollo-server.d.ts.map +1 -0
  197. package/dist/patterns/graphql/apollo-server.js +523 -0
  198. package/dist/patterns/graphql/apollo-server.js.map +1 -0
  199. package/dist/patterns/graphql/index.d.ts +11 -0
  200. package/dist/patterns/graphql/index.d.ts.map +1 -0
  201. package/dist/patterns/graphql/index.js +12 -0
  202. package/dist/patterns/graphql/index.js.map +1 -0
  203. package/dist/patterns/graphql/types.d.ts +213 -0
  204. package/dist/patterns/graphql/types.d.ts.map +1 -0
  205. package/dist/patterns/graphql/types.js +16 -0
  206. package/dist/patterns/graphql/types.js.map +1 -0
  207. package/dist/patterns/http-clients/axios.d.ts +148 -0
  208. package/dist/patterns/http-clients/axios.d.ts.map +1 -0
  209. package/dist/patterns/http-clients/axios.js +652 -0
  210. package/dist/patterns/http-clients/axios.js.map +1 -0
  211. package/dist/patterns/http-clients/fetch.d.ts +88 -0
  212. package/dist/patterns/http-clients/fetch.d.ts.map +1 -0
  213. package/dist/patterns/http-clients/fetch.js +364 -0
  214. package/dist/patterns/http-clients/fetch.js.map +1 -0
  215. package/dist/patterns/http-clients/index.d.ts +36 -0
  216. package/dist/patterns/http-clients/index.d.ts.map +1 -0
  217. package/dist/patterns/http-clients/index.js +50 -0
  218. package/dist/patterns/http-clients/index.js.map +1 -0
  219. package/dist/patterns/http-clients/property-access.d.ts +46 -0
  220. package/dist/patterns/http-clients/property-access.d.ts.map +1 -0
  221. package/dist/patterns/http-clients/property-access.js +818 -0
  222. package/dist/patterns/http-clients/property-access.js.map +1 -0
  223. package/dist/patterns/http-clients/type-inference.d.ts +48 -0
  224. package/dist/patterns/http-clients/type-inference.d.ts.map +1 -0
  225. package/dist/patterns/http-clients/type-inference.js +293 -0
  226. package/dist/patterns/http-clients/type-inference.js.map +1 -0
  227. package/dist/patterns/http-clients/types.d.ts +168 -0
  228. package/dist/patterns/http-clients/types.d.ts.map +1 -0
  229. package/dist/patterns/http-clients/types.js +10 -0
  230. package/dist/patterns/http-clients/types.js.map +1 -0
  231. package/dist/patterns/http-clients/url-extractor.d.ts +53 -0
  232. package/dist/patterns/http-clients/url-extractor.d.ts.map +1 -0
  233. package/dist/patterns/http-clients/url-extractor.js +338 -0
  234. package/dist/patterns/http-clients/url-extractor.js.map +1 -0
  235. package/dist/patterns/index.d.ts +44 -0
  236. package/dist/patterns/index.d.ts.map +1 -0
  237. package/dist/patterns/index.js +49 -0
  238. package/dist/patterns/index.js.map +1 -0
  239. package/dist/patterns/python/aiohttp.d.ts +21 -0
  240. package/dist/patterns/python/aiohttp.d.ts.map +1 -0
  241. package/dist/patterns/python/aiohttp.js +188 -0
  242. package/dist/patterns/python/aiohttp.js.map +1 -0
  243. package/dist/patterns/python/httpx.d.ts +20 -0
  244. package/dist/patterns/python/httpx.d.ts.map +1 -0
  245. package/dist/patterns/python/httpx.js +183 -0
  246. package/dist/patterns/python/httpx.js.map +1 -0
  247. package/dist/patterns/python/index.d.ts +32 -0
  248. package/dist/patterns/python/index.d.ts.map +1 -0
  249. package/dist/patterns/python/index.js +63 -0
  250. package/dist/patterns/python/index.js.map +1 -0
  251. package/dist/patterns/python/property-access.d.ts +27 -0
  252. package/dist/patterns/python/property-access.d.ts.map +1 -0
  253. package/dist/patterns/python/property-access.js +132 -0
  254. package/dist/patterns/python/property-access.js.map +1 -0
  255. package/dist/patterns/python/requests.d.ts +19 -0
  256. package/dist/patterns/python/requests.d.ts.map +1 -0
  257. package/dist/patterns/python/requests.js +239 -0
  258. package/dist/patterns/python/requests.js.map +1 -0
  259. package/dist/patterns/python/types.d.ts +95 -0
  260. package/dist/patterns/python/types.d.ts.map +1 -0
  261. package/dist/patterns/python/types.js +43 -0
  262. package/dist/patterns/python/types.js.map +1 -0
  263. package/dist/patterns/registry.d.ts +181 -0
  264. package/dist/patterns/registry.d.ts.map +1 -0
  265. package/dist/patterns/registry.js +304 -0
  266. package/dist/patterns/registry.js.map +1 -0
  267. package/dist/patterns/rest/express.d.ts +78 -0
  268. package/dist/patterns/rest/express.d.ts.map +1 -0
  269. package/dist/patterns/rest/express.js +289 -0
  270. package/dist/patterns/rest/express.js.map +1 -0
  271. package/dist/patterns/rest/fastify.d.ts +93 -0
  272. package/dist/patterns/rest/fastify.d.ts.map +1 -0
  273. package/dist/patterns/rest/fastify.js +420 -0
  274. package/dist/patterns/rest/fastify.js.map +1 -0
  275. package/dist/patterns/rest/index.d.ts +31 -0
  276. package/dist/patterns/rest/index.d.ts.map +1 -0
  277. package/dist/patterns/rest/index.js +45 -0
  278. package/dist/patterns/rest/index.js.map +1 -0
  279. package/dist/patterns/rest/middleware.d.ts +25 -0
  280. package/dist/patterns/rest/middleware.d.ts.map +1 -0
  281. package/dist/patterns/rest/middleware.js +219 -0
  282. package/dist/patterns/rest/middleware.js.map +1 -0
  283. package/dist/patterns/rest/path-parser.d.ts +50 -0
  284. package/dist/patterns/rest/path-parser.d.ts.map +1 -0
  285. package/dist/patterns/rest/path-parser.js +137 -0
  286. package/dist/patterns/rest/path-parser.js.map +1 -0
  287. package/dist/patterns/rest/response-inference.d.ts +44 -0
  288. package/dist/patterns/rest/response-inference.d.ts.map +1 -0
  289. package/dist/patterns/rest/response-inference.js +218 -0
  290. package/dist/patterns/rest/response-inference.js.map +1 -0
  291. package/dist/patterns/rest/types.d.ts +102 -0
  292. package/dist/patterns/rest/types.d.ts.map +1 -0
  293. package/dist/patterns/rest/types.js +10 -0
  294. package/dist/patterns/rest/types.js.map +1 -0
  295. package/dist/patterns/types.d.ts +105 -0
  296. package/dist/patterns/types.d.ts.map +1 -0
  297. package/dist/patterns/types.js +11 -0
  298. package/dist/patterns/types.js.map +1 -0
  299. package/dist/report/index.d.ts +11 -0
  300. package/dist/report/index.d.ts.map +1 -0
  301. package/dist/report/index.js +55 -0
  302. package/dist/report/index.js.map +1 -0
  303. package/dist/tools/contract-comments.d.ts +48 -0
  304. package/dist/tools/contract-comments.d.ts.map +1 -0
  305. package/dist/tools/contract-comments.js +130 -0
  306. package/dist/tools/contract-comments.js.map +1 -0
  307. package/dist/tools/index.d.ts +6 -0
  308. package/dist/tools/index.d.ts.map +1 -0
  309. package/dist/tools/index.js +6 -0
  310. package/dist/tools/index.js.map +1 -0
  311. package/dist/tools/scaffold.d.ts +38 -0
  312. package/dist/tools/scaffold.d.ts.map +1 -0
  313. package/dist/tools/scaffold.js +373 -0
  314. package/dist/tools/scaffold.js.map +1 -0
  315. package/dist/trace/index.d.ts +28 -0
  316. package/dist/trace/index.d.ts.map +1 -0
  317. package/dist/trace/index.js +45 -0
  318. package/dist/trace/index.js.map +1 -0
  319. package/dist/types.d.ts +135 -0
  320. package/dist/types.d.ts.map +1 -0
  321. package/dist/types.js +22 -0
  322. package/dist/types.js.map +1 -0
  323. package/dist/watch/cache.d.ts +41 -0
  324. package/dist/watch/cache.d.ts.map +1 -0
  325. package/dist/watch/cache.js +230 -0
  326. package/dist/watch/cache.js.map +1 -0
  327. package/dist/watch/index.d.ts +9 -0
  328. package/dist/watch/index.d.ts.map +1 -0
  329. package/dist/watch/index.js +7 -0
  330. package/dist/watch/index.js.map +1 -0
  331. package/dist/watch/project.d.ts +128 -0
  332. package/dist/watch/project.d.ts.map +1 -0
  333. package/dist/watch/project.js +152 -0
  334. package/dist/watch/project.js.map +1 -0
  335. package/dist/watch/watcher.d.ts +76 -0
  336. package/dist/watch/watcher.d.ts.map +1 -0
  337. package/dist/watch/watcher.js +235 -0
  338. package/dist/watch/watcher.js.map +1 -0
  339. package/package.json +70 -0
@@ -0,0 +1,338 @@
1
+ /**
2
+ * URL Extraction Utilities
3
+ *
4
+ * Extract URL information from AST nodes for HTTP client calls.
5
+ * Handles static strings, template literals, variable references,
6
+ * and string concatenation.
7
+ *
8
+ * @module patterns/http-clients/url-extractor
9
+ * @see .context/ADR-P2-3-HTTP-CLIENT-TRACING.md
10
+ */
11
+ import { Node, SyntaxKind } from 'ts-morph';
12
+ /* ═══════════════════════════════════════════════════════════════════════════
13
+ * 🔗 Public API
14
+ * ═══════════════════════════════════════════════════════════════════════════ */
15
+ /**
16
+ * Extract URL information from an AST node.
17
+ *
18
+ * Handles:
19
+ * - String literals: `'/api/users'`
20
+ * - Template literals: `` `/api/users/${id}` ``
21
+ * - Variable references: `API_URL`
22
+ * - Concatenation: `baseUrl + '/users'`
23
+ *
24
+ * @param node - The AST node to extract URL from
25
+ * @returns URLExtractionResult or undefined if not extractable
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const urlNode = callExpr.getArguments()[0];
30
+ * const result = extractURL(urlNode);
31
+ * // { raw: '/api/users', static: '/api/users', isDynamic: false }
32
+ * ```
33
+ */
34
+ export function extractURL(node) {
35
+ if (!node)
36
+ return undefined;
37
+ // Handle string literals
38
+ if (Node.isStringLiteral(node)) {
39
+ const value = node.getLiteralValue();
40
+ return parseStaticURL(value);
41
+ }
42
+ // Handle no-substitution template literals (static templates)
43
+ if (Node.isNoSubstitutionTemplateLiteral(node)) {
44
+ const value = node.getLiteralValue();
45
+ return parseStaticURL(value);
46
+ }
47
+ // Handle template expressions with substitutions
48
+ if (Node.isTemplateExpression(node)) {
49
+ return parseTemplateExpression(node);
50
+ }
51
+ // Handle identifier references (variable names)
52
+ if (Node.isIdentifier(node)) {
53
+ return resolveIdentifier(node);
54
+ }
55
+ // Handle binary expressions (concatenation)
56
+ if (Node.isBinaryExpression(node)) {
57
+ return parseBinaryExpression(node);
58
+ }
59
+ // Handle call expressions like URL.toString()
60
+ if (Node.isCallExpression(node)) {
61
+ const expr = node.getExpression();
62
+ if (Node.isPropertyAccessExpression(expr)) {
63
+ const methodName = expr.getName();
64
+ if (methodName === 'toString') {
65
+ // URL object's toString() - mark as dynamic
66
+ return {
67
+ raw: 'URL.toString()',
68
+ isDynamic: true,
69
+ pathParams: [],
70
+ queryParams: [],
71
+ };
72
+ }
73
+ }
74
+ }
75
+ return undefined;
76
+ }
77
+ /**
78
+ * Compose a baseURL with a path.
79
+ *
80
+ * Handles:
81
+ * - Trailing slashes in baseURL
82
+ * - Missing leading slashes in path
83
+ * - Full URL baseURLs
84
+ *
85
+ * @param baseURL - Base URL (e.g., '/api' or 'https://api.example.com')
86
+ * @param path - Path to append (e.g., '/users' or 'users')
87
+ * @returns Composed URL
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * composeURL('/api', '/users') // '/api/users'
92
+ * composeURL('/api/', 'users') // '/api/users'
93
+ * composeURL('https://api.com', '/users') // 'https://api.com/users'
94
+ * ```
95
+ */
96
+ export function composeURL(baseURL, path) {
97
+ // Normalize base URL - remove trailing slash
98
+ const normalizedBase = baseURL.replace(/\/+$/, '');
99
+ // Normalize path - ensure leading slash
100
+ const normalizedPath = path.startsWith('/') ? path : `/${path}`;
101
+ return normalizedBase + normalizedPath;
102
+ }
103
+ /* ═══════════════════════════════════════════════════════════════════════════
104
+ * 🔧 Static URL Parsing
105
+ * ═══════════════════════════════════════════════════════════════════════════ */
106
+ /**
107
+ * Parse a static URL string and extract path/query params.
108
+ *
109
+ * @internal
110
+ */
111
+ function parseStaticURL(url) {
112
+ const pathParams = [];
113
+ const queryParams = [];
114
+ // Check for Express-style path params like :userId
115
+ const expressParamRegex = /:(\w+)/g;
116
+ let match;
117
+ while ((match = expressParamRegex.exec(url)) !== null) {
118
+ pathParams.push(match[1]);
119
+ }
120
+ // Extract query parameters
121
+ const queryIndex = url.indexOf('?');
122
+ if (queryIndex !== -1) {
123
+ const queryString = url.slice(queryIndex + 1);
124
+ const params = queryString.split('&');
125
+ for (const param of params) {
126
+ const [key] = param.split('=');
127
+ if (key) {
128
+ // Remove any template placeholders in query param names
129
+ const cleanKey = key.replace(/\$\{[^}]+\}/, '').trim();
130
+ if (cleanKey) {
131
+ queryParams.push(cleanKey);
132
+ }
133
+ }
134
+ }
135
+ }
136
+ const hasExpressParams = pathParams.length > 0;
137
+ return {
138
+ raw: url,
139
+ static: hasExpressParams ? undefined : url,
140
+ isDynamic: hasExpressParams,
141
+ pattern: hasExpressParams ? url : undefined,
142
+ pathParams: pathParams.length > 0 ? pathParams : undefined,
143
+ queryParams: queryParams.length > 0 ? queryParams : undefined,
144
+ };
145
+ }
146
+ /* ═══════════════════════════════════════════════════════════════════════════
147
+ * 📝 Template Expression Parsing
148
+ * ═══════════════════════════════════════════════════════════════════════════ */
149
+ /**
150
+ * Get the literal text from a template head/middle/tail node.
151
+ *
152
+ * @internal
153
+ */
154
+ function getTemplatePartText(node) {
155
+ // Use getText() and strip the template delimiters
156
+ const text = node.getText();
157
+ // TemplateHead: `text${ -> extract "text"
158
+ // TemplateMiddle: }text${ -> extract "text"
159
+ // TemplateTail: }text` -> extract "text"
160
+ // Remove leading ` or }
161
+ let result = text;
162
+ if (result.startsWith('`')) {
163
+ result = result.slice(1);
164
+ }
165
+ else if (result.startsWith('}')) {
166
+ result = result.slice(1);
167
+ }
168
+ // Remove trailing ${ or `
169
+ if (result.endsWith('${')) {
170
+ result = result.slice(0, -2);
171
+ }
172
+ else if (result.endsWith('`')) {
173
+ result = result.slice(0, -1);
174
+ }
175
+ return result;
176
+ }
177
+ /**
178
+ * Parse a template expression with substitutions.
179
+ *
180
+ * @internal
181
+ */
182
+ function parseTemplateExpression(node) {
183
+ if (!Node.isTemplateExpression(node))
184
+ return { raw: '', isDynamic: true };
185
+ const head = node.getHead();
186
+ const spans = node.getTemplateSpans();
187
+ let pattern = getTemplatePartText(head);
188
+ const pathParams = [];
189
+ const queryParams = [];
190
+ for (const span of spans) {
191
+ const expr = span.getExpression();
192
+ let paramName = 'param';
193
+ // Try to extract parameter name from expression
194
+ if (Node.isIdentifier(expr)) {
195
+ paramName = expr.getText();
196
+ }
197
+ else if (Node.isPropertyAccessExpression(expr)) {
198
+ // Get the property name: user.id -> id
199
+ paramName = expr.getName();
200
+ }
201
+ else if (Node.isElementAccessExpression(expr)) {
202
+ // Get array index identifier if possible
203
+ const argExpr = expr.getArgumentExpression();
204
+ if (argExpr && Node.isNumericLiteral(argExpr)) {
205
+ paramName = `item${argExpr.getText()}`;
206
+ }
207
+ }
208
+ // Check if we're in query params section
209
+ const literal = span.getLiteral();
210
+ const literalText = getTemplatePartText(literal);
211
+ const isInQuerySection = pattern.includes('?') || literalText.includes('?');
212
+ if (isInQuerySection && !pattern.includes('?')) {
213
+ // We're adding a query param
214
+ const beforeQuestion = literalText.indexOf('?');
215
+ if (beforeQuestion !== -1) {
216
+ pattern += `:${paramName}` + literalText.slice(0, beforeQuestion + 1);
217
+ pathParams.push(paramName);
218
+ // Continue parsing query params
219
+ const afterQuestion = literalText.slice(beforeQuestion + 1);
220
+ if (afterQuestion.includes('=')) {
221
+ const queryKey = afterQuestion.split('=')[0];
222
+ if (queryKey)
223
+ queryParams.push(queryKey);
224
+ }
225
+ pattern += afterQuestion;
226
+ }
227
+ else {
228
+ pattern += `:${paramName}` + literalText;
229
+ queryParams.push(paramName);
230
+ }
231
+ }
232
+ else {
233
+ pattern += `:${paramName}` + literalText;
234
+ pathParams.push(paramName);
235
+ }
236
+ // Extract any query params from literal text
237
+ const queryMatch = literalText.match(/[?&](\w+)=/g);
238
+ if (queryMatch) {
239
+ for (const q of queryMatch) {
240
+ const key = q.replace(/[?&=]/g, '');
241
+ if (key && !queryParams.includes(key)) {
242
+ queryParams.push(key);
243
+ }
244
+ }
245
+ }
246
+ }
247
+ // Build the raw template string representation
248
+ const rawParts = [getTemplatePartText(head)];
249
+ for (const span of spans) {
250
+ rawParts.push('${', span.getExpression().getText(), '}');
251
+ rawParts.push(getTemplatePartText(span.getLiteral()));
252
+ }
253
+ const raw = rawParts.join('');
254
+ return {
255
+ raw,
256
+ isDynamic: true,
257
+ pattern,
258
+ pathParams: pathParams.length > 0 ? pathParams : undefined,
259
+ queryParams: queryParams.length > 0 ? queryParams : undefined,
260
+ };
261
+ }
262
+ /* ═══════════════════════════════════════════════════════════════════════════
263
+ * 🔍 Identifier Resolution
264
+ * ═══════════════════════════════════════════════════════════════════════════ */
265
+ /**
266
+ * Resolve an identifier to its value.
267
+ *
268
+ * @internal
269
+ */
270
+ function resolveIdentifier(node) {
271
+ if (!Node.isIdentifier(node))
272
+ return undefined;
273
+ const name = node.getText();
274
+ const symbol = node.getSymbol();
275
+ if (!symbol) {
276
+ return {
277
+ raw: name,
278
+ isDynamic: true,
279
+ pathParams: [],
280
+ };
281
+ }
282
+ // Try to find the variable declaration
283
+ const declarations = symbol.getDeclarations();
284
+ for (const decl of declarations) {
285
+ if (Node.isVariableDeclaration(decl)) {
286
+ const initializer = decl.getInitializer();
287
+ if (initializer) {
288
+ const result = extractURL(initializer);
289
+ if (result)
290
+ return result;
291
+ }
292
+ }
293
+ }
294
+ return {
295
+ raw: name,
296
+ isDynamic: true,
297
+ pathParams: [],
298
+ };
299
+ }
300
+ /* ═══════════════════════════════════════════════════════════════════════════
301
+ * ➕ Binary Expression Parsing
302
+ * ═══════════════════════════════════════════════════════════════════════════ */
303
+ /**
304
+ * Parse binary expression (concatenation).
305
+ *
306
+ * @internal
307
+ */
308
+ function parseBinaryExpression(node) {
309
+ if (!Node.isBinaryExpression(node))
310
+ return undefined;
311
+ const operator = node.getOperatorToken().getKind();
312
+ if (operator !== SyntaxKind.PlusToken)
313
+ return undefined;
314
+ const left = extractURL(node.getLeft());
315
+ const right = extractURL(node.getRight());
316
+ if (!left && !right) {
317
+ return {
318
+ raw: node.getText(),
319
+ isDynamic: true,
320
+ pathParams: [],
321
+ };
322
+ }
323
+ const leftRaw = left?.raw || node.getLeft().getText();
324
+ const rightRaw = right?.raw || node.getRight().getText();
325
+ return {
326
+ raw: leftRaw + rightRaw,
327
+ isDynamic: true,
328
+ pathParams: [
329
+ ...(left?.pathParams || []),
330
+ ...(right?.pathParams || []),
331
+ ],
332
+ queryParams: [
333
+ ...(left?.queryParams || []),
334
+ ...(right?.queryParams || []),
335
+ ],
336
+ };
337
+ }
338
+ //# sourceMappingURL=url-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-extractor.js","sourceRoot":"","sources":["../../../src/patterns/http-clients/url-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Pattern Matcher Module
3
+ *
4
+ * Public API for the pattern matcher abstraction that enables pluggable
5
+ * framework-agnostic API detection.
6
+ *
7
+ * ## Overview
8
+ *
9
+ * The pattern matcher system provides:
10
+ * - **Type Definitions**: Core types for pattern matching ({@link PatternType}, {@link PatternDef})
11
+ * - **Error Handling**: Typed errors with machine-readable codes ({@link PatternErrorCodes})
12
+ * - **Base Classes**: Abstract base for custom matchers ({@link BasePatternMatcher})
13
+ * - **Registry**: Singleton registry for pattern matchers ({@link registerPattern}, {@link scanForPatterns})
14
+ * - **Extractors**: Schema extraction utilities ({@link extractSchemaNode})
15
+ *
16
+ * ## Quick Start
17
+ *
18
+ * ```typescript
19
+ * import {
20
+ * registerPattern,
21
+ * scanForPatterns,
22
+ * BasePatternMatcher
23
+ * } from './patterns';
24
+ *
25
+ * // Register a custom matcher
26
+ * class MyMatcher extends BasePatternMatcher { ... }
27
+ * registerPattern(new MyMatcher());
28
+ *
29
+ * // Scan for patterns
30
+ * const matches = scanForPatterns(sourceFile);
31
+ * ```
32
+ *
33
+ * @module patterns
34
+ * @see .context/ADR-P2-1-PATTERN-MATCHER.md
35
+ */
36
+ export type { PatternType, SchemaLocation, PatternDef, MatchCaptures, MatchResult, } from './types.js';
37
+ export { PatternErrorCodes, PatternRegistryError, PatternNotFoundError, PatternValidationError, PatternMatchError, PatternExtractionError, } from './errors.js';
38
+ export type { PatternErrorCode } from './errors.js';
39
+ export type { PatternMatcher } from './base.js';
40
+ export { BasePatternMatcher } from './base.js';
41
+ export { registerPattern, getPattern, getPatternsByFramework, getPatternsByType, hasPattern, listPatterns, listFrameworks, scanForPatterns, } from './registry.js';
42
+ export type { ScanOptions } from './registry.js';
43
+ export { extractSchemaNode, extractFromArg, extractFromNamedArg, extractFromReturn, extractFromTypeParam, extractFromBody, extractFromChainMethod, extractFromDecoratorArg, } from './extractors.js';
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAMH,YAAY,EACV,WAAW,EACX,cAAc,EACd,UAAU,EACV,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAC;AAMpB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAM/C,OAAO,EACL,eAAe,EACf,UAAU,EACV,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAMjD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Pattern Matcher Module
3
+ *
4
+ * Public API for the pattern matcher abstraction that enables pluggable
5
+ * framework-agnostic API detection.
6
+ *
7
+ * ## Overview
8
+ *
9
+ * The pattern matcher system provides:
10
+ * - **Type Definitions**: Core types for pattern matching ({@link PatternType}, {@link PatternDef})
11
+ * - **Error Handling**: Typed errors with machine-readable codes ({@link PatternErrorCodes})
12
+ * - **Base Classes**: Abstract base for custom matchers ({@link BasePatternMatcher})
13
+ * - **Registry**: Singleton registry for pattern matchers ({@link registerPattern}, {@link scanForPatterns})
14
+ * - **Extractors**: Schema extraction utilities ({@link extractSchemaNode})
15
+ *
16
+ * ## Quick Start
17
+ *
18
+ * ```typescript
19
+ * import {
20
+ * registerPattern,
21
+ * scanForPatterns,
22
+ * BasePatternMatcher
23
+ * } from './patterns';
24
+ *
25
+ * // Register a custom matcher
26
+ * class MyMatcher extends BasePatternMatcher { ... }
27
+ * registerPattern(new MyMatcher());
28
+ *
29
+ * // Scan for patterns
30
+ * const matches = scanForPatterns(sourceFile);
31
+ * ```
32
+ *
33
+ * @module patterns
34
+ * @see .context/ADR-P2-1-PATTERN-MATCHER.md
35
+ */
36
+ // ─────────────────────────────────────────────────────────────────────────────
37
+ // ⚠️ Error Types and Codes
38
+ // ─────────────────────────────────────────────────────────────────────────────
39
+ export { PatternErrorCodes, PatternRegistryError, PatternNotFoundError, PatternValidationError, PatternMatchError, PatternExtractionError, } from './errors.js';
40
+ export { BasePatternMatcher } from './base.js';
41
+ // ─────────────────────────────────────────────────────────────────────────────
42
+ // 📝 Registry Functions
43
+ // ─────────────────────────────────────────────────────────────────────────────
44
+ export { registerPattern, getPattern, getPatternsByFramework, getPatternsByType, hasPattern, listPatterns, listFrameworks, scanForPatterns, } from './registry.js';
45
+ // ─────────────────────────────────────────────────────────────────────────────
46
+ // 🔍 Schema Extractors
47
+ // ─────────────────────────────────────────────────────────────────────────────
48
+ export { extractSchemaNode, extractFromArg, extractFromNamedArg, extractFromReturn, extractFromTypeParam, extractFromBody, extractFromChainMethod, extractFromDecoratorArg, } from './extractors.js';
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAcH,gFAAgF;AAChF,2BAA2B;AAC3B,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AASrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,gFAAgF;AAChF,wBAAwB;AACxB,gFAAgF;AAEhF,OAAO,EACL,eAAe,EACf,UAAU,EACV,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,eAAe,GAChB,MAAM,eAAe,CAAC;AAIvB,gFAAgF;AAChF,uBAAuB;AACvB,gFAAgF;AAEhF,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Python aiohttp library HTTP client detection
3
+ *
4
+ * Detects calls to the aiohttp library:
5
+ * - aiohttp.ClientSession().get(), etc.
6
+ * - session.get(), session.post() within context managers
7
+ *
8
+ * aiohttp is always async and uses context managers heavily
9
+ *
10
+ * @see .context/TASK_MAP_P3.md - Task P3-4
11
+ */
12
+ import type { PythonHttpCall } from './types.js';
13
+ /**
14
+ * Detect HTTP calls from the aiohttp library in Python source code
15
+ */
16
+ export declare function detectAiohttpCalls(content: string): PythonHttpCall[];
17
+ /**
18
+ * Get the response properties that aiohttp library supports
19
+ */
20
+ export declare function getAiohttpResponseProperties(): string[];
21
+ //# sourceMappingURL=aiohttp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiohttp.d.ts","sourceRoot":"","sources":["../../../src/patterns/python/aiohttp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,YAAY,CAAC;AAUpB;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAsFpE;AAiHD;;GAEG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,EAAE,CAEvD"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Python aiohttp library HTTP client detection
3
+ *
4
+ * Detects calls to the aiohttp library:
5
+ * - aiohttp.ClientSession().get(), etc.
6
+ * - session.get(), session.post() within context managers
7
+ *
8
+ * aiohttp is always async and uses context managers heavily
9
+ *
10
+ * @see .context/TASK_MAP_P3.md - Task P3-4
11
+ */
12
+ import { HTTP_CLIENT_PATTERNS, normalizeHttpMethod } from './types.js';
13
+ const AIOHTTP_PATTERN = HTTP_CLIENT_PATTERNS.aiohttp;
14
+ /**
15
+ * Track known session variable names
16
+ */
17
+ const sessionVars = new Set();
18
+ /**
19
+ * Detect HTTP calls from the aiohttp library in Python source code
20
+ */
21
+ export function detectAiohttpCalls(content) {
22
+ const calls = [];
23
+ const lines = content.split('\n');
24
+ // First pass: detect imports
25
+ const hasAiohttpImport = /^\s*import\s+aiohttp\b/m.test(content) ||
26
+ /^\s*from\s+aiohttp\s+import\s+/.test(content);
27
+ if (!hasAiohttpImport) {
28
+ return [];
29
+ }
30
+ // Second pass: find session variables
31
+ sessionVars.clear();
32
+ // Match: async with aiohttp.ClientSession() as session:
33
+ const asyncWithSessionRegex = /async\s+with\s+(?:aiohttp\.)?ClientSession\s*\([^)]*\)\s+as\s+(\w+)/g;
34
+ let match;
35
+ while ((match = asyncWithSessionRegex.exec(content)) !== null) {
36
+ sessionVars.add(match[1]);
37
+ }
38
+ // Match: session = aiohttp.ClientSession()
39
+ const sessionCreateRegex = /\b(\w+)\s*=\s*(?:aiohttp\.)?ClientSession\s*\(/g;
40
+ while ((match = sessionCreateRegex.exec(content)) !== null) {
41
+ sessionVars.add(match[1]);
42
+ }
43
+ // Also match common variable names that might be sessions
44
+ // (client, session, http_session, api_session)
45
+ const commonSessionNames = ['session', 'client', 'http_session', 'api_session'];
46
+ for (const name of commonSessionNames) {
47
+ const regex = new RegExp(`\\b${name}\\s*=\\s*(?:aiohttp\\.)?ClientSession\\s*\\(`, 'g');
48
+ if (regex.test(content)) {
49
+ sessionVars.add(name);
50
+ }
51
+ }
52
+ // Third pass: detect HTTP calls line by line
53
+ for (let i = 0; i < lines.length; i++) {
54
+ const line = lines[i];
55
+ const lineNum = i + 1;
56
+ // Detect session.method() calls in context managers
57
+ // Pattern: async with session.get(...) as response:
58
+ const asyncWithMethodRegex = /async\s+with\s+(\w+)\.(get|post|put|patch|delete|head|options|request)\s*\(/gi;
59
+ while ((match = asyncWithMethodRegex.exec(line)) !== null) {
60
+ const sessionVar = match[1];
61
+ const method = normalizeHttpMethod(match[2]);
62
+ // Check if it's a known session or likely a session
63
+ if (method && (sessionVars.has(sessionVar) || isLikelySession(sessionVar, content))) {
64
+ const call = createHttpCall(method, 'aiohttp', line, lineNum, match.index);
65
+ call.isSession = true;
66
+ call.isAsync = true;
67
+ // Extract response variable from "as response"
68
+ const asMatch = line.match(/as\s+(\w+)\s*:/);
69
+ if (asMatch) {
70
+ call.responseVariable = asMatch[1];
71
+ }
72
+ calls.push(call);
73
+ }
74
+ }
75
+ // Detect await session.method() calls (not in context manager)
76
+ // Pattern: await session.get(...)
77
+ for (const sessionVar of sessionVars) {
78
+ const awaitCallRegex = new RegExp(`await\\s+${escapeRegex(sessionVar)}\\.(get|post|put|patch|delete|head|options|request)\\s*\\(`, 'gi');
79
+ while ((match = awaitCallRegex.exec(line)) !== null) {
80
+ const method = normalizeHttpMethod(match[1]);
81
+ if (method) {
82
+ const call = createHttpCall(method, 'aiohttp', line, lineNum, match.index);
83
+ call.isSession = true;
84
+ call.isAsync = true;
85
+ calls.push(call);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ return calls;
91
+ }
92
+ /**
93
+ * Check if a variable name is likely a session based on context
94
+ */
95
+ function isLikelySession(varName, content) {
96
+ // Common patterns that indicate aiohttp session
97
+ const sessionIndicators = [
98
+ `${varName} = aiohttp.ClientSession`,
99
+ `${varName} = ClientSession`,
100
+ `aiohttp.ClientSession() as ${varName}`,
101
+ `ClientSession() as ${varName}`
102
+ ];
103
+ for (const indicator of sessionIndicators) {
104
+ if (content.includes(indicator)) {
105
+ return true;
106
+ }
107
+ }
108
+ // Variable names that suggest sessions
109
+ const sessionNamePatterns = /^(session|client|http_client|api_client|http_session|api_session)$/i;
110
+ return sessionNamePatterns.test(varName);
111
+ }
112
+ /**
113
+ * Create a PythonHttpCall from a detected call
114
+ */
115
+ function createHttpCall(method, library, line, lineNum, column) {
116
+ const call = {
117
+ method,
118
+ library,
119
+ line: lineNum,
120
+ column,
121
+ isAsync: true // aiohttp is always async
122
+ };
123
+ // Extract URL
124
+ const urlInfo = extractUrl(line);
125
+ if (urlInfo) {
126
+ call.url = urlInfo.url;
127
+ call.isDynamicUrl = urlInfo.isDynamic;
128
+ call.pathParams = urlInfo.pathParams;
129
+ }
130
+ // Detect query params
131
+ if (/\bparams\s*=/.test(line)) {
132
+ call.hasQueryParams = true;
133
+ }
134
+ // URL with query string
135
+ if (call.url?.includes('?')) {
136
+ call.hasQueryParams = true;
137
+ }
138
+ // Detect headers
139
+ if (/\bheaders\s*=/.test(line)) {
140
+ call.hasHeaders = true;
141
+ }
142
+ // Detect body
143
+ if (/\bjson\s*=/.test(line) || /\bdata\s*=/.test(line)) {
144
+ call.hasBody = true;
145
+ }
146
+ return call;
147
+ }
148
+ /**
149
+ * Extract URL from a call line
150
+ */
151
+ function extractUrl(line) {
152
+ // Match f-strings first
153
+ const fstringMatch = line.match(/f["']([^"']+)["']/);
154
+ if (fstringMatch) {
155
+ const url = fstringMatch[1];
156
+ const pathParams = [];
157
+ let paramMatch;
158
+ const paramRegex = /\{(\w+)\}/g;
159
+ while ((paramMatch = paramRegex.exec(url)) !== null) {
160
+ pathParams.push(paramMatch[1]);
161
+ }
162
+ return { url, isDynamic: true, pathParams };
163
+ }
164
+ // Match regular strings - look for method call with string arg
165
+ const stringMatch = line.match(/\.(get|post|put|patch|delete|head|options|request)\s*\(\s*["']([^"']+)["']/i);
166
+ if (stringMatch) {
167
+ return { url: stringMatch[2], isDynamic: false, pathParams: [] };
168
+ }
169
+ // Generic string match after opening paren
170
+ const genericMatch = line.match(/\(\s*["']([^"']+)["']/);
171
+ if (genericMatch) {
172
+ return { url: genericMatch[1], isDynamic: false, pathParams: [] };
173
+ }
174
+ return null;
175
+ }
176
+ /**
177
+ * Escape special regex characters in a string
178
+ */
179
+ function escapeRegex(str) {
180
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
181
+ }
182
+ /**
183
+ * Get the response properties that aiohttp library supports
184
+ */
185
+ export function getAiohttpResponseProperties() {
186
+ return AIOHTTP_PATTERN.responseAccess;
187
+ }
188
+ //# sourceMappingURL=aiohttp.js.map