alita-sdk 0.3.257__py3-none-any.whl → 0.3.562__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 +155 -0
  6. alita_sdk/cli/agent_loader.py +215 -0
  7. alita_sdk/cli/agent_ui.py +228 -0
  8. alita_sdk/cli/agents.py +3601 -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/toolkit.py +327 -0
  23. alita_sdk/cli/toolkit_loader.py +85 -0
  24. alita_sdk/cli/tools/__init__.py +43 -0
  25. alita_sdk/cli/tools/approval.py +224 -0
  26. alita_sdk/cli/tools/filesystem.py +1751 -0
  27. alita_sdk/cli/tools/planning.py +389 -0
  28. alita_sdk/cli/tools/terminal.py +414 -0
  29. alita_sdk/community/__init__.py +72 -12
  30. alita_sdk/community/inventory/__init__.py +236 -0
  31. alita_sdk/community/inventory/config.py +257 -0
  32. alita_sdk/community/inventory/enrichment.py +2137 -0
  33. alita_sdk/community/inventory/extractors.py +1469 -0
  34. alita_sdk/community/inventory/ingestion.py +3172 -0
  35. alita_sdk/community/inventory/knowledge_graph.py +1457 -0
  36. alita_sdk/community/inventory/parsers/__init__.py +218 -0
  37. alita_sdk/community/inventory/parsers/base.py +295 -0
  38. alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
  39. alita_sdk/community/inventory/parsers/go_parser.py +851 -0
  40. alita_sdk/community/inventory/parsers/html_parser.py +389 -0
  41. alita_sdk/community/inventory/parsers/java_parser.py +593 -0
  42. alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
  43. alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
  44. alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
  45. alita_sdk/community/inventory/parsers/python_parser.py +604 -0
  46. alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
  47. alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
  48. alita_sdk/community/inventory/parsers/text_parser.py +322 -0
  49. alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
  50. alita_sdk/community/inventory/patterns/__init__.py +61 -0
  51. alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
  52. alita_sdk/community/inventory/patterns/loader.py +348 -0
  53. alita_sdk/community/inventory/patterns/registry.py +198 -0
  54. alita_sdk/community/inventory/presets.py +535 -0
  55. alita_sdk/community/inventory/retrieval.py +1403 -0
  56. alita_sdk/community/inventory/toolkit.py +173 -0
  57. alita_sdk/community/inventory/toolkit_utils.py +176 -0
  58. alita_sdk/community/inventory/visualize.py +1370 -0
  59. alita_sdk/configurations/__init__.py +11 -0
  60. alita_sdk/configurations/ado.py +148 -2
  61. alita_sdk/configurations/azure_search.py +1 -1
  62. alita_sdk/configurations/bigquery.py +1 -1
  63. alita_sdk/configurations/bitbucket.py +94 -2
  64. alita_sdk/configurations/browser.py +18 -0
  65. alita_sdk/configurations/carrier.py +19 -0
  66. alita_sdk/configurations/confluence.py +130 -1
  67. alita_sdk/configurations/delta_lake.py +1 -1
  68. alita_sdk/configurations/figma.py +76 -5
  69. alita_sdk/configurations/github.py +65 -1
  70. alita_sdk/configurations/gitlab.py +81 -0
  71. alita_sdk/configurations/google_places.py +17 -0
  72. alita_sdk/configurations/jira.py +103 -0
  73. alita_sdk/configurations/openapi.py +111 -0
  74. alita_sdk/configurations/postman.py +1 -1
  75. alita_sdk/configurations/qtest.py +72 -3
  76. alita_sdk/configurations/report_portal.py +115 -0
  77. alita_sdk/configurations/salesforce.py +19 -0
  78. alita_sdk/configurations/service_now.py +1 -12
  79. alita_sdk/configurations/sharepoint.py +167 -0
  80. alita_sdk/configurations/sonar.py +18 -0
  81. alita_sdk/configurations/sql.py +20 -0
  82. alita_sdk/configurations/testio.py +101 -0
  83. alita_sdk/configurations/testrail.py +88 -0
  84. alita_sdk/configurations/xray.py +94 -1
  85. alita_sdk/configurations/zephyr_enterprise.py +94 -1
  86. alita_sdk/configurations/zephyr_essential.py +95 -0
  87. alita_sdk/runtime/clients/artifact.py +21 -4
  88. alita_sdk/runtime/clients/client.py +458 -67
  89. alita_sdk/runtime/clients/mcp_discovery.py +342 -0
  90. alita_sdk/runtime/clients/mcp_manager.py +262 -0
  91. alita_sdk/runtime/clients/sandbox_client.py +352 -0
  92. alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
  93. alita_sdk/runtime/langchain/assistant.py +183 -43
  94. alita_sdk/runtime/langchain/constants.py +647 -1
  95. alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
  96. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +209 -31
  97. alita_sdk/runtime/langchain/document_loaders/AlitaImageLoader.py +1 -1
  98. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
  99. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -3
  100. alita_sdk/runtime/langchain/document_loaders/AlitaMarkdownLoader.py +66 -0
  101. alita_sdk/runtime/langchain/document_loaders/AlitaPDFLoader.py +79 -10
  102. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +52 -15
  103. alita_sdk/runtime/langchain/document_loaders/AlitaPythonLoader.py +9 -0
  104. alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -4
  105. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +15 -2
  106. alita_sdk/runtime/langchain/document_loaders/ImageParser.py +30 -0
  107. alita_sdk/runtime/langchain/document_loaders/constants.py +189 -41
  108. alita_sdk/runtime/langchain/interfaces/llm_processor.py +4 -2
  109. alita_sdk/runtime/langchain/langraph_agent.py +407 -92
  110. alita_sdk/runtime/langchain/utils.py +102 -8
  111. alita_sdk/runtime/llms/preloaded.py +2 -6
  112. alita_sdk/runtime/models/mcp_models.py +61 -0
  113. alita_sdk/runtime/skills/__init__.py +91 -0
  114. alita_sdk/runtime/skills/callbacks.py +498 -0
  115. alita_sdk/runtime/skills/discovery.py +540 -0
  116. alita_sdk/runtime/skills/executor.py +610 -0
  117. alita_sdk/runtime/skills/input_builder.py +371 -0
  118. alita_sdk/runtime/skills/models.py +330 -0
  119. alita_sdk/runtime/skills/registry.py +355 -0
  120. alita_sdk/runtime/skills/skill_runner.py +330 -0
  121. alita_sdk/runtime/toolkits/__init__.py +28 -0
  122. alita_sdk/runtime/toolkits/application.py +14 -4
  123. alita_sdk/runtime/toolkits/artifact.py +24 -9
  124. alita_sdk/runtime/toolkits/datasource.py +13 -6
  125. alita_sdk/runtime/toolkits/mcp.py +780 -0
  126. alita_sdk/runtime/toolkits/planning.py +178 -0
  127. alita_sdk/runtime/toolkits/skill_router.py +238 -0
  128. alita_sdk/runtime/toolkits/subgraph.py +11 -6
  129. alita_sdk/runtime/toolkits/tools.py +314 -70
  130. alita_sdk/runtime/toolkits/vectorstore.py +11 -5
  131. alita_sdk/runtime/tools/__init__.py +24 -0
  132. alita_sdk/runtime/tools/application.py +16 -4
  133. alita_sdk/runtime/tools/artifact.py +367 -33
  134. alita_sdk/runtime/tools/data_analysis.py +183 -0
  135. alita_sdk/runtime/tools/function.py +100 -4
  136. alita_sdk/runtime/tools/graph.py +81 -0
  137. alita_sdk/runtime/tools/image_generation.py +218 -0
  138. alita_sdk/runtime/tools/llm.py +1013 -177
  139. alita_sdk/runtime/tools/loop.py +3 -1
  140. alita_sdk/runtime/tools/loop_output.py +3 -1
  141. alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
  142. alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
  143. alita_sdk/runtime/tools/mcp_server_tool.py +3 -1
  144. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  145. alita_sdk/runtime/tools/planning/models.py +246 -0
  146. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  147. alita_sdk/runtime/tools/router.py +2 -1
  148. alita_sdk/runtime/tools/sandbox.py +375 -0
  149. alita_sdk/runtime/tools/skill_router.py +776 -0
  150. alita_sdk/runtime/tools/tool.py +3 -1
  151. alita_sdk/runtime/tools/vectorstore.py +69 -65
  152. alita_sdk/runtime/tools/vectorstore_base.py +163 -90
  153. alita_sdk/runtime/utils/AlitaCallback.py +137 -21
  154. alita_sdk/runtime/utils/mcp_client.py +492 -0
  155. alita_sdk/runtime/utils/mcp_oauth.py +361 -0
  156. alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
  157. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  158. alita_sdk/runtime/utils/streamlit.py +41 -14
  159. alita_sdk/runtime/utils/toolkit_utils.py +28 -9
  160. alita_sdk/runtime/utils/utils.py +48 -0
  161. alita_sdk/tools/__init__.py +135 -37
  162. alita_sdk/tools/ado/__init__.py +2 -2
  163. alita_sdk/tools/ado/repos/__init__.py +15 -19
  164. alita_sdk/tools/ado/repos/repos_wrapper.py +12 -20
  165. alita_sdk/tools/ado/test_plan/__init__.py +26 -8
  166. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -28
  167. alita_sdk/tools/ado/wiki/__init__.py +27 -12
  168. alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -40
  169. alita_sdk/tools/ado/work_item/__init__.py +27 -12
  170. alita_sdk/tools/ado/work_item/ado_wrapper.py +95 -11
  171. alita_sdk/tools/advanced_jira_mining/__init__.py +12 -8
  172. alita_sdk/tools/aws/delta_lake/__init__.py +14 -11
  173. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  174. alita_sdk/tools/azure_ai/search/__init__.py +13 -8
  175. alita_sdk/tools/base/tool.py +5 -1
  176. alita_sdk/tools/base_indexer_toolkit.py +454 -110
  177. alita_sdk/tools/bitbucket/__init__.py +27 -19
  178. alita_sdk/tools/bitbucket/api_wrapper.py +285 -27
  179. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
  180. alita_sdk/tools/browser/__init__.py +41 -16
  181. alita_sdk/tools/browser/crawler.py +3 -1
  182. alita_sdk/tools/browser/utils.py +15 -6
  183. alita_sdk/tools/carrier/__init__.py +18 -17
  184. alita_sdk/tools/carrier/backend_reports_tool.py +8 -4
  185. alita_sdk/tools/carrier/excel_reporter.py +8 -4
  186. alita_sdk/tools/chunkers/__init__.py +3 -1
  187. alita_sdk/tools/chunkers/code/codeparser.py +1 -1
  188. alita_sdk/tools/chunkers/sematic/json_chunker.py +2 -1
  189. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  190. alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
  191. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  192. alita_sdk/tools/cloud/aws/__init__.py +11 -7
  193. alita_sdk/tools/cloud/azure/__init__.py +11 -7
  194. alita_sdk/tools/cloud/gcp/__init__.py +11 -7
  195. alita_sdk/tools/cloud/k8s/__init__.py +11 -7
  196. alita_sdk/tools/code/linter/__init__.py +9 -8
  197. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  198. alita_sdk/tools/code/sonar/__init__.py +20 -13
  199. alita_sdk/tools/code_indexer_toolkit.py +199 -0
  200. alita_sdk/tools/confluence/__init__.py +21 -14
  201. alita_sdk/tools/confluence/api_wrapper.py +197 -58
  202. alita_sdk/tools/confluence/loader.py +14 -2
  203. alita_sdk/tools/custom_open_api/__init__.py +11 -5
  204. alita_sdk/tools/elastic/__init__.py +10 -8
  205. alita_sdk/tools/elitea_base.py +546 -64
  206. alita_sdk/tools/figma/__init__.py +11 -8
  207. alita_sdk/tools/figma/api_wrapper.py +352 -153
  208. alita_sdk/tools/github/__init__.py +17 -17
  209. alita_sdk/tools/github/api_wrapper.py +9 -26
  210. alita_sdk/tools/github/github_client.py +81 -12
  211. alita_sdk/tools/github/schemas.py +2 -1
  212. alita_sdk/tools/github/tool.py +5 -1
  213. alita_sdk/tools/gitlab/__init__.py +18 -13
  214. alita_sdk/tools/gitlab/api_wrapper.py +224 -80
  215. alita_sdk/tools/gitlab_org/__init__.py +13 -10
  216. alita_sdk/tools/google/bigquery/__init__.py +13 -13
  217. alita_sdk/tools/google/bigquery/tool.py +5 -1
  218. alita_sdk/tools/google_places/__init__.py +20 -11
  219. alita_sdk/tools/jira/__init__.py +21 -11
  220. alita_sdk/tools/jira/api_wrapper.py +315 -168
  221. alita_sdk/tools/keycloak/__init__.py +10 -8
  222. alita_sdk/tools/localgit/__init__.py +8 -3
  223. alita_sdk/tools/localgit/local_git.py +62 -54
  224. alita_sdk/tools/localgit/tool.py +5 -1
  225. alita_sdk/tools/memory/__init__.py +38 -14
  226. alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
  227. alita_sdk/tools/ocr/__init__.py +10 -8
  228. alita_sdk/tools/openapi/__init__.py +281 -108
  229. alita_sdk/tools/openapi/api_wrapper.py +883 -0
  230. alita_sdk/tools/openapi/tool.py +20 -0
  231. alita_sdk/tools/pandas/__init__.py +18 -11
  232. alita_sdk/tools/pandas/api_wrapper.py +40 -45
  233. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  234. alita_sdk/tools/postman/__init__.py +10 -11
  235. alita_sdk/tools/postman/api_wrapper.py +19 -8
  236. alita_sdk/tools/postman/postman_analysis.py +8 -1
  237. alita_sdk/tools/pptx/__init__.py +10 -10
  238. alita_sdk/tools/qtest/__init__.py +21 -14
  239. alita_sdk/tools/qtest/api_wrapper.py +1784 -88
  240. alita_sdk/tools/rally/__init__.py +12 -10
  241. alita_sdk/tools/report_portal/__init__.py +22 -16
  242. alita_sdk/tools/salesforce/__init__.py +21 -16
  243. alita_sdk/tools/servicenow/__init__.py +20 -16
  244. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  245. alita_sdk/tools/sharepoint/__init__.py +16 -14
  246. alita_sdk/tools/sharepoint/api_wrapper.py +179 -39
  247. alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
  248. alita_sdk/tools/sharepoint/utils.py +8 -2
  249. alita_sdk/tools/slack/__init__.py +11 -7
  250. alita_sdk/tools/sql/__init__.py +21 -19
  251. alita_sdk/tools/sql/api_wrapper.py +71 -23
  252. alita_sdk/tools/testio/__init__.py +20 -13
  253. alita_sdk/tools/testrail/__init__.py +12 -11
  254. alita_sdk/tools/testrail/api_wrapper.py +214 -46
  255. alita_sdk/tools/utils/__init__.py +28 -4
  256. alita_sdk/tools/utils/content_parser.py +182 -62
  257. alita_sdk/tools/utils/text_operations.py +254 -0
  258. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
  259. alita_sdk/tools/xray/__init__.py +17 -14
  260. alita_sdk/tools/xray/api_wrapper.py +58 -113
  261. alita_sdk/tools/yagmail/__init__.py +8 -3
  262. alita_sdk/tools/zephyr/__init__.py +11 -7
  263. alita_sdk/tools/zephyr_enterprise/__init__.py +15 -9
  264. alita_sdk/tools/zephyr_enterprise/api_wrapper.py +30 -15
  265. alita_sdk/tools/zephyr_essential/__init__.py +15 -10
  266. alita_sdk/tools/zephyr_essential/api_wrapper.py +297 -54
  267. alita_sdk/tools/zephyr_essential/client.py +6 -4
  268. alita_sdk/tools/zephyr_scale/__init__.py +12 -8
  269. alita_sdk/tools/zephyr_scale/api_wrapper.py +39 -31
  270. alita_sdk/tools/zephyr_squad/__init__.py +11 -7
  271. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/METADATA +184 -37
  272. alita_sdk-0.3.562.dist-info/RECORD +450 -0
  273. alita_sdk-0.3.562.dist-info/entry_points.txt +2 -0
  274. alita_sdk/tools/bitbucket/tools.py +0 -304
  275. alita_sdk-0.3.257.dist-info/RECORD +0 -343
  276. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/WHEEL +0 -0
  277. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/licenses/LICENSE +0 -0
  278. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,593 @@
