tree-sitter-analyzer 0.9.1__py3-none-any.whl → 0.9.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.

Potentially problematic release.


This version of tree-sitter-analyzer might be problematic. Click here for more details.

Files changed (61) hide show
  1. tree_sitter_analyzer/__init__.py +132 -132
  2. tree_sitter_analyzer/__main__.py +11 -11
  3. tree_sitter_analyzer/api.py +533 -533
  4. tree_sitter_analyzer/cli/__init__.py +39 -39
  5. tree_sitter_analyzer/cli/__main__.py +12 -12
  6. tree_sitter_analyzer/cli/commands/__init__.py +26 -26
  7. tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
  8. tree_sitter_analyzer/cli/commands/base_command.py +182 -178
  9. tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
  10. tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
  11. tree_sitter_analyzer/core/__init__.py +15 -15
  12. tree_sitter_analyzer/core/analysis_engine.py +74 -78
  13. tree_sitter_analyzer/core/cache_service.py +320 -320
  14. tree_sitter_analyzer/core/engine.py +566 -566
  15. tree_sitter_analyzer/core/parser.py +293 -293
  16. tree_sitter_analyzer/encoding_utils.py +459 -459
  17. tree_sitter_analyzer/file_handler.py +210 -210
  18. tree_sitter_analyzer/formatters/__init__.py +1 -1
  19. tree_sitter_analyzer/formatters/base_formatter.py +167 -167
  20. tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
  21. tree_sitter_analyzer/formatters/java_formatter.py +18 -18
  22. tree_sitter_analyzer/formatters/python_formatter.py +19 -19
  23. tree_sitter_analyzer/interfaces/__init__.py +9 -9
  24. tree_sitter_analyzer/interfaces/cli.py +528 -528
  25. tree_sitter_analyzer/interfaces/cli_adapter.py +344 -343
  26. tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
  27. tree_sitter_analyzer/language_detector.py +53 -53
  28. tree_sitter_analyzer/languages/__init__.py +10 -10
  29. tree_sitter_analyzer/languages/java_plugin.py +1 -1
  30. tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
  31. tree_sitter_analyzer/languages/python_plugin.py +755 -755
  32. tree_sitter_analyzer/mcp/__init__.py +34 -45
  33. tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
  34. tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
  35. tree_sitter_analyzer/mcp/server.py +623 -568
  36. tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
  37. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +681 -673
  38. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -247
  39. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
  40. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +310 -308
  41. tree_sitter_analyzer/mcp/tools/table_format_tool.py +386 -379
  42. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +563 -559
  43. tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
  44. tree_sitter_analyzer/models.py +10 -10
  45. tree_sitter_analyzer/output_manager.py +253 -253
  46. tree_sitter_analyzer/plugins/__init__.py +280 -280
  47. tree_sitter_analyzer/plugins/base.py +529 -529
  48. tree_sitter_analyzer/plugins/manager.py +379 -379
  49. tree_sitter_analyzer/queries/__init__.py +26 -26
  50. tree_sitter_analyzer/queries/java.py +391 -391
  51. tree_sitter_analyzer/queries/javascript.py +148 -148
  52. tree_sitter_analyzer/queries/python.py +285 -285
  53. tree_sitter_analyzer/queries/typescript.py +229 -229
  54. tree_sitter_analyzer/query_loader.py +257 -257
  55. tree_sitter_analyzer/security/validator.py +246 -241
  56. tree_sitter_analyzer/utils.py +294 -277
  57. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/METADATA +1 -1
  58. tree_sitter_analyzer-0.9.2.dist-info/RECORD +77 -0
  59. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/entry_points.txt +1 -0
  60. tree_sitter_analyzer-0.9.1.dist-info/RECORD +0 -77
  61. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/WHEEL +0 -0
