tree-sitter-analyzer 0.1.0__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 tree-sitter-analyzer might be problematic. Click here for more details.

Files changed (78) hide show
  1. tree_sitter_analyzer/__init__.py +121 -0
  2. tree_sitter_analyzer/__main__.py +12 -0
  3. tree_sitter_analyzer/api.py +539 -0
  4. tree_sitter_analyzer/cli/__init__.py +39 -0
  5. tree_sitter_analyzer/cli/__main__.py +13 -0
  6. tree_sitter_analyzer/cli/commands/__init__.py +27 -0
  7. tree_sitter_analyzer/cli/commands/advanced_command.py +88 -0
  8. tree_sitter_analyzer/cli/commands/base_command.py +155 -0
  9. tree_sitter_analyzer/cli/commands/default_command.py +19 -0
  10. tree_sitter_analyzer/cli/commands/partial_read_command.py +133 -0
  11. tree_sitter_analyzer/cli/commands/query_command.py +82 -0
  12. tree_sitter_analyzer/cli/commands/structure_command.py +121 -0
  13. tree_sitter_analyzer/cli/commands/summary_command.py +93 -0
  14. tree_sitter_analyzer/cli/commands/table_command.py +233 -0
  15. tree_sitter_analyzer/cli/info_commands.py +121 -0
  16. tree_sitter_analyzer/cli_main.py +276 -0
  17. tree_sitter_analyzer/core/__init__.py +20 -0
  18. tree_sitter_analyzer/core/analysis_engine.py +574 -0
  19. tree_sitter_analyzer/core/cache_service.py +330 -0
  20. tree_sitter_analyzer/core/engine.py +560 -0
  21. tree_sitter_analyzer/core/parser.py +288 -0
  22. tree_sitter_analyzer/core/query.py +502 -0
  23. tree_sitter_analyzer/encoding_utils.py +460 -0
  24. tree_sitter_analyzer/exceptions.py +340 -0
  25. tree_sitter_analyzer/file_handler.py +222 -0
  26. tree_sitter_analyzer/formatters/__init__.py +1 -0
  27. tree_sitter_analyzer/formatters/base_formatter.py +168 -0
  28. tree_sitter_analyzer/formatters/formatter_factory.py +74 -0
  29. tree_sitter_analyzer/formatters/java_formatter.py +270 -0
  30. tree_sitter_analyzer/formatters/python_formatter.py +235 -0
  31. tree_sitter_analyzer/interfaces/__init__.py +10 -0
  32. tree_sitter_analyzer/interfaces/cli.py +557 -0
  33. tree_sitter_analyzer/interfaces/cli_adapter.py +319 -0
  34. tree_sitter_analyzer/interfaces/mcp_adapter.py +170 -0
  35. tree_sitter_analyzer/interfaces/mcp_server.py +416 -0
  36. tree_sitter_analyzer/java_analyzer.py +219 -0
  37. tree_sitter_analyzer/language_detector.py +400 -0
  38. tree_sitter_analyzer/language_loader.py +228 -0
  39. tree_sitter_analyzer/languages/__init__.py +11 -0
  40. tree_sitter_analyzer/languages/java_plugin.py +1113 -0
  41. tree_sitter_analyzer/languages/python_plugin.py +712 -0
  42. tree_sitter_analyzer/mcp/__init__.py +32 -0
  43. tree_sitter_analyzer/mcp/resources/__init__.py +47 -0
  44. tree_sitter_analyzer/mcp/resources/code_file_resource.py +213 -0
  45. tree_sitter_analyzer/mcp/resources/project_stats_resource.py +550 -0
  46. tree_sitter_analyzer/mcp/server.py +319 -0
  47. tree_sitter_analyzer/mcp/tools/__init__.py +36 -0
  48. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +558 -0
  49. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +245 -0
  50. tree_sitter_analyzer/mcp/tools/base_tool.py +55 -0
  51. tree_sitter_analyzer/mcp/tools/get_positions_tool.py +448 -0
  52. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +302 -0
  53. tree_sitter_analyzer/mcp/tools/table_format_tool.py +359 -0
  54. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +476 -0
  55. tree_sitter_analyzer/mcp/utils/__init__.py +106 -0
  56. tree_sitter_analyzer/mcp/utils/error_handler.py +549 -0
  57. tree_sitter_analyzer/models.py +481 -0
  58. tree_sitter_analyzer/output_manager.py +264 -0
  59. tree_sitter_analyzer/plugins/__init__.py +334 -0
  60. tree_sitter_analyzer/plugins/base.py +446 -0
  61. tree_sitter_analyzer/plugins/java_plugin.py +625 -0
  62. tree_sitter_analyzer/plugins/javascript_plugin.py +439 -0
  63. tree_sitter_analyzer/plugins/manager.py +355 -0
  64. tree_sitter_analyzer/plugins/plugin_loader.py +83 -0
  65. tree_sitter_analyzer/plugins/python_plugin.py +598 -0
  66. tree_sitter_analyzer/plugins/registry.py +366 -0
  67. tree_sitter_analyzer/queries/__init__.py +27 -0
  68. tree_sitter_analyzer/queries/java.py +394 -0
  69. tree_sitter_analyzer/queries/javascript.py +149 -0
  70. tree_sitter_analyzer/queries/python.py +286 -0
  71. tree_sitter_analyzer/queries/typescript.py +230 -0
  72. tree_sitter_analyzer/query_loader.py +260 -0
  73. tree_sitter_analyzer/table_formatter.py +448 -0
  74. tree_sitter_analyzer/utils.py +201 -0
  75. tree_sitter_analyzer-0.1.0.dist-info/METADATA +581 -0
  76. tree_sitter_analyzer-0.1.0.dist-info/RECORD +78 -0
  77. tree_sitter_analyzer-0.1.0.dist-info/WHEEL +4 -0
  78. tree_sitter_analyzer-0.1.0.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Summary Command
