alita-sdk 0.3.257__py3-none-any.whl → 0.3.584__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.

Potentially problematic release.


This version of alita-sdk might be problematic. Click here for more details.

Files changed (281) 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 +3794 -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 +323 -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 +493 -105
  110. alita_sdk/runtime/langchain/utils.py +118 -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 +25 -9
  124. alita_sdk/runtime/toolkits/datasource.py +13 -6
  125. alita_sdk/runtime/toolkits/mcp.py +782 -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 +1032 -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/constants.py +5 -1
  155. alita_sdk/runtime/utils/mcp_client.py +492 -0
  156. alita_sdk/runtime/utils/mcp_oauth.py +361 -0
  157. alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
  158. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  159. alita_sdk/runtime/utils/streamlit.py +41 -14
  160. alita_sdk/runtime/utils/toolkit_utils.py +28 -9
  161. alita_sdk/runtime/utils/utils.py +48 -0
  162. alita_sdk/tools/__init__.py +135 -37
  163. alita_sdk/tools/ado/__init__.py +2 -2
  164. alita_sdk/tools/ado/repos/__init__.py +16 -19
  165. alita_sdk/tools/ado/repos/repos_wrapper.py +12 -20
  166. alita_sdk/tools/ado/test_plan/__init__.py +27 -8
  167. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -28
  168. alita_sdk/tools/ado/wiki/__init__.py +28 -12
  169. alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -40
  170. alita_sdk/tools/ado/work_item/__init__.py +28 -12
  171. alita_sdk/tools/ado/work_item/ado_wrapper.py +95 -11
  172. alita_sdk/tools/advanced_jira_mining/__init__.py +13 -8
  173. alita_sdk/tools/aws/delta_lake/__init__.py +15 -11
  174. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  175. alita_sdk/tools/azure_ai/search/__init__.py +14 -8
  176. alita_sdk/tools/base/tool.py +5 -1
  177. alita_sdk/tools/base_indexer_toolkit.py +454 -110
  178. alita_sdk/tools/bitbucket/__init__.py +28 -19
  179. alita_sdk/tools/bitbucket/api_wrapper.py +285 -27
  180. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
  181. alita_sdk/tools/browser/__init__.py +41 -16
  182. alita_sdk/tools/browser/crawler.py +3 -1
  183. alita_sdk/tools/browser/utils.py +15 -6
  184. alita_sdk/tools/carrier/__init__.py +18 -17
  185. alita_sdk/tools/carrier/backend_reports_tool.py +8 -4
  186. alita_sdk/tools/carrier/excel_reporter.py +8 -4
  187. alita_sdk/tools/chunkers/__init__.py +3 -1
  188. alita_sdk/tools/chunkers/code/codeparser.py +1 -1
  189. alita_sdk/tools/chunkers/sematic/json_chunker.py +2 -1
  190. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  191. alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
  192. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  193. alita_sdk/tools/cloud/aws/__init__.py +12 -7
  194. alita_sdk/tools/cloud/azure/__init__.py +12 -7
  195. alita_sdk/tools/cloud/gcp/__init__.py +12 -7
  196. alita_sdk/tools/cloud/k8s/__init__.py +12 -7
  197. alita_sdk/tools/code/linter/__init__.py +10 -8
  198. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  199. alita_sdk/tools/code/sonar/__init__.py +21 -13
  200. alita_sdk/tools/code_indexer_toolkit.py +199 -0
  201. alita_sdk/tools/confluence/__init__.py +22 -14
  202. alita_sdk/tools/confluence/api_wrapper.py +197 -58
  203. alita_sdk/tools/confluence/loader.py +14 -2
  204. alita_sdk/tools/custom_open_api/__init__.py +12 -5
  205. alita_sdk/tools/elastic/__init__.py +11 -8
  206. alita_sdk/tools/elitea_base.py +546 -64
  207. alita_sdk/tools/figma/__init__.py +60 -11
  208. alita_sdk/tools/figma/api_wrapper.py +1400 -167
  209. alita_sdk/tools/figma/figma_client.py +73 -0
  210. alita_sdk/tools/figma/toon_tools.py +2748 -0
  211. alita_sdk/tools/github/__init__.py +18 -17
  212. alita_sdk/tools/github/api_wrapper.py +9 -26
  213. alita_sdk/tools/github/github_client.py +81 -12
  214. alita_sdk/tools/github/schemas.py +2 -1
  215. alita_sdk/tools/github/tool.py +5 -1
  216. alita_sdk/tools/gitlab/__init__.py +19 -13
  217. alita_sdk/tools/gitlab/api_wrapper.py +256 -80
  218. alita_sdk/tools/gitlab_org/__init__.py +14 -10
  219. alita_sdk/tools/google/bigquery/__init__.py +14 -13
  220. alita_sdk/tools/google/bigquery/tool.py +5 -1
  221. alita_sdk/tools/google_places/__init__.py +21 -11
  222. alita_sdk/tools/jira/__init__.py +22 -11
  223. alita_sdk/tools/jira/api_wrapper.py +315 -168
  224. alita_sdk/tools/keycloak/__init__.py +11 -8
  225. alita_sdk/tools/localgit/__init__.py +9 -3
  226. alita_sdk/tools/localgit/local_git.py +62 -54
  227. alita_sdk/tools/localgit/tool.py +5 -1
  228. alita_sdk/tools/memory/__init__.py +38 -14
  229. alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
  230. alita_sdk/tools/ocr/__init__.py +11 -8
  231. alita_sdk/tools/openapi/__init__.py +491 -106
  232. alita_sdk/tools/openapi/api_wrapper.py +1357 -0
  233. alita_sdk/tools/openapi/tool.py +20 -0
  234. alita_sdk/tools/pandas/__init__.py +20 -12
  235. alita_sdk/tools/pandas/api_wrapper.py +40 -45
  236. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  237. alita_sdk/tools/postman/__init__.py +11 -11
  238. alita_sdk/tools/postman/api_wrapper.py +19 -8
  239. alita_sdk/tools/postman/postman_analysis.py +8 -1
  240. alita_sdk/tools/pptx/__init__.py +11 -10
  241. alita_sdk/tools/qtest/__init__.py +22 -14
  242. alita_sdk/tools/qtest/api_wrapper.py +1784 -88
  243. alita_sdk/tools/rally/__init__.py +13 -10
  244. alita_sdk/tools/report_portal/__init__.py +23 -16
  245. alita_sdk/tools/salesforce/__init__.py +22 -16
  246. alita_sdk/tools/servicenow/__init__.py +21 -16
  247. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  248. alita_sdk/tools/sharepoint/__init__.py +17 -14
  249. alita_sdk/tools/sharepoint/api_wrapper.py +179 -39
  250. alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
  251. alita_sdk/tools/sharepoint/utils.py +8 -2
  252. alita_sdk/tools/slack/__init__.py +13 -8
  253. alita_sdk/tools/sql/__init__.py +22 -19
  254. alita_sdk/tools/sql/api_wrapper.py +71 -23
  255. alita_sdk/tools/testio/__init__.py +21 -13
  256. alita_sdk/tools/testrail/__init__.py +13 -11
  257. alita_sdk/tools/testrail/api_wrapper.py +214 -46
  258. alita_sdk/tools/utils/__init__.py +28 -4
  259. alita_sdk/tools/utils/content_parser.py +241 -55
  260. alita_sdk/tools/utils/text_operations.py +254 -0
  261. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
  262. alita_sdk/tools/xray/__init__.py +18 -14
  263. alita_sdk/tools/xray/api_wrapper.py +58 -113
  264. alita_sdk/tools/yagmail/__init__.py +9 -3
  265. alita_sdk/tools/zephyr/__init__.py +12 -7
  266. alita_sdk/tools/zephyr_enterprise/__init__.py +16 -9
  267. alita_sdk/tools/zephyr_enterprise/api_wrapper.py +30 -15
  268. alita_sdk/tools/zephyr_essential/__init__.py +16 -10
  269. alita_sdk/tools/zephyr_essential/api_wrapper.py +297 -54
  270. alita_sdk/tools/zephyr_essential/client.py +6 -4
  271. alita_sdk/tools/zephyr_scale/__init__.py +13 -8
  272. alita_sdk/tools/zephyr_scale/api_wrapper.py +39 -31
  273. alita_sdk/tools/zephyr_squad/__init__.py +12 -7
  274. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/METADATA +184 -37
  275. alita_sdk-0.3.584.dist-info/RECORD +452 -0
  276. alita_sdk-0.3.584.dist-info/entry_points.txt +2 -0
  277. alita_sdk/tools/bitbucket/tools.py +0 -304
  278. alita_sdk-0.3.257.dist-info/RECORD +0 -343
  279. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/WHEEL +0 -0
  280. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/licenses/LICENSE +0 -0
  281. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,629 @@