@@ -1,210 +1,210 @@
1
- #!/usr/bin/env python3
2
- """
3
- File Handler Module
4
-
5
- This module provides file reading functionality with encoding detection and fallback.
6
- """
7
-
8
- import os
9
-
10
- from .encoding_utils import read_file_safe
11
- from .utils import log_error, log_info, log_warning
12
-
13
-
14
- def detect_language_from_extension(file_path: str) -> str:
15
- """
16
- Detect programming language from file extension
17
-
18
- Args:
19
- file_path: File path to analyze
20
-
21
- Returns:
22
- Language name or 'unknown' if not recognized
23
- """
24
- extension = os.path.splitext(file_path)[1].lower()
25
-
26
- extension_map = {
27
- ".java": "java",
28
- ".py": "python",
29
- ".js": "javascript",
30
- ".ts": "typescript",
31
- ".cpp": "cpp",
32
- ".c": "c",
33
- ".h": "c",
34
- ".hpp": "cpp",
35
- ".cs": "csharp",
36
- ".go": "go",
37
- ".rs": "rust",
38
- ".rb": "ruby",
39
- ".php": "php",
40
- ".kt": "kotlin",
41
- ".scala": "scala",
42
- ".swift": "swift",
43
- }
44
-
45
- return extension_map.get(extension, "unknown")
46
-
47
-
48
- def read_file_with_fallback(file_path: str) -> bytes | None:
49
- """
50
- Read file with encoding fallback using unified encoding utilities
51
-
52
- Args:
53
- file_path: Path to the file to read
54
-
55
- Returns:
56
- File content as bytes, or None if file doesn't exist
57
- """
58
- # まずファイルの存在を確認
59
- if not os.path.exists(file_path):
60
- log_error(f"File does not exist: {file_path}")
61
- return None
62
-
63
- try:
64
- content, detected_encoding = read_file_safe(file_path)
65
- log_info(
66
- f"Successfully read file {file_path} with encoding: {detected_encoding}"
67
- )
68
- return content.encode("utf-8")
69
-
70
- except Exception as e:
71
- log_error(f"Failed to read file {file_path}: {e}")
72
- return None
73
-
74
-
75
- def read_file_partial(
76
- file_path: str,
77
- start_line: int,
78
- end_line: int | None = None,
79
- start_column: int | None = None,
80
- end_column: int | None = None,
81
- ) -> str | None:
82
- """
83
- 指定した行番号・列番号範囲でファイルの一部を読み込み
84
-
85
- Args:
86
- file_path: 読み込むファイルのパス
87
- start_line: 開始行番号(1ベース)
88
- end_line: 終了行番号(Noneの場合はファイル末尾まで、1ベース)
89
- start_column: 開始列番号(0ベース、省略可)
90
- end_column: 終了列番号(0ベース、省略可)
91
-
92
- Returns:
93
- 指定範囲のファイル内容(文字列)、エラーの場合はNone
94
- """
95
- # ファイルの存在確認
96
- if not os.path.exists(file_path):
97
- log_error(f"File does not exist: {file_path}")
98
- return None
99
-
100
- # パラメータ検証
101
- if start_line < 1:
102
- log_error(f"Invalid start_line: {start_line}. Line numbers start from 1.")
103
- return None
104
-
105
- if end_line is not None and end_line < start_line:
106
- log_error(f"Invalid range: end_line ({end_line}) < start_line ({start_line})")
107
- return None
108
-
109
- try:
110
- # ファイル全体を安全に読み込み
111
- content, detected_encoding = read_file_safe(file_path)
112
-
113
- # 行に分割
114
- lines = content.splitlines(keepends=True)
115
- total_lines = len(lines)
116
-
117
- # 行範囲の調整
118
- start_idx = start_line - 1 # 0ベースに変換
119
- end_idx = min(
120
- end_line - 1 if end_line is not None else total_lines - 1, total_lines - 1
121
- )
122
-
123
- # 範囲チェック
124
- if start_idx >= total_lines:
125
- log_warning(
126
- f"start_line ({start_line}) exceeds file length ({total_lines})"
127
- )
128
- return ""
129
-
130
- # 指定範囲の行を取得
131
- selected_lines = lines[start_idx : end_idx + 1]
132
-
133
- # 列範囲の処理
134
- if start_column is not None or end_column is not None:
135
- processed_lines = []
136
- for i, line in enumerate(selected_lines):
137
- # 改行文字を除去して処理
138
- line_content = line.rstrip("\r\n")
139
-
140
- if i == 0 and start_column is not None:
141
- # 最初の行:開始列から
142
- line_content = (
143
- line_content[start_column:]
144
- if start_column < len(line_content)
145
- else ""
146
- )
147
-
148
- if i == len(selected_lines) - 1 and end_column is not None:
149
- # 最後の行:終了列まで
150
- if i == 0 and start_column is not None:
151
- # 単一行の場合:開始列と終了列の両方を適用
152
- col_end = (
153
- end_column - start_column
154
- if end_column >= start_column
155
- else 0
156
- )
157
- line_content = line_content[:col_end] if col_end > 0 else ""
158
- else:
159
- line_content = (
160
- line_content[:end_column]
161
- if end_column < len(line_content)
162
- else line_content
163
- )
164
-
165
- # 元の改行文字を保持(最後の行以外)
166
- if i < len(selected_lines) - 1:
167
- # 元の行の改行文字を取得
168
- original_line = lines[start_idx + i]
169
- if original_line.endswith("\r\n"):
170
- line_content += "\r\n"
171
- elif original_line.endswith("\n"):
172
- line_content += "\n"
173
- elif original_line.endswith("\r"):
174
- line_content += "\r"
175
-
176
- processed_lines.append(line_content)
177
-
178
- result = "".join(processed_lines)
179
- else:
180
- # 列指定なしの場合は行をそのまま結合
181
- result = "".join(selected_lines)
182
-
183
- log_info(
184
- f"Successfully read partial file {file_path}: "
185
- f"lines {start_line}-{end_line or total_lines}"
186
- f"{f', columns {start_column}-{end_column}' if start_column is not None or end_column is not None else ''}"
187
- )
188
-
189
- return result
190
-
191
- except Exception as e:
192
- log_error(f"Failed to read partial file {file_path}: {e}")
193
- return None
194
-
195
-
196
- def read_file_lines_range(
197
- file_path: str, start_line: int, end_line: int | None = None
198
- ) -> str | None:
199
- """
200
- 指定した行番号範囲でファイルの一部を読み込み(列指定なし)
201
-
202
- Args:
203
- file_path: 読み込むファイルのパス
204
- start_line: 開始行番号(1ベース)
205
- end_line: 終了行番号(Noneの場合はファイル末尾まで、1ベース)
206
-
207
- Returns:
208
- 指定範囲のファイル内容(文字列)、エラーの場合はNone
209
- """
210
- return read_file_partial(file_path, start_line, end_line)
1
+ #!/usr/bin/env python3
2
+ """
3
+ File Handler Module
4
+
5
+ This module provides file reading functionality with encoding detection and fallback.
6
+ """
7
+
8
+ import os
9
+
10
+ from .encoding_utils import read_file_safe
11
+ from .utils import log_error, log_info, log_warning
12
+
13
+
14
+ def detect_language_from_extension(file_path: str) -> str:
15
+ """
16
+ Detect programming language from file extension
17
+
18
+ Args:
19
+ file_path: File path to analyze
20
+
21
+ Returns:
22
+ Language name or 'unknown' if not recognized
23
+ """
24
+ extension = os.path.splitext(file_path)[1].lower()
25
+
26
+ extension_map = {
27
+ ".java": "java",
28
+ ".py": "python",
29
+ ".js": "javascript",
30
+ ".ts": "typescript",
31
+ ".cpp": "cpp",
32
+ ".c": "c",
33
+ ".h": "c",
34
+ ".hpp": "cpp",
35
+ ".cs": "csharp",
36
+ ".go": "go",
37
+ ".rs": "rust",
38
+ ".rb": "ruby",
39
+ ".php": "php",
40
+ ".kt": "kotlin",
41
+ ".scala": "scala",
42
+ ".swift": "swift",
43
+ }
44
+
45
+ return extension_map.get(extension, "unknown")
46
+
47
+
48
+ def read_file_with_fallback(file_path: str) -> bytes | None:
49
+ """
50
+ Read file with encoding fallback using unified encoding utilities
51
+
52
+ Args:
53
+ file_path: Path to the file to read
54
+
55
+ Returns:
56
+ File content as bytes, or None if file doesn't exist
57
+ """
58
+ # Check file existence first
59
+ if not os.path.exists(file_path):
60
+ log_error(f"File does not exist: {file_path}")
61
+ return None
62
+
63
+ try:
64
+ content, detected_encoding = read_file_safe(file_path)
65
+ log_info(
66
+ f"Successfully read file {file_path} with encoding: {detected_encoding}"
67
+ )
68
+ return content.encode("utf-8")
69
+
70
+ except Exception as e:
71
+ log_error(f"Failed to read file {file_path}: {e}")
72
+ return None
73
+
74
+
75
+ def read_file_partial(
76
+ file_path: str,
77
+ start_line: int,
78
+ end_line: int | None = None,
79
+ start_column: int | None = None,
80
+ end_column: int | None = None,
81
+ ) -> str | None:
82
+ """
83
+ Read partial file content by line/column range
84
+
85
+ Args:
86
+ file_path: Path to file
87
+ start_line: Start line (1-based)
88
+ end_line: End line (1-based, None means EOF)
89
+ start_column: Start column (0-based, optional)
90
+ end_column: End column (0-based, optional)
91
+
92
+ Returns:
93
+ Selected content string, or None on error
94
+ """
95
+ # Check file existence
96
+ if not os.path.exists(file_path):
97
+ log_error(f"File does not exist: {file_path}")
98
+ return None
99
+
100
+ # Parameter validation
101
+ if start_line < 1:
102
+ log_error(f"Invalid start_line: {start_line}. Line numbers start from 1.")
103
+ return None
104
+
105
+ if end_line is not None and end_line < start_line:
106
+ log_error(f"Invalid range: end_line ({end_line}) < start_line ({start_line})")
107
+ return None
108
+
109
+ try:
110
+ # Read whole file safely
111
+ content, detected_encoding = read_file_safe(file_path)
112
+
113
+ # Split to lines
114
+ lines = content.splitlines(keepends=True)
115
+ total_lines = len(lines)
116
+
117
+ # Adjust line indexes
118
+ start_idx = start_line - 1 # convert to 0-based
119
+ end_idx = min(
120
+ end_line - 1 if end_line is not None else total_lines - 1, total_lines - 1
121
+ )
122
+
123
+ # Range check
124
+ if start_idx >= total_lines:
125
+ log_warning(
126
+ f"start_line ({start_line}) exceeds file length ({total_lines})"
127
+ )
128
+ return ""
129
+
130
+ # Select lines
131
+ selected_lines = lines[start_idx : end_idx + 1]
132
+
133
+ # Handle column range
134
+ if start_column is not None or end_column is not None:
135
+ processed_lines = []
136
+ for i, line in enumerate(selected_lines):
137
+ # Strip newline for processing
138
+ line_content = line.rstrip("\r\n")
139
+
140
+ if i == 0 and start_column is not None:
141
+ # First line: apply start_column
142
+ line_content = (
143
+ line_content[start_column:]
144
+ if start_column < len(line_content)
145
+ else ""
146
+ )
147
+
148
+ if i == len(selected_lines) - 1 and end_column is not None:
149
+ # Last line: apply end_column
150
+ if i == 0 and start_column is not None:
151
+ # Single line: apply both start and end columns
152
+ col_end = (
153
+ end_column - start_column
154
+ if end_column >= start_column
155
+ else 0
156
+ )
157
+ line_content = line_content[:col_end] if col_end > 0 else ""
158
+ else:
159
+ line_content = (
160
+ line_content[:end_column]
161
+ if end_column < len(line_content)
162
+ else line_content
163
+ )
164
+
165
+ # Preserve original newline (except last line)
166
+ if i < len(selected_lines) - 1:
167
+ # Detect original newline char of the line
168
+ original_line = lines[start_idx + i]
169
+ if original_line.endswith("\r\n"):
170
+ line_content += "\r\n"
171
+ elif original_line.endswith("\n"):
172
+ line_content += "\n"
173
+ elif original_line.endswith("\r"):
174
+ line_content += "\r"
175
+
176
+ processed_lines.append(line_content)
177
+
178
+ result = "".join(processed_lines)
179
+ else:
180
+ # No column range: join lines directly
181
+ result = "".join(selected_lines)
182
+
183
+ log_info(
184
+ f"Successfully read partial file {file_path}: "
185
+ f"lines {start_line}-{end_line or total_lines}"
186
+ f"{f', columns {start_column}-{end_column}' if start_column is not None or end_column is not None else ''}"
187
+ )
188
+
189
+ return result
190
+
191
+ except Exception as e:
192
+ log_error(f"Failed to read partial file {file_path}: {e}")
193
+ return None
194
+
195
+
196
+ def read_file_lines_range(
197
+ file_path: str, start_line: int, end_line: int | None = None
198
+ ) -> str | None:
199
+ """
200
+ 指定した行番号範囲でファイルの一部を読み込み(列指定なし)
201
+
202
+ Args:
203
+ file_path: 読み込むファイルのパス
204
+ start_line: 開始行番号(1ベース)
205
+ end_line: 終了行番号(Noneの場合はファイル末尾まで、1ベース)
206
+
207
+ Returns:
208
+ 指定範囲のファイル内容(文字列)、エラーの場合はNone
209
+ """
210
+ return read_file_partial(file_path, start_line, end_line)
@@ -1 +1 @@
1
- # Language-specific formatters
1
+ # Language-specific formatters