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,416 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ MCP Server Interface
5
+
6
+ New MCP server implementation that uses the API facade for all operations.
7
+ Provides a clean separation between MCP protocol concerns and core analysis logic.
8
+ """
9
+
10
+ import asyncio
11
+ import json
12
+ import logging
13
+ import sys
14
+ from pathlib import Path
15
+ from typing import Any, Dict, List, Optional
16
+
17
+ try:
18
+ from mcp.server import Server
19
+ from mcp.server.models import InitializationOptions
20
+ from mcp.server.stdio import stdio_server
21
+ from mcp.types import (
22
+ Resource,
23
+ TextContent,
24
+ Tool,
25
+ )
26
+ MCP_AVAILABLE = True
27
+ except ImportError:
28
+ MCP_AVAILABLE = False
29
+
30
+ from .. import api
31
+ from ..utils import log_error, log_info, log_warning
32
+
33
+ # Configure logging for MCP
34
+ logging.basicConfig(
35
+ level=logging.INFO,
36
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
37
+ )
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ class TreeSitterAnalyzerMCPServer:
42
+ """
43
+ MCP Server for Tree-sitter Analyzer using the new API facade.
44
+
45
+ This server provides code analysis capabilities through the Model Context Protocol,
46
+ using the unified API facade for all operations.
47
+ """
48
+
49
+ def __init__(self) -> None:
50
+ """Initialize the MCP server."""
51
+ if not MCP_AVAILABLE:
52
+ raise ImportError("MCP library not available. Please install mcp package.")
53
+
54
+ self.server: Optional[Server] = None
55
+ self.name = "tree-sitter-analyzer"
56
+ self.version = "2.0.0"
57
+
58
+ log_info(f"Initializing {self.name} v{self.version}")
59
+
60
+ def create_server(self) -> Server:
61
+ """Create and configure the MCP server."""
62
+ server = Server(self.name)
63
+
64
+ @server.list_tools()
65
+ async def handle_list_tools() -> List[Tool]:
66
+ """List available tools."""
67
+ return [
68
+ Tool(
69
+ name="analyze_file",
70
+ description="Analyze a source code file comprehensively",
71
+ inputSchema={
72
+ "type": "object",
73
+ "properties": {
74
+ "file_path": {
75
+ "type": "string",
76
+ "description": "Path to the source file to analyze"
77
+ },
78
+ "language": {
79
+ "type": "string",
80
+ "description": "Programming language (optional, auto-detected if not specified)"
81
+ },
82
+ "queries": {
83
+ "type": "array",
84
+ "items": {"type": "string"},
85
+ "description": "List of query names to execute (optional)"
86
+ },
87
+ "include_elements": {
88
+ "type": "boolean",
89
+ "description": "Whether to extract code elements",
90
+ "default": True
91
+ },
92
+ "include_queries": {
93
+ "type": "boolean",
94
+ "description": "Whether to execute queries",
95
+ "default": True
96
+ }
97
+ },
98
+ "required": ["file_path"],
99
+ "additionalProperties": False
100
+ }
101
+ ),
102
+ Tool(
103
+ name="analyze_code",
104
+ description="Analyze source code directly (without file)",
105
+ inputSchema={
106
+ "type": "object",
107
+ "properties": {
108
+ "source_code": {
109
+ "type": "string",
110
+ "description": "Source code string to analyze"
111
+ },
112
+ "language": {
113
+ "type": "string",
114
+ "description": "Programming language"
115
+ },
116
+ "queries": {
117
+ "type": "array",
118
+ "items": {"type": "string"},
119
+ "description": "List of query names to execute (optional)"
120
+ },
121
+ "include_elements": {
122
+ "type": "boolean",
123
+ "description": "Whether to extract code elements",
124
+ "default": True
125
+ },
126
+ "include_queries": {
127
+ "type": "boolean",
128
+ "description": "Whether to execute queries",
129
+ "default": True
130
+ }
131
+ },
132
+ "required": ["source_code", "language"],
133
+ "additionalProperties": False
134
+ }
135
+ ),
136
+ Tool(
137
+ name="extract_elements",
138
+ description="Extract code elements from a file",
139
+ inputSchema={
140
+ "type": "object",
141
+ "properties": {
142
+ "file_path": {
143
+ "type": "string",
144
+ "description": "Path to the source file"
145
+ },
146
+ "language": {
147
+ "type": "string",
148
+ "description": "Programming language (optional, auto-detected if not specified)"
149
+ },
150
+ "element_types": {
151
+ "type": "array",
152
+ "items": {"type": "string"},
153
+ "description": "Types of elements to extract (optional)"
154
+ }
155
+ },
156
+ "required": ["file_path"],
157
+ "additionalProperties": False
158
+ }
159
+ ),
160
+ Tool(
161
+ name="execute_query",
162
+ description="Execute a specific query on a file",
163
+ inputSchema={
164
+ "type": "object",
165
+ "properties": {
166
+ "file_path": {
167
+ "type": "string",
168
+ "description": "Path to the source file"
169
+ },
170
+ "query_name": {
171
+ "type": "string",
172
+ "description": "Name of the query to execute"
173
+ },
174
+ "language": {
175
+ "type": "string",
176
+ "description": "Programming language (optional, auto-detected if not specified)"
177
+ }
178
+ },
179
+ "required": ["file_path", "query_name"],
180
+ "additionalProperties": False
181
+ }
182
+ ),
183
+ Tool(
184
+ name="validate_file",
185
+ description="Validate a source code file",
186
+ inputSchema={
187
+ "type": "object",
188
+ "properties": {
189
+ "file_path": {
190
+ "type": "string",
191
+ "description": "Path to the source file to validate"
192
+ }
193
+ },
194
+ "required": ["file_path"],
195
+ "additionalProperties": False
196
+ }
197
+ ),
198
+ Tool(
199
+ name="get_supported_languages",
200
+ description="Get list of supported programming languages",
201
+ inputSchema={
202
+ "type": "object",
203
+ "properties": {},
204
+ "additionalProperties": False
205
+ }
206
+ ),
207
+ Tool(
208
+ name="get_available_queries",
209
+ description="Get available queries for a specific language",
210
+ inputSchema={
211
+ "type": "object",
212
+ "properties": {
213
+ "language": {
214
+ "type": "string",
215
+ "description": "Programming language name"
216
+ }
217
+ },
218
+ "required": ["language"],
219
+ "additionalProperties": False
220
+ }
221
+ ),
222
+ Tool(
223
+ name="get_framework_info",
224
+ description="Get information about the analyzer framework",
225
+ inputSchema={
226
+ "type": "object",
227
+ "properties": {},
228
+ "additionalProperties": False
229
+ }
230
+ )
231
+ ]
232
+
233
+ @server.call_tool()
234
+ async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextContent]:
235
+ """Handle tool calls."""
236
+ try:
237
+ result = None
238
+
239
+ if name == "analyze_file":
240
+ result = api.analyze_file(
241
+ file_path=arguments["file_path"],
242
+ language=arguments.get("language"),
243
+ queries=arguments.get("queries"),
244
+ include_elements=arguments.get("include_elements", True),
245
+ include_queries=arguments.get("include_queries", True)
246
+ )
247
+
248
+ elif name == "analyze_code":
249
+ result = api.analyze_code(
250
+ source_code=arguments["source_code"],
251
+ language=arguments["language"],
252
+ queries=arguments.get("queries"),
253
+ include_elements=arguments.get("include_elements", True),
254
+ include_queries=arguments.get("include_queries", True)
255
+ )
256
+
257
+ elif name == "extract_elements":
258
+ result = api.extract_elements(
259
+ file_path=arguments["file_path"],
260
+ language=arguments.get("language"),
261
+ element_types=arguments.get("element_types")
262
+ )
263
+
264
+ elif name == "execute_query":
265
+ result = api.execute_query(
266
+ file_path=arguments["file_path"],
267
+ query_name=arguments["query_name"],
268
+ language=arguments.get("language")
269
+ )
270
+
271
+ elif name == "validate_file":
272
+ result = api.validate_file(arguments["file_path"])
273
+
274
+ elif name == "get_supported_languages":
275
+ result = {
276
+ "languages": api.get_supported_languages(),
277
+ "total": len(api.get_supported_languages())
278
+ }
279
+
280
+ elif name == "get_available_queries":
281
+ queries = api.get_available_queries(arguments["language"])
282
+ result = {
283
+ "language": arguments["language"],
284
+ "queries": queries,
285
+ "total": len(queries)
286
+ }
287
+
288
+ elif name == "get_framework_info":
289
+ result = api.get_framework_info()
290
+
291
+ else:
292
+ raise ValueError(f"Unknown tool: {name}")
293
+
294
+ return [
295
+ TextContent(
296
+ type="text",
297
+ text=json.dumps(result, indent=2, ensure_ascii=False)
298
+ )
299
+ ]
300
+
301
+ except Exception as e:
302
+ log_error(f"Tool call error for {name}: {e}")
303
+ error_result = {
304
+ "error": str(e),
305
+ "tool": name,
306
+ "arguments": arguments,
307
+ "success": False
308
+ }
309
+ return [
310
+ TextContent(
311
+ type="text",
312
+ text=json.dumps(error_result, indent=2, ensure_ascii=False)
313
+ )
314
+ ]
315
+
316
+ @server.list_resources()
317
+ async def handle_list_resources() -> List[Resource]:
318
+ """List available resources."""
319
+ return [
320
+ Resource(
321
+ uri="code://file/{file_path}",
322
+ name="Code File Analysis",
323
+ description="Access to code file content and analysis",
324
+ mimeType="application/json"
325
+ ),
326
+ Resource(
327
+ uri="code://stats/{stats_type}",
328
+ name="Project Statistics",
329
+ description="Access to project statistics and analysis data",
330
+ mimeType="application/json"
331
+ )
332
+ ]
333
+
334
+ @server.read_resource()
335
+ async def handle_read_resource(uri: str) -> str:
336
+ """Read resource content."""
337
+ try:
338
+ if uri.startswith("code://file/"):
339
+ # Extract file path from URI
340
+ file_path = uri[len("code://file/"):]
341
+
342
+ # Analyze the file
343
+ result = api.analyze_file(file_path)
344
+ return json.dumps(result, indent=2, ensure_ascii=False)
345
+
346
+ elif uri.startswith("code://stats/"):
347
+ # Extract stats type from URI
348
+ stats_type = uri[len("code://stats/"):]
349
+
350
+ # Get framework info as basic stats
351
+ if stats_type == "framework":
352
+ result = api.get_framework_info()
353
+ elif stats_type == "languages":
354
+ result = {
355
+ "supported_languages": api.get_supported_languages(),
356
+ "total_languages": len(api.get_supported_languages())
357
+ }
358
+ else:
359
+ raise ValueError(f"Unknown stats type: {stats_type}")
360
+
361
+ return json.dumps(result, indent=2, ensure_ascii=False)
362
+
363
+ else:
364
+ raise ValueError(f"Resource not found: {uri}")
365
+
366
+ except Exception as e:
367
+ log_error(f"Resource read error for {uri}: {e}")
368
+ error_result = {
369
+ "error": str(e),
370
+ "uri": uri,
371
+ "success": False
372
+ }
373
+ return json.dumps(error_result, indent=2, ensure_ascii=False)
374
+
375
+ self.server = server
376
+ log_info("MCP server created successfully")
377
+ return server
378
+
379
+ async def run(self) -> None:
380
+ """Run the MCP server."""
381
+ server = self.create_server()
382
+
383
+ # Initialize server options
384
+ options = InitializationOptions(
385
+ server_name=self.name,
386
+ server_version=self.version,
387
+ capabilities={
388
+ "tools": {},
389
+ "resources": {}
390
+ }
391
+ )
392
+
393
+ log_info(f"Starting MCP server: {self.name} v{self.version}")
394
+
395
+ try:
396
+ async with stdio_server() as (read_stream, write_stream):
397
+ await server.run(read_stream, write_stream, options)
398
+ except Exception as e:
399
+ log_error(f"Server error: {e}")
400
+ raise
401
+
402
+
403
+ async def main() -> None:
404
+ """Main entry point for the MCP server."""
405
+ try:
406
+ server = TreeSitterAnalyzerMCPServer()
407
+ await server.run()
408
+ except KeyboardInterrupt:
409
+ log_info("Server stopped by user")
410
+ except Exception as e:
411
+ log_error(f"Server failed: {e}")
412
+ sys.exit(1)
413
+
414
+
415
+ if __name__ == "__main__":
416
+ asyncio.run(main())
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Java Code Analyzer with tree-sitter
5
+ """
6
+ import json
7
+ import sys
8
+ from pathlib import Path
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ try:
12
+ import tree_sitter
13
+ import tree_sitter_java as tsjava
14
+ from tree_sitter import Language, Node, Parser
15
+
16
+ TREE_SITTER_AVAILABLE = True
17
+ except ImportError:
18
+ TREE_SITTER_AVAILABLE = False
19
+ from .utils import log_error
20
+
21
+ log_error(
22
+ "tree-sitter libraries not found. Please install tree-sitter and tree-sitter-java."
23
+ )
24
+
25
+ from .file_handler import read_file_with_fallback
26
+ from .output_manager import output_error, output_info, output_warning
27
+ from .utils import log_error, log_info, log_warning
28
+
29
+
30
+ class CodeAnalyzer:
31
+ """
32
+ Tree-sitterを使用してソースコードを解析するコアクラス。
33
+
34
+ Attributes:
35
+ language: Tree-sitter言語オブジェクト
36
+ parser: Tree-sitterパーサー
37
+ source_code_bytes: 解析対象のソースコードのバイト列
38
+ tree: 構築されたAST
39
+ """
40
+
41
+ def __init__(self, language: str = "java") -> None:
42
+ """
43
+ 指定された言語用のパーサーを初期化する。
44
+
45
+ Args:
46
+ language: 解析対象のプログラミング言語。現在はJavaのみサポート。
47
+
48
+ Raises:
49
+ SystemExit: Tree-sitterライブラリの初期化に失敗した場合
50
+ """
51
+ if not TREE_SITTER_AVAILABLE:
52
+ output_error("ERROR: Tree-sitter libraries not available.")
53
+ raise RuntimeError("Tree-sitter libraries not available")
54
+
55
+ try:
56
+ if language != "java":
57
+ output_warning(
58
+ f"WARNING: Currently only Java is supported. Using Java parser."
59
+ )
60
+
61
+ self.language = Language(tsjava.language())
62
+ self.parser = Parser(self.language)
63
+ self.source_code_bytes: bytes = b""
64
+ self.tree: Optional[tree_sitter.Tree] = None
65
+
66
+ except Exception as e:
67
+ output_error(
68
+ f"ERROR: '{language}' 言語の初期化に失敗しました。ライブラリが正しくインストールされているか確認してください。"
69
+ )
70
+ output_error(f"詳細: {e}")
71
+ raise RuntimeError(f"Failed to initialize language '{language}': {e}")
72
+
73
+ def parse_file(self, file_path: str) -> bool:
74
+ """
75
+ 指定されたファイルを解析し、AST(抽象構文木)を構築する。
76
+
77
+ Args:
78
+ file_path: 解析するソースファイルのパス
79
+
80
+ Returns:
81
+ 解析に成功した場合はTrue、失敗した場合はFalse
82
+
83
+ Raises:
84
+ None: エラーは内部でハンドリングし、戻り値で示す
85
+ """
86
+ try:
87
+ source_bytes = read_file_with_fallback(file_path)
88
+ if source_bytes is None:
89
+ output_error(
90
+ f"ERROR: ファイル '{file_path}' の読み込みに失敗しました。"
91
+ )
92
+ return False
93
+
94
+ self.source_code_bytes = source_bytes
95
+ self.tree = self.parser.parse(self.source_code_bytes)
96
+
97
+ if self.tree is None:
98
+ output_error(f"ERROR: '{file_path}' のAST構築に失敗しました。")
99
+ return False
100
+
101
+ log_info(f"INFO: '{file_path}' の解析が完了し、ASTを構築しました。")
102
+ return True
103
+
104
+ except Exception as e:
105
+ output_error(f"ERROR: ファイル解析中にエラーが発生しました: {e}")
106
+ return False
107
+
108
+ def execute_query(self, query_string: str) -> List[Dict[str, Any]]:
109
+ """
110
+ ASTに対して指定されたクエリを実行し、マッチしたノードの情報を抽出する。
111
+
112
+ Args:
113
+ query_string: 実行するTree-sitterクエリ
114
+
115
+ Returns:
116
+ マッチした各ノードの情報(内容、位置、キャプチャ名)のリスト
117
+
118
+ Raises:
119
+ None: エラーは内部でハンドリングし、空リストを返す
120
+ """
121
+ if not self.tree:
122
+ output_error(
123
+ "ERROR: ASTが構築されていません。先にparse_fileを実行してください。"
124
+ )
125
+ return []
126
+
127
+ try:
128
+ query = self.language.query(query_string)
129
+ except Exception as e:
130
+ output_error(
131
+ f"ERROR: クエリのコンパイルに失敗しました。\nクエリ: {query_string}\nエラー: {e}"
132
+ )
133
+ return []
134
+
135
+ try:
136
+ captures = query.captures(self.tree.root_node)
137
+ except Exception as e:
138
+ output_error(f"ERROR: クエリの実行に失敗しました: {e}")
139
+ return []
140
+
141
+ results = []
142
+
143
+ # Tree-sitter 0.24以降の辞書形式に対応
144
+ try:
145
+ if isinstance(captures, dict):
146
+ # 新しい辞書形式: {capture_name: [nodes...]}
147
+ for capture_name, nodes in captures.items():
148
+ if isinstance(nodes, list):
149
+ for node in nodes:
150
+ try:
151
+ start_line = node.start_point[0] + 1
152
+ end_line = node.end_point[0] + 1
153
+ node_text = self.source_code_bytes[
154
+ node.start_byte : node.end_byte
155
+ ].decode("utf-8", errors="ignore")
156
+
157
+ results.append(
158
+ {
159
+ "capture_name": capture_name,
160
+ "content": node_text,
161
+ "start_line": start_line,
162
+ "end_line": end_line,
163
+ "node_type": node.type,
164
+ }
165
+ )
166
+ except Exception as e:
167
+ output_warning(
168
+ f"WARNING: ノード処理中にエラーが発生しました: {e}"
169
+ )
170
+ continue
171
+ else:
172
+ # 古い形式への対応(フォールバック)
173
+ if hasattr(captures, "__iter__"):
174
+ for capture in captures:
175
+ try:
176
+ if isinstance(capture, tuple) and len(capture) == 2:
177
+ node, capture_name = capture
178
+ start_line = node.start_point[0] + 1
179
+ end_line = node.end_point[0] + 1
180
+ node_text = self.source_code_bytes[
181
+ node.start_byte : node.end_byte
182
+ ].decode("utf-8", errors="ignore")
183
+
184
+ results.append(
185
+ {
186
+ "capture_name": capture_name,
187
+ "content": node_text,
188
+ "start_line": start_line,
189
+ "end_line": end_line,
190
+ "node_type": node.type,
191
+ }
192
+ )
193
+ except Exception as e:
194
+ output_warning(
195
+ f"WARNING: ノード処理中にエラーが発生しました: {e}"
196
+ )
197
+ continue
198
+
199
+ except Exception as e:
200
+ output_error(f"ERROR: capture処理中に予期しないエラーが発生しました: {e}")
201
+ return []
202
+
203
+ return results
204
+
205
+
206
+ def main() -> None:
207
+ """
208
+ モジュールが直接実行された場合のエントリーポイント。
209
+ 通常はcli.pyを使用することを推奨。
210
+ """
211
+ output_warning("注意: 直接的なモジュール実行は非推奨です。")
212
+ output_warning("代わりに以下を使用してください:")
213
+ output_info(" uv run java-analyzer <file> --query-key <key>")
214
+ output_info(" または")
215
+ output_info(" python -m tree_sitter_analyzer.cli <file> --query-key <key>")
216
+
217
+
218
+ if __name__ == "__main__":
219
+ main()