jarvis-ai-assistant 0.7.8__py3-none-any.whl → 1.0.2__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
|
@@ -2,17 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
|
-
from typing import List
|
|
5
|
+
from typing import List
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from typing import Set
|
|
8
|
+
from typing import cast
|
|
6
9
|
|
|
7
|
-
from tree_sitter import Language
|
|
10
|
+
from tree_sitter import Language
|
|
11
|
+
from tree_sitter import Node
|
|
8
12
|
|
|
9
13
|
from ..base_language import BaseLanguageSupport
|
|
10
|
-
from ..dependency_analyzer import Dependency
|
|
14
|
+
from ..dependency_analyzer import Dependency
|
|
15
|
+
from ..dependency_analyzer import DependencyAnalyzer
|
|
16
|
+
from ..dependency_analyzer import DependencyGraph
|
|
11
17
|
from ..file_ignore import filter_walk_dirs
|
|
12
|
-
from ..symbol_extractor import Symbol
|
|
18
|
+
from ..symbol_extractor import Symbol
|
|
19
|
+
from ..symbol_extractor import SymbolExtractor
|
|
13
20
|
from ..tree_sitter_extractor import TreeSitterExtractor
|
|
14
21
|
|
|
15
|
-
|
|
16
22
|
# --- Rust Symbol Query ---
|
|
17
23
|
|
|
18
24
|
RUST_SYMBOL_QUERY = """
|
|
@@ -49,8 +55,6 @@ RUST_SYMBOL_QUERY = """
|
|
|
49
55
|
(type_item
|
|
50
56
|
name: (type_identifier) @type.name)
|
|
51
57
|
|
|
52
|
-
(extern_block) @extern
|
|
53
|
-
|
|
54
58
|
(attribute_item) @attribute
|
|
55
59
|
"""
|
|
56
60
|
|
|
@@ -58,13 +62,17 @@ RUST_SYMBOL_QUERY = """
|
|
|
58
62
|
|
|
59
63
|
try:
|
|
60
64
|
import tree_sitter_rust
|
|
61
|
-
|
|
65
|
+
|
|
66
|
+
RUST_LANGUAGE: Optional[Language] = cast(
|
|
67
|
+
Optional[Language], tree_sitter_rust.language()
|
|
68
|
+
)
|
|
62
69
|
except (ImportError, Exception):
|
|
63
70
|
RUST_LANGUAGE = None
|
|
64
71
|
|
|
65
72
|
|
|
66
73
|
# --- Rust Symbol Extractor ---
|
|
67
74
|
|
|
75
|
+
|
|
68
76
|
class RustSymbolExtractor(TreeSitterExtractor):
|
|
69
77
|
"""Extracts symbols from Rust code using tree-sitter."""
|
|
70
78
|
|
|
@@ -73,7 +81,9 @@ class RustSymbolExtractor(TreeSitterExtractor):
|
|
|
73
81
|
raise RuntimeError("Rust tree-sitter grammar not available.")
|
|
74
82
|
super().__init__(RUST_LANGUAGE, RUST_SYMBOL_QUERY)
|
|
75
83
|
|
|
76
|
-
def _create_symbol_from_capture(
|
|
84
|
+
def _create_symbol_from_capture(
|
|
85
|
+
self, node: Node, name: str, file_path: str
|
|
86
|
+
) -> Optional[Symbol]:
|
|
77
87
|
"""Maps a tree-sitter capture to a Symbol object."""
|
|
78
88
|
kind_map = {
|
|
79
89
|
"function.name": "function",
|
|
@@ -90,7 +100,7 @@ class RustSymbolExtractor(TreeSitterExtractor):
|
|
|
90
100
|
"extern": "extern",
|
|
91
101
|
"attribute": "attribute",
|
|
92
102
|
}
|
|
93
|
-
|
|
103
|
+
|
|
94
104
|
symbol_kind = kind_map.get(name)
|
|
95
105
|
if not symbol_kind:
|
|
96
106
|
return None
|
|
@@ -98,44 +108,56 @@ class RustSymbolExtractor(TreeSitterExtractor):
|
|
|
98
108
|
# 对于 attribute,提取属性内容作为名称
|
|
99
109
|
if symbol_kind == "attribute":
|
|
100
110
|
# 提取属性文本
|
|
101
|
-
|
|
111
|
+
if node.text is None:
|
|
112
|
+
return None
|
|
113
|
+
attr_text = node.text.decode("utf8").strip()
|
|
102
114
|
# 移除开头的 # 或 #!
|
|
103
|
-
if attr_text.startswith(
|
|
115
|
+
if attr_text.startswith("#!"):
|
|
104
116
|
attr_text = attr_text[2:].strip()
|
|
105
|
-
elif attr_text.startswith(
|
|
117
|
+
elif attr_text.startswith("#"):
|
|
106
118
|
attr_text = attr_text[1:].strip()
|
|
107
119
|
# 移除外层的 []
|
|
108
|
-
if attr_text.startswith(
|
|
120
|
+
if attr_text.startswith("[") and attr_text.endswith("]"):
|
|
109
121
|
attr_text = attr_text[1:-1].strip()
|
|
110
|
-
|
|
122
|
+
|
|
111
123
|
# 提取属性名称(可能是 test, derive(Debug), cfg(test) 等)
|
|
112
124
|
# 对于简单属性如 #[test],直接使用 test
|
|
113
125
|
# 对于复杂属性如 #[derive(Debug)],使用 derive
|
|
114
126
|
# 对于路径属性如 #[cfg(test)],使用 cfg
|
|
115
|
-
attr_name =
|
|
116
|
-
|
|
127
|
+
attr_name = (
|
|
128
|
+
attr_text.split("(")[0]
|
|
129
|
+
.split("[")[0]
|
|
130
|
+
.split("=")[0]
|
|
131
|
+
.split(",")[0]
|
|
132
|
+
.strip()
|
|
133
|
+
)
|
|
134
|
+
|
|
117
135
|
# 如果属性名称为空或只包含空白,使用整个属性文本(去掉括号)
|
|
118
|
-
if not attr_name or attr_name ==
|
|
136
|
+
if not attr_name or attr_name == "":
|
|
119
137
|
symbol_name = attr_text if attr_text else "attribute"
|
|
120
138
|
else:
|
|
121
139
|
# 使用属性名称,但保留完整文本用于显示
|
|
122
140
|
symbol_name = attr_name
|
|
123
141
|
elif symbol_kind == "extern":
|
|
124
142
|
# 对于 extern 块,提取 extern 关键字后的内容作为名称
|
|
125
|
-
|
|
143
|
+
if node.text is None:
|
|
144
|
+
return None
|
|
145
|
+
extern_text = node.text.decode("utf8").strip()
|
|
126
146
|
# 提取 extern "C" 或 extern "Rust" 等
|
|
127
147
|
if '"' in extern_text:
|
|
128
148
|
# 提取引号中的内容
|
|
129
149
|
start = extern_text.find('"')
|
|
130
150
|
end = extern_text.find('"', start + 1)
|
|
131
151
|
if end > start:
|
|
132
|
-
symbol_name = f"extern_{extern_text[start+1:end]}"
|
|
152
|
+
symbol_name = f"extern_{extern_text[start + 1 : end]}"
|
|
133
153
|
else:
|
|
134
154
|
symbol_name = "extern"
|
|
135
155
|
else:
|
|
136
156
|
symbol_name = "extern"
|
|
137
157
|
else:
|
|
138
|
-
|
|
158
|
+
if node.text is None:
|
|
159
|
+
return None
|
|
160
|
+
symbol_name = node.text.decode("utf8")
|
|
139
161
|
|
|
140
162
|
return Symbol(
|
|
141
163
|
name=symbol_name,
|
|
@@ -148,101 +170,114 @@ class RustSymbolExtractor(TreeSitterExtractor):
|
|
|
148
170
|
|
|
149
171
|
# --- Rust Dependency Analyzer ---
|
|
150
172
|
|
|
173
|
+
|
|
151
174
|
class RustDependencyAnalyzer(DependencyAnalyzer):
|
|
152
175
|
"""Analyzes Rust use and mod dependencies."""
|
|
153
176
|
|
|
154
177
|
def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
|
|
155
178
|
"""Analyzes Rust use and mod statements."""
|
|
156
179
|
dependencies: List[Dependency] = []
|
|
157
|
-
|
|
180
|
+
|
|
158
181
|
# Match use statements: use crate::module or use std::collections
|
|
159
|
-
use_pattern = re.compile(r
|
|
160
|
-
|
|
182
|
+
use_pattern = re.compile(r"use\s+([^;]+);")
|
|
183
|
+
|
|
161
184
|
# Match mod declarations: mod module_name;
|
|
162
|
-
mod_pattern = re.compile(r
|
|
163
|
-
|
|
164
|
-
for line_num, line in enumerate(content.split(
|
|
185
|
+
mod_pattern = re.compile(r"mod\s+(\w+)\s*;")
|
|
186
|
+
|
|
187
|
+
for line_num, line in enumerate(content.split("\n"), start=1):
|
|
165
188
|
# Check for use statements
|
|
166
189
|
use_match = use_pattern.search(line)
|
|
167
190
|
if use_match:
|
|
168
191
|
use_path = use_match.group(1).strip()
|
|
169
192
|
# Extract the crate/module name
|
|
170
|
-
parts = use_path.split(
|
|
193
|
+
parts = use_path.split("::")
|
|
171
194
|
if parts:
|
|
172
195
|
crate_name = parts[0]
|
|
173
|
-
symbol =
|
|
174
|
-
dependencies.append(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
196
|
+
symbol = "::".join(parts[1:]) if len(parts) > 1 else None
|
|
197
|
+
dependencies.append(
|
|
198
|
+
Dependency(
|
|
199
|
+
from_module=crate_name,
|
|
200
|
+
imported_symbol=symbol,
|
|
201
|
+
file_path=file_path,
|
|
202
|
+
line=line_num,
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
|
|
181
206
|
# Check for mod declarations
|
|
182
207
|
mod_match = mod_pattern.search(line)
|
|
183
208
|
if mod_match:
|
|
184
209
|
mod_name = mod_match.group(1)
|
|
185
|
-
dependencies.append(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
210
|
+
dependencies.append(
|
|
211
|
+
Dependency(
|
|
212
|
+
from_module=mod_name,
|
|
213
|
+
imported_symbol=None,
|
|
214
|
+
file_path=file_path,
|
|
215
|
+
line=line_num,
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
|
|
192
219
|
return dependencies
|
|
193
220
|
|
|
194
221
|
def build_dependency_graph(self, project_root: str) -> DependencyGraph:
|
|
195
222
|
"""Builds a dependency graph for a Rust project."""
|
|
196
223
|
graph = DependencyGraph()
|
|
197
|
-
|
|
224
|
+
|
|
198
225
|
for root, dirs, files in os.walk(project_root):
|
|
199
226
|
dirs[:] = filter_walk_dirs(dirs)
|
|
200
|
-
|
|
227
|
+
|
|
201
228
|
for file in files:
|
|
202
|
-
if not file.endswith(
|
|
229
|
+
if not file.endswith(".rs"):
|
|
203
230
|
continue
|
|
204
|
-
|
|
231
|
+
|
|
205
232
|
file_path = os.path.join(root, file)
|
|
206
233
|
try:
|
|
207
|
-
with open(file_path,
|
|
234
|
+
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
208
235
|
content = f.read()
|
|
209
|
-
|
|
236
|
+
|
|
210
237
|
dependencies = self.analyze_imports(file_path, content)
|
|
211
238
|
for dep in dependencies:
|
|
212
239
|
# For Rust, resolve mod declarations to file paths
|
|
213
|
-
if not dep.from_module.startswith(
|
|
240
|
+
if not dep.from_module.startswith(
|
|
241
|
+
("std", "core", "alloc", "proc_macro")
|
|
242
|
+
):
|
|
214
243
|
# Try to resolve local modules
|
|
215
|
-
dep_path = self._resolve_module_path(
|
|
244
|
+
dep_path = self._resolve_module_path(
|
|
245
|
+
project_root, dep.from_module, file_path
|
|
246
|
+
)
|
|
216
247
|
if dep_path and dep_path != file_path:
|
|
217
248
|
graph.add_dependency(file_path, dep_path)
|
|
218
249
|
except Exception:
|
|
219
250
|
continue
|
|
220
|
-
|
|
251
|
+
|
|
221
252
|
return graph
|
|
222
253
|
|
|
223
|
-
def _resolve_module_path(
|
|
254
|
+
def _resolve_module_path(
|
|
255
|
+
self, project_root: str, module_name: str, from_file: str
|
|
256
|
+
) -> Optional[str]:
|
|
224
257
|
"""Resolve a Rust module name to a file path."""
|
|
225
258
|
# Rust modules can be:
|
|
226
259
|
# 1. mod.rs in a directory
|
|
227
260
|
# 2. module_name.rs in the same directory
|
|
228
261
|
# 3. module_name/mod.rs
|
|
229
|
-
|
|
262
|
+
|
|
230
263
|
base_dir = os.path.dirname(from_file)
|
|
231
|
-
|
|
264
|
+
|
|
232
265
|
# Try module_name.rs in same directory
|
|
233
266
|
module_file = os.path.join(base_dir, f"{module_name}.rs")
|
|
234
267
|
if os.path.exists(module_file):
|
|
235
268
|
return module_file
|
|
236
|
-
|
|
269
|
+
|
|
237
270
|
# Try module_name/mod.rs
|
|
238
271
|
module_dir = os.path.join(base_dir, module_name)
|
|
239
272
|
mod_rs = os.path.join(module_dir, "mod.rs")
|
|
240
273
|
if os.path.exists(mod_rs):
|
|
241
274
|
return mod_rs
|
|
242
|
-
|
|
275
|
+
|
|
243
276
|
# Try in parent directories (for nested modules)
|
|
244
277
|
current_dir = base_dir
|
|
245
|
-
while current_dir != project_root and current_dir != os.path.dirname(
|
|
278
|
+
while current_dir != project_root and current_dir != os.path.dirname(
|
|
279
|
+
current_dir
|
|
280
|
+
):
|
|
246
281
|
module_file = os.path.join(current_dir, f"{module_name}.rs")
|
|
247
282
|
if os.path.exists(module_file):
|
|
248
283
|
return module_file
|
|
@@ -251,12 +286,12 @@ class RustDependencyAnalyzer(DependencyAnalyzer):
|
|
|
251
286
|
if os.path.exists(mod_rs):
|
|
252
287
|
return mod_rs
|
|
253
288
|
current_dir = os.path.dirname(current_dir)
|
|
254
|
-
|
|
289
|
+
|
|
255
290
|
return None
|
|
256
291
|
|
|
257
292
|
def _is_source_file(self, file_path: str) -> bool:
|
|
258
293
|
"""Check if a file is a Rust source file."""
|
|
259
|
-
return file_path.endswith(
|
|
294
|
+
return file_path.endswith(".rs")
|
|
260
295
|
|
|
261
296
|
|
|
262
297
|
class RustLanguageSupport(BaseLanguageSupport):
|
|
@@ -264,11 +299,11 @@ class RustLanguageSupport(BaseLanguageSupport):
|
|
|
264
299
|
|
|
265
300
|
@property
|
|
266
301
|
def language_name(self) -> str:
|
|
267
|
-
return
|
|
302
|
+
return "rust"
|
|
268
303
|
|
|
269
304
|
@property
|
|
270
305
|
def file_extensions(self) -> Set[str]:
|
|
271
|
-
return {
|
|
306
|
+
return {".rs"}
|
|
272
307
|
|
|
273
308
|
def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
|
|
274
309
|
try:
|
|
@@ -278,4 +313,3 @@ class RustLanguageSupport(BaseLanguageSupport):
|
|
|
278
313
|
|
|
279
314
|
def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
|
|
280
315
|
return RustDependencyAnalyzer()
|
|
281
|
-
|
|
@@ -2,18 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
|
-
from typing import List
|
|
5
|
+
from typing import List
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from typing import Set
|
|
8
|
+
from typing import cast
|
|
6
9
|
|
|
7
10
|
from ..base_language import BaseLanguageSupport
|
|
8
|
-
from ..dependency_analyzer import Dependency
|
|
11
|
+
from ..dependency_analyzer import Dependency
|
|
12
|
+
from ..dependency_analyzer import DependencyAnalyzer
|
|
13
|
+
from ..dependency_analyzer import DependencyGraph
|
|
9
14
|
from ..file_ignore import filter_walk_dirs
|
|
10
|
-
from ..symbol_extractor import Symbol
|
|
15
|
+
from ..symbol_extractor import Symbol
|
|
16
|
+
from ..symbol_extractor import SymbolExtractor
|
|
11
17
|
from ..tree_sitter_extractor import TreeSitterExtractor
|
|
12
18
|
|
|
13
19
|
try:
|
|
14
|
-
from tree_sitter import Language, Node
|
|
15
20
|
import tree_sitter_typescript
|
|
16
|
-
|
|
21
|
+
from tree_sitter import Language
|
|
22
|
+
from tree_sitter import Node
|
|
23
|
+
|
|
24
|
+
TS_LANGUAGE: Optional[Language] = cast(
|
|
25
|
+
Optional[Language], tree_sitter_typescript.language_typescript()
|
|
26
|
+
)
|
|
17
27
|
except (ImportError, Exception):
|
|
18
28
|
TS_LANGUAGE = None
|
|
19
29
|
|
|
@@ -71,13 +81,12 @@ class TypeScriptSymbolExtractor(TreeSitterExtractor):
|
|
|
71
81
|
if not TS_LANGUAGE:
|
|
72
82
|
raise RuntimeError("TypeScript tree-sitter grammar not available.")
|
|
73
83
|
# 如果传入的是 PyCapsule,需要转换为 Language 对象
|
|
74
|
-
|
|
75
|
-
lang = Language(TS_LANGUAGE)
|
|
76
|
-
else:
|
|
77
|
-
lang = TS_LANGUAGE
|
|
84
|
+
lang = Language(TS_LANGUAGE)
|
|
78
85
|
super().__init__(lang, TS_SYMBOL_QUERY)
|
|
79
86
|
|
|
80
|
-
def _create_symbol_from_capture(
|
|
87
|
+
def _create_symbol_from_capture(
|
|
88
|
+
self, node: Node, name: str, file_path: str
|
|
89
|
+
) -> Optional[Symbol]:
|
|
81
90
|
"""Maps a tree-sitter capture to a Symbol object."""
|
|
82
91
|
kind_map = {
|
|
83
92
|
"function.name": "function",
|
|
@@ -92,7 +101,7 @@ class TypeScriptSymbolExtractor(TreeSitterExtractor):
|
|
|
92
101
|
"variable.name": "variable",
|
|
93
102
|
"decorator": "decorator",
|
|
94
103
|
}
|
|
95
|
-
|
|
104
|
+
|
|
96
105
|
symbol_kind = kind_map.get(name)
|
|
97
106
|
if not symbol_kind:
|
|
98
107
|
return None
|
|
@@ -102,16 +111,22 @@ class TypeScriptSymbolExtractor(TreeSitterExtractor):
|
|
|
102
111
|
symbol_name = "<anonymous_arrow_function>"
|
|
103
112
|
elif name == "decorator":
|
|
104
113
|
# Extract decorator name (e.g., @Component -> Component)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
114
|
+
if node.text is None:
|
|
115
|
+
return None
|
|
116
|
+
decorator_text = node.text.decode("utf8").strip()
|
|
117
|
+
if decorator_text.startswith("@"):
|
|
118
|
+
symbol_name = decorator_text[1:].split("(")[0].strip()
|
|
108
119
|
else:
|
|
109
|
-
symbol_name = decorator_text.split(
|
|
120
|
+
symbol_name = decorator_text.split("(")[0].strip()
|
|
110
121
|
elif name == "generator.name":
|
|
111
|
-
|
|
122
|
+
if node.text is None:
|
|
123
|
+
return None
|
|
124
|
+
symbol_name = node.text.decode("utf8")
|
|
112
125
|
else:
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
if node.text is None:
|
|
127
|
+
return None
|
|
128
|
+
symbol_name = node.text.decode("utf8")
|
|
129
|
+
|
|
115
130
|
if not symbol_name:
|
|
116
131
|
return None
|
|
117
132
|
|
|
@@ -126,13 +141,14 @@ class TypeScriptSymbolExtractor(TreeSitterExtractor):
|
|
|
126
141
|
|
|
127
142
|
# --- TypeScript Dependency Analyzer ---
|
|
128
143
|
|
|
144
|
+
|
|
129
145
|
class TypeScriptDependencyAnalyzer(DependencyAnalyzer):
|
|
130
146
|
"""Analyzes TypeScript import dependencies."""
|
|
131
147
|
|
|
132
148
|
def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
|
|
133
149
|
"""Analyzes TypeScript import statements."""
|
|
134
150
|
dependencies: List[Dependency] = []
|
|
135
|
-
|
|
151
|
+
|
|
136
152
|
# ES6 import statements (same as JavaScript)
|
|
137
153
|
# import module from 'path'
|
|
138
154
|
# import { symbol } from 'path'
|
|
@@ -140,16 +156,16 @@ class TypeScriptDependencyAnalyzer(DependencyAnalyzer):
|
|
|
140
156
|
# import type { Type } from 'path'
|
|
141
157
|
import_pattern = re.compile(
|
|
142
158
|
r'import\s+(?:type\s+)?(?:(?:\*\s+as\s+(\w+)|(\{[^}]*\})|(\w+))\s+from\s+)?["\']([^"\']+)["\']',
|
|
143
|
-
re.MULTILINE
|
|
159
|
+
re.MULTILINE,
|
|
144
160
|
)
|
|
145
|
-
|
|
161
|
+
|
|
146
162
|
# CommonJS require statements
|
|
147
163
|
require_pattern = re.compile(
|
|
148
164
|
r'(?:const|let|var)\s+\w+\s*=\s*require\(["\']([^"\']+)["\']\)|require\(["\']([^"\']+)["\']\)',
|
|
149
|
-
re.MULTILINE
|
|
165
|
+
re.MULTILINE,
|
|
150
166
|
)
|
|
151
|
-
|
|
152
|
-
for line_num, line in enumerate(content.split(
|
|
167
|
+
|
|
168
|
+
for line_num, line in enumerate(content.split("\n"), start=1):
|
|
153
169
|
# Check for ES6 imports
|
|
154
170
|
import_match = import_pattern.search(line)
|
|
155
171
|
if import_match:
|
|
@@ -158,97 +174,115 @@ class TypeScriptDependencyAnalyzer(DependencyAnalyzer):
|
|
|
158
174
|
# Extract imported symbols if any
|
|
159
175
|
symbols_group = import_match.group(2) or import_match.group(1)
|
|
160
176
|
imported_symbol = None
|
|
161
|
-
if symbols_group and symbols_group.startswith(
|
|
177
|
+
if symbols_group and symbols_group.startswith("{"):
|
|
162
178
|
# Extract first symbol from { symbol1, symbol2 }
|
|
163
|
-
symbol_match = re.search(r
|
|
179
|
+
symbol_match = re.search(r"\{([^}]+)\}", symbols_group)
|
|
164
180
|
if symbol_match:
|
|
165
|
-
first_symbol = symbol_match.group(1).split(
|
|
166
|
-
imported_symbol = first_symbol.split(
|
|
167
|
-
|
|
168
|
-
dependencies.append(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
181
|
+
first_symbol = symbol_match.group(1).split(",")[0].strip()
|
|
182
|
+
imported_symbol = first_symbol.split(" as ")[0].strip()
|
|
183
|
+
|
|
184
|
+
dependencies.append(
|
|
185
|
+
Dependency(
|
|
186
|
+
from_module=module_path,
|
|
187
|
+
imported_symbol=imported_symbol,
|
|
188
|
+
file_path=file_path,
|
|
189
|
+
line=line_num,
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
|
|
175
193
|
# Check for require statements
|
|
176
194
|
require_match = require_pattern.search(line)
|
|
177
195
|
if require_match:
|
|
178
196
|
module_path = require_match.group(1) or require_match.group(2)
|
|
179
197
|
if module_path:
|
|
180
|
-
dependencies.append(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
198
|
+
dependencies.append(
|
|
199
|
+
Dependency(
|
|
200
|
+
from_module=module_path,
|
|
201
|
+
imported_symbol=None,
|
|
202
|
+
file_path=file_path,
|
|
203
|
+
line=line_num,
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
|
|
187
207
|
return dependencies
|
|
188
208
|
|
|
189
209
|
def build_dependency_graph(self, project_root: str) -> DependencyGraph:
|
|
190
210
|
"""Builds a dependency graph for a TypeScript project."""
|
|
191
211
|
graph = DependencyGraph()
|
|
192
|
-
|
|
212
|
+
|
|
193
213
|
for root, dirs, files in os.walk(project_root):
|
|
194
214
|
dirs[:] = filter_walk_dirs(dirs)
|
|
195
|
-
|
|
215
|
+
|
|
196
216
|
for file in files:
|
|
197
|
-
if not file.endswith((
|
|
217
|
+
if not file.endswith((".ts", ".tsx", ".cts", ".mts")):
|
|
198
218
|
continue
|
|
199
|
-
|
|
219
|
+
|
|
200
220
|
file_path = os.path.join(root, file)
|
|
201
221
|
try:
|
|
202
|
-
with open(file_path,
|
|
222
|
+
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
203
223
|
content = f.read()
|
|
204
|
-
|
|
224
|
+
|
|
205
225
|
dependencies = self.analyze_imports(file_path, content)
|
|
206
226
|
for dep in dependencies:
|
|
207
227
|
# Skip node_modules and external packages
|
|
208
|
-
if dep.from_module.startswith(
|
|
209
|
-
|
|
228
|
+
if dep.from_module.startswith(
|
|
229
|
+
(".", "/")
|
|
230
|
+
) or not dep.from_module.startswith("http"):
|
|
231
|
+
dep_path = self._resolve_module_path(
|
|
232
|
+
project_root, dep.from_module, file_path
|
|
233
|
+
)
|
|
210
234
|
if dep_path and dep_path != file_path:
|
|
211
235
|
graph.add_dependency(file_path, dep_path)
|
|
212
236
|
except Exception:
|
|
213
237
|
continue
|
|
214
|
-
|
|
238
|
+
|
|
215
239
|
return graph
|
|
216
240
|
|
|
217
|
-
def _resolve_module_path(
|
|
241
|
+
def _resolve_module_path(
|
|
242
|
+
self, project_root: str, module_name: str, from_file: str
|
|
243
|
+
) -> Optional[str]:
|
|
218
244
|
"""Resolve a TypeScript module name to a file path."""
|
|
219
245
|
if not module_name:
|
|
220
246
|
return None
|
|
221
|
-
|
|
247
|
+
|
|
222
248
|
# Handle relative imports
|
|
223
|
-
if module_name.startswith(
|
|
249
|
+
if module_name.startswith("."):
|
|
224
250
|
base_dir = os.path.dirname(from_file)
|
|
225
251
|
# Resolve relative path
|
|
226
|
-
if module_name.endswith((
|
|
252
|
+
if module_name.endswith((".ts", ".tsx")):
|
|
227
253
|
# Direct file reference
|
|
228
254
|
resolved = os.path.normpath(os.path.join(base_dir, module_name))
|
|
229
255
|
else:
|
|
230
256
|
# Try with .ts extension
|
|
231
|
-
resolved = os.path.normpath(os.path.join(base_dir, module_name +
|
|
257
|
+
resolved = os.path.normpath(os.path.join(base_dir, module_name + ".ts"))
|
|
232
258
|
if not os.path.exists(resolved):
|
|
233
259
|
# Try with .tsx extension
|
|
234
|
-
resolved = os.path.normpath(
|
|
260
|
+
resolved = os.path.normpath(
|
|
261
|
+
os.path.join(base_dir, module_name + ".tsx")
|
|
262
|
+
)
|
|
235
263
|
if not os.path.exists(resolved):
|
|
236
264
|
# Try index.ts
|
|
237
|
-
resolved = os.path.normpath(
|
|
265
|
+
resolved = os.path.normpath(
|
|
266
|
+
os.path.join(base_dir, module_name, "index.ts")
|
|
267
|
+
)
|
|
238
268
|
if not os.path.exists(resolved):
|
|
239
|
-
resolved = os.path.normpath(
|
|
240
|
-
|
|
269
|
+
resolved = os.path.normpath(
|
|
270
|
+
os.path.join(base_dir, module_name, "index.tsx")
|
|
271
|
+
)
|
|
272
|
+
|
|
241
273
|
if os.path.exists(resolved) and os.path.isfile(resolved):
|
|
242
274
|
return resolved
|
|
243
|
-
|
|
275
|
+
|
|
244
276
|
# Handle absolute imports (from project root)
|
|
245
|
-
if module_name.startswith(
|
|
246
|
-
resolved = os.path.normpath(
|
|
247
|
-
|
|
248
|
-
|
|
277
|
+
if module_name.startswith("/"):
|
|
278
|
+
resolved = os.path.normpath(
|
|
279
|
+
os.path.join(project_root, module_name.lstrip("/"))
|
|
280
|
+
)
|
|
281
|
+
if not resolved.endswith((".ts", ".tsx")):
|
|
282
|
+
resolved += ".ts"
|
|
249
283
|
if os.path.exists(resolved) and os.path.isfile(resolved):
|
|
250
284
|
return resolved
|
|
251
|
-
|
|
285
|
+
|
|
252
286
|
# For node_modules and external packages, we can't resolve without package.json
|
|
253
287
|
# Return None to skip them
|
|
254
288
|
return None
|
|
@@ -256,6 +290,7 @@ class TypeScriptDependencyAnalyzer(DependencyAnalyzer):
|
|
|
256
290
|
|
|
257
291
|
# --- TypeScript Language Support ---
|
|
258
292
|
|
|
293
|
+
|
|
259
294
|
class TypeScriptLanguageSupport(BaseLanguageSupport):
|
|
260
295
|
"""TypeScript语言支持。"""
|
|
261
296
|
|
|
@@ -265,7 +300,7 @@ class TypeScriptLanguageSupport(BaseLanguageSupport):
|
|
|
265
300
|
|
|
266
301
|
@property
|
|
267
302
|
def file_extensions(self) -> Set[str]:
|
|
268
|
-
return {
|
|
303
|
+
return {".ts", ".tsx", ".cts", ".mts"}
|
|
269
304
|
|
|
270
305
|
def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
|
|
271
306
|
if not TS_LANGUAGE:
|
|
@@ -277,4 +312,3 @@ class TypeScriptLanguageSupport(BaseLanguageSupport):
|
|
|
277
312
|
|
|
278
313
|
def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
|
|
279
314
|
return TypeScriptDependencyAnalyzer()
|
|
280
|
-
|