5
+
6
+ Handles summary functionality with specified element types.
7
+ """
8
+ from typing import TYPE_CHECKING
9
+
10
+ from ...output_manager import output_data, output_json, output_section
11
+ from .base_command import BaseCommand
12
+
13
+ if TYPE_CHECKING:
14
+ from ...models import AnalysisResult
15
+
16
+
17
+ class SummaryCommand(BaseCommand):
18
+ """Command for summary analysis with specified element types."""
19
+
20
+ async def execute_async(self, language: str) -> int:
21
+ analysis_result = await self.analyze_file(language)
22
+ if not analysis_result:
23
+ return 1
24
+
25
+ self._output_summary_analysis(analysis_result)
26
+ return 0
27
+
28
+ def _output_summary_analysis(self, analysis_result: "AnalysisResult") -> None:
29
+ """Output summary analysis results."""
30
+ output_section("要約結果")
31
+
32
+ # Get summary types from args (default: classes,methods)
33
+ summary_types = getattr(self.args, 'summary', 'classes,methods')
34
+ if summary_types:
35
+ requested_types = [t.strip() for t in summary_types.split(',')]
36
+ else:
37
+ requested_types = ['classes', 'methods']
38
+
39
+ # Extract elements by type
40
+ classes = [e for e in analysis_result.elements if e.__class__.__name__ == 'Class']
41
+ methods = [e for e in analysis_result.elements if e.__class__.__name__ == 'Function']
42
+ fields = [e for e in analysis_result.elements if e.__class__.__name__ == 'Variable']
43
+ imports = [e for e in analysis_result.elements if e.__class__.__name__ == 'Import']
44
+
45
+ summary_data = {
46
+ 'file_path': analysis_result.file_path,
47
+ 'language': analysis_result.language,
48
+ 'summary': {}
49
+ }
50
+
51
+ if 'classes' in requested_types:
52
+ summary_data['summary']['classes'] = [
53
+ {'name': getattr(c, 'name', 'unknown')} for c in classes
54
+ ]
55
+
56
+ if 'methods' in requested_types:
57
+ summary_data['summary']['methods'] = [
58
+ {'name': getattr(m, 'name', 'unknown')} for m in methods
59
+ ]
60
+
61
+ if 'fields' in requested_types:
62
+ summary_data['summary']['fields'] = [
63
+ {'name': getattr(f, 'name', 'unknown')} for f in fields
64
+ ]
65
+
66
+ if 'imports' in requested_types:
67
+ summary_data['summary']['imports'] = [
68
+ {'name': getattr(i, 'name', 'unknown')} for i in imports
69
+ ]
70
+
71
+ if self.args.output_format == "json":
72
+ output_json(summary_data)
73
+ else:
74
+ self._output_text_format(summary_data, requested_types)
75
+
76
+ def _output_text_format(self, summary_data: dict, requested_types: list) -> None:
77
+ """Output summary in human-readable text format."""
78
+ output_data(f"ファイル: {summary_data['file_path']}")
79
+ output_data(f"言語: {summary_data['language']}")
80
+
81
+ for element_type in requested_types:
82
+ if element_type in summary_data['summary']:
83
+ elements = summary_data['summary'][element_type]
84
+ type_name_map = {
85
+ 'classes': 'クラス',
86
+ 'methods': 'メソッド',
87
+ 'fields': 'フィールド',
88
+ 'imports': 'インポート'
89
+ }
90
+ type_name = type_name_map.get(element_type, element_type)
91
+ output_data(f"\n{type_name} ({len(elements)}個):")
92
+ for element in elements:
93
+ output_data(f" - {element['name']}")
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Table Command
5
+
6
+ Handles table format output generation.
7
+ """
8
+
9
+ import sys
10
+
11
+ from ...output_manager import output_error
12
+ from ...table_formatter import create_table_formatter
13
+ from .base_command import BaseCommand
14
+
15
+
16
+ class TableCommand(BaseCommand):
17
+ """Command for generating table format output."""
18
+
19
+ async def execute_async(self, language: str) -> int:
20
+ """Execute table format generation."""
21
+ try:
22
+ # Perform analysis
23
+ analysis_result = await self.analyze_file(language)
24
+ if not analysis_result:
25
+ return 1
26
+
27
+ # Convert analysis result to structure format
28
+ structure_result = self._convert_to_structure_format(
29
+ analysis_result, language
30
+ )
31
+
32
+ # Create table formatter
33
+ include_javadoc = getattr(self.args, "include_javadoc", False)
34
+ formatter = create_table_formatter(
35
+ self.args.table, language, include_javadoc
36
+ )
37
+ table_output = formatter.format_structure(structure_result)
38
+
39
+ # Output table
40
+ self._output_table(table_output)
41
+
42
+ return 0
43
+
44
+ except Exception as e:
45
+ output_error(f"ERROR: テーブル形式での解析でエラーが発生しました: {e}")
46
+ return 1
47
+
48
+ def _convert_to_structure_format(self, analysis_result, language: str) -> dict:
49
+ """Convert AnalysisResult to the format expected by table formatter."""
50
+ classes = []
51
+ methods = []
52
+ fields = []
53
+ imports = []
54
+ package_name = "unknown"
55
+
56
+ # Process each element
57
+ for i, element in enumerate(analysis_result.elements):
58
+ try:
59
+ element_type = getattr(element, "__class__", type(element)).__name__
60
+ element_name = getattr(element, "name", None)
61
+
62
+ if element_type == "Package":
63
+ package_name = element_name
64
+ elif element_type == "Class":
65
+ classes.append(self._convert_class_element(element, i))
66
+ elif element_type == "Function":
67
+ methods.append(self._convert_function_element(element, language))
68
+ elif element_type == "Variable":
69
+ fields.append(self._convert_variable_element(element, language))
70
+ elif element_type == "Import":
71
+ imports.append(self._convert_import_element(element))
72
+
73
+ except Exception as element_error:
74
+ output_error(f"ERROR: Element {i} processing failed: {element_error}")
75
+ continue
76
+
77
+ return {
78
+ "file_path": analysis_result.file_path,
79
+ "language": analysis_result.language,
80
+ "line_count": analysis_result.line_count,
81
+ "package": {"name": package_name},
82
+ "classes": classes,
83
+ "methods": methods,
84
+ "fields": fields,
85
+ "imports": imports,
86
+ "statistics": {
87
+ "method_count": len(methods),
88
+ "field_count": len(fields),
89
+ "class_count": len(classes),
90
+ "import_count": len(imports),
91
+ },
92
+ }
93
+
94
+ def _convert_class_element(self, element, index: int) -> dict:
95
+ """Convert class element to table format."""
96
+ element_name = getattr(element, "name", None)
97
+ final_name = element_name if element_name else f"UnknownClass_{index}"
98
+
99
+ return {
100
+ "name": final_name,
101
+ "type": "class",
102
+ "visibility": "public",
103
+ "line_range": {
104
+ "start": getattr(element, "start_line", 0),
105
+ "end": getattr(element, "end_line", 0),
106
+ },
107
+ }
108
+
109
+ def _convert_function_element(self, element, language: str) -> dict:
110
+ """Convert function element to table format."""
111
+ # Process parameters based on language
112
+ params = getattr(element, "parameters", [])
113
+ processed_params = self._process_parameters(params, language)
114
+
115
+ # Get visibility
116
+ visibility = self._get_element_visibility(element)
117
+
118
+ # Get JavaDoc if enabled
119
+ include_javadoc = getattr(self.args, "include_javadoc", False)
120
+ javadoc = getattr(element, "docstring", "") or "" if include_javadoc else ""
121
+
122
+ return {
123
+ "name": getattr(element, "name", str(element)),
124
+ "visibility": visibility,
125
+ "return_type": getattr(element, "return_type", "Any"),
126
+ "parameters": processed_params,
127
+ "is_constructor": getattr(element, "is_constructor", False),
128
+ "is_static": getattr(element, "is_static", False),
129
+ "complexity_score": getattr(element, "complexity_score", 1),
130
+ "line_range": {
131
+ "start": getattr(element, "start_line", 0),
132
+ "end": getattr(element, "end_line", 0),
133
+ },
134
+ "javadoc": javadoc,
135
+ }
136
+
137
+ def _convert_variable_element(self, element, language: str) -> dict:
138
+ """Convert variable element to table format."""
139
+ # Get field type based on language
140
+ if language == "python":
141
+ field_type = getattr(element, "variable_type", "") or ""
142
+ else:
143
+ field_type = getattr(element, "variable_type", "") or getattr(
144
+ element, "field_type", ""
145
+ )
146
+
147
+ # Get visibility
148
+ field_visibility = self._get_element_visibility(element)
149
+
150
+ # Get JavaDoc if enabled
151
+ include_javadoc = getattr(self.args, "include_javadoc", False)
152
+ javadoc = getattr(element, "docstring", "") or "" if include_javadoc else ""
153
+
154
+ return {
155
+ "name": getattr(element, "name", str(element)),
156
+ "type": field_type,
157
+ "visibility": field_visibility,
158
+ "modifiers": getattr(element, "modifiers", []),
159
+ "line_range": {
160
+ "start": getattr(element, "start_line", 0),
161
+ "end": getattr(element, "end_line", 0),
162
+ },
163
+ "javadoc": javadoc,
164
+ }
165
+
166
+ def _convert_import_element(self, element) -> dict:
167
+ """Convert import element to table format."""
168
+ return {
169
+ "statement": getattr(element, "name", str(element)),
170
+ "name": getattr(element, "name", str(element)),
171
+ }
172
+
173
+ def _process_parameters(self, params, language: str) -> list:
174
+ """Process parameters based on language syntax."""
175
+ if isinstance(params, str):
176
+ param_list = []
177
+ if params.strip():
178
+ param_names = [p.strip() for p in params.split(",") if p.strip()]
179
+ param_list = [{"name": name, "type": "Any"} for name in param_names]
180
+ return param_list
181
+ elif isinstance(params, list):
182
+ param_list = []
183
+ for param in params:
184
+ if isinstance(param, str):
185
+ param = param.strip()
186
+ if language == "python":
187
+ # Python format: "name: type"
188
+ if ":" in param:
189
+ parts = param.split(":", 1)
190
+ param_name = parts[0].strip()
191
+ param_type = parts[1].strip() if len(parts) > 1 else "Any"
192
+ param_list.append({"name": param_name, "type": param_type})
193
+ else:
194
+ param_list.append({"name": param, "type": "Any"})
195
+ else:
196
+ # Java format: "Type name"
197
+ last_space_idx = param.rfind(" ")
198
+ if last_space_idx != -1:
199
+ param_type = param[:last_space_idx].strip()
200
+ param_name = param[last_space_idx + 1 :].strip()
201
+ if param_type and param_name:
202
+ param_list.append(
203
+ {"name": param_name, "type": param_type}
204
+ )
205
+ else:
206
+ param_list.append({"name": param, "type": "Any"})
207
+ else:
208
+ param_list.append({"name": param, "type": "Any"})
209
+ elif isinstance(param, dict):
210
+ param_list.append(param)
211
+ else:
212
+ param_list.append({"name": str(param), "type": "Any"})
213
+ return param_list
214
+ else:
215
+ return []
216
+
217
+ def _get_element_visibility(self, element) -> str:
218
+ """Get element visibility."""
219
+ visibility = getattr(element, "visibility", "public")
220
+ if hasattr(element, "is_private") and getattr(element, "is_private", False):
221
+ visibility = "private"
222
+ elif hasattr(element, "is_public") and getattr(element, "is_public", False):
223
+ visibility = "public"
224
+ return visibility
225
+
226
+ def _output_table(self, table_output: str) -> None:
227
+ """Output the table with proper encoding."""
228
+ try:
229
+ # Windows対応: UTF-8エンコーディングで出力
230
+ sys.stdout.buffer.write(table_output.encode("utf-8"))
231
+ except (AttributeError, UnicodeEncodeError):
232
+ # フォールバック: 通常のprint
233
+ print(table_output, end="")
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Information Commands for CLI
5
+
6
+ Commands that display information without requiring file analysis.
7
+ """
8
+
9
+ from abc import ABC, abstractmethod
10
+ from argparse import Namespace
11
+
12
+ from ..language_detector import detect_language_from_file, detector
13
+ from ..output_manager import output_data, output_error, output_info, output_list
14
+ from ..query_loader import query_loader
15
+
16
+
17
+ class InfoCommand(ABC):
18
+ """Base class for information commands that don't require file analysis."""
19
+
20
+ def __init__(self, args: Namespace):
21
+ self.args = args
22
+
23
+ @abstractmethod
24
+ def execute(self) -> int:
25
+ """Execute the information command."""
26
+ pass
27
+
28
+
29
+ class ListQueriesCommand(InfoCommand):
30
+ """Command to list available queries."""
31
+
32
+ def execute(self) -> int:
33
+ if self.args.language:
34
+ language = self.args.language
35
+ elif hasattr(self.args, "file_path") and self.args.file_path:
36
+ language = detect_language_from_file(self.args.file_path)
37
+ else:
38
+ output_list("サポートされている言語:")
39
+ for lang in query_loader.list_supported_languages():
40
+ output_list(f" {lang}")
41
+ queries = query_loader.list_queries_for_language(lang)
42
+ for query_key in queries:
43
+ description = (
44
+ query_loader.get_query_description(lang, query_key)
45
+ or "説明なし"
46
+ )
47
+ output_list(f" {query_key:<20} - {description}")
48
+ return 0
49
+
50
+ output_list(f"利用可能なクエリキー ({language}):")
51
+ for query_key in query_loader.list_queries_for_language(language):
52
+ description = (
53
+ query_loader.get_query_description(language, query_key) or "説明なし"
54
+ )
55
+ output_list(f" {query_key:<20} - {description}")
56
+ return 0
57
+
58
+
59
+ class DescribeQueryCommand(InfoCommand):
60
+ """Command to describe a specific query."""
61
+
62
+ def execute(self) -> int:
63
+ if self.args.language:
64
+ language = self.args.language
65
+ elif hasattr(self.args, "file_path") and self.args.file_path:
66
+ language = detect_language_from_file(self.args.file_path)
67
+ else:
68
+ output_error(
69
+ "ERROR: クエリ説明表示には--languageまたは対象ファイルの指定が必要です"
70
+ )
71
+ return 1
72
+
73
+ try:
74
+ query_description = query_loader.get_query_description(
75
+ language, self.args.describe_query
76
+ )
77
+ query_content = query_loader.get_query(language, self.args.describe_query)
78
+
79
+ if query_description is None or query_content is None:
80
+ output_error(
81
+ f"ERROR: クエリ '{self.args.describe_query}' が言語 '{language}' で見つかりません"
82
+ )
83
+ return 1
84
+
85
+ output_info(
86
+ f"クエリキー '{self.args.describe_query}' ({language}): {query_description}"
87
+ )
88
+ output_data(f"クエリ内容:\n{query_content}")
89
+ except ValueError as e:
90
+ output_error(f"ERROR: {e}")
91
+ return 1
92
+ return 0
93
+
94
+
95
+ class ShowLanguagesCommand(InfoCommand):
96
+ """Command to show supported languages."""
97
+
98
+ def execute(self) -> int:
99
+ output_list("サポートされている言語:")
100
+ for language in detector.get_supported_languages():
101
+ info = detector.get_language_info(language)
102
+ extensions = ", ".join(info["extensions"][:5])
103
+ if len(info["extensions"]) > 5:
104
+ extensions += f", ... (他{len(info['extensions'])-5}個)"
105
+ output_list(f" {language:<12} - 拡張子: {extensions}")
106
+ return 0
107
+
108
+
109
+ class ShowExtensionsCommand(InfoCommand):
110
+ """Command to show supported extensions."""
111
+
112
+ def execute(self) -> int:
113
+ output_list("サポートされている拡張子:")
114
+ supported_extensions = detector.get_supported_extensions()
115
+ for i in range(0, len(supported_extensions), 8):
116
+ line = " " + " ".join(
117
+ f"{ext:<6}" for ext in supported_extensions[i : i + 8]
118
+ )
119
+ output_list(line)
120
+ output_info(f"\n合計 {len(supported_extensions)} 個の拡張子をサポート")
121
+ return 0