1
+ """
2
+ Java Parser - Regex-based parsing.
3
+
4
+ This parser uses regex patterns for Java analysis:
5
+ - Import/package detection
6
+ - Class, interface, enum extraction
7
+ - Inheritance and implementation patterns
8
+ - Method and field detection
9
+ - Annotation support
10
+
11
+ Works without external dependencies like tree-sitter.
12
+ """
13
+
14
+ import re
15
+ import hashlib
16
+ import logging
17
+ import time
18
+ import concurrent.futures
19
+ from pathlib import Path
20
+ from typing import Dict, List, Optional, Set, Union, Tuple
21
+
22
+ from .base import (
23
+ BaseParser, ParseResult, Symbol, Relationship,
24
+ SymbolType, RelationshipType, Scope, Position, Range,
25
+ parser_registry
26
+ )
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+
31
+ # Comprehensive regex patterns for Java
32
+ PATTERNS = {
33
+ # Package
34
+ 'package': re.compile(
35
+ r'package\s+([\w.]+)\s*;',
36
+ re.MULTILINE
37
+ ),
38
+
39
+ # Imports
40
+ 'import': re.compile(
41
+ r'import\s+(?:static\s+)?([\w.]+(?:\.\*)?)\s*;',
42
+ re.MULTILINE
43
+ ),
44
+
45
+ # Classes
46
+ 'class_def': re.compile(
47
+ r'(?:public\s+|private\s+|protected\s+)?(?:abstract\s+|final\s+)?class\s+(\w+)'
48
+ r'(?:<[^>]+>)?' # Generics
49
+ r'(?:\s+extends\s+(\w+)(?:<[^>]+>)?)?'
50
+ r'(?:\s+implements\s+([\w,\s<>]+))?',
51
+ re.MULTILINE
52
+ ),
53
+
54
+ # Interfaces
55
+ 'interface_def': re.compile(
56
+ r'(?:public\s+|private\s+|protected\s+)?interface\s+(\w+)'
57
+ r'(?:<[^>]+>)?'
58
+ r'(?:\s+extends\s+([\w,\s<>]+))?',
59
+ re.MULTILINE
60
+ ),
61
+
62
+ # Enums
63
+ 'enum_def': re.compile(
64
+ r'(?:public\s+|private\s+|protected\s+)?enum\s+(\w+)'
65
+ r'(?:\s+implements\s+([\w,\s<>]+))?',
66
+ re.MULTILINE
67
+ ),
68
+
69
+ # Records (Java 14+)
70
+ 'record_def': re.compile(
71
+ r'(?:public\s+|private\s+|protected\s+)?record\s+(\w+)\s*\([^)]*\)'
72
+ r'(?:\s+implements\s+([\w,\s<>]+))?',
73
+ re.MULTILINE
74
+ ),
75
+
76
+ # Methods
77
+ 'method_def': re.compile(
78
+ r'(?:public\s+|private\s+|protected\s+)?'
79
+ r'(?:static\s+)?(?:final\s+)?(?:synchronized\s+)?(?:abstract\s+)?'
80
+ r'(?:<[^>]+>\s+)?' # Generic type params
81
+ r'([\w<>\[\],\s]+)\s+' # Return type
82
+ r'(\w+)\s*' # Method name
83
+ r'\([^)]*\)', # Parameters
84
+ re.MULTILINE
85
+ ),
86
+
87
+ # Constructors
88
+ 'constructor_def': re.compile(
89
+ r'(?:public\s+|private\s+|protected\s+)?(\w+)\s*\([^)]*\)\s*(?:throws\s+[\w,\s]+)?\s*\{',
90
+ re.MULTILINE
91
+ ),
92
+
93
+ # Fields
94
+ 'field_def': re.compile(
95
+ r'(?:public\s+|private\s+|protected\s+)?'
96
+ r'(?:static\s+)?(?:final\s+)?'
97
+ r'([\w<>\[\],\s]+)\s+' # Type
98
+ r'(\w+)\s*' # Name
99
+ r'(?:=|;)',
100
+ re.MULTILINE
101
+ ),
102
+
103
+ # Annotations
104
+ 'annotation': re.compile(
105
+ r'@(\w+)(?:\([^)]*\))?',
106
+ re.MULTILINE
107
+ ),
108
+
109
+ # Method calls
110
+ 'method_call': re.compile(
111
+ r'(?:(\w+)\.)?(\w+)\s*\(',
112
+ re.MULTILINE
113
+ ),
114
+
115
+ # Object instantiation
116
+ 'new_instance': re.compile(
117
+ r'new\s+(\w+)\s*(?:<[^>]*>)?\s*\(',
118
+ re.MULTILINE
119
+ ),
120
+
121
+ # JavaDoc @see
122
+ 'javadoc_see': re.compile(
123
+ r'@see\s+(?:#|{@link\s+)?(\w+(?:\.\w+)*)',
124
+ re.MULTILINE
125
+ ),
126
+
127
+ # Type references in generics
128
+ 'generic_type': re.compile(
129
+ r'<(\w+)(?:\s*,\s*(\w+))*>',
130
+ re.MULTILINE
131
+ ),
132
+ }
133
+
134
+
135
+ def _parse_single_file(file_path: str) -> Tuple[str, ParseResult]:
136
+ """Parse a single Java file."""
137
+ try:
138
+ parser = JavaParser()
139
+ result = parser.parse_file(file_path)
140
+ return file_path, result
141
+ except Exception as e:
142
+ logger.warning(f"Failed to parse {file_path}: {e}")
143
+ return file_path, ParseResult(
144
+ file_path=file_path,
145
+ language="java",
146
+ symbols=[],
147
+ relationships=[]
148
+ )
149
+
150
+
151
+ class JavaParser(BaseParser):
152
+ """
153
+ Java parser using regex patterns.
154
+
155
+ Extracts classes, interfaces, methods, and relationships.
156
+ """
157
+
158
+ def __init__(self):
159
+ super().__init__("java")
160
+ self._current_file = ""
161
+ self._current_content = ""
162
+ self._current_package = ""
163
+
164
+ # Cross-file resolution
165
+ self._global_classes: Dict[str, str] = {} # class_name -> file_path
166
+ self._global_interfaces: Dict[str, str] = {}
167
+
168
+ def _get_supported_extensions(self) -> Set[str]:
169
+ return {'.java'}
170
+
171
+ def parse_file(self, file_path: Union[str, Path], content: Optional[str] = None) -> ParseResult:
172
+ """Parse a Java file."""
173
+ start_time = time.time()
174
+ file_path = str(file_path)
175
+ self._current_file = file_path
176
+
177
+ try:
178
+ if content is None:
179
+ with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
180
+ content = f.read()
181
+
182
+ self._current_content = content
183
+
184
+ # Extract package
185
+ pkg_match = PATTERNS['package'].search(content)
186
+ self._current_package = pkg_match.group(1) if pkg_match else ""
187
+
188
+ symbols = self._extract_symbols(content, file_path)
189
+ relationships = self._extract_relationships(content, symbols, file_path)
190
+ imports = self._extract_imports(content)
191
+
192
+ result = ParseResult(
193
+ file_path=file_path,
194
+ language="java",
195
+ symbols=symbols,
196
+ relationships=relationships,
197
+ imports=imports,
198
+ parse_time=time.time() - start_time
199
+ )
200
+
201
+ return self.validate_result(result)
202
+
203
+ except Exception as e:
204
+ logger.error(f"Failed to parse Java file {file_path}: {e}")
205
+ return ParseResult(
206
+ file_path=file_path,
207
+ language="java",
208
+ symbols=[],
209
+ relationships=[],
210
+ parse_time=time.time() - start_time,
211
+ errors=[str(e)]
212
+ )
213
+
214
+ def _extract_symbols(self, content: str, file_path: str) -> List[Symbol]:
215
+ """Extract symbols from Java content."""
216
+ symbols = []
217
+ lines = content.split('\n')
218
+ class_name = Path(file_path).stem
219
+
220
+ # Module/file symbol
221
+ full_name = f"{self._current_package}.{class_name}" if self._current_package else class_name
222
+ symbols.append(Symbol(
223
+ name=class_name,
224
+ symbol_type=SymbolType.MODULE,
225
+ scope=Scope.GLOBAL,
226
+ range=Range(Position(1, 0), Position(len(lines), 0)),
227
+ file_path=file_path,
228
+ full_name=full_name
229
+ ))
230
+
231
+ # Classes
232
+ for match in PATTERNS['class_def'].finditer(content):
233
+ line = content[:match.start()].count('\n') + 1
234
+ name = match.group(1)
235
+ extends = match.group(2)
236
+
237
+ symbols.append(Symbol(
238
+ name=name,
239
+ symbol_type=SymbolType.CLASS,
240
+ scope=Scope.GLOBAL,
241
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
242
+ file_path=file_path,
243
+ full_name=f"{self._current_package}.{name}" if self._current_package else name,
244
+ visibility='public' if 'public' in match.group(0) else 'package',
245
+ metadata={'extends': extends} if extends else {}
246
+ ))
247
+
248
+ # Interfaces
249
+ for match in PATTERNS['interface_def'].finditer(content):
250
+ line = content[:match.start()].count('\n') + 1
251
+ name = match.group(1)
252
+
253
+ symbols.append(Symbol(
254
+ name=name,
255
+ symbol_type=SymbolType.INTERFACE,
256
+ scope=Scope.GLOBAL,
257
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
258
+ file_path=file_path,
259
+ full_name=f"{self._current_package}.{name}" if self._current_package else name,
260
+ visibility='public' if 'public' in match.group(0) else 'package'
261
+ ))
262
+
263
+ # Enums
264
+ for match in PATTERNS['enum_def'].finditer(content):
265
+ line = content[:match.start()].count('\n') + 1
266
+ name = match.group(1)
267
+
268
+ symbols.append(Symbol(
269
+ name=name,
270
+ symbol_type=SymbolType.ENUM,
271
+ scope=Scope.GLOBAL,
272
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
273
+ file_path=file_path,
274
+ full_name=f"{self._current_package}.{name}" if self._current_package else name,
275
+ visibility='public' if 'public' in match.group(0) else 'package'
276
+ ))
277
+
278
+ # Records
279
+ for match in PATTERNS['record_def'].finditer(content):
280
+ line = content[:match.start()].count('\n') + 1
281
+ name = match.group(1)
282
+
283
+ symbols.append(Symbol(
284
+ name=name,
285
+ symbol_type=SymbolType.CLASS,
286
+ scope=Scope.GLOBAL,
287
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
288
+ file_path=file_path,
289
+ full_name=f"{self._current_package}.{name}" if self._current_package else name,
290
+ visibility='public' if 'public' in match.group(0) else 'package',
291
+ metadata={'is_record': True}
292
+ ))
293
+
294
+ # Methods
295
+ for match in PATTERNS['method_def'].finditer(content):
296
+ line = content[:match.start()].count('\n') + 1
297
+ return_type = match.group(1).strip()
298
+ name = match.group(2)
299
+
300
+ # Skip if it looks like a constructor (return type == class name)
301
+ if name in [s.name for s in symbols if s.symbol_type in (SymbolType.CLASS, SymbolType.INTERFACE)]:
302
+ continue
303
+
304
+ symbols.append(Symbol(
305
+ name=name,
306
+ symbol_type=SymbolType.METHOD,
307
+ scope=Scope.CLASS,
308
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
309
+ file_path=file_path,
310
+ return_type=return_type,
311
+ visibility='public' if 'public' in match.group(0) else ('private' if 'private' in match.group(0) else 'protected'),
312
+ is_static='static' in match.group(0),
313
+ is_async='synchronized' in match.group(0) # Using is_async for synchronized
314
+ ))
315
+
316
+ # Fields
317
+ for match in PATTERNS['field_def'].finditer(content):
318
+ line = content[:match.start()].count('\n') + 1
319
+ field_type = match.group(1).strip()
320
+ name = match.group(2)
321
+
322
+ # Skip common false positives (method returns, etc.)
323
+ if field_type in ('return', 'throw', 'if', 'else', 'for', 'while', 'switch', 'case'):
324
+ continue
325
+
326
+ symbols.append(Symbol(
327
+ name=name,
328
+ symbol_type=SymbolType.FIELD,
329
+ scope=Scope.CLASS,
330
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
331
+ file_path=file_path,
332
+ return_type=field_type,
333
+ visibility='public' if 'public' in match.group(0) else ('private' if 'private' in match.group(0) else 'protected'),
334
+ is_static='static' in match.group(0)
335
+ ))
336
+
337
+ # Imports as symbols
338
+ for match in PATTERNS['import'].finditer(content):
339
+ line = content[:match.start()].count('\n') + 1
340
+ import_path = match.group(1)
341
+ name = import_path.split('.')[-1]
342
+
343
+ symbols.append(Symbol(
344
+ name=name,
345
+ symbol_type=SymbolType.IMPORT,
346
+ scope=Scope.GLOBAL,
347
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
348
+ file_path=file_path,
349
+ metadata={'full_path': import_path, 'is_static': 'static' in match.group(0)}
350
+ ))
351
+
352
+ return symbols
353
+
354
+ def _extract_relationships(self, content: str, symbols: List[Symbol], file_path: str) -> List[Relationship]:
355
+ """Extract relationships from Java content."""
356
+ relationships = []
357
+ module_name = Path(file_path).stem
358
+
359
+ # Import relationships
360
+ for match in PATTERNS['import'].finditer(content):
361
+ line = content[:match.start()].count('\n') + 1
362
+ import_path = match.group(1)
363
+
364
+ relationships.append(Relationship(
365
+ source_symbol=module_name,
366
+ target_symbol=import_path,
367
+ relationship_type=RelationshipType.IMPORTS,
368
+ source_file=file_path,
369
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
370
+ confidence=1.0
371
+ ))
372
+
373
+ # Inheritance (extends)
374
+ for match in PATTERNS['class_def'].finditer(content):
375
+ class_name = match.group(1)
376
+ extends = match.group(2)
377
+ implements = match.group(3)
378
+ line = content[:match.start()].count('\n') + 1
379
+
380
+ if extends:
381
+ relationships.append(Relationship(
382
+ source_symbol=class_name,
383
+ target_symbol=extends,
384
+ relationship_type=RelationshipType.INHERITANCE,
385
+ source_file=file_path,
386
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
387
+ confidence=0.95
388
+ ))
389
+
390
+ if implements:
391
+ for iface in implements.split(','):
392
+ iface = re.sub(r'<[^>]*>', '', iface).strip() # Remove generics
393
+ if iface:
394
+ relationships.append(Relationship(
395
+ source_symbol=class_name,
396
+ target_symbol=iface,
397
+ relationship_type=RelationshipType.IMPLEMENTATION,
398
+ source_file=file_path,
399
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
400
+ confidence=0.95
401
+ ))
402
+
403
+ # Interface extension
404
+ for match in PATTERNS['interface_def'].finditer(content):
405
+ iface_name = match.group(1)
406
+ extends = match.group(2)
407
+ if extends:
408
+ line = content[:match.start()].count('\n') + 1
409
+ for parent in extends.split(','):
410
+ parent = re.sub(r'<[^>]*>', '', parent).strip()
411
+ if parent:
412
+ relationships.append(Relationship(
413
+ source_symbol=iface_name,
414
+ target_symbol=parent,
415
+ relationship_type=RelationshipType.INHERITANCE,
416
+ source_file=file_path,
417
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
418
+ confidence=0.95
419
+ ))
420
+
421
+ # Enum implementation
422
+ for match in PATTERNS['enum_def'].finditer(content):
423
+ enum_name = match.group(1)
424
+ implements = match.group(2)
425
+ if implements:
426
+ line = content[:match.start()].count('\n') + 1
427
+ for iface in implements.split(','):
428
+ iface = re.sub(r'<[^>]*>', '', iface).strip()
429
+ if iface:
430
+ relationships.append(Relationship(
431
+ source_symbol=enum_name,
432
+ target_symbol=iface,
433
+ relationship_type=RelationshipType.IMPLEMENTATION,
434
+ source_file=file_path,
435
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
436
+ confidence=0.95
437
+ ))
438
+
439
+ # Object instantiation (new)
440
+ for match in PATTERNS['new_instance'].finditer(content):
441
+ type_name = match.group(1)
442
+ line = content[:match.start()].count('\n') + 1
443
+
444
+ relationships.append(Relationship(
445
+ source_symbol=module_name,
446
+ target_symbol=type_name,
447
+ relationship_type=RelationshipType.USES,
448
+ source_file=file_path,
449
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
450
+ confidence=0.85
451
+ ))
452
+
453
+ # Annotation relationships
454
+ annotations_found = list(PATTERNS['annotation'].finditer(content))
455
+ for i, match in enumerate(annotations_found):
456
+ ann_name = match.group(1)
457
+ line = content[:match.start()].count('\n') + 1
458
+
459
+ # Find the next class, interface, method, or field
460
+ remaining = content[match.end():]
461
+ target = None
462
+
463
+ class_match = PATTERNS['class_def'].search(remaining)
464
+ iface_match = PATTERNS['interface_def'].search(remaining)
465
+ method_match = PATTERNS['method_def'].search(remaining)
466
+
467
+ if class_match and (not method_match or class_match.start() < method_match.start()):
468
+ target = class_match.group(1)
469
+ elif iface_match and (not method_match or iface_match.start() < method_match.start()):
470
+ target = iface_match.group(1)
471
+ elif method_match:
472
+ target = method_match.group(2)
473
+
474
+ if target:
475
+ relationships.append(Relationship(
476
+ source_symbol=ann_name,
477
+ target_symbol=target,
478
+ relationship_type=RelationshipType.DECORATES,
479
+ source_file=file_path,
480
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
481
+ confidence=0.90
482
+ ))
483
+
484
+ # JavaDoc @see references
485
+ for match in PATTERNS['javadoc_see'].finditer(content):
486
+ ref = match.group(1)
487
+ line = content[:match.start()].count('\n') + 1
488
+
489
+ relationships.append(Relationship(
490
+ source_symbol=module_name,
491
+ target_symbol=ref,
492
+ relationship_type=RelationshipType.REFERENCES,
493
+ source_file=file_path,
494
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
495
+ confidence=0.80
496
+ ))
497
+
498
+ return relationships
499
+
500
+ def _extract_imports(self, content: str) -> List[str]:
501
+ """Extract import paths."""
502
+ imports = []
503
+ for match in PATTERNS['import'].finditer(content):
504
+ imports.append(match.group(1))
505
+ return list(set(imports))
506
+
507
+ def parse_multiple_files(self, file_paths: List[str], max_workers: int = 4) -> Dict[str, ParseResult]:
508
+ """Parse multiple Java files with cross-file resolution."""
509
+ results: Dict[str, ParseResult] = {}
510
+ total = len(file_paths)
511
+
512
+ self._global_classes = {}
513
+ self._global_interfaces = {}
514
+
515
+ logger.info(f"Parsing {total} Java files")
516
+ start_time = time.time()
517
+
518
+ with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
519
+ futures = {executor.submit(_parse_single_file, fp): fp for fp in file_paths}
520
+
521
+ for future in concurrent.futures.as_completed(futures):
522
+ try:
523
+ fp, result = future.result(timeout=60)
524
+ results[fp] = result
525
+ except Exception as e:
526
+ fp = futures[future]
527
+ logger.error(f"Failed to parse {fp}: {e}")
528
+ results[fp] = ParseResult(
529
+ file_path=fp,
530
+ language="java",
531
+ symbols=[],
532
+ relationships=[],
533
+ errors=[str(e)]
534
+ )
535
+
536
+ # Build global registry
537
+ for fp, result in results.items():
538
+ self._build_global_registry(fp, result)
539
+
540
+ # Enhance relationships
541
+ for fp, result in results.items():
542
+ self._enhance_relationships(fp, result)
543
+
544
+ elapsed = time.time() - start_time
545
+ logger.info(f"Parsed {len(results)} Java files in {elapsed:.2f}s")
546
+
547
+ return results
548
+
549
+ def _build_global_registry(self, file_path: str, result: ParseResult):
550
+ """Build global class/interface registry."""
551
+ for symbol in result.symbols:
552
+ if symbol.symbol_type == SymbolType.CLASS:
553
+ self._global_classes[symbol.name] = file_path
554
+ if symbol.full_name:
555
+ self._global_classes[symbol.full_name] = file_path
556
+ elif symbol.symbol_type == SymbolType.INTERFACE:
557
+ self._global_interfaces[symbol.name] = file_path
558
+ if symbol.full_name:
559
+ self._global_interfaces[symbol.full_name] = file_path
560
+
561
+ def _enhance_relationships(self, file_path: str, result: ParseResult):
562
+ """Enhance relationships with cross-file info."""
563
+ for rel in result.relationships:
564
+ target = rel.target_symbol
565
+
566
+ # Extract simple name from qualified
567
+ simple_name = target.split('.')[-1] if '.' in target else target
568
+
569
+ # Check global registries
570
+ if target in self._global_classes:
571
+ target_file = self._global_classes[target]
572
+ if target_file != file_path:
573
+ rel.target_file = target_file
574
+ rel.is_cross_file = True
575
+ elif simple_name in self._global_classes:
576
+ target_file = self._global_classes[simple_name]
577
+ if target_file != file_path:
578
+ rel.target_file = target_file
579
+ rel.is_cross_file = True
580
+ elif target in self._global_interfaces:
581
+ target_file = self._global_interfaces[target]
582
+ if target_file != file_path:
583
+ rel.target_file = target_file
584
+ rel.is_cross_file = True
585
+ elif simple_name in self._global_interfaces:
586
+ target_file = self._global_interfaces[simple_name]
587
+ if target_file != file_path:
588
+ rel.target_file = target_file
589
+ rel.is_cross_file = True
590
+
591
+
592
+ # Register the parser
593
+ parser_registry.register_parser(JavaParser())