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,708 @@
1
+ /**
2
+ * 🔧 tRPC Router/Procedure Extractor
3
+ *
4
+ * AST-based extraction of tRPC router definitions and Zod schemas.
5
+ * This module provides utilities to:
6
+ * - Parse TypeScript files containing tRPC routers
7
+ * - Extract procedure definitions (query, mutation, subscription)
8
+ * - Convert Zod schemas to NormalizedSchema format
9
+ *
10
+ * Uses ts-morph for AST analysis, supporting patterns like:
11
+ * - `t.router({ ... })` - Standard tRPC v10+ pattern
12
+ * - `createTRPCRouter({ ... })` - Next.js/T3 pattern
13
+ * - Nested routers via object composition
14
+ *
15
+ * @module adapters/trpc/extractor
16
+ */
17
+ import { Project, Node, } from 'ts-morph';
18
+ // ============================================================================
19
+ // Project Creation
20
+ // ============================================================================
21
+ /**
22
+ * Create a new ts-morph Project instance for AST analysis.
23
+ *
24
+ * Configures the project without tsconfig to allow standalone
25
+ * file analysis without project-wide compilation context.
26
+ *
27
+ * @returns A new ts-morph Project instance
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const project = createProject();
32
+ * const sourceFile = project.addSourceFileAtPath('./router.ts');
33
+ * const procedures = extractProcedures(sourceFile);
34
+ * ```
35
+ */
36
+ export function createProject() {
37
+ return new Project({
38
+ tsConfigFilePath: undefined,
39
+ skipAddingFilesFromTsConfig: true,
40
+ });
41
+ }
42
+ // ============================================================================
43
+ // Procedure Extraction
44
+ // ============================================================================
45
+ /**
46
+ * Extract all procedures from a tRPC router source file.
47
+ *
48
+ * Scans the file for router definitions and extracts all procedure
49
+ * definitions, including those in nested routers. Each procedure
50
+ * is returned with its full path, type, and schema nodes.
51
+ *
52
+ * Supported patterns:
53
+ * - `t.router({ user: t.procedure.query(...) })`
54
+ * - `createTRPCRouter({ users: userRouter })`
55
+ * - `createRouter({ nested: { deep: procedure } })`
56
+ *
57
+ * @param sourceFile - The ts-morph SourceFile to analyze
58
+ * @returns Array of ProcedureInfo objects for all found procedures
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const project = createProject();
63
+ * const file = project.addSourceFileAtPath('./server/routers/index.ts');
64
+ * const procedures = extractProcedures(file);
65
+ *
66
+ * for (const proc of procedures) {
67
+ * console.log(`${proc.path.join('.')} - ${proc.type}`);
68
+ * // Output: "users.getById - query"
69
+ * }
70
+ * ```
71
+ */
72
+ export function extractProcedures(sourceFile) {
73
+ const procedures = [];
74
+ const filePath = sourceFile.getFilePath();
75
+ // Find all router calls and extract procedures
76
+ sourceFile.forEachDescendant((node) => {
77
+ if (Node.isCallExpression(node) && isRouterCall(node)) {
78
+ const procs = parseRouterObject(node, [], filePath);
79
+ procedures.push(...procs);
80
+ }
81
+ });
82
+ return procedures;
83
+ }
84
+ /**
85
+ * Check if a call expression is a tRPC router call.
86
+ *
87
+ * Matches patterns like:
88
+ * - `t.router(...)` - Method call on object
89
+ * - `trpc.router(...)` - Namespaced call
90
+ * - `createRouter(...)` - Function call
91
+ * - `createTRPCRouter(...)` - T3/Next.js pattern
92
+ *
93
+ * @param node - The AST node to check
94
+ * @returns True if the node is a router call expression
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * sourceFile.forEachDescendant((node) => {
99
+ * if (Node.isCallExpression(node) && isRouterCall(node)) {
100
+ * // Process router definition
101
+ * }
102
+ * });
103
+ * ```
104
+ */
105
+ export function isRouterCall(node) {
106
+ if (!Node.isCallExpression(node))
107
+ return false;
108
+ const expr = node.getExpression();
109
+ // Match patterns like: t.router(), trpc.router(), createRouter(), createTRPCRouter()
110
+ if (Node.isPropertyAccessExpression(expr)) {
111
+ return expr.getName() === 'router';
112
+ }
113
+ // Match direct function calls
114
+ if (Node.isIdentifier(expr)) {
115
+ const name = expr.getText();
116
+ return name === 'createRouter' || name === 'createTRPCRouter';
117
+ }
118
+ return false;
119
+ }
120
+ /**
121
+ * Check if a node is a tRPC procedure chain.
122
+ *
123
+ * Procedure chains are method chains that terminate in `.query()`,
124
+ * `.mutation()`, or `.subscription()`. This function walks up the
125
+ * chain to find these terminal methods.
126
+ *
127
+ * @param node - The AST node to check
128
+ * @returns True if the node is a procedure chain
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // These would return true:
133
+ * // t.procedure.input(z.string()).query(...)
134
+ * // t.procedure.mutation(...)
135
+ * // publicProcedure.subscription(...)
136
+ * ```
137
+ */
138
+ export function isProcedureChain(node) {
139
+ if (!node)
140
+ return false;
141
+ // Walk up the call chain to find terminal methods
142
+ let current = node;
143
+ while (Node.isCallExpression(current)) {
144
+ const expr = current.getExpression();
145
+ if (Node.isPropertyAccessExpression(expr)) {
146
+ const methodName = expr.getName();
147
+ if (methodName === 'query' || methodName === 'mutation' || methodName === 'subscription') {
148
+ return true;
149
+ }
150
+ }
151
+ // Move to inner expression to keep checking
152
+ if (Node.isPropertyAccessExpression(expr)) {
153
+ const inner = expr.getExpression();
154
+ if (Node.isCallExpression(inner)) {
155
+ current = inner;
156
+ continue;
157
+ }
158
+ }
159
+ break;
160
+ }
161
+ return false;
162
+ }
163
+ /**
164
+ * Parse a router object literal and extract all procedures.
165
+ *
166
+ * Recursively processes router definitions, handling:
167
+ * - Direct procedure definitions
168
+ * - Nested router references
169
+ * - Inline nested routers
170
+ *
171
+ * @param routerCall - The router call expression node
172
+ * @param currentPath - Current path prefix for nested routers
173
+ * @param filePath - Path to the source file
174
+ * @returns Array of ProcedureInfo for all found procedures
175
+ */
176
+ export function parseRouterObject(routerCall, currentPath, filePath) {
177
+ const procedures = [];
178
+ const args = routerCall.getArguments();
179
+ if (args.length === 0)
180
+ return procedures;
181
+ const routerObj = args[0];
182
+ if (!Node.isObjectLiteralExpression(routerObj))
183
+ return procedures;
184
+ for (const prop of routerObj.getProperties()) {
185
+ if (!Node.isPropertyAssignment(prop))
186
+ continue;
187
+ const propName = prop.getName();
188
+ const init = prop.getInitializer();
189
+ if (!init)
190
+ continue;
191
+ // Check if it's a nested router
192
+ if (isNestedRouter(init)) {
193
+ // Recursively parse nested router
194
+ const nestedCall = extractRouterCall(init);
195
+ if (nestedCall) {
196
+ const nested = parseRouterObject(nestedCall, [...currentPath, propName], filePath);
197
+ procedures.push(...nested);
198
+ }
199
+ }
200
+ else if (isProcedureChain(init)) {
201
+ // Parse procedure definition
202
+ const procInfo = parseProcedureChain(init, [...currentPath, propName], filePath);
203
+ if (procInfo) {
204
+ procedures.push(procInfo);
205
+ }
206
+ }
207
+ }
208
+ return procedures;
209
+ }
210
+ /**
211
+ * Check if a node represents a nested router.
212
+ *
213
+ * @param node - The AST node to check
214
+ * @returns True if the node is a nested router definition or reference
215
+ */
216
+ function isNestedRouter(node) {
217
+ // Direct router call
218
+ if (Node.isCallExpression(node) && isRouterCall(node)) {
219
+ return true;
220
+ }
221
+ // Identifier referencing a router (e.g., userRouter)
222
+ if (Node.isIdentifier(node)) {
223
+ const name = node.getText();
224
+ return name.endsWith('Router') || name.endsWith('router');
225
+ }
226
+ return false;
227
+ }
228
+ /**
229
+ * Extract the router call from a node.
230
+ *
231
+ * Handles both direct router calls and identifier references
232
+ * to router variables.
233
+ *
234
+ * @param node - The AST node to extract from
235
+ * @returns The router CallExpression, or null if not found
236
+ */
237
+ function extractRouterCall(node) {
238
+ if (Node.isCallExpression(node) && isRouterCall(node)) {
239
+ return node;
240
+ }
241
+ // For identifier references, we need to follow the variable declaration
242
+ if (Node.isIdentifier(node)) {
243
+ const symbol = node.getSymbol();
244
+ if (symbol) {
245
+ const declarations = symbol.getDeclarations();
246
+ for (const decl of declarations) {
247
+ if (Node.isVariableDeclaration(decl)) {
248
+ const init = decl.getInitializer();
249
+ if (init && Node.isCallExpression(init) && isRouterCall(init)) {
250
+ return init;
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ return null;
257
+ }
258
+ /**
259
+ * Parse a procedure method chain to extract input/output schemas.
260
+ *
261
+ * Walks the method chain (`.input().output().query()`) and extracts:
262
+ * - Input schema from `.input(zodSchema)`
263
+ * - Output schema from `.output(zodSchema)`
264
+ * - Procedure type from terminal method (`.query()`, `.mutation()`, `.subscription()`)
265
+ *
266
+ * @param node - The procedure chain call expression
267
+ * @param path - Full path to this procedure
268
+ * @param filePath - Path to the source file
269
+ * @returns ProcedureInfo or null if parsing fails
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * // For: t.procedure.input(z.object({ id: z.string() })).query(...)
274
+ * // Returns: { path: ['getById'], type: 'query', inputSchema: <Node>, ... }
275
+ * ```
276
+ */
277
+ export function parseProcedureChain(node, path, filePath) {
278
+ if (!Node.isCallExpression(node))
279
+ return null;
280
+ const location = {
281
+ file: filePath,
282
+ line: node.getStartLineNumber(),
283
+ };
284
+ let inputSchema;
285
+ let outputSchema;
286
+ let procedureType = 'query';
287
+ // Walk up the method chain to collect .input(), .output(), etc.
288
+ let current = node;
289
+ while (current && Node.isCallExpression(current)) {
290
+ const expr = current.getExpression();
291
+ if (Node.isPropertyAccessExpression(expr)) {
292
+ const methodName = expr.getName();
293
+ const args = current.getArguments();
294
+ switch (methodName) {
295
+ case 'input':
296
+ if (args.length > 0)
297
+ inputSchema = args[0];
298
+ break;
299
+ case 'output':
300
+ if (args.length > 0)
301
+ outputSchema = args[0];
302
+ break;
303
+ case 'query':
304
+ procedureType = 'query';
305
+ break;
306
+ case 'mutation':
307
+ procedureType = 'mutation';
308
+ break;
309
+ case 'subscription':
310
+ procedureType = 'subscription';
311
+ break;
312
+ }
313
+ // Move up the chain
314
+ const inner = expr.getExpression();
315
+ if (Node.isCallExpression(inner)) {
316
+ current = inner;
317
+ }
318
+ else {
319
+ break;
320
+ }
321
+ }
322
+ else {
323
+ break;
324
+ }
325
+ }
326
+ return {
327
+ path,
328
+ type: procedureType,
329
+ inputSchema,
330
+ outputSchema,
331
+ location,
332
+ };
333
+ }
334
+ // ============================================================================
335
+ // Zod Schema Conversion
336
+ // ============================================================================
337
+ /**
338
+ * Convert a Zod schema AST node to NormalizedSchema.
339
+ *
340
+ * Parses Zod schema definitions and converts them to the framework's
341
+ * NormalizedSchema format. Supports common Zod types:
342
+ * - Primitives: `z.string()`, `z.number()`, `z.boolean()`
343
+ * - Objects: `z.object({ ... })`
344
+ * - Arrays: `z.array(...)`
345
+ * - Unions: `z.union([...])`, `z.enum([...])`
346
+ * - Modifiers: `.optional()`, `.nullable()`, `.default()`
347
+ * - Constraints: `.min()`, `.max()`, `.email()`, etc.
348
+ *
349
+ * @param node - The AST node containing the Zod schema
350
+ * @param ref - The SchemaRef for source tracking
351
+ * @param location - Source location for error reporting
352
+ * @param name - Optional schema name
353
+ * @returns The converted NormalizedSchema
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * const schema = zodToNormalizedSchema(
358
+ * inputSchemaNode,
359
+ * { source: 'trpc', id: 'trpc:users.create@./router.ts' },
360
+ * { file: './router.ts', line: 42 },
361
+ * 'users.create.input'
362
+ * );
363
+ * ```
364
+ */
365
+ export function zodToNormalizedSchema(node, ref, location, name) {
366
+ const properties = {};
367
+ const required = [];
368
+ // Parse z.object({...})
369
+ if (Node.isCallExpression(node)) {
370
+ const expr = node.getExpression();
371
+ const exprText = expr.getText();
372
+ if (exprText === 'z.object' || exprText.endsWith('.object')) {
373
+ const args = node.getArguments();
374
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
375
+ parseZodObjectProperties(args[0], properties, required);
376
+ }
377
+ }
378
+ }
379
+ // Handle identifier references to named schemas
380
+ if (Node.isIdentifier(node)) {
381
+ const schema = resolveZodSchemaReference(node);
382
+ if (schema) {
383
+ return zodToNormalizedSchema(schema, ref, location, name);
384
+ }
385
+ }
386
+ return {
387
+ name: name || ref.id.split('@')[0].split(':')[1],
388
+ properties,
389
+ required,
390
+ source: ref,
391
+ location,
392
+ };
393
+ }
394
+ /**
395
+ * Resolve a Zod schema reference (identifier) to its definition.
396
+ *
397
+ * Follows variable declarations to find the actual schema definition.
398
+ * Used for patterns like `const UserSchema = z.object({ ... })`.
399
+ *
400
+ * @param node - The identifier node to resolve
401
+ * @returns The resolved schema AST node, or null if not found
402
+ */
403
+ function resolveZodSchemaReference(node) {
404
+ if (!Node.isIdentifier(node))
405
+ return null;
406
+ const symbol = node.getSymbol();
407
+ if (!symbol)
408
+ return null;
409
+ const declarations = symbol.getDeclarations();
410
+ for (const decl of declarations) {
411
+ if (Node.isVariableDeclaration(decl)) {
412
+ const init = decl.getInitializer();
413
+ if (init)
414
+ return init;
415
+ }
416
+ }
417
+ return null;
418
+ }
419
+ /**
420
+ * Parse properties from a `z.object({ ... })` call.
421
+ *
422
+ * Extracts each property definition and determines which are required.
423
+ * Properties with `.optional()`, `.nullish()`, or `.default()` are
424
+ * considered optional.
425
+ *
426
+ * @param obj - The object literal expression node
427
+ * @param properties - Map to populate with property definitions
428
+ * @param required - Array to populate with required property names
429
+ */
430
+ function parseZodObjectProperties(obj, properties, required) {
431
+ for (const prop of obj.getProperties()) {
432
+ if (!Node.isPropertyAssignment(prop))
433
+ continue;
434
+ const propName = prop.getName();
435
+ const init = prop.getInitializer();
436
+ if (!init)
437
+ continue;
438
+ const propDef = parseZodTypeToPropDef(init);
439
+ properties[propName] = propDef;
440
+ const initText = init.getText();
441
+ // Check if not optional and not with default
442
+ if (!initText.includes('.optional()') &&
443
+ !initText.includes('.nullish()') &&
444
+ !initText.includes('.default(')) {
445
+ required.push(propName);
446
+ }
447
+ }
448
+ }
449
+ /**
450
+ * Parse a Zod type expression to PropertyDef.
451
+ *
452
+ * Converts a single property's Zod schema to PropertyDef format,
453
+ * extracting type, optionality, nullability, and constraints.
454
+ *
455
+ * @param node - The Zod type expression node
456
+ * @returns The converted PropertyDef
457
+ */
458
+ function parseZodTypeToPropDef(node) {
459
+ const text = node.getText();
460
+ const type = parseZodTypeToNormalized(node);
461
+ const constraints = extractZodConstraints(text);
462
+ const isOptional = text.includes('.optional()') || text.includes('.nullish()') || text.includes('.default(');
463
+ const isNullable = text.includes('.nullable()') || text.includes('.nullish()');
464
+ return {
465
+ type,
466
+ optional: isOptional,
467
+ nullable: isNullable,
468
+ readonly: false,
469
+ deprecated: false,
470
+ constraints: Object.keys(constraints).length > 0 ? constraints : undefined,
471
+ };
472
+ }
473
+ /**
474
+ * Parse a Zod type to NormalizedType.
475
+ *
476
+ * Recursively converts Zod types to the framework's NormalizedType format.
477
+ * Handles nested types (arrays, objects, unions) and method chains.
478
+ *
479
+ * Supported Zod types:
480
+ * - `z.string()` → `{ kind: 'primitive', value: 'string' }`
481
+ * - `z.number()` → `{ kind: 'primitive', value: 'number' }`
482
+ * - `z.boolean()` → `{ kind: 'primitive', value: 'boolean' }`
483
+ * - `z.array(T)` → `{ kind: 'array', element: T }`
484
+ * - `z.object({})` → `{ kind: 'object', schema: {...} }`
485
+ * - `z.enum([])` → `{ kind: 'union', variants: [...] }`
486
+ * - `z.literal(v)` → `{ kind: 'literal', value: v }`
487
+ *
488
+ * @param node - The Zod type AST node
489
+ * @returns The converted NormalizedType
490
+ */
491
+ function parseZodTypeToNormalized(node) {
492
+ const text = node.getText();
493
+ const trimmedText = text.trim();
494
+ // First, resolve identifier references
495
+ if (Node.isIdentifier(node)) {
496
+ const resolved = resolveZodSchemaReference(node);
497
+ if (resolved) {
498
+ return parseZodTypeToNormalized(resolved);
499
+ }
500
+ return { kind: 'ref', name: node.getText() };
501
+ }
502
+ // Handle chained methods (e.g., z.string().optional())
503
+ // Must check BEFORE primitive types to unwrap the chain
504
+ if (Node.isCallExpression(node)) {
505
+ const expr = node.getExpression();
506
+ if (Node.isPropertyAccessExpression(expr)) {
507
+ const methodName = expr.getName();
508
+ // Skip over .optional(), .nullable(), .default(), etc. and parse inner
509
+ if (['optional', 'nullable', 'nullish', 'default', 'describe',
510
+ 'min', 'max', 'int', 'positive', 'email', 'uuid', 'url'].includes(methodName)) {
511
+ const inner = expr.getExpression();
512
+ return parseZodTypeToNormalized(inner);
513
+ }
514
+ }
515
+ }
516
+ // z.string()
517
+ if (trimmedText.startsWith('z.string()') || trimmedText.startsWith('z.string(')) {
518
+ return { kind: 'primitive', value: 'string' };
519
+ }
520
+ // z.number()
521
+ if (trimmedText.startsWith('z.number()') || trimmedText.startsWith('z.number(')) {
522
+ return { kind: 'primitive', value: 'number' };
523
+ }
524
+ // z.boolean()
525
+ if (trimmedText.startsWith('z.boolean()') || trimmedText.startsWith('z.boolean(')) {
526
+ return { kind: 'primitive', value: 'boolean' };
527
+ }
528
+ // z.date()
529
+ if (trimmedText.startsWith('z.date()') || trimmedText.startsWith('z.date(')) {
530
+ return { kind: 'primitive', value: 'string' }; // Date serialized as string
531
+ }
532
+ // z.enum([...])
533
+ if (trimmedText.startsWith('z.enum(')) {
534
+ const enumMatch = text.match(/z\.enum\(\[(.*?)\]\)/s);
535
+ if (enumMatch) {
536
+ const values = enumMatch[1]
537
+ .split(',')
538
+ .map(v => v.trim().replace(/['"]/g, ''))
539
+ .filter(v => v.length > 0);
540
+ const variants = values.map(v => ({
541
+ kind: 'literal',
542
+ value: v,
543
+ }));
544
+ return { kind: 'union', variants };
545
+ }
546
+ }
547
+ // z.array(...)
548
+ if (trimmedText.startsWith('z.array(')) {
549
+ if (Node.isCallExpression(node)) {
550
+ const args = node.getArguments();
551
+ if (args.length > 0) {
552
+ const elementType = parseZodTypeToNormalized(args[0]);
553
+ return { kind: 'array', element: elementType };
554
+ }
555
+ }
556
+ return { kind: 'array', element: { kind: 'unknown' } };
557
+ }
558
+ // z.object(...) - check multiple patterns
559
+ if (trimmedText.startsWith('z.object(') || trimmedText.startsWith('z.object({')) {
560
+ if (Node.isCallExpression(node)) {
561
+ const args = node.getArguments();
562
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
563
+ const properties = {};
564
+ const required = [];
565
+ parseZodObjectProperties(args[0], properties, required);
566
+ return {
567
+ kind: 'object',
568
+ schema: {
569
+ properties,
570
+ required,
571
+ source: { source: 'trpc', id: 'inline' },
572
+ },
573
+ };
574
+ }
575
+ }
576
+ return { kind: 'object', schema: { properties: {}, required: [], source: { source: 'trpc', id: 'inline' } } };
577
+ }
578
+ // z.literal(...)
579
+ if (trimmedText.startsWith('z.literal(')) {
580
+ const match = text.match(/z\.literal\(['"](.+?)['"]\)/);
581
+ if (match) {
582
+ return { kind: 'literal', value: match[1] };
583
+ }
584
+ const numMatch = text.match(/z\.literal\((\d+)\)/);
585
+ if (numMatch) {
586
+ return { kind: 'literal', value: parseInt(numMatch[1]) };
587
+ }
588
+ const boolMatch = text.match(/z\.literal\((true|false)\)/);
589
+ if (boolMatch) {
590
+ return { kind: 'literal', value: boolMatch[1] === 'true' };
591
+ }
592
+ }
593
+ // z.union([...])
594
+ if (trimmedText.startsWith('z.union(')) {
595
+ if (Node.isCallExpression(node)) {
596
+ const args = node.getArguments();
597
+ if (args.length > 0 && Node.isArrayLiteralExpression(args[0])) {
598
+ const variants = args[0].getElements().map(el => parseZodTypeToNormalized(el));
599
+ return { kind: 'union', variants };
600
+ }
601
+ }
602
+ }
603
+ // Fallback: Check if this is a CallExpression that looks like z.X pattern
604
+ if (Node.isCallExpression(node)) {
605
+ const expr = node.getExpression();
606
+ if (Node.isPropertyAccessExpression(expr)) {
607
+ const objExpr = expr.getExpression();
608
+ if (Node.isIdentifier(objExpr) && objExpr.getText() === 'z') {
609
+ const methodName = expr.getName();
610
+ if (methodName === 'object') {
611
+ const args = node.getArguments();
612
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
613
+ const properties = {};
614
+ const required = [];
615
+ parseZodObjectProperties(args[0], properties, required);
616
+ return {
617
+ kind: 'object',
618
+ schema: {
619
+ properties,
620
+ required,
621
+ source: { source: 'trpc', id: 'inline' },
622
+ },
623
+ };
624
+ }
625
+ }
626
+ }
627
+ }
628
+ }
629
+ return { kind: 'unknown' };
630
+ }
631
+ /**
632
+ * Extract validation constraints from a Zod type chain.
633
+ *
634
+ * Parses the Zod method chain text to extract constraints like:
635
+ * - String: `.min(n)`, `.max(n)`, `.email()`, `.uuid()`, `.url()`
636
+ * - Number: `.min(n)`, `.max(n)`, `.int()`, `.positive()`
637
+ *
638
+ * @param text - The Zod type chain as text
639
+ * @returns Extracted constraints object
640
+ *
641
+ * @example
642
+ * ```typescript
643
+ * extractZodConstraints('z.string().min(1).max(100).email()')
644
+ * // { minLength: 1, maxLength: 100, format: 'email' }
645
+ * ```
646
+ */
647
+ function extractZodConstraints(text) {
648
+ const constraints = {};
649
+ // String constraints
650
+ const minLengthMatch = text.match(/\.min\((\d+)\)/);
651
+ const maxLengthMatch = text.match(/\.max\((\d+)\)/);
652
+ // For strings
653
+ if (text.includes('z.string()')) {
654
+ if (minLengthMatch)
655
+ constraints.minLength = parseInt(minLengthMatch[1]);
656
+ if (maxLengthMatch)
657
+ constraints.maxLength = parseInt(maxLengthMatch[1]);
658
+ // Format constraints
659
+ if (text.includes('.email()'))
660
+ constraints.format = 'email';
661
+ if (text.includes('.uuid()'))
662
+ constraints.format = 'uuid';
663
+ if (text.includes('.url()'))
664
+ constraints.format = 'url';
665
+ }
666
+ // Number constraints
667
+ if (text.includes('z.number()')) {
668
+ if (minLengthMatch)
669
+ constraints.minimum = parseInt(minLengthMatch[1]);
670
+ if (maxLengthMatch)
671
+ constraints.maximum = parseInt(maxLengthMatch[1]);
672
+ }
673
+ return constraints;
674
+ }
675
+ // ============================================================================
676
+ // Utility Functions
677
+ // ============================================================================
678
+ /**
679
+ * Create an empty NormalizedSchema.
680
+ *
681
+ * Used for procedures without explicit input or output schemas.
682
+ * Returns a valid schema with empty properties.
683
+ *
684
+ * @param ref - The SchemaRef for source tracking
685
+ * @param location - Source location for error reporting
686
+ * @param name - Optional schema name
687
+ * @returns An empty NormalizedSchema
688
+ *
689
+ * @example
690
+ * ```typescript
691
+ * // For a procedure with no .input() call
692
+ * const emptyInput = createEmptySchema(
693
+ * ref,
694
+ * { file: './router.ts', line: 10 },
695
+ * 'users.list.input'
696
+ * );
697
+ * ```
698
+ */
699
+ export function createEmptySchema(ref, location, name) {
700
+ return {
701
+ name: name || ref.id.split('@')[0].split(':')[1],
702
+ properties: {},
703
+ required: [],
704
+ source: ref,
705
+ location,
706
+ };
707
+ }
708
+ //# sourceMappingURL=extractor.js.map