codeguardian-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 (335) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +348 -0
  3. package/dist/agent/agentTools.d.ts +26 -0
  4. package/dist/agent/agentTools.d.ts.map +1 -0
  5. package/dist/agent/agentTools.js +699 -0
  6. package/dist/agent/agentTools.js.map +1 -0
  7. package/dist/agent/autoValidator.d.ts +110 -0
  8. package/dist/agent/autoValidator.d.ts.map +1 -0
  9. package/dist/agent/autoValidator.js +964 -0
  10. package/dist/agent/autoValidator.js.map +1 -0
  11. package/dist/agent/fileWatcher.d.ts +28 -0
  12. package/dist/agent/fileWatcher.d.ts.map +1 -0
  13. package/dist/agent/fileWatcher.js +88 -0
  14. package/dist/agent/fileWatcher.js.map +1 -0
  15. package/dist/agent/guardianPersistence.d.ts +98 -0
  16. package/dist/agent/guardianPersistence.d.ts.map +1 -0
  17. package/dist/agent/guardianPersistence.js +296 -0
  18. package/dist/agent/guardianPersistence.js.map +1 -0
  19. package/dist/agent/mcpNotifications.d.ts +38 -0
  20. package/dist/agent/mcpNotifications.d.ts.map +1 -0
  21. package/dist/agent/mcpNotifications.js +81 -0
  22. package/dist/agent/mcpNotifications.js.map +1 -0
  23. package/dist/analyzers/aiPatterns.d.ts +16 -0
  24. package/dist/analyzers/aiPatterns.d.ts.map +1 -0
  25. package/dist/analyzers/aiPatterns.js +103 -0
  26. package/dist/analyzers/aiPatterns.js.map +1 -0
  27. package/dist/analyzers/antiPatterns.d.ts +60 -0
  28. package/dist/analyzers/antiPatterns.d.ts.map +1 -0
  29. package/dist/analyzers/antiPatterns.js +198 -0
  30. package/dist/analyzers/antiPatterns.js.map +1 -0
  31. package/dist/analyzers/builtinTypes.d.ts +18 -0
  32. package/dist/analyzers/builtinTypes.d.ts.map +1 -0
  33. package/dist/analyzers/builtinTypes.js +1275 -0
  34. package/dist/analyzers/builtinTypes.js.map +1 -0
  35. package/dist/analyzers/complexity.d.ts +14 -0
  36. package/dist/analyzers/complexity.d.ts.map +1 -0
  37. package/dist/analyzers/complexity.js +610 -0
  38. package/dist/analyzers/complexity.js.map +1 -0
  39. package/dist/analyzers/findingVerifier.d.ts +59 -0
  40. package/dist/analyzers/findingVerifier.d.ts.map +1 -0
  41. package/dist/analyzers/findingVerifier.js +1169 -0
  42. package/dist/analyzers/findingVerifier.js.map +1 -0
  43. package/dist/analyzers/impactAnalyzer.d.ts +53 -0
  44. package/dist/analyzers/impactAnalyzer.d.ts.map +1 -0
  45. package/dist/analyzers/impactAnalyzer.js +152 -0
  46. package/dist/analyzers/impactAnalyzer.js.map +1 -0
  47. package/dist/analyzers/languageDetector.d.ts +48 -0
  48. package/dist/analyzers/languageDetector.d.ts.map +1 -0
  49. package/dist/analyzers/languageDetector.js +404 -0
  50. package/dist/analyzers/languageDetector.js.map +1 -0
  51. package/dist/analyzers/parsers/incrementalParser.d.ts +53 -0
  52. package/dist/analyzers/parsers/incrementalParser.d.ts.map +1 -0
  53. package/dist/analyzers/parsers/incrementalParser.js +193 -0
  54. package/dist/analyzers/parsers/incrementalParser.js.map +1 -0
  55. package/dist/analyzers/parsers/scopeResolver.d.ts +92 -0
  56. package/dist/analyzers/parsers/scopeResolver.d.ts.map +1 -0
  57. package/dist/analyzers/parsers/scopeResolver.js +324 -0
  58. package/dist/analyzers/parsers/scopeResolver.js.map +1 -0
  59. package/dist/analyzers/parsers/semanticIndex.d.ts +127 -0
  60. package/dist/analyzers/parsers/semanticIndex.d.ts.map +1 -0
  61. package/dist/analyzers/parsers/semanticIndex.js +429 -0
  62. package/dist/analyzers/parsers/semanticIndex.js.map +1 -0
  63. package/dist/analyzers/parsers/sessionDiffAnalyzer.d.ts +42 -0
  64. package/dist/analyzers/parsers/sessionDiffAnalyzer.d.ts.map +1 -0
  65. package/dist/analyzers/parsers/sessionDiffAnalyzer.js +233 -0
  66. package/dist/analyzers/parsers/sessionDiffAnalyzer.js.map +1 -0
  67. package/dist/analyzers/parsers/treeSitterParser.d.ts +76 -0
  68. package/dist/analyzers/parsers/treeSitterParser.d.ts.map +1 -0
  69. package/dist/analyzers/parsers/treeSitterParser.js +709 -0
  70. package/dist/analyzers/parsers/treeSitterParser.js.map +1 -0
  71. package/dist/analyzers/relevanceScorer.d.ts +43 -0
  72. package/dist/analyzers/relevanceScorer.d.ts.map +1 -0
  73. package/dist/analyzers/relevanceScorer.js +200 -0
  74. package/dist/analyzers/relevanceScorer.js.map +1 -0
  75. package/dist/analyzers/standardLibrary.d.ts +22 -0
  76. package/dist/analyzers/standardLibrary.d.ts.map +1 -0
  77. package/dist/analyzers/standardLibrary.js +211 -0
  78. package/dist/analyzers/standardLibrary.js.map +1 -0
  79. package/dist/analyzers/symbolGraph.d.ts +30 -0
  80. package/dist/analyzers/symbolGraph.d.ts.map +1 -0
  81. package/dist/analyzers/symbolGraph.js +380 -0
  82. package/dist/analyzers/symbolGraph.js.map +1 -0
  83. package/dist/analyzers/symbolTable.d.ts +18 -0
  84. package/dist/analyzers/symbolTable.d.ts.map +1 -0
  85. package/dist/analyzers/symbolTable.js +176 -0
  86. package/dist/analyzers/symbolTable.js.map +1 -0
  87. package/dist/analyzers/typeChecker.d.ts +13 -0
  88. package/dist/analyzers/typeChecker.d.ts.map +1 -0
  89. package/dist/analyzers/typeChecker.js +580 -0
  90. package/dist/analyzers/typeChecker.js.map +1 -0
  91. package/dist/analyzers/usagePatterns.d.ts +42 -0
  92. package/dist/analyzers/usagePatterns.d.ts.map +1 -0
  93. package/dist/analyzers/usagePatterns.js +75 -0
  94. package/dist/analyzers/usagePatterns.js.map +1 -0
  95. package/dist/api-contract/context/backend.d.ts +19 -0
  96. package/dist/api-contract/context/backend.d.ts.map +1 -0
  97. package/dist/api-contract/context/backend.js +64 -0
  98. package/dist/api-contract/context/backend.js.map +1 -0
  99. package/dist/api-contract/context/contract.d.ts +34 -0
  100. package/dist/api-contract/context/contract.d.ts.map +1 -0
  101. package/dist/api-contract/context/contract.js +306 -0
  102. package/dist/api-contract/context/contract.js.map +1 -0
  103. package/dist/api-contract/context/frontend.d.ts +19 -0
  104. package/dist/api-contract/context/frontend.d.ts.map +1 -0
  105. package/dist/api-contract/context/frontend.js +64 -0
  106. package/dist/api-contract/context/frontend.js.map +1 -0
  107. package/dist/api-contract/detector.d.ts +28 -0
  108. package/dist/api-contract/detector.d.ts.map +1 -0
  109. package/dist/api-contract/detector.js +393 -0
  110. package/dist/api-contract/detector.js.map +1 -0
  111. package/dist/api-contract/extractors/python.d.ts +32 -0
  112. package/dist/api-contract/extractors/python.d.ts.map +1 -0
  113. package/dist/api-contract/extractors/python.js +521 -0
  114. package/dist/api-contract/extractors/python.js.map +1 -0
  115. package/dist/api-contract/extractors/pythonAstUtils.d.ts +44 -0
  116. package/dist/api-contract/extractors/pythonAstUtils.d.ts.map +1 -0
  117. package/dist/api-contract/extractors/pythonAstUtils.js +489 -0
  118. package/dist/api-contract/extractors/pythonAstUtils.js.map +1 -0
  119. package/dist/api-contract/extractors/tsAstUtils.d.ts +47 -0
  120. package/dist/api-contract/extractors/tsAstUtils.d.ts.map +1 -0
  121. package/dist/api-contract/extractors/tsAstUtils.js +173 -0
  122. package/dist/api-contract/extractors/tsAstUtils.js.map +1 -0
  123. package/dist/api-contract/extractors/typescript.d.ts +32 -0
  124. package/dist/api-contract/extractors/typescript.d.ts.map +1 -0
  125. package/dist/api-contract/extractors/typescript.js +666 -0
  126. package/dist/api-contract/extractors/typescript.js.map +1 -0
  127. package/dist/api-contract/index.d.ts +104 -0
  128. package/dist/api-contract/index.d.ts.map +1 -0
  129. package/dist/api-contract/index.js +232 -0
  130. package/dist/api-contract/index.js.map +1 -0
  131. package/dist/api-contract/types.d.ts +151 -0
  132. package/dist/api-contract/types.d.ts.map +1 -0
  133. package/dist/api-contract/types.js +19 -0
  134. package/dist/api-contract/types.js.map +1 -0
  135. package/dist/api-contract/validators/endpoint.d.ts +21 -0
  136. package/dist/api-contract/validators/endpoint.d.ts.map +1 -0
  137. package/dist/api-contract/validators/endpoint.js +224 -0
  138. package/dist/api-contract/validators/endpoint.js.map +1 -0
  139. package/dist/api-contract/validators/index.d.ts +40 -0
  140. package/dist/api-contract/validators/index.d.ts.map +1 -0
  141. package/dist/api-contract/validators/index.js +875 -0
  142. package/dist/api-contract/validators/index.js.map +1 -0
  143. package/dist/api-contract/validators/parameter.d.ts +17 -0
  144. package/dist/api-contract/validators/parameter.d.ts.map +1 -0
  145. package/dist/api-contract/validators/parameter.js +250 -0
  146. package/dist/api-contract/validators/parameter.js.map +1 -0
  147. package/dist/api-contract/validators/type.d.ts +38 -0
  148. package/dist/api-contract/validators/type.d.ts.map +1 -0
  149. package/dist/api-contract/validators/type.js +244 -0
  150. package/dist/api-contract/validators/type.js.map +1 -0
  151. package/dist/context/apiContract/complexTypeSupport.d.ts +83 -0
  152. package/dist/context/apiContract/complexTypeSupport.d.ts.map +1 -0
  153. package/dist/context/apiContract/complexTypeSupport.js +665 -0
  154. package/dist/context/apiContract/complexTypeSupport.js.map +1 -0
  155. package/dist/context/apiContract/graphqlSupport.d.ts +105 -0
  156. package/dist/context/apiContract/graphqlSupport.d.ts.map +1 -0
  157. package/dist/context/apiContract/graphqlSupport.js +671 -0
  158. package/dist/context/apiContract/graphqlSupport.js.map +1 -0
  159. package/dist/context/apiContract/index.d.ts +14 -0
  160. package/dist/context/apiContract/index.d.ts.map +1 -0
  161. package/dist/context/apiContract/index.js +17 -0
  162. package/dist/context/apiContract/index.js.map +1 -0
  163. package/dist/context/apiContract/webSocketSupport.d.ts +104 -0
  164. package/dist/context/apiContract/webSocketSupport.d.ts.map +1 -0
  165. package/dist/context/apiContract/webSocketSupport.js +465 -0
  166. package/dist/context/apiContract/webSocketSupport.js.map +1 -0
  167. package/dist/context/apiContractContext.d.ts +15 -0
  168. package/dist/context/apiContractContext.d.ts.map +1 -0
  169. package/dist/context/apiContractContext.js +979 -0
  170. package/dist/context/apiContractContext.js.map +1 -0
  171. package/dist/context/apiContractExtraction.d.ts +52 -0
  172. package/dist/context/apiContractExtraction.d.ts.map +1 -0
  173. package/dist/context/apiContractExtraction.js +438 -0
  174. package/dist/context/apiContractExtraction.js.map +1 -0
  175. package/dist/context/contextLineage.d.ts +79 -0
  176. package/dist/context/contextLineage.d.ts.map +1 -0
  177. package/dist/context/contextLineage.js +259 -0
  178. package/dist/context/contextLineage.js.map +1 -0
  179. package/dist/context/contextOrchestrator.d.ts +57 -0
  180. package/dist/context/contextOrchestrator.d.ts.map +1 -0
  181. package/dist/context/contextOrchestrator.js +162 -0
  182. package/dist/context/contextOrchestrator.js.map +1 -0
  183. package/dist/context/intentTracker.d.ts +73 -0
  184. package/dist/context/intentTracker.d.ts.map +1 -0
  185. package/dist/context/intentTracker.js +168 -0
  186. package/dist/context/intentTracker.js.map +1 -0
  187. package/dist/context/projectContext.d.ts +219 -0
  188. package/dist/context/projectContext.d.ts.map +1 -0
  189. package/dist/context/projectContext.js +1984 -0
  190. package/dist/context/projectContext.js.map +1 -0
  191. package/dist/prompts/index.d.ts +17 -0
  192. package/dist/prompts/index.d.ts.map +1 -0
  193. package/dist/prompts/index.js +260 -0
  194. package/dist/prompts/index.js.map +1 -0
  195. package/dist/prompts/library.d.ts +51 -0
  196. package/dist/prompts/library.d.ts.map +1 -0
  197. package/dist/prompts/library.js +65 -0
  198. package/dist/prompts/library.js.map +1 -0
  199. package/dist/prompts/templates.d.ts +44 -0
  200. package/dist/prompts/templates.d.ts.map +1 -0
  201. package/dist/prompts/templates.js +97 -0
  202. package/dist/prompts/templates.js.map +1 -0
  203. package/dist/queue/jobPersistence.d.ts +46 -0
  204. package/dist/queue/jobPersistence.d.ts.map +1 -0
  205. package/dist/queue/jobPersistence.js +158 -0
  206. package/dist/queue/jobPersistence.js.map +1 -0
  207. package/dist/queue/jobQueue.d.ts +116 -0
  208. package/dist/queue/jobQueue.d.ts.map +1 -0
  209. package/dist/queue/jobQueue.js +275 -0
  210. package/dist/queue/jobQueue.js.map +1 -0
  211. package/dist/queue/validationJob.d.ts +69 -0
  212. package/dist/queue/validationJob.d.ts.map +1 -0
  213. package/dist/queue/validationJob.js +435 -0
  214. package/dist/queue/validationJob.js.map +1 -0
  215. package/dist/resources/index.d.ts +15 -0
  216. package/dist/resources/index.d.ts.map +1 -0
  217. package/dist/resources/index.js +328 -0
  218. package/dist/resources/index.js.map +1 -0
  219. package/dist/resources/validationReportStore.d.ts +170 -0
  220. package/dist/resources/validationReportStore.d.ts.map +1 -0
  221. package/dist/resources/validationReportStore.js +515 -0
  222. package/dist/resources/validationReportStore.js.map +1 -0
  223. package/dist/server.d.ts +12 -0
  224. package/dist/server.d.ts.map +1 -0
  225. package/dist/server.js +102 -0
  226. package/dist/server.js.map +1 -0
  227. package/dist/tools/asyncValidation.d.ts +19 -0
  228. package/dist/tools/asyncValidation.d.ts.map +1 -0
  229. package/dist/tools/asyncValidation.js +346 -0
  230. package/dist/tools/asyncValidation.js.map +1 -0
  231. package/dist/tools/buildContext.d.ts +17 -0
  232. package/dist/tools/buildContext.d.ts.map +1 -0
  233. package/dist/tools/buildContext.js +188 -0
  234. package/dist/tools/buildContext.js.map +1 -0
  235. package/dist/tools/getDependencyGraph.d.ts +16 -0
  236. package/dist/tools/getDependencyGraph.d.ts.map +1 -0
  237. package/dist/tools/getDependencyGraph.js +436 -0
  238. package/dist/tools/getDependencyGraph.js.map +1 -0
  239. package/dist/tools/incrementalValidation.d.ts +71 -0
  240. package/dist/tools/incrementalValidation.d.ts.map +1 -0
  241. package/dist/tools/incrementalValidation.js +203 -0
  242. package/dist/tools/incrementalValidation.js.map +1 -0
  243. package/dist/tools/index.d.ts +24 -0
  244. package/dist/tools/index.d.ts.map +1 -0
  245. package/dist/tools/index.js +106 -0
  246. package/dist/tools/index.js.map +1 -0
  247. package/dist/tools/validateCode.d.ts +17 -0
  248. package/dist/tools/validateCode.d.ts.map +1 -0
  249. package/dist/tools/validateCode.js +368 -0
  250. package/dist/tools/validateCode.js.map +1 -0
  251. package/dist/tools/validateCodeLite.d.ts +2 -0
  252. package/dist/tools/validateCodeLite.d.ts.map +1 -0
  253. package/dist/tools/validateCodeLite.js +2 -0
  254. package/dist/tools/validateCodeLite.js.map +1 -0
  255. package/dist/tools/validation/builtins.d.ts +92 -0
  256. package/dist/tools/validation/builtins.d.ts.map +1 -0
  257. package/dist/tools/validation/builtins.js +2184 -0
  258. package/dist/tools/validation/builtins.js.map +1 -0
  259. package/dist/tools/validation/contextualNaming.d.ts +99 -0
  260. package/dist/tools/validation/contextualNaming.d.ts.map +1 -0
  261. package/dist/tools/validation/contextualNaming.js +959 -0
  262. package/dist/tools/validation/contextualNaming.js.map +1 -0
  263. package/dist/tools/validation/deadCode.d.ts +115 -0
  264. package/dist/tools/validation/deadCode.d.ts.map +1 -0
  265. package/dist/tools/validation/deadCode.js +861 -0
  266. package/dist/tools/validation/deadCode.js.map +1 -0
  267. package/dist/tools/validation/extractors/index.d.ts +131 -0
  268. package/dist/tools/validation/extractors/index.d.ts.map +1 -0
  269. package/dist/tools/validation/extractors/index.js +233 -0
  270. package/dist/tools/validation/extractors/index.js.map +1 -0
  271. package/dist/tools/validation/extractors/javascript.d.ts +73 -0
  272. package/dist/tools/validation/extractors/javascript.d.ts.map +1 -0
  273. package/dist/tools/validation/extractors/javascript.js +1841 -0
  274. package/dist/tools/validation/extractors/javascript.js.map +1 -0
  275. package/dist/tools/validation/extractors/python.d.ts +93 -0
  276. package/dist/tools/validation/extractors/python.d.ts.map +1 -0
  277. package/dist/tools/validation/extractors/python.js +799 -0
  278. package/dist/tools/validation/extractors/python.js.map +1 -0
  279. package/dist/tools/validation/manifest.d.ts +45 -0
  280. package/dist/tools/validation/manifest.d.ts.map +1 -0
  281. package/dist/tools/validation/manifest.js +719 -0
  282. package/dist/tools/validation/manifest.js.map +1 -0
  283. package/dist/tools/validation/parser.d.ts +58 -0
  284. package/dist/tools/validation/parser.d.ts.map +1 -0
  285. package/dist/tools/validation/parser.js +232 -0
  286. package/dist/tools/validation/parser.js.map +1 -0
  287. package/dist/tools/validation/registry.d.ts +15 -0
  288. package/dist/tools/validation/registry.d.ts.map +1 -0
  289. package/dist/tools/validation/registry.js +169 -0
  290. package/dist/tools/validation/registry.js.map +1 -0
  291. package/dist/tools/validation/scoring.d.ts +54 -0
  292. package/dist/tools/validation/scoring.d.ts.map +1 -0
  293. package/dist/tools/validation/scoring.js +242 -0
  294. package/dist/tools/validation/scoring.js.map +1 -0
  295. package/dist/tools/validation/types.d.ts +120 -0
  296. package/dist/tools/validation/types.d.ts.map +1 -0
  297. package/dist/tools/validation/types.js +11 -0
  298. package/dist/tools/validation/types.js.map +1 -0
  299. package/dist/tools/validation/unusedLocals.d.ts +36 -0
  300. package/dist/tools/validation/unusedLocals.d.ts.map +1 -0
  301. package/dist/tools/validation/unusedLocals.js +333 -0
  302. package/dist/tools/validation/unusedLocals.js.map +1 -0
  303. package/dist/tools/validation/validation.d.ts +98 -0
  304. package/dist/tools/validation/validation.d.ts.map +1 -0
  305. package/dist/tools/validation/validation.js +1837 -0
  306. package/dist/tools/validation/validation.js.map +1 -0
  307. package/dist/types/codeGraph.d.ts +163 -0
  308. package/dist/types/codeGraph.d.ts.map +1 -0
  309. package/dist/types/codeGraph.js +9 -0
  310. package/dist/types/codeGraph.js.map +1 -0
  311. package/dist/types/symbolGraph.d.ts +68 -0
  312. package/dist/types/symbolGraph.d.ts.map +1 -0
  313. package/dist/types/symbolGraph.js +10 -0
  314. package/dist/types/symbolGraph.js.map +1 -0
  315. package/dist/types/tools.d.ts +43 -0
  316. package/dist/types/tools.d.ts.map +1 -0
  317. package/dist/types/tools.js +7 -0
  318. package/dist/types/tools.js.map +1 -0
  319. package/dist/utils/fileFilter.d.ts +37 -0
  320. package/dist/utils/fileFilter.d.ts.map +1 -0
  321. package/dist/utils/fileFilter.js +91 -0
  322. package/dist/utils/fileFilter.js.map +1 -0
  323. package/dist/utils/gitUtils.d.ts +28 -0
  324. package/dist/utils/gitUtils.d.ts.map +1 -0
  325. package/dist/utils/gitUtils.js +81 -0
  326. package/dist/utils/gitUtils.js.map +1 -0
  327. package/dist/utils/logger.d.ts +15 -0
  328. package/dist/utils/logger.d.ts.map +1 -0
  329. package/dist/utils/logger.js +38 -0
  330. package/dist/utils/logger.js.map +1 -0
  331. package/dist/utils/serialization.d.ts +25 -0
  332. package/dist/utils/serialization.d.ts.map +1 -0
  333. package/dist/utils/serialization.js +53 -0
  334. package/dist/utils/serialization.js.map +1 -0
  335. package/package.json +90 -0
@@ -0,0 +1,666 @@
1
+ /**
2
+ * API Contract Guardian - TypeScript Extractor (AST-based)
3
+ *
4
+ * Extracts API service functions and TypeScript types/interfaces using AST.
5
+ *
6
+ * @format
7
+ */
8
+ import * as fs from "fs/promises";
9
+ import * as path from "path";
10
+ import { glob } from "glob";
11
+ import { logger } from "../../utils/logger.js";
12
+ import { getParser } from "../../tools/validation/parser.js";
13
+ import { extractEndpointFromArguments as extractEndpointFromArgumentsTS, extractHttpMethodFromArguments as extractHttpMethodFromArgumentsTS, findEnclosingFunctionName, getNodeText, mapToHttpMethod, } from "./tsAstUtils.js";
14
+ // ============================================================================
15
+ // Service Extraction
16
+ // ============================================================================
17
+ /**
18
+ * Extract all API service functions from a project
19
+ */
20
+ export async function extractServices(projectPath) {
21
+ const services = [];
22
+ // Find service files
23
+ const servicePatterns = [
24
+ `${projectPath}/**/services/**/*.ts`,
25
+ `${projectPath}/**/api/**/*.ts`,
26
+ `${projectPath}/**/clients/**/*.ts`,
27
+ `${projectPath}/src/lib/api.ts`,
28
+ `${projectPath}/lib/api.ts`,
29
+ ];
30
+ const excludePatterns = [
31
+ "**/node_modules/**",
32
+ "**/*.test.ts",
33
+ "**/*.spec.ts",
34
+ "**/dist/**",
35
+ "**/build/**",
36
+ ];
37
+ for (const pattern of servicePatterns) {
38
+ const files = await glob(pattern, {
39
+ ignore: excludePatterns,
40
+ nodir: true,
41
+ absolute: true,
42
+ });
43
+ for (const file of files) {
44
+ try {
45
+ const content = await fs.readFile(file, "utf-8");
46
+ const fileServices = extractServicesFromFile(content, file);
47
+ services.push(...fileServices);
48
+ }
49
+ catch (err) {
50
+ logger.debug(`Failed to extract services from ${file}`);
51
+ }
52
+ }
53
+ }
54
+ logger.info(`Extracted ${services.length} API services from ${projectPath}`);
55
+ return services;
56
+ }
57
+ /**
58
+ * Extract service functions from a single file using AST
59
+ */
60
+ export function extractServicesFromFile(content, filePath) {
61
+ const services = [];
62
+ try {
63
+ const parser = getParser("typescript");
64
+ const tree = parser.parse(content);
65
+ // Traverse AST to find API calls
66
+ traverseNode(tree.rootNode, content, filePath, services);
67
+ }
68
+ catch (err) {
69
+ logger.debug(`AST parsing failed for ${filePath}, falling back to regex`);
70
+ return extractServicesFromFileRegex(content, filePath);
71
+ }
72
+ return services;
73
+ }
74
+ /**
75
+ * Recursively traverse AST nodes to find API calls
76
+ */
77
+ function traverseNode(node, content, filePath, services) {
78
+ if (!node)
79
+ return;
80
+ // Look for call expressions (method calls)
81
+ if (node.type === "call_expression") {
82
+ const service = extractServiceFromCall(node, content, filePath);
83
+ if (service) {
84
+ services.push(service);
85
+ }
86
+ }
87
+ // Recursively traverse children
88
+ for (const child of node.children || []) {
89
+ traverseNode(child, content, filePath, services);
90
+ }
91
+ }
92
+ /**
93
+ * Common patterns for direct API helper function names
94
+ */
95
+ const API_HELPER_PATTERNS = [
96
+ /^fetch/i, // fetchApi, fetchData, fetchJson
97
+ /^api(?:Call|Request|Fetch)?$/i, // api, apiCall, apiRequest, apiFetch
98
+ /^(?:make|do|send)Request$/i, // makeRequest, doRequest, sendRequest
99
+ /^request$/i,
100
+ /^http(?:Client|Request)?$/i,
101
+ ];
102
+ /**
103
+ * Extract service from a call expression node
104
+ */
105
+ function extractServiceFromCall(node, content, filePath) {
106
+ // Get the function being called
107
+ const functionNode = node.childForFieldName("function");
108
+ if (!functionNode)
109
+ return null;
110
+ // Case 1: Method call like ApiService.post or api.get
111
+ if (functionNode.type === "member_expression") {
112
+ const objectNode = functionNode.childForFieldName("object");
113
+ const propertyNode = functionNode.childForFieldName("property");
114
+ if (!objectNode || !propertyNode)
115
+ return null;
116
+ const objectName = getNodeText(objectNode, content);
117
+ const methodName = getNodeText(propertyNode, content);
118
+ // Check if it's an API call pattern
119
+ const isApiCall = objectName === "ApiService" ||
120
+ objectName === "api" ||
121
+ objectName === "axios" ||
122
+ objectName === "client" ||
123
+ objectName.endsWith("Api") ||
124
+ objectName.endsWith("Service");
125
+ if (!isApiCall)
126
+ return null;
127
+ // Map method name to HTTP method
128
+ const httpMethod = mapToHttpMethod(methodName);
129
+ if (!httpMethod)
130
+ return null;
131
+ // Extract arguments
132
+ const argumentsNode = node.childForFieldName("arguments");
133
+ if (!argumentsNode)
134
+ return null;
135
+ const extracted = extractEndpointFromArgumentsTS(argumentsNode, content);
136
+ if (!extracted)
137
+ return null;
138
+ const endpoint = extracted.endpoint;
139
+ // Try to find the enclosing function/method name
140
+ const enclosingFunction = findEnclosingFunctionName(node, content);
141
+ // Extract request/response types from the enclosing function/method
142
+ const { requestType, responseType } = extractTypesFromEnclosingFunction(node, content, httpMethod);
143
+ return {
144
+ name: enclosingFunction || `${methodName}_${endpoint.replace(/[^a-zA-Z0-9]/g, "_")}`,
145
+ method: httpMethod,
146
+ endpoint,
147
+ requestType,
148
+ responseType,
149
+ queryParams: extracted.queryParams.length > 0 ? extracted.queryParams : undefined,
150
+ file: filePath,
151
+ line: node.startPosition.row + 1,
152
+ };
153
+ }
154
+ // Case 2: Direct function call like fetchApi('/endpoint', { method: 'POST' })
155
+ // This handles wrapper functions (fetchApi, apiCall, request, etc.)
156
+ if (functionNode.type === "identifier") {
157
+ const funcName = getNodeText(functionNode, content);
158
+ // Check if the function name matches common API helper patterns
159
+ const isApiHelper = API_HELPER_PATTERNS.some(p => p.test(funcName));
160
+ if (!isApiHelper)
161
+ return null;
162
+ // Extract arguments
163
+ const argumentsNode = node.childForFieldName("arguments");
164
+ if (!argumentsNode)
165
+ return null;
166
+ const extracted = extractEndpointFromArgumentsTS(argumentsNode, content);
167
+ if (!extracted)
168
+ return null;
169
+ const endpoint = extracted.endpoint;
170
+ // Try to detect HTTP method from the options argument (e.g., { method: 'POST' })
171
+ const httpMethod = extractHttpMethodFromArgumentsTS(argumentsNode, content) || "GET";
172
+ // Try to find the enclosing function/method name
173
+ const enclosingFunction = findEnclosingFunctionName(node, content);
174
+ const { requestType, responseType } = extractTypesFromEnclosingFunction(node, content, httpMethod);
175
+ return {
176
+ name: enclosingFunction || `${funcName}_${endpoint.replace(/[^a-zA-Z0-9]/g, "_")}`,
177
+ method: httpMethod,
178
+ endpoint,
179
+ requestType,
180
+ responseType,
181
+ queryParams: extracted.queryParams.length > 0 ? extracted.queryParams : undefined,
182
+ file: filePath,
183
+ line: node.startPosition.row + 1,
184
+ };
185
+ }
186
+ return null;
187
+ }
188
+ /**
189
+ * Best-effort request/response type extraction.
190
+ *
191
+ * This is intentionally heuristic: callers use it to enrich API contract mappings,
192
+ * not as a compiler-grade typechecker.
193
+ */
194
+ function extractTypesFromEnclosingFunction(node, content, method) {
195
+ let current = node;
196
+ const result = {};
197
+ while (current) {
198
+ // Arrow function (common in React hooks/services)
199
+ if (current.type === "arrow_function") {
200
+ // Response type
201
+ const returnTypeNode = current.childForFieldName?.("return_type");
202
+ if (returnTypeNode) {
203
+ const returnTypeText = normalizeTypeText(getNodeText(returnTypeNode, content));
204
+ result.responseType = unwrapCommonGenerics(returnTypeText);
205
+ }
206
+ // Request type (first non-primitive typed param on write methods)
207
+ if (method === "POST" || method === "PUT" || method === "PATCH") {
208
+ const parametersNode = current.childForFieldName?.("parameters");
209
+ if (parametersNode) {
210
+ const params = collectTypedParameters(parametersNode, content);
211
+ for (const p of params) {
212
+ if (p.type && !isPrimitiveType(p.type)) {
213
+ result.requestType = unwrapCommonGenerics(p.type);
214
+ break;
215
+ }
216
+ }
217
+ }
218
+ }
219
+ return result;
220
+ }
221
+ // Method definition (class services)
222
+ if (current.type === "method_definition") {
223
+ const returnTypeNode = current.childForFieldName?.("return_type");
224
+ if (returnTypeNode) {
225
+ const returnTypeText = normalizeTypeText(getNodeText(returnTypeNode, content));
226
+ result.responseType = unwrapCommonGenerics(returnTypeText);
227
+ }
228
+ if (method === "POST" || method === "PUT" || method === "PATCH") {
229
+ const parametersNode = current.childForFieldName?.("parameters");
230
+ if (parametersNode) {
231
+ const params = collectTypedParameters(parametersNode, content);
232
+ for (const p of params) {
233
+ if (p.type && !isPrimitiveType(p.type)) {
234
+ result.requestType = unwrapCommonGenerics(p.type);
235
+ break;
236
+ }
237
+ }
238
+ }
239
+ }
240
+ return result;
241
+ }
242
+ // Function declaration
243
+ if (current.type === "function_declaration") {
244
+ const returnTypeNode = current.childForFieldName?.("return_type");
245
+ if (returnTypeNode) {
246
+ const returnTypeText = normalizeTypeText(getNodeText(returnTypeNode, content));
247
+ result.responseType = unwrapCommonGenerics(returnTypeText);
248
+ }
249
+ if (method === "POST" || method === "PUT" || method === "PATCH") {
250
+ const parametersNode = current.childForFieldName?.("parameters");
251
+ if (parametersNode) {
252
+ const params = collectTypedParameters(parametersNode, content);
253
+ for (const p of params) {
254
+ if (p.type && !isPrimitiveType(p.type)) {
255
+ result.requestType = unwrapCommonGenerics(p.type);
256
+ break;
257
+ }
258
+ }
259
+ }
260
+ }
261
+ return result;
262
+ }
263
+ current = current.parent;
264
+ }
265
+ return result;
266
+ }
267
+ function collectTypedParameters(parametersNode, content) {
268
+ const out = [];
269
+ for (const child of parametersNode.children || []) {
270
+ if (!child)
271
+ continue;
272
+ // tree-sitter-typescript: required_parameter / optional_parameter / identifier
273
+ if (child.type === "required_parameter" ||
274
+ child.type === "optional_parameter" ||
275
+ child.type === "identifier") {
276
+ const nameNode = child.childForFieldName?.("name") || child;
277
+ const typeNode = child.childForFieldName?.("type");
278
+ const name = nameNode ? getNodeText(nameNode, content) : "";
279
+ const typeText = typeNode
280
+ ? normalizeTypeText(getNodeText(typeNode, content))
281
+ : undefined;
282
+ if (name)
283
+ out.push({ name, type: typeText });
284
+ }
285
+ }
286
+ return out;
287
+ }
288
+ function normalizeTypeText(typeText) {
289
+ return typeText.replace(/^\s*:\s*/, "").trim();
290
+ }
291
+ function unwrapCommonGenerics(typeText) {
292
+ let t = typeText.trim();
293
+ // Strip trailing array syntax
294
+ while (t.endsWith("[]")) {
295
+ t = t.slice(0, -2).trim();
296
+ }
297
+ // Common wrappers
298
+ const wrappers = [
299
+ "Promise",
300
+ "AxiosResponse",
301
+ "ApiResponse",
302
+ "Response",
303
+ "Array",
304
+ "ReadonlyArray",
305
+ ];
306
+ for (let i = 0; i < 5; i++) {
307
+ const m = t.match(/^([A-Za-z0-9_$.]+)\s*<\s*(.+)\s*>$/);
308
+ if (!m)
309
+ break;
310
+ const name = m[1];
311
+ const inner = m[2];
312
+ if (!wrappers.includes(name.split(".").pop() || name))
313
+ break;
314
+ t = inner.trim();
315
+ }
316
+ return t;
317
+ }
318
+ function isPrimitiveType(typeName) {
319
+ const raw = typeName.trim();
320
+ if (!raw)
321
+ return true;
322
+ // Literal types
323
+ if (/^['"`].*['"`]$/.test(raw))
324
+ return true;
325
+ if (/^[0-9]+(?:\.[0-9]+)?$/.test(raw))
326
+ return true;
327
+ // Union: only primitive if all parts are primitive
328
+ const unionParts = raw.split("|").map((p) => p.trim()).filter(Boolean);
329
+ if (unionParts.length > 1) {
330
+ return unionParts.every((p) => isPrimitiveType(p));
331
+ }
332
+ // Arrays / generics
333
+ const unwrapped = unwrapCommonGenerics(raw);
334
+ const base = unwrapped.replace(/\[\]$/g, "").trim();
335
+ const primitives = new Set([
336
+ "string",
337
+ "number",
338
+ "boolean",
339
+ "null",
340
+ "undefined",
341
+ "any",
342
+ "unknown",
343
+ "void",
344
+ "never",
345
+ "object",
346
+ "Record",
347
+ ]);
348
+ const lower = base.toLowerCase();
349
+ if (primitives.has(lower))
350
+ return true;
351
+ // Sometimes TS nodes preserve casing (Record/Promise)
352
+ const head = base.split(/[<\s]/)[0];
353
+ if (primitives.has(head) || primitives.has(head.toLowerCase()))
354
+ return true;
355
+ return false;
356
+ }
357
+ // ============================================================================
358
+ // Fallback Regex Extraction
359
+ // ============================================================================
360
+ /**
361
+ * Fallback regex-based extraction when AST fails
362
+ */
363
+ function extractServicesFromFileRegex(content, filePath) {
364
+ const services = [];
365
+ const lines = content.split("\n");
366
+ for (let i = 0; i < lines.length; i++) {
367
+ const line = lines[i];
368
+ const lineNum = i + 1;
369
+ // Pattern: ApiService.post('/endpoint', data)
370
+ // Pattern: api.get('/endpoint')
371
+ const apiCallMatch = line.match(/(?:ApiService|api|axios|client|[A-Za-z]+Api|[A-Za-z]+Service)\.(get|post|put|patch|delete)\s*\(\s*["'`]([^"'`]+)["'`]/i);
372
+ if (apiCallMatch) {
373
+ const method = apiCallMatch[1].toUpperCase();
374
+ const endpoint = apiCallMatch[2];
375
+ // Try to find function name
376
+ const funcMatch = line.match(/(?:export\s+)?(?:async\s+)?(?:function|const)\s+(\w+)/) ||
377
+ lines.slice(Math.max(0, i - 5), i).join(" ").match(/(\w+)\s*[:=]\s*(?:async\s*)?\(/);
378
+ const funcName = funcMatch ? funcMatch[1] : `api_${method.toLowerCase()}`;
379
+ services.push({
380
+ name: funcName,
381
+ method,
382
+ endpoint,
383
+ file: filePath,
384
+ line: lineNum,
385
+ });
386
+ }
387
+ }
388
+ return services;
389
+ }
390
+ // ============================================================================
391
+ // Type Extraction
392
+ // ============================================================================
393
+ /**
394
+ * Extract all TypeScript types/interfaces from a project
395
+ */
396
+ export async function extractTypes(projectPath) {
397
+ const types = [];
398
+ // Find type definition files
399
+ const typePatterns = [
400
+ `${projectPath}/**/types/**/*.ts`,
401
+ `${projectPath}/**/interfaces/**/*.ts`,
402
+ `${projectPath}/**/models/**/*.ts`,
403
+ `${projectPath}/src/services/**/*.ts`, // Include services folder for inline types
404
+ `${projectPath}/src/types.ts`,
405
+ `${projectPath}/types.ts`,
406
+ ];
407
+ const excludePatterns = [
408
+ "**/node_modules/**",
409
+ "**/*.test.ts",
410
+ "**/*.spec.ts",
411
+ "**/dist/**",
412
+ "**/build/**",
413
+ ];
414
+ for (const pattern of typePatterns) {
415
+ const files = await glob(pattern, {
416
+ ignore: excludePatterns,
417
+ nodir: true,
418
+ absolute: true,
419
+ });
420
+ for (const file of files) {
421
+ try {
422
+ const content = await fs.readFile(file, "utf-8");
423
+ const fileTypes = extractTypesFromFile(content, file);
424
+ types.push(...fileTypes);
425
+ }
426
+ catch (err) {
427
+ logger.debug(`Failed to extract types from ${file}`);
428
+ }
429
+ }
430
+ }
431
+ logger.info(`Extracted ${types.length} types from ${projectPath}`);
432
+ return types;
433
+ }
434
+ /**
435
+ * Extract types/interfaces from a single file using AST
436
+ */
437
+ export function extractTypesFromFile(content, filePath) {
438
+ const types = [];
439
+ try {
440
+ const parser = getParser("typescript");
441
+ const tree = parser.parse(content);
442
+ traverseTypes(tree.rootNode, content, filePath, types);
443
+ }
444
+ catch (err) {
445
+ logger.debug(`AST parsing failed for ${filePath}, falling back to regex`);
446
+ return extractTypesFromFileRegex(content, filePath);
447
+ }
448
+ return types;
449
+ }
450
+ /**
451
+ * Recursively traverse AST to find type definitions
452
+ */
453
+ function traverseTypes(node, content, filePath, types) {
454
+ if (!node)
455
+ return;
456
+ // Interface declaration
457
+ if (node.type === "interface_declaration") {
458
+ const type = extractInterface(node, content, filePath);
459
+ if (type)
460
+ types.push(type);
461
+ }
462
+ // Type alias declaration
463
+ if (node.type === "type_alias_declaration") {
464
+ const type = extractTypeAlias(node, content, filePath);
465
+ if (type)
466
+ types.push(type);
467
+ }
468
+ // Recursively traverse children
469
+ for (const child of node.children || []) {
470
+ traverseTypes(child, content, filePath, types);
471
+ }
472
+ }
473
+ /**
474
+ * Extract interface definition
475
+ */
476
+ function extractInterface(node, content, filePath) {
477
+ const nameNode = node.childForFieldName("name");
478
+ if (!nameNode)
479
+ return null;
480
+ const name = getNodeText(nameNode, content);
481
+ const bodyNode = node.childForFieldName("body");
482
+ if (!bodyNode)
483
+ return null;
484
+ const fields = extractFieldsFromBody(bodyNode, content);
485
+ return {
486
+ name,
487
+ fields,
488
+ file: filePath,
489
+ line: node.startPosition.row + 1,
490
+ kind: "interface",
491
+ };
492
+ }
493
+ /**
494
+ * Extract type alias definition
495
+ */
496
+ function extractTypeAlias(node, content, filePath) {
497
+ const nameNode = node.childForFieldName("name");
498
+ if (!nameNode)
499
+ return null;
500
+ const name = getNodeText(nameNode, content);
501
+ // For object type aliases
502
+ const valueNode = node.childForFieldName("value");
503
+ if (valueNode && valueNode.type === "object_type") {
504
+ const fields = extractFieldsFromBody(valueNode, content);
505
+ return {
506
+ name,
507
+ fields,
508
+ file: filePath,
509
+ line: node.startPosition.row + 1,
510
+ kind: "type",
511
+ };
512
+ }
513
+ return null;
514
+ }
515
+ /**
516
+ * Extract fields from interface/type body
517
+ */
518
+ function extractFieldsFromBody(bodyNode, content) {
519
+ const fields = [];
520
+ for (const child of bodyNode.children || []) {
521
+ if (child.type === "property_signature" || child.type === "field_definition") {
522
+ const nameNode = child.childForFieldName("name");
523
+ const typeNode = child.childForFieldName("type");
524
+ if (nameNode) {
525
+ const name = getNodeText(nameNode, content);
526
+ const type = typeNode ? getNodeText(typeNode, content) : "any";
527
+ // Check if optional
528
+ const isOptional = child.type === "property_signature" &&
529
+ child.children.some((c) => c.type === "?");
530
+ fields.push({
531
+ name,
532
+ type,
533
+ required: !isOptional,
534
+ optional: isOptional,
535
+ });
536
+ }
537
+ }
538
+ }
539
+ return fields;
540
+ }
541
+ /**
542
+ * Fallback regex-based type extraction
543
+ */
544
+ function extractTypesFromFileRegex(content, filePath) {
545
+ const types = [];
546
+ const lines = content.split("\n");
547
+ let currentType = null;
548
+ for (let i = 0; i < lines.length; i++) {
549
+ const line = lines[i];
550
+ // Interface declaration
551
+ const interfaceMatch = line.match(/(?:export\s+)?interface\s+(\w+)(?:\s+extends\s+[^{]+)?\s*\{/);
552
+ if (interfaceMatch) {
553
+ if (currentType) {
554
+ types.push(currentType);
555
+ }
556
+ currentType = {
557
+ name: interfaceMatch[1],
558
+ kind: "interface",
559
+ fields: [],
560
+ file: filePath,
561
+ line: i + 1,
562
+ };
563
+ continue;
564
+ }
565
+ // Type alias declaration
566
+ const typeMatch = line.match(/(?:export\s+)?type\s+(\w+)\s*=\s*\{/);
567
+ if (typeMatch) {
568
+ if (currentType) {
569
+ types.push(currentType);
570
+ }
571
+ currentType = {
572
+ name: typeMatch[1],
573
+ kind: "type",
574
+ fields: [],
575
+ file: filePath,
576
+ line: i + 1,
577
+ };
578
+ continue;
579
+ }
580
+ // Extract field
581
+ if (currentType) {
582
+ const isIndented = line.startsWith(" ") || line.startsWith("\t");
583
+ const isEmpty = line.trim() === "";
584
+ const isComment = line.trim().startsWith("//");
585
+ if (!isIndented && !isEmpty && !isComment) {
586
+ types.push(currentType);
587
+ currentType = null;
588
+ continue;
589
+ }
590
+ const fieldMatch = line.match(/(\w+)(\?)?:\s*([^;\[\{]+)(?:\[\])?(?:\s*;)?/);
591
+ if (fieldMatch) {
592
+ currentType.fields.push({
593
+ name: fieldMatch[1],
594
+ type: fieldMatch[3].trim(),
595
+ required: !fieldMatch[2],
596
+ optional: !!fieldMatch[2],
597
+ });
598
+ }
599
+ }
600
+ }
601
+ if (currentType) {
602
+ types.push(currentType);
603
+ }
604
+ return types;
605
+ }
606
+ // ============================================================================
607
+ // API Configuration Extraction
608
+ // ============================================================================
609
+ /**
610
+ * Extract API configuration from a project
611
+ */
612
+ export async function extractApiConfig(projectPath) {
613
+ let apiBaseUrl = "/api";
614
+ let httpClient = "fetch";
615
+ // Check for API config files
616
+ const configPaths = [
617
+ path.join(projectPath, "src/config/api.ts"),
618
+ path.join(projectPath, "src/lib/api.ts"),
619
+ path.join(projectPath, "lib/api.ts"),
620
+ path.join(projectPath, "utils/api.ts"),
621
+ path.join(projectPath, "src/api/client.ts"),
622
+ path.join(projectPath, "src/services/api.ts"),
623
+ ];
624
+ for (const configPath of configPaths) {
625
+ if (await fileExists(configPath)) {
626
+ try {
627
+ const content = await fs.readFile(configPath, "utf-8");
628
+ // Detect HTTP client
629
+ if (content.includes("axios")) {
630
+ httpClient = "axios";
631
+ }
632
+ else if (content.includes("react-query") || content.includes("useQuery")) {
633
+ httpClient = "react-query";
634
+ }
635
+ else if (content.includes("swr")) {
636
+ httpClient = "swr";
637
+ }
638
+ else if (content.includes("ApiService")) {
639
+ httpClient = "fetch"; // Custom service using fetch
640
+ }
641
+ // Extract base URL
642
+ const baseUrlMatch = content.match(/baseURL\s*[:=]\s*["']([^"']+)["']/) ||
643
+ content.match(/baseUrl\s*[:=]\s*["']([^"']+)["']/) ||
644
+ content.match(/API_BASE_URL\s*[:=]\s*["']([^"']+)["']/);
645
+ if (baseUrlMatch) {
646
+ apiBaseUrl = baseUrlMatch[1];
647
+ }
648
+ break;
649
+ }
650
+ catch {
651
+ // Continue to next file
652
+ }
653
+ }
654
+ }
655
+ return { apiBaseUrl, httpClient };
656
+ }
657
+ async function fileExists(filePath) {
658
+ try {
659
+ const stats = await fs.stat(filePath);
660
+ return stats.isFile();
661
+ }
662
+ catch {
663
+ return false;
664
+ }
665
+ }
666
+ //# sourceMappingURL=typescript.js.map