alita-sdk 0.3.379__py3-none-any.whl → 0.3.627__py3-none-any.whl

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 (278) hide show
  1. alita_sdk/cli/__init__.py +10 -0
  2. alita_sdk/cli/__main__.py +17 -0
  3. alita_sdk/cli/agent/__init__.py +5 -0
  4. alita_sdk/cli/agent/default.py +258 -0
  5. alita_sdk/cli/agent_executor.py +156 -0
  6. alita_sdk/cli/agent_loader.py +245 -0
  7. alita_sdk/cli/agent_ui.py +228 -0
  8. alita_sdk/cli/agents.py +3113 -0
  9. alita_sdk/cli/callbacks.py +647 -0
  10. alita_sdk/cli/cli.py +168 -0
  11. alita_sdk/cli/config.py +306 -0
  12. alita_sdk/cli/context/__init__.py +30 -0
  13. alita_sdk/cli/context/cleanup.py +198 -0
  14. alita_sdk/cli/context/manager.py +731 -0
  15. alita_sdk/cli/context/message.py +285 -0
  16. alita_sdk/cli/context/strategies.py +289 -0
  17. alita_sdk/cli/context/token_estimation.py +127 -0
  18. alita_sdk/cli/formatting.py +182 -0
  19. alita_sdk/cli/input_handler.py +419 -0
  20. alita_sdk/cli/inventory.py +1073 -0
  21. alita_sdk/cli/mcp_loader.py +315 -0
  22. alita_sdk/cli/testcases/__init__.py +94 -0
  23. alita_sdk/cli/testcases/data_generation.py +119 -0
  24. alita_sdk/cli/testcases/discovery.py +96 -0
  25. alita_sdk/cli/testcases/executor.py +84 -0
  26. alita_sdk/cli/testcases/logger.py +85 -0
  27. alita_sdk/cli/testcases/parser.py +172 -0
  28. alita_sdk/cli/testcases/prompts.py +91 -0
  29. alita_sdk/cli/testcases/reporting.py +125 -0
  30. alita_sdk/cli/testcases/setup.py +108 -0
  31. alita_sdk/cli/testcases/test_runner.py +282 -0
  32. alita_sdk/cli/testcases/utils.py +39 -0
  33. alita_sdk/cli/testcases/validation.py +90 -0
  34. alita_sdk/cli/testcases/workflow.py +196 -0
  35. alita_sdk/cli/toolkit.py +327 -0
  36. alita_sdk/cli/toolkit_loader.py +85 -0
  37. alita_sdk/cli/tools/__init__.py +43 -0
  38. alita_sdk/cli/tools/approval.py +224 -0
  39. alita_sdk/cli/tools/filesystem.py +1751 -0
  40. alita_sdk/cli/tools/planning.py +389 -0
  41. alita_sdk/cli/tools/terminal.py +414 -0
  42. alita_sdk/community/__init__.py +72 -12
  43. alita_sdk/community/inventory/__init__.py +236 -0
  44. alita_sdk/community/inventory/config.py +257 -0
  45. alita_sdk/community/inventory/enrichment.py +2137 -0
  46. alita_sdk/community/inventory/extractors.py +1469 -0
  47. alita_sdk/community/inventory/ingestion.py +3172 -0
  48. alita_sdk/community/inventory/knowledge_graph.py +1457 -0
  49. alita_sdk/community/inventory/parsers/__init__.py +218 -0
  50. alita_sdk/community/inventory/parsers/base.py +295 -0
  51. alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
  52. alita_sdk/community/inventory/parsers/go_parser.py +851 -0
  53. alita_sdk/community/inventory/parsers/html_parser.py +389 -0
  54. alita_sdk/community/inventory/parsers/java_parser.py +593 -0
  55. alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
  56. alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
  57. alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
  58. alita_sdk/community/inventory/parsers/python_parser.py +604 -0
  59. alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
  60. alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
  61. alita_sdk/community/inventory/parsers/text_parser.py +322 -0
  62. alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
  63. alita_sdk/community/inventory/patterns/__init__.py +61 -0
  64. alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
  65. alita_sdk/community/inventory/patterns/loader.py +348 -0
  66. alita_sdk/community/inventory/patterns/registry.py +198 -0
  67. alita_sdk/community/inventory/presets.py +535 -0
  68. alita_sdk/community/inventory/retrieval.py +1403 -0
  69. alita_sdk/community/inventory/toolkit.py +173 -0
  70. alita_sdk/community/inventory/toolkit_utils.py +176 -0
  71. alita_sdk/community/inventory/visualize.py +1370 -0
  72. alita_sdk/configurations/__init__.py +1 -1
  73. alita_sdk/configurations/ado.py +141 -20
  74. alita_sdk/configurations/bitbucket.py +94 -2
  75. alita_sdk/configurations/confluence.py +130 -1
  76. alita_sdk/configurations/figma.py +76 -0
  77. alita_sdk/configurations/gitlab.py +91 -0
  78. alita_sdk/configurations/jira.py +103 -0
  79. alita_sdk/configurations/openapi.py +329 -0
  80. alita_sdk/configurations/qtest.py +72 -1
  81. alita_sdk/configurations/report_portal.py +96 -0
  82. alita_sdk/configurations/sharepoint.py +148 -0
  83. alita_sdk/configurations/testio.py +83 -0
  84. alita_sdk/configurations/testrail.py +88 -0
  85. alita_sdk/configurations/xray.py +93 -0
  86. alita_sdk/configurations/zephyr_enterprise.py +93 -0
  87. alita_sdk/configurations/zephyr_essential.py +75 -0
  88. alita_sdk/runtime/clients/artifact.py +3 -3
  89. alita_sdk/runtime/clients/client.py +388 -46
  90. alita_sdk/runtime/clients/mcp_discovery.py +342 -0
  91. alita_sdk/runtime/clients/mcp_manager.py +262 -0
  92. alita_sdk/runtime/clients/sandbox_client.py +8 -21
  93. alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
  94. alita_sdk/runtime/langchain/assistant.py +157 -39
  95. alita_sdk/runtime/langchain/constants.py +647 -1
  96. alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
  97. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +103 -60
  98. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
  99. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -4
  100. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +226 -7
  101. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
  102. alita_sdk/runtime/langchain/document_loaders/constants.py +40 -19
  103. alita_sdk/runtime/langchain/langraph_agent.py +405 -84
  104. alita_sdk/runtime/langchain/utils.py +106 -7
  105. alita_sdk/runtime/llms/preloaded.py +2 -6
  106. alita_sdk/runtime/models/mcp_models.py +61 -0
  107. alita_sdk/runtime/skills/__init__.py +91 -0
  108. alita_sdk/runtime/skills/callbacks.py +498 -0
  109. alita_sdk/runtime/skills/discovery.py +540 -0
  110. alita_sdk/runtime/skills/executor.py +610 -0
  111. alita_sdk/runtime/skills/input_builder.py +371 -0
  112. alita_sdk/runtime/skills/models.py +330 -0
  113. alita_sdk/runtime/skills/registry.py +355 -0
  114. alita_sdk/runtime/skills/skill_runner.py +330 -0
  115. alita_sdk/runtime/toolkits/__init__.py +31 -0
  116. alita_sdk/runtime/toolkits/application.py +29 -10
  117. alita_sdk/runtime/toolkits/artifact.py +20 -11
  118. alita_sdk/runtime/toolkits/datasource.py +13 -6
  119. alita_sdk/runtime/toolkits/mcp.py +783 -0
  120. alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
  121. alita_sdk/runtime/toolkits/planning.py +178 -0
  122. alita_sdk/runtime/toolkits/skill_router.py +238 -0
  123. alita_sdk/runtime/toolkits/subgraph.py +251 -6
  124. alita_sdk/runtime/toolkits/tools.py +356 -69
  125. alita_sdk/runtime/toolkits/vectorstore.py +11 -5
  126. alita_sdk/runtime/tools/__init__.py +10 -3
  127. alita_sdk/runtime/tools/application.py +27 -6
  128. alita_sdk/runtime/tools/artifact.py +511 -28
  129. alita_sdk/runtime/tools/data_analysis.py +183 -0
  130. alita_sdk/runtime/tools/function.py +67 -35
  131. alita_sdk/runtime/tools/graph.py +10 -4
  132. alita_sdk/runtime/tools/image_generation.py +148 -46
  133. alita_sdk/runtime/tools/llm.py +1003 -128
  134. alita_sdk/runtime/tools/loop.py +3 -1
  135. alita_sdk/runtime/tools/loop_output.py +3 -1
  136. alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
  137. alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
  138. alita_sdk/runtime/tools/mcp_server_tool.py +8 -5
  139. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  140. alita_sdk/runtime/tools/planning/models.py +246 -0
  141. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  142. alita_sdk/runtime/tools/router.py +2 -4
  143. alita_sdk/runtime/tools/sandbox.py +65 -48
  144. alita_sdk/runtime/tools/skill_router.py +776 -0
  145. alita_sdk/runtime/tools/tool.py +3 -1
  146. alita_sdk/runtime/tools/vectorstore.py +9 -3
  147. alita_sdk/runtime/tools/vectorstore_base.py +70 -14
  148. alita_sdk/runtime/utils/AlitaCallback.py +137 -21
  149. alita_sdk/runtime/utils/constants.py +5 -1
  150. alita_sdk/runtime/utils/mcp_client.py +492 -0
  151. alita_sdk/runtime/utils/mcp_oauth.py +361 -0
  152. alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
  153. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  154. alita_sdk/runtime/utils/serialization.py +155 -0
  155. alita_sdk/runtime/utils/streamlit.py +40 -13
  156. alita_sdk/runtime/utils/toolkit_utils.py +30 -9
  157. alita_sdk/runtime/utils/utils.py +36 -0
  158. alita_sdk/tools/__init__.py +134 -35
  159. alita_sdk/tools/ado/repos/__init__.py +51 -32
  160. alita_sdk/tools/ado/repos/repos_wrapper.py +148 -89
  161. alita_sdk/tools/ado/test_plan/__init__.py +25 -9
  162. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +23 -1
  163. alita_sdk/tools/ado/utils.py +1 -18
  164. alita_sdk/tools/ado/wiki/__init__.py +25 -12
  165. alita_sdk/tools/ado/wiki/ado_wrapper.py +291 -22
  166. alita_sdk/tools/ado/work_item/__init__.py +26 -13
  167. alita_sdk/tools/ado/work_item/ado_wrapper.py +73 -11
  168. alita_sdk/tools/advanced_jira_mining/__init__.py +11 -8
  169. alita_sdk/tools/aws/delta_lake/__init__.py +13 -9
  170. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  171. alita_sdk/tools/azure_ai/search/__init__.py +11 -8
  172. alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
  173. alita_sdk/tools/base/tool.py +5 -1
  174. alita_sdk/tools/base_indexer_toolkit.py +271 -84
  175. alita_sdk/tools/bitbucket/__init__.py +17 -11
  176. alita_sdk/tools/bitbucket/api_wrapper.py +59 -11
  177. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +49 -35
  178. alita_sdk/tools/browser/__init__.py +5 -4
  179. alita_sdk/tools/carrier/__init__.py +5 -6
  180. alita_sdk/tools/carrier/backend_reports_tool.py +6 -6
  181. alita_sdk/tools/carrier/run_ui_test_tool.py +6 -6
  182. alita_sdk/tools/carrier/ui_reports_tool.py +5 -5
  183. alita_sdk/tools/chunkers/__init__.py +3 -1
  184. alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
  185. alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
  186. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  187. alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
  188. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  189. alita_sdk/tools/cloud/aws/__init__.py +10 -7
  190. alita_sdk/tools/cloud/azure/__init__.py +10 -7
  191. alita_sdk/tools/cloud/gcp/__init__.py +10 -7
  192. alita_sdk/tools/cloud/k8s/__init__.py +10 -7
  193. alita_sdk/tools/code/linter/__init__.py +10 -8
  194. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  195. alita_sdk/tools/code/sonar/__init__.py +11 -8
  196. alita_sdk/tools/code_indexer_toolkit.py +82 -22
  197. alita_sdk/tools/confluence/__init__.py +22 -16
  198. alita_sdk/tools/confluence/api_wrapper.py +107 -30
  199. alita_sdk/tools/confluence/loader.py +14 -2
  200. alita_sdk/tools/custom_open_api/__init__.py +12 -5
  201. alita_sdk/tools/elastic/__init__.py +11 -8
  202. alita_sdk/tools/elitea_base.py +493 -30
  203. alita_sdk/tools/figma/__init__.py +58 -11
  204. alita_sdk/tools/figma/api_wrapper.py +1235 -143
  205. alita_sdk/tools/figma/figma_client.py +73 -0
  206. alita_sdk/tools/figma/toon_tools.py +2748 -0
  207. alita_sdk/tools/github/__init__.py +14 -15
  208. alita_sdk/tools/github/github_client.py +224 -100
  209. alita_sdk/tools/github/graphql_client_wrapper.py +119 -33
  210. alita_sdk/tools/github/schemas.py +14 -5
  211. alita_sdk/tools/github/tool.py +5 -1
  212. alita_sdk/tools/github/tool_prompts.py +9 -22
  213. alita_sdk/tools/gitlab/__init__.py +16 -11
  214. alita_sdk/tools/gitlab/api_wrapper.py +218 -48
  215. alita_sdk/tools/gitlab_org/__init__.py +10 -9
  216. alita_sdk/tools/gitlab_org/api_wrapper.py +63 -64
  217. alita_sdk/tools/google/bigquery/__init__.py +13 -12
  218. alita_sdk/tools/google/bigquery/tool.py +5 -1
  219. alita_sdk/tools/google_places/__init__.py +11 -8
  220. alita_sdk/tools/google_places/api_wrapper.py +1 -1
  221. alita_sdk/tools/jira/__init__.py +17 -10
  222. alita_sdk/tools/jira/api_wrapper.py +92 -41
  223. alita_sdk/tools/keycloak/__init__.py +11 -8
  224. alita_sdk/tools/localgit/__init__.py +9 -3
  225. alita_sdk/tools/localgit/local_git.py +62 -54
  226. alita_sdk/tools/localgit/tool.py +5 -1
  227. alita_sdk/tools/memory/__init__.py +12 -4
  228. alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
  229. alita_sdk/tools/ocr/__init__.py +11 -8
  230. alita_sdk/tools/openapi/__init__.py +491 -106
  231. alita_sdk/tools/openapi/api_wrapper.py +1368 -0
  232. alita_sdk/tools/openapi/tool.py +20 -0
  233. alita_sdk/tools/pandas/__init__.py +20 -12
  234. alita_sdk/tools/pandas/api_wrapper.py +38 -25
  235. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  236. alita_sdk/tools/postman/__init__.py +10 -9
  237. alita_sdk/tools/pptx/__init__.py +11 -10
  238. alita_sdk/tools/pptx/pptx_wrapper.py +1 -1
  239. alita_sdk/tools/qtest/__init__.py +31 -11
  240. alita_sdk/tools/qtest/api_wrapper.py +2135 -86
  241. alita_sdk/tools/rally/__init__.py +10 -9
  242. alita_sdk/tools/rally/api_wrapper.py +1 -1
  243. alita_sdk/tools/report_portal/__init__.py +12 -8
  244. alita_sdk/tools/salesforce/__init__.py +10 -8
  245. alita_sdk/tools/servicenow/__init__.py +17 -15
  246. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  247. alita_sdk/tools/sharepoint/__init__.py +10 -7
  248. alita_sdk/tools/sharepoint/api_wrapper.py +129 -38
  249. alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
  250. alita_sdk/tools/sharepoint/utils.py +8 -2
  251. alita_sdk/tools/slack/__init__.py +10 -7
  252. alita_sdk/tools/slack/api_wrapper.py +2 -2
  253. alita_sdk/tools/sql/__init__.py +12 -9
  254. alita_sdk/tools/testio/__init__.py +10 -7
  255. alita_sdk/tools/testrail/__init__.py +11 -10
  256. alita_sdk/tools/testrail/api_wrapper.py +1 -1
  257. alita_sdk/tools/utils/__init__.py +9 -4
  258. alita_sdk/tools/utils/content_parser.py +103 -18
  259. alita_sdk/tools/utils/text_operations.py +410 -0
  260. alita_sdk/tools/utils/tool_prompts.py +79 -0
  261. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +30 -13
  262. alita_sdk/tools/xray/__init__.py +13 -9
  263. alita_sdk/tools/yagmail/__init__.py +9 -3
  264. alita_sdk/tools/zephyr/__init__.py +10 -7
  265. alita_sdk/tools/zephyr_enterprise/__init__.py +11 -7
  266. alita_sdk/tools/zephyr_essential/__init__.py +10 -7
  267. alita_sdk/tools/zephyr_essential/api_wrapper.py +30 -13
  268. alita_sdk/tools/zephyr_essential/client.py +2 -2
  269. alita_sdk/tools/zephyr_scale/__init__.py +11 -8
  270. alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
  271. alita_sdk/tools/zephyr_squad/__init__.py +10 -7
  272. {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/METADATA +154 -8
  273. alita_sdk-0.3.627.dist-info/RECORD +468 -0
  274. alita_sdk-0.3.627.dist-info/entry_points.txt +2 -0
  275. alita_sdk-0.3.379.dist-info/RECORD +0 -360
  276. {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/WHEEL +0 -0
  277. {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/licenses/LICENSE +0 -0
  278. {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,851 @@
1
+ """
2
+ Go Parser - Regex-based parser for Go source files.
3
+
4
+ Extracts symbols and relationships from .go files using comprehensive
5
+ regex patterns. Supports Go-specific features like interfaces, goroutines,
6
+ channels, defer, and struct embedding.
7
+ """
8
+
9
+ import re
10
+ from typing import Dict, List, Optional, Set, Tuple
11
+ from pathlib import Path
12
+ from concurrent.futures import ThreadPoolExecutor
13
+ import logging
14
+
15
+ from .base import (
16
+ BaseParser,
17
+ ParseResult,
18
+ Symbol,
19
+ Relationship,
20
+ RelationshipType,
21
+ SymbolType,
22
+ Scope,
23
+ Position,
24
+ Range,
25
+ parser_registry,
26
+ )
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+ from typing import Any
31
+
32
+
33
+ # Comprehensive Go regex patterns
34
+ PATTERNS = {
35
+ # Package declaration
36
+ 'package': re.compile(
37
+ r'^\s*package\s+(\w+)',
38
+ re.MULTILINE
39
+ ),
40
+
41
+ # Import statements
42
+ 'import_single': re.compile(
43
+ r'^\s*import\s+(?:(\w+)\s+)?"([^"]+)"',
44
+ re.MULTILINE
45
+ ),
46
+ 'import_block': re.compile(
47
+ r'import\s*\(\s*([\s\S]*?)\s*\)',
48
+ re.MULTILINE
49
+ ),
50
+ 'import_line': re.compile(
51
+ r'^\s*(?:(\w+)\s+)?"([^"]+)"',
52
+ re.MULTILINE
53
+ ),
54
+
55
+ # Struct declarations
56
+ 'struct': re.compile(
57
+ r'^\s*type\s+(\w+)\s+struct\s*\{',
58
+ re.MULTILINE
59
+ ),
60
+
61
+ # Interface declarations
62
+ 'interface': re.compile(
63
+ r'^\s*type\s+(\w+)\s+interface\s*\{',
64
+ re.MULTILINE
65
+ ),
66
+
67
+ # Type alias and definitions
68
+ 'type_alias': re.compile(
69
+ r'^\s*type\s+(\w+)\s*=\s*([^\n{]+)',
70
+ re.MULTILINE
71
+ ),
72
+ 'type_def': re.compile(
73
+ r'^\s*type\s+(\w+)\s+([^\n={]+)',
74
+ re.MULTILINE
75
+ ),
76
+
77
+ # Function declarations
78
+ 'function': re.compile(
79
+ r'^\s*func\s+(\w+)\s*(?:\[[^\]]+\])?\s*\([^)]*\)\s*(?:\([^)]*\)|[^\n{]+)?',
80
+ re.MULTILINE
81
+ ),
82
+
83
+ # Method declarations (with receiver)
84
+ 'method': re.compile(
85
+ r'^\s*func\s+\(\s*(\w+)\s+\*?(\w+)\s*\)\s*(\w+)\s*(?:\[[^\]]+\])?\s*\([^)]*\)',
86
+ re.MULTILINE
87
+ ),
88
+
89
+ # Variable declarations
90
+ 'var': re.compile(
91
+ r'^\s*var\s+(\w+)\s+([^\n=]+)',
92
+ re.MULTILINE
93
+ ),
94
+ 'var_block': re.compile(
95
+ r'var\s*\(\s*([\s\S]*?)\s*\)',
96
+ re.MULTILINE
97
+ ),
98
+
99
+ # Constant declarations
100
+ 'const': re.compile(
101
+ r'^\s*const\s+(\w+)\s*(?:([^\n=]+))?\s*=',
102
+ re.MULTILINE
103
+ ),
104
+ 'const_block': re.compile(
105
+ r'const\s*\(\s*([\s\S]*?)\s*\)',
106
+ re.MULTILINE
107
+ ),
108
+
109
+ # Struct field with embedded type
110
+ 'embedded_type': re.compile(
111
+ r'^\s*\*?([A-Z]\w*)\s*$',
112
+ re.MULTILINE
113
+ ),
114
+
115
+ # Struct field with type
116
+ 'struct_field': re.compile(
117
+ r'^\s*(\w+)\s+(\*?\[?\]?\*?(?:map\[[^\]]+\])?[A-Z]\w*)',
118
+ re.MULTILINE
119
+ ),
120
+
121
+ # Interface method
122
+ 'interface_method': re.compile(
123
+ r'^\s*(\w+)\s*\([^)]*\)',
124
+ re.MULTILINE
125
+ ),
126
+
127
+ # Function calls
128
+ 'function_call': re.compile(
129
+ r'(?:^|[^\w.])(\w+)\s*\(',
130
+ re.MULTILINE
131
+ ),
132
+
133
+ # Method calls
134
+ 'method_call': re.compile(
135
+ r'\.(\w+)\s*\(',
136
+ re.MULTILINE
137
+ ),
138
+
139
+ # Type assertions
140
+ 'type_assertion': re.compile(
141
+ r'\.\(\s*\*?(\w+)\s*\)',
142
+ re.MULTILINE
143
+ ),
144
+
145
+ # Struct literal / composite literal
146
+ 'struct_literal': re.compile(
147
+ r'([A-Z]\w*)\s*\{',
148
+ re.MULTILINE
149
+ ),
150
+
151
+ # Package qualified access
152
+ 'pkg_access': re.compile(
153
+ r'(\w+)\.([A-Z]\w*)',
154
+ re.MULTILINE
155
+ ),
156
+
157
+ # Goroutine
158
+ 'goroutine': re.compile(
159
+ r'\bgo\s+(\w+)',
160
+ re.MULTILINE
161
+ ),
162
+
163
+ # Channel operations
164
+ 'channel_make': re.compile(
165
+ r'make\s*\(\s*chan\s+([^\),]+)',
166
+ re.MULTILINE
167
+ ),
168
+
169
+ # Defer statement
170
+ 'defer': re.compile(
171
+ r'\bdefer\s+(\w+)',
172
+ re.MULTILINE
173
+ ),
174
+
175
+ # Error handling pattern
176
+ 'error_return': re.compile(
177
+ r'return\s+(?:\w+,\s*)?(\w+Error|errors\.New|fmt\.Errorf)',
178
+ re.MULTILINE
179
+ ),
180
+
181
+ # Doc comments
182
+ 'doc_comment': re.compile(
183
+ r'^//\s*(.+)',
184
+ re.MULTILINE
185
+ ),
186
+
187
+ # Build tags
188
+ 'build_tag': re.compile(
189
+ r'//go:build\s+(.+)',
190
+ re.MULTILINE
191
+ ),
192
+ 'plus_build': re.compile(
193
+ r'//\s*\+build\s+(.+)',
194
+ re.MULTILINE
195
+ ),
196
+ }
197
+
198
+
199
+ class GoParser(BaseParser):
200
+ """Go source code parser using regex patterns."""
201
+
202
+ # Global symbol registry for cross-file resolution
203
+ _global_symbols: Dict[str, Set[str]] = {}
204
+ _symbol_to_file: Dict[str, str] = {}
205
+
206
+ def __init__(self):
207
+ super().__init__("go")
208
+
209
+ def _get_supported_extensions(self) -> Set[str]:
210
+ return {'.go'}
211
+
212
+ def _make_range(self, content: str, start_offset: int, end_line: int) -> Range:
213
+ """Create a Range object from content and offset."""
214
+ start_line = content[:start_offset].count('\n') + 1
215
+ last_newline = content.rfind('\n', 0, start_offset)
216
+ start_col = start_offset - last_newline - 1 if last_newline >= 0 else start_offset
217
+ return Range(
218
+ start=Position(line=start_line, column=start_col),
219
+ end=Position(line=end_line, column=0)
220
+ )
221
+
222
+ def _make_symbol(
223
+ self,
224
+ name: str,
225
+ symbol_type: SymbolType,
226
+ content: str,
227
+ file_path: str,
228
+ start_offset: int,
229
+ end_line: int,
230
+ scope: Scope = Scope.GLOBAL,
231
+ parent: Optional[str] = None,
232
+ full_name: Optional[str] = None,
233
+ docstring: Optional[str] = None,
234
+ visibility: Optional[str] = None,
235
+ is_static: bool = False,
236
+ is_async: bool = False,
237
+ return_type: Optional[str] = None,
238
+ metadata: Optional[Dict[str, Any]] = None
239
+ ) -> Symbol:
240
+ """Create a Symbol with correct fields."""
241
+ return Symbol(
242
+ name=name,
243
+ symbol_type=symbol_type,
244
+ scope=scope,
245
+ range=self._make_range(content, start_offset, end_line),
246
+ file_path=file_path,
247
+ parent_symbol=parent,
248
+ full_name=full_name,
249
+ visibility=visibility,
250
+ is_static=is_static,
251
+ is_async=is_async,
252
+ docstring=docstring,
253
+ return_type=return_type,
254
+ metadata=metadata or {}
255
+ )
256
+
257
+ def _make_relationship(
258
+ self,
259
+ source: str,
260
+ target: str,
261
+ rel_type: RelationshipType,
262
+ file_path: str,
263
+ content: str,
264
+ offset: int,
265
+ metadata: Optional[Dict[str, Any]] = None
266
+ ) -> Relationship:
267
+ """Create a Relationship with correct fields."""
268
+ return Relationship(
269
+ source_symbol=source,
270
+ target_symbol=target,
271
+ relationship_type=rel_type,
272
+ source_file=file_path,
273
+ source_range=self._make_range(content, offset, content[:offset].count('\n') + 1),
274
+ metadata=metadata or {}
275
+ )
276
+
277
+ def parse_file(self, file_path: str, content: Optional[str] = None) -> ParseResult:
278
+ """Parse Go source code and extract symbols and relationships."""
279
+ if content is None:
280
+ try:
281
+ with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
282
+ content = f.read()
283
+ except Exception as e:
284
+ return ParseResult(
285
+ file_path=file_path,
286
+ language=self.language,
287
+ symbols=[],
288
+ relationships=[],
289
+ errors=[str(e)]
290
+ )
291
+
292
+ symbols = self._extract_symbols(content, file_path)
293
+ relationships = self._extract_relationships(content, file_path, symbols)
294
+
295
+ return ParseResult(
296
+ symbols=symbols,
297
+ relationships=relationships,
298
+ file_path=file_path,
299
+ language=self.language
300
+ )
301
+
302
+ def _extract_symbols(self, content: str, file_path: str) -> List[Symbol]:
303
+ """Extract all symbols from Go source code."""
304
+ symbols = []
305
+ package_name = self._extract_package(content)
306
+
307
+ # Extract structs
308
+ for match in PATTERNS['struct'].finditer(content):
309
+ name = match.group(1)
310
+
311
+ docstring = self._find_preceding_doc(content, match.start())
312
+ is_exported = name[0].isupper()
313
+
314
+ # Find embedded types in struct
315
+ struct_content = self._extract_block_content(content, match.end())
316
+ embedded = self._find_embedded_types(struct_content)
317
+
318
+ metadata = {'exported': is_exported}
319
+ if embedded:
320
+ metadata['embedded_types'] = embedded
321
+
322
+ symbols.append(self._make_symbol(
323
+ name=name,
324
+ symbol_type=SymbolType.CLASS,
325
+ content=content,
326
+ file_path=file_path,
327
+ start_offset=match.start(),
328
+ end_line=self._find_block_end(content, match.end()),
329
+ full_name=f"{package_name}.{name}" if package_name else name,
330
+ docstring=docstring,
331
+ visibility='public' if is_exported else 'private',
332
+ metadata=metadata
333
+ ))
334
+
335
+ # Extract interfaces
336
+ for match in PATTERNS['interface'].finditer(content):
337
+ name = match.group(1)
338
+
339
+ docstring = self._find_preceding_doc(content, match.start())
340
+ is_exported = name[0].isupper()
341
+
342
+ # Find embedded interfaces
343
+ iface_content = self._extract_block_content(content, match.end())
344
+ embedded = self._find_embedded_types(iface_content)
345
+
346
+ metadata = {'exported': is_exported}
347
+ if embedded:
348
+ metadata['embedded_interfaces'] = embedded
349
+
350
+ symbols.append(self._make_symbol(
351
+ name=name,
352
+ symbol_type=SymbolType.INTERFACE,
353
+ content=content,
354
+ file_path=file_path,
355
+ start_offset=match.start(),
356
+ end_line=self._find_block_end(content, match.end()),
357
+ full_name=f"{package_name}.{name}" if package_name else name,
358
+ docstring=docstring,
359
+ visibility='public' if is_exported else 'private',
360
+ metadata=metadata
361
+ ))
362
+
363
+ # Extract type aliases
364
+ for match in PATTERNS['type_alias'].finditer(content):
365
+ name, aliased = match.groups()
366
+ line = content[:match.start()].count('\n') + 1
367
+
368
+ # Skip if it's actually a struct or interface (handled above)
369
+ if 'struct' in aliased or 'interface' in aliased:
370
+ continue
371
+
372
+ is_exported = name[0].isupper()
373
+
374
+ symbols.append(self._make_symbol(
375
+ name=name,
376
+ symbol_type=SymbolType.TYPE_ALIAS,
377
+ content=content,
378
+ file_path=file_path,
379
+ start_offset=match.start(),
380
+ end_line=line,
381
+ full_name=f"{package_name}.{name}" if package_name else name,
382
+ visibility='public' if is_exported else 'private',
383
+ metadata={
384
+ 'exported': is_exported,
385
+ 'aliased_type': aliased.strip()
386
+ }
387
+ ))
388
+
389
+ # Extract type definitions (non-alias, non-struct, non-interface)
390
+ for match in PATTERNS['type_def'].finditer(content):
391
+ name, underlying = match.groups()
392
+ line = content[:match.start()].count('\n') + 1
393
+
394
+ # Skip struct, interface, and already handled aliases
395
+ if 'struct' in underlying or 'interface' in underlying or '=' in underlying:
396
+ continue
397
+
398
+ is_exported = name[0].isupper()
399
+
400
+ symbols.append(self._make_symbol(
401
+ name=name,
402
+ symbol_type=SymbolType.TYPE_ALIAS,
403
+ content=content,
404
+ file_path=file_path,
405
+ start_offset=match.start(),
406
+ end_line=line,
407
+ full_name=f"{package_name}.{name}" if package_name else name,
408
+ visibility='public' if is_exported else 'private',
409
+ metadata={
410
+ 'exported': is_exported,
411
+ 'underlying_type': underlying.strip()
412
+ }
413
+ ))
414
+
415
+ # Extract functions
416
+ for match in PATTERNS['function'].finditer(content):
417
+ name = match.group(1)
418
+
419
+ docstring = self._find_preceding_doc(content, match.start())
420
+ is_exported = name[0].isupper()
421
+
422
+ # Parse return type if present
423
+ full_match = match.group(0)
424
+ return_type = self._extract_return_type(full_match)
425
+
426
+ metadata = {'exported': is_exported}
427
+ if return_type:
428
+ metadata['return_type'] = return_type
429
+
430
+ symbols.append(self._make_symbol(
431
+ name=name,
432
+ symbol_type=SymbolType.FUNCTION,
433
+ content=content,
434
+ file_path=file_path,
435
+ start_offset=match.start(),
436
+ end_line=self._find_block_end(content, match.end()),
437
+ full_name=f"{package_name}.{name}" if package_name else name,
438
+ docstring=docstring,
439
+ visibility='public' if is_exported else 'private',
440
+ return_type=return_type,
441
+ metadata=metadata
442
+ ))
443
+
444
+ # Extract methods
445
+ for match in PATTERNS['method'].finditer(content):
446
+ receiver_name, receiver_type, method_name = match.groups()
447
+
448
+ docstring = self._find_preceding_doc(content, match.start())
449
+ is_exported = method_name[0].isupper()
450
+
451
+ symbols.append(self._make_symbol(
452
+ name=method_name,
453
+ symbol_type=SymbolType.METHOD,
454
+ content=content,
455
+ file_path=file_path,
456
+ start_offset=match.start(),
457
+ end_line=self._find_block_end(content, match.end()),
458
+ full_name=f"{package_name}.{receiver_type}.{method_name}" if package_name else f"{receiver_type}.{method_name}",
459
+ parent=receiver_type,
460
+ docstring=docstring,
461
+ visibility='public' if is_exported else 'private',
462
+ metadata={
463
+ 'exported': is_exported,
464
+ 'receiver_type': receiver_type,
465
+ 'receiver_name': receiver_name
466
+ }
467
+ ))
468
+
469
+ # Extract package-level variables
470
+ for match in PATTERNS['var'].finditer(content):
471
+ name, var_type = match.groups()
472
+ line = content[:match.start()].count('\n') + 1
473
+
474
+ is_exported = name[0].isupper()
475
+
476
+ symbols.append(self._make_symbol(
477
+ name=name,
478
+ symbol_type=SymbolType.VARIABLE,
479
+ content=content,
480
+ file_path=file_path,
481
+ start_offset=match.start(),
482
+ end_line=line,
483
+ full_name=f"{package_name}.{name}" if package_name else name,
484
+ visibility='public' if is_exported else 'private',
485
+ metadata={
486
+ 'exported': is_exported,
487
+ 'type': var_type.strip()
488
+ }
489
+ ))
490
+
491
+ # Extract constants
492
+ for match in PATTERNS['const'].finditer(content):
493
+ name, const_type = match.groups()
494
+ line = content[:match.start()].count('\n') + 1
495
+
496
+ is_exported = name[0].isupper()
497
+
498
+ metadata = {'exported': is_exported}
499
+ if const_type:
500
+ metadata['type'] = const_type.strip()
501
+
502
+ symbols.append(self._make_symbol(
503
+ name=name,
504
+ symbol_type=SymbolType.CONSTANT,
505
+ content=content,
506
+ file_path=file_path,
507
+ start_offset=match.start(),
508
+ end_line=line,
509
+ full_name=f"{package_name}.{name}" if package_name else name,
510
+ visibility='public' if is_exported else 'private',
511
+ metadata=metadata
512
+ ))
513
+
514
+ return symbols
515
+
516
+ def _extract_relationships(
517
+ self,
518
+ content: str,
519
+ file_path: str,
520
+ symbols: List[Symbol]
521
+ ) -> List[Relationship]:
522
+ """Extract relationships from Go source code."""
523
+ relationships = []
524
+ current_scope = Path(file_path).stem
525
+ package_name = self._extract_package(content)
526
+
527
+ # Extract single imports
528
+ for match in PATTERNS['import_single'].finditer(content):
529
+ alias, path = match.groups()
530
+
531
+ relationships.append(self._make_relationship(
532
+ source=package_name or current_scope,
533
+ target=path,
534
+ rel_type=RelationshipType.IMPORTS,
535
+ file_path=file_path,
536
+ content=content,
537
+ offset=match.start(),
538
+ metadata={'alias': alias} if alias else None
539
+ ))
540
+
541
+ # Extract import blocks
542
+ for match in PATTERNS['import_block'].finditer(content):
543
+ block_content = match.group(1)
544
+
545
+ for line_match in PATTERNS['import_line'].finditer(block_content):
546
+ alias, path = line_match.groups()
547
+
548
+ metadata = {}
549
+ if alias:
550
+ metadata['alias'] = alias
551
+ if alias == '_':
552
+ metadata['blank_import'] = True
553
+
554
+ relationships.append(self._make_relationship(
555
+ source=package_name or current_scope,
556
+ target=path,
557
+ rel_type=RelationshipType.IMPORTS,
558
+ file_path=file_path,
559
+ content=content,
560
+ offset=match.start(),
561
+ metadata=metadata if metadata else None
562
+ ))
563
+
564
+ # Extract struct embedding (composition)
565
+ for match in PATTERNS['struct'].finditer(content):
566
+ struct_name = match.group(1)
567
+
568
+ struct_content = self._extract_block_content(content, match.end())
569
+ embedded = self._find_embedded_types(struct_content)
570
+
571
+ for embedded_type in embedded:
572
+ relationships.append(self._make_relationship(
573
+ source=struct_name,
574
+ target=embedded_type,
575
+ rel_type=RelationshipType.COMPOSITION,
576
+ file_path=file_path,
577
+ content=content,
578
+ offset=match.start(),
579
+ metadata={'embedding': True}
580
+ ))
581
+
582
+ # Extract interface embedding
583
+ for match in PATTERNS['interface'].finditer(content):
584
+ iface_name = match.group(1)
585
+
586
+ iface_content = self._extract_block_content(content, match.end())
587
+ embedded = self._find_embedded_types(iface_content)
588
+
589
+ for embedded_iface in embedded:
590
+ relationships.append(self._make_relationship(
591
+ source=iface_name,
592
+ target=embedded_iface,
593
+ rel_type=RelationshipType.INHERITANCE,
594
+ file_path=file_path,
595
+ content=content,
596
+ offset=match.start(),
597
+ metadata={'embedding': True}
598
+ ))
599
+
600
+ # Extract method relationships (receiver type)
601
+ for match in PATTERNS['method'].finditer(content):
602
+ _, receiver_type, method_name = match.groups()
603
+
604
+ relationships.append(self._make_relationship(
605
+ source=method_name,
606
+ target=receiver_type,
607
+ rel_type=RelationshipType.CONTAINS,
608
+ file_path=file_path,
609
+ content=content,
610
+ offset=match.start()
611
+ ))
612
+
613
+ # Extract function calls
614
+ symbol_names = {s.name for s in symbols}
615
+ for match in PATTERNS['function_call'].finditer(content):
616
+ func_name = match.group(1)
617
+
618
+ # Skip keywords, builtins, and local symbols
619
+ if func_name not in symbol_names and func_name not in {
620
+ 'if', 'for', 'switch', 'select', 'go', 'defer', 'return', 'range',
621
+ 'make', 'new', 'len', 'cap', 'append', 'copy', 'delete', 'close',
622
+ 'panic', 'recover', 'print', 'println', 'complex', 'real', 'imag',
623
+ 'func', 'type', 'var', 'const', 'map', 'chan', 'interface', 'struct'
624
+ }:
625
+ relationships.append(self._make_relationship(
626
+ source=current_scope,
627
+ target=func_name,
628
+ rel_type=RelationshipType.CALLS,
629
+ file_path=file_path,
630
+ content=content,
631
+ offset=match.start()
632
+ ))
633
+
634
+ # Extract package-qualified calls
635
+ for match in PATTERNS['pkg_access'].finditer(content):
636
+ pkg, name = match.groups()
637
+
638
+ # Skip if pkg looks like a variable (lowercase)
639
+ if pkg[0].islower() and pkg not in {'os', 'io', 'fmt', 'log', 'net', 'http', 'sync', 'time', 'json', 'xml', 'sql'}:
640
+ continue
641
+
642
+ relationships.append(self._make_relationship(
643
+ source=current_scope,
644
+ target=f"{pkg}.{name}",
645
+ rel_type=RelationshipType.REFERENCES,
646
+ file_path=file_path,
647
+ content=content,
648
+ offset=match.start()
649
+ ))
650
+
651
+ # Extract struct literal usage (instantiation)
652
+ for match in PATTERNS['struct_literal'].finditer(content):
653
+ type_name = match.group(1)
654
+
655
+ if type_name not in symbol_names:
656
+ relationships.append(self._make_relationship(
657
+ source=current_scope,
658
+ target=type_name,
659
+ rel_type=RelationshipType.USES,
660
+ file_path=file_path,
661
+ content=content,
662
+ offset=match.start()
663
+ ))
664
+
665
+ # Extract type assertions
666
+ for match in PATTERNS['type_assertion'].finditer(content):
667
+ type_name = match.group(1)
668
+
669
+ relationships.append(self._make_relationship(
670
+ source=current_scope,
671
+ target=type_name,
672
+ rel_type=RelationshipType.REFERENCES,
673
+ file_path=file_path,
674
+ content=content,
675
+ offset=match.start(),
676
+ metadata={'type_assertion': True}
677
+ ))
678
+
679
+ # Extract goroutine calls
680
+ for match in PATTERNS['goroutine'].finditer(content):
681
+ func_name = match.group(1)
682
+
683
+ if func_name not in {'func'}: # Skip anonymous functions
684
+ relationships.append(self._make_relationship(
685
+ source=current_scope,
686
+ target=func_name,
687
+ rel_type=RelationshipType.CALLS,
688
+ file_path=file_path,
689
+ content=content,
690
+ offset=match.start(),
691
+ metadata={'goroutine': True}
692
+ ))
693
+
694
+ # Extract deferred calls
695
+ for match in PATTERNS['defer'].finditer(content):
696
+ func_name = match.group(1)
697
+
698
+ if func_name not in {'func'}: # Skip anonymous functions
699
+ relationships.append(self._make_relationship(
700
+ source=current_scope,
701
+ target=func_name,
702
+ rel_type=RelationshipType.CALLS,
703
+ file_path=file_path,
704
+ content=content,
705
+ offset=match.start(),
706
+ metadata={'deferred': True}
707
+ ))
708
+
709
+ return relationships
710
+
711
+ def _extract_package(self, content: str) -> Optional[str]:
712
+ """Extract package name from content."""
713
+ match = PATTERNS['package'].search(content)
714
+ return match.group(1) if match else None
715
+
716
+ def _extract_block_content(self, content: str, start: int) -> str:
717
+ """Extract content between braces."""
718
+ brace_count = 0
719
+ block_start = None
720
+
721
+ for i, char in enumerate(content[start:], start):
722
+ if char == '{':
723
+ if block_start is None:
724
+ block_start = i + 1
725
+ brace_count += 1
726
+ elif char == '}':
727
+ brace_count -= 1
728
+ if brace_count == 0 and block_start is not None:
729
+ return content[block_start:i]
730
+
731
+ return ""
732
+
733
+ def _find_embedded_types(self, block_content: str) -> List[str]:
734
+ """Find embedded types in a struct or interface block."""
735
+ embedded = []
736
+
737
+ for line in block_content.split('\n'):
738
+ line = line.strip()
739
+ if not line or line.startswith('//'):
740
+ continue
741
+
742
+ # Check for embedded type (just a type name, possibly with *)
743
+ match = re.match(r'^\*?([A-Z]\w*)(?:\s*`[^`]*`)?$', line)
744
+ if match:
745
+ embedded.append(match.group(1))
746
+
747
+ return embedded
748
+
749
+ def _extract_return_type(self, func_decl: str) -> Optional[str]:
750
+ """Extract return type from function declaration."""
751
+ # Look for return type after parameters
752
+ match = re.search(r'\)\s*(?:\([^)]+\)|([^\n{]+))', func_decl)
753
+ if match:
754
+ ret = match.group(1) or match.group(0)
755
+ ret = ret.strip()
756
+ if ret and not ret.startswith('{'):
757
+ # Clean up
758
+ ret = re.sub(r'^\)\s*', '', ret)
759
+ return ret.strip() if ret else None
760
+ return None
761
+
762
+ def _find_preceding_doc(self, content: str, position: int) -> Optional[str]:
763
+ """Find doc comment preceding a position."""
764
+ before = content[:position]
765
+ lines = before.split('\n')
766
+
767
+ doc_lines = []
768
+ for line in reversed(lines[:-1]):
769
+ stripped = line.strip()
770
+ if stripped.startswith('//'):
771
+ # Skip build tags
772
+ if stripped.startswith('//go:') or stripped.startswith('// +build'):
773
+ break
774
+ doc_lines.insert(0, stripped[2:].strip())
775
+ elif stripped == '':
776
+ continue
777
+ else:
778
+ break
779
+
780
+ return '\n'.join(doc_lines) if doc_lines else None
781
+
782
+ def _find_block_end(self, content: str, start: int) -> int:
783
+ """Find the end line of a code block."""
784
+ brace_count = 0
785
+ in_block = False
786
+
787
+ for i, char in enumerate(content[start:], start):
788
+ if char == '{':
789
+ brace_count += 1
790
+ in_block = True
791
+ elif char == '}':
792
+ brace_count -= 1
793
+ if in_block and brace_count == 0:
794
+ return content[:i].count('\n') + 1
795
+
796
+ return content[:start].count('\n') + 1
797
+
798
+ def parse_multiple_files(
799
+ self,
800
+ files: List[Tuple[str, Optional[str]]],
801
+ resolve_cross_file: bool = True,
802
+ max_workers: int = 4
803
+ ) -> Dict[str, ParseResult]:
804
+ """
805
+ Parse multiple Go files with optional cross-file resolution.
806
+
807
+ Args:
808
+ files: List of (file_path, content) tuples
809
+ resolve_cross_file: Whether to resolve cross-file references
810
+ max_workers: Maximum number of parallel workers
811
+
812
+ Returns:
813
+ Dict mapping file paths to ParseResult objects
814
+ """
815
+ results = {}
816
+
817
+ def parse_single(file_info: Tuple[str, Optional[str]]) -> Tuple[str, Optional[ParseResult]]:
818
+ file_path, content = file_info
819
+ if content is None:
820
+ try:
821
+ with open(file_path, 'r', encoding='utf-8') as f:
822
+ content = f.read()
823
+ except Exception as e:
824
+ logger.warning(f"Failed to read {file_path}: {e}")
825
+ return file_path, None
826
+
827
+ try:
828
+ result = self.parse(content, file_path)
829
+ return file_path, result
830
+ except Exception as e:
831
+ logger.warning(f"Failed to parse {file_path}: {e}")
832
+ return file_path, None
833
+
834
+ # Parse files in parallel
835
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
836
+ for file_path, result in executor.map(parse_single, files):
837
+ if result:
838
+ results[file_path] = result
839
+
840
+ # Register symbols for cross-file resolution
841
+ if resolve_cross_file:
842
+ for symbol in result.symbols:
843
+ self._symbol_to_file[symbol.name] = file_path
844
+ if symbol.qualified_name:
845
+ self._symbol_to_file[symbol.qualified_name] = file_path
846
+
847
+ return results
848
+
849
+
850
+ # Register the parser
851
+ parser_registry.register_parser(GoParser())