1
+ """
2
+ JavaScript/TypeScript Parser - Regex-based parsing.
3
+
4
+ This parser uses regex patterns for JavaScript/TypeScript analysis:
5
+ - Import/export detection
6
+ - Class and function extraction
7
+ - Inheritance patterns
8
+ - Function calls and references
9
+
10
+ Works without external dependencies like tree-sitter.
11
+ """
12
+
13
+ import re
14
+ import hashlib
15
+ import logging
16
+ import time
17
+ import concurrent.futures
18
+ from pathlib import Path
19
+ from typing import Dict, List, Optional, Set, Union, Tuple
20
+
21
+ from .base import (
22
+ BaseParser, ParseResult, Symbol, Relationship,
23
+ SymbolType, RelationshipType, Scope, Position, Range,
24
+ parser_registry
25
+ )
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ # Comprehensive regex patterns for JavaScript/TypeScript
31
+ PATTERNS = {
32
+ # ES6 imports
33
+ 'import_default': re.compile(
34
+ r'import\s+(\w+)\s+from\s+[\'"]([^\'"]+)[\'"]',
35
+ re.MULTILINE
36
+ ),
37
+ 'import_named': re.compile(
38
+ r'import\s+\{([^}]+)\}\s+from\s+[\'"]([^\'"]+)[\'"]',
39
+ re.MULTILINE
40
+ ),
41
+ 'import_all': re.compile(
42
+ r'import\s+\*\s+as\s+(\w+)\s+from\s+[\'"]([^\'"]+)[\'"]',
43
+ re.MULTILINE
44
+ ),
45
+ 'import_side_effect': re.compile(
46
+ r'import\s+[\'"]([^\'"]+)[\'"]',
47
+ re.MULTILINE
48
+ ),
49
+ 'import_type': re.compile(
50
+ r'import\s+type\s+\{([^}]+)\}\s+from\s+[\'"]([^\'"]+)[\'"]',
51
+ re.MULTILINE
52
+ ),
53
+
54
+ # CommonJS
55
+ 'require': re.compile(
56
+ r'(?:const|let|var)\s+(\w+)\s*=\s*require\s*\(\s*[\'"]([^\'"]+)[\'"]\s*\)',
57
+ re.MULTILINE
58
+ ),
59
+ 'require_destructure': re.compile(
60
+ r'(?:const|let|var)\s+\{([^}]+)\}\s*=\s*require\s*\(\s*[\'"]([^\'"]+)[\'"]\s*\)',
61
+ re.MULTILINE
62
+ ),
63
+
64
+ # Dynamic import
65
+ 'dynamic_import': re.compile(
66
+ r'import\s*\(\s*[\'"]([^\'"]+)[\'"]\s*\)',
67
+ re.MULTILINE
68
+ ),
69
+
70
+ # Exports
71
+ 'export_default': re.compile(
72
+ r'export\s+default\s+(?:class|function|const|let|var)?\s*(\w+)?',
73
+ re.MULTILINE
74
+ ),
75
+ 'export_named': re.compile(
76
+ r'export\s+(?:const|let|var|function|class|interface|type|enum)\s+(\w+)',
77
+ re.MULTILINE
78
+ ),
79
+ 'export_from': re.compile(
80
+ r'export\s+\{([^}]+)\}\s+from\s+[\'"]([^\'"]+)[\'"]',
81
+ re.MULTILINE
82
+ ),
83
+ 'export_all': re.compile(
84
+ r'export\s+\*\s+from\s+[\'"]([^\'"]+)[\'"]',
85
+ re.MULTILINE
86
+ ),
87
+
88
+ # Classes
89
+ 'class_def': re.compile(
90
+ r'(?:export\s+)?(?:abstract\s+)?class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([\w,\s]+))?',
91
+ re.MULTILINE
92
+ ),
93
+
94
+ # Functions
95
+ 'function_def': re.compile(
96
+ r'(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\([^)]*\)',
97
+ re.MULTILINE
98
+ ),
99
+ 'arrow_function': re.compile(
100
+ r'(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[a-zA-Z_]\w*)\s*=>',
101
+ re.MULTILINE
102
+ ),
103
+ 'method_def': re.compile(
104
+ r'^\s*(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*\w+)?\s*\{',
105
+ re.MULTILINE
106
+ ),
107
+
108
+ # Interfaces and types (TypeScript)
109
+ 'interface_def': re.compile(
110
+ r'(?:export\s+)?interface\s+(\w+)(?:\s+extends\s+([\w,\s]+))?',
111
+ re.MULTILINE
112
+ ),
113
+ 'type_alias': re.compile(
114
+ r'(?:export\s+)?type\s+(\w+)\s*=',
115
+ re.MULTILINE
116
+ ),
117
+ 'enum_def': re.compile(
118
+ r'(?:export\s+)?enum\s+(\w+)',
119
+ re.MULTILINE
120
+ ),
121
+
122
+ # Variables
123
+ 'const_def': re.compile(
124
+ r'(?:export\s+)?const\s+(\w+)\s*(?::\s*[\w<>\[\]|&\s]+)?\s*=',
125
+ re.MULTILINE
126
+ ),
127
+
128
+ # Function calls
129
+ 'function_call': re.compile(
130
+ r'(?<![.\w])(\w+)\s*\(',
131
+ re.MULTILINE
132
+ ),
133
+
134
+ # JSX component usage
135
+ 'jsx_component': re.compile(
136
+ r'<([A-Z]\w*)[>\s/]',
137
+ re.MULTILINE
138
+ ),
139
+
140
+ # Decorators (TypeScript/experimental)
141
+ 'decorator': re.compile(
142
+ r'@(\w+)(?:\([^)]*\))?',
143
+ re.MULTILINE
144
+ ),
145
+ }
146
+
147
+
148
+ def _parse_single_file(file_path: str) -> Tuple[str, ParseResult]:
149
+ """Parse a single JavaScript file."""
150
+ try:
151
+ parser = JavaScriptParser()
152
+ result = parser.parse_file(file_path)
153
+ return file_path, result
154
+ except Exception as e:
155
+ logger.warning(f"Failed to parse {file_path}: {e}")
156
+ return file_path, ParseResult(
157
+ file_path=file_path,
158
+ language="javascript",
159
+ symbols=[],
160
+ relationships=[]
161
+ )
162
+
163
+
164
+ class JavaScriptParser(BaseParser):
165
+ """
166
+ JavaScript/TypeScript parser using regex patterns.
167
+
168
+ Extracts imports, exports, classes, functions, and relationships.
169
+ """
170
+
171
+ def __init__(self):
172
+ super().__init__("javascript")
173
+ self._current_file = ""
174
+ self._current_content = ""
175
+
176
+ # Cross-file resolution
177
+ self._global_exports: Dict[str, str] = {} # export_name -> file_path
178
+ self._global_classes: Dict[str, str] = {}
179
+ self._global_functions: Dict[str, str] = {}
180
+
181
+ def _get_supported_extensions(self) -> Set[str]:
182
+ return {'.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'}
183
+
184
+ def parse_file(self, file_path: Union[str, Path], content: Optional[str] = None) -> ParseResult:
185
+ """Parse a JavaScript/TypeScript file."""
186
+ start_time = time.time()
187
+ file_path = str(file_path)
188
+ self._current_file = file_path
189
+
190
+ try:
191
+ if content is None:
192
+ with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
193
+ content = f.read()
194
+
195
+ self._current_content = content
196
+
197
+ symbols = self._extract_symbols(content, file_path)
198
+ relationships = self._extract_relationships(content, symbols, file_path)
199
+ imports = self._extract_imports(content)
200
+ exports = self._extract_exports(content)
201
+
202
+ result = ParseResult(
203
+ file_path=file_path,
204
+ language="javascript",
205
+ symbols=symbols,
206
+ relationships=relationships,
207
+ imports=imports,
208
+ exports=exports,
209
+ parse_time=time.time() - start_time
210
+ )
211
+
212
+ return self.validate_result(result)
213
+
214
+ except Exception as e:
215
+ logger.error(f"Failed to parse JS file {file_path}: {e}")
216
+ return ParseResult(
217
+ file_path=file_path,
218
+ language="javascript",
219
+ symbols=[],
220
+ relationships=[],
221
+ parse_time=time.time() - start_time,
222
+ errors=[str(e)]
223
+ )
224
+
225
+ def _extract_symbols(self, content: str, file_path: str) -> List[Symbol]:
226
+ """Extract symbols from JavaScript content."""
227
+ symbols = []
228
+ lines = content.split('\n')
229
+
230
+ # Module symbol
231
+ symbols.append(Symbol(
232
+ name=Path(file_path).stem,
233
+ symbol_type=SymbolType.MODULE,
234
+ scope=Scope.GLOBAL,
235
+ range=Range(Position(1, 0), Position(len(lines), 0)),
236
+ file_path=file_path
237
+ ))
238
+
239
+ # Classes
240
+ for match in PATTERNS['class_def'].finditer(content):
241
+ line = content[:match.start()].count('\n') + 1
242
+ class_name = match.group(1)
243
+ extends = match.group(2)
244
+
245
+ symbols.append(Symbol(
246
+ name=class_name,
247
+ symbol_type=SymbolType.CLASS,
248
+ scope=Scope.GLOBAL,
249
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
250
+ file_path=file_path,
251
+ is_exported='export' in match.group(0),
252
+ metadata={'extends': extends} if extends else {}
253
+ ))
254
+
255
+ # Interfaces (TypeScript)
256
+ for match in PATTERNS['interface_def'].finditer(content):
257
+ line = content[:match.start()].count('\n') + 1
258
+ symbols.append(Symbol(
259
+ name=match.group(1),
260
+ symbol_type=SymbolType.INTERFACE,
261
+ scope=Scope.GLOBAL,
262
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
263
+ file_path=file_path,
264
+ is_exported='export' in match.group(0)
265
+ ))
266
+
267
+ # Type aliases
268
+ for match in PATTERNS['type_alias'].finditer(content):
269
+ line = content[:match.start()].count('\n') + 1
270
+ symbols.append(Symbol(
271
+ name=match.group(1),
272
+ symbol_type=SymbolType.TYPE_ALIAS,
273
+ scope=Scope.GLOBAL,
274
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
275
+ file_path=file_path,
276
+ is_exported='export' in match.group(0)
277
+ ))
278
+
279
+ # Enums
280
+ for match in PATTERNS['enum_def'].finditer(content):
281
+ line = content[:match.start()].count('\n') + 1
282
+ symbols.append(Symbol(
283
+ name=match.group(1),
284
+ symbol_type=SymbolType.ENUM,
285
+ scope=Scope.GLOBAL,
286
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
287
+ file_path=file_path,
288
+ is_exported='export' in match.group(0)
289
+ ))
290
+
291
+ # Functions
292
+ for match in PATTERNS['function_def'].finditer(content):
293
+ line = content[:match.start()].count('\n') + 1
294
+ symbols.append(Symbol(
295
+ name=match.group(1),
296
+ symbol_type=SymbolType.FUNCTION,
297
+ scope=Scope.GLOBAL,
298
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
299
+ file_path=file_path,
300
+ is_async='async' in match.group(0),
301
+ is_exported='export' in match.group(0)
302
+ ))
303
+
304
+ # Arrow functions
305
+ for match in PATTERNS['arrow_function'].finditer(content):
306
+ line = content[:match.start()].count('\n') + 1
307
+ symbols.append(Symbol(
308
+ name=match.group(1),
309
+ symbol_type=SymbolType.FUNCTION,
310
+ scope=Scope.GLOBAL,
311
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
312
+ file_path=file_path,
313
+ is_async='async' in match.group(0)
314
+ ))
315
+
316
+ # Constants
317
+ for match in PATTERNS['const_def'].finditer(content):
318
+ line = content[:match.start()].count('\n') + 1
319
+ name = match.group(1)
320
+ # Skip if already added as arrow function
321
+ if not any(s.name == name and s.symbol_type == SymbolType.FUNCTION for s in symbols):
322
+ symbols.append(Symbol(
323
+ name=name,
324
+ symbol_type=SymbolType.CONSTANT if name.isupper() else SymbolType.VARIABLE,
325
+ scope=Scope.GLOBAL,
326
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
327
+ file_path=file_path,
328
+ is_exported='export' in match.group(0)
329
+ ))
330
+
331
+ # Imports as symbols
332
+ for match in PATTERNS['import_default'].finditer(content):
333
+ line = content[:match.start()].count('\n') + 1
334
+ symbols.append(Symbol(
335
+ name=match.group(1),
336
+ symbol_type=SymbolType.IMPORT,
337
+ scope=Scope.GLOBAL,
338
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
339
+ file_path=file_path,
340
+ metadata={'from': match.group(2), 'type': 'default'}
341
+ ))
342
+
343
+ for match in PATTERNS['import_named'].finditer(content):
344
+ line = content[:match.start()].count('\n') + 1
345
+ names = [n.strip().split(' as ')[0].strip() for n in match.group(1).split(',')]
346
+ for name in names:
347
+ if name:
348
+ symbols.append(Symbol(
349
+ name=name,
350
+ symbol_type=SymbolType.IMPORT,
351
+ scope=Scope.GLOBAL,
352
+ range=Range(Position(line, 0), Position(line, len(match.group(0)))),
353
+ file_path=file_path,
354
+ metadata={'from': match.group(2), 'type': 'named'}
355
+ ))
356
+
357
+ return symbols
358
+
359
+ def _extract_relationships(self, content: str, symbols: List[Symbol], file_path: str) -> List[Relationship]:
360
+ """Extract relationships from JavaScript content."""
361
+ relationships = []
362
+ module_name = Path(file_path).stem
363
+ symbol_names = {s.name for s in symbols}
364
+
365
+ # Import relationships
366
+ for match in PATTERNS['import_default'].finditer(content):
367
+ line = content[:match.start()].count('\n') + 1
368
+ relationships.append(Relationship(
369
+ source_symbol=module_name,
370
+ target_symbol=match.group(2),
371
+ relationship_type=RelationshipType.IMPORTS,
372
+ source_file=file_path,
373
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
374
+ confidence=1.0
375
+ ))
376
+
377
+ for match in PATTERNS['import_named'].finditer(content):
378
+ line = content[:match.start()].count('\n') + 1
379
+ relationships.append(Relationship(
380
+ source_symbol=module_name,
381
+ target_symbol=match.group(2),
382
+ relationship_type=RelationshipType.IMPORTS,
383
+ source_file=file_path,
384
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
385
+ confidence=1.0
386
+ ))
387
+
388
+ for match in PATTERNS['import_all'].finditer(content):
389
+ line = content[:match.start()].count('\n') + 1
390
+ relationships.append(Relationship(
391
+ source_symbol=module_name,
392
+ target_symbol=match.group(2),
393
+ relationship_type=RelationshipType.IMPORTS,
394
+ source_file=file_path,
395
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
396
+ confidence=1.0
397
+ ))
398
+
399
+ for match in PATTERNS['require'].finditer(content):
400
+ line = content[:match.start()].count('\n') + 1
401
+ relationships.append(Relationship(
402
+ source_symbol=module_name,
403
+ target_symbol=match.group(2),
404
+ relationship_type=RelationshipType.IMPORTS,
405
+ source_file=file_path,
406
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
407
+ confidence=1.0
408
+ ))
409
+
410
+ for match in PATTERNS['dynamic_import'].finditer(content):
411
+ line = content[:match.start()].count('\n') + 1
412
+ relationships.append(Relationship(
413
+ source_symbol=module_name,
414
+ target_symbol=match.group(1),
415
+ relationship_type=RelationshipType.IMPORTS,
416
+ source_file=file_path,
417
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
418
+ confidence=0.9
419
+ ))
420
+
421
+ # Inheritance relationships
422
+ for match in PATTERNS['class_def'].finditer(content):
423
+ class_name = match.group(1)
424
+ extends = match.group(2)
425
+ implements = match.group(3)
426
+ line = content[:match.start()].count('\n') + 1
427
+
428
+ if extends:
429
+ relationships.append(Relationship(
430
+ source_symbol=class_name,
431
+ target_symbol=extends,
432
+ relationship_type=RelationshipType.INHERITANCE,
433
+ source_file=file_path,
434
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
435
+ confidence=0.95
436
+ ))
437
+
438
+ if implements:
439
+ for iface in implements.split(','):
440
+ iface = iface.strip()
441
+ if iface:
442
+ relationships.append(Relationship(
443
+ source_symbol=class_name,
444
+ target_symbol=iface,
445
+ relationship_type=RelationshipType.IMPLEMENTATION,
446
+ source_file=file_path,
447
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
448
+ confidence=0.95
449
+ ))
450
+
451
+ # Interface extension
452
+ for match in PATTERNS['interface_def'].finditer(content):
453
+ iface_name = match.group(1)
454
+ extends = match.group(2)
455
+ if extends:
456
+ line = content[:match.start()].count('\n') + 1
457
+ for parent in extends.split(','):
458
+ parent = parent.strip()
459
+ if parent:
460
+ relationships.append(Relationship(
461
+ source_symbol=iface_name,
462
+ target_symbol=parent,
463
+ relationship_type=RelationshipType.INHERITANCE,
464
+ source_file=file_path,
465
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
466
+ confidence=0.95
467
+ ))
468
+
469
+ # JSX component usage
470
+ for match in PATTERNS['jsx_component'].finditer(content):
471
+ component = match.group(1)
472
+ if component in symbol_names or component[0].isupper():
473
+ line = content[:match.start()].count('\n') + 1
474
+ relationships.append(Relationship(
475
+ source_symbol=module_name,
476
+ target_symbol=component,
477
+ relationship_type=RelationshipType.USES,
478
+ source_file=file_path,
479
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
480
+ confidence=0.85
481
+ ))
482
+
483
+ # Decorator relationships
484
+ for match in PATTERNS['decorator'].finditer(content):
485
+ dec_name = match.group(1)
486
+ line = content[:match.start()].count('\n') + 1
487
+
488
+ # Find what's being decorated (next class/function)
489
+ remaining = content[match.end():]
490
+ class_match = PATTERNS['class_def'].search(remaining)
491
+ func_match = PATTERNS['function_def'].search(remaining)
492
+
493
+ target = None
494
+ if class_match and (not func_match or class_match.start() < func_match.start()):
495
+ target = class_match.group(1)
496
+ elif func_match:
497
+ target = func_match.group(1)
498
+
499
+ if target:
500
+ relationships.append(Relationship(
501
+ source_symbol=dec_name,
502
+ target_symbol=target,
503
+ relationship_type=RelationshipType.DECORATES,
504
+ source_file=file_path,
505
+ source_range=Range(Position(line, 0), Position(line, len(match.group(0)))),
506
+ confidence=0.90
507
+ ))
508
+
509
+ return relationships
510
+
511
+ def _extract_imports(self, content: str) -> List[str]:
512
+ """Extract import paths."""
513
+ imports = []
514
+
515
+ for match in PATTERNS['import_default'].finditer(content):
516
+ imports.append(match.group(2))
517
+ for match in PATTERNS['import_named'].finditer(content):
518
+ imports.append(match.group(2))
519
+ for match in PATTERNS['import_all'].finditer(content):
520
+ imports.append(match.group(2))
521
+ for match in PATTERNS['import_side_effect'].finditer(content):
522
+ imports.append(match.group(1))
523
+ for match in PATTERNS['require'].finditer(content):
524
+ imports.append(match.group(2))
525
+ for match in PATTERNS['dynamic_import'].finditer(content):
526
+ imports.append(match.group(1))
527
+
528
+ return list(set(imports))
529
+
530
+ def _extract_exports(self, content: str) -> List[str]:
531
+ """Extract export names."""
532
+ exports = []
533
+
534
+ for match in PATTERNS['export_default'].finditer(content):
535
+ if match.group(1):
536
+ exports.append(match.group(1))
537
+ else:
538
+ exports.append('default')
539
+
540
+ for match in PATTERNS['export_named'].finditer(content):
541
+ exports.append(match.group(1))
542
+
543
+ for match in PATTERNS['export_from'].finditer(content):
544
+ names = [n.strip().split(' as ')[0].strip() for n in match.group(1).split(',')]
545
+ exports.extend([n for n in names if n])
546
+
547
+ return list(set(exports))
548
+
549
+ def parse_multiple_files(self, file_paths: List[str], max_workers: int = 4) -> Dict[str, ParseResult]:
550
+ """Parse multiple JavaScript files with cross-file resolution."""
551
+ results: Dict[str, ParseResult] = {}
552
+ total = len(file_paths)
553
+
554
+ self._global_exports = {}
555
+ self._global_classes = {}
556
+ self._global_functions = {}
557
+
558
+ logger.info(f"Parsing {total} JavaScript files")
559
+ start_time = time.time()
560
+
561
+ # Parse in parallel
562
+ with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
563
+ futures = {executor.submit(_parse_single_file, fp): fp for fp in file_paths}
564
+
565
+ for future in concurrent.futures.as_completed(futures):
566
+ try:
567
+ fp, result = future.result(timeout=60)
568
+ results[fp] = result
569
+ except Exception as e:
570
+ fp = futures[future]
571
+ logger.error(f"Failed to parse {fp}: {e}")
572
+ results[fp] = ParseResult(
573
+ file_path=fp,
574
+ language="javascript",
575
+ symbols=[],
576
+ relationships=[],
577
+ errors=[str(e)]
578
+ )
579
+
580
+ # Build global registry
581
+ for fp, result in results.items():
582
+ self._build_global_registry(fp, result)
583
+
584
+ # Enhance relationships
585
+ for fp, result in results.items():
586
+ self._enhance_relationships(fp, result)
587
+
588
+ elapsed = time.time() - start_time
589
+ logger.info(f"Parsed {len(results)} JavaScript files in {elapsed:.2f}s")
590
+
591
+ return results
592
+
593
+ def _build_global_registry(self, file_path: str, result: ParseResult):
594
+ """Build global export registry."""
595
+ for exp in result.exports:
596
+ self._global_exports[exp] = file_path
597
+
598
+ for symbol in result.symbols:
599
+ if symbol.is_exported:
600
+ if symbol.symbol_type == SymbolType.CLASS:
601
+ self._global_classes[symbol.name] = file_path
602
+ elif symbol.symbol_type == SymbolType.FUNCTION:
603
+ self._global_functions[symbol.name] = file_path
604
+
605
+ def _enhance_relationships(self, file_path: str, result: ParseResult):
606
+ """Enhance relationships with cross-file info."""
607
+ for rel in result.relationships:
608
+ target = rel.target_symbol
609
+
610
+ # Check global registries
611
+ if target in self._global_exports:
612
+ target_file = self._global_exports[target]
613
+ if target_file != file_path:
614
+ rel.target_file = target_file
615
+ rel.is_cross_file = True
616
+ elif target in self._global_classes:
617
+ target_file = self._global_classes[target]
618
+ if target_file != file_path:
619
+ rel.target_file = target_file
620
+ rel.is_cross_file = True
621
+ elif target in self._global_functions:
622
+ target_file = self._global_functions[target]
623
+ if target_file != file_path:
624
+ rel.target_file = target_file
625
+ rel.is_cross_file = True
626
+
627
+
628
+ # Register the parser
629
+ parser_registry.register_parser(JavaScriptParser())