tree-sitter-analyzer 0.9.2__py3-none-any.whl → 0.9.4__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.
- tree_sitter_analyzer/__init__.py +1 -1
- tree_sitter_analyzer/cli/commands/base_command.py +2 -3
- tree_sitter_analyzer/cli/commands/default_command.py +18 -18
- tree_sitter_analyzer/cli/commands/partial_read_command.py +139 -141
- tree_sitter_analyzer/cli/commands/query_command.py +92 -88
- tree_sitter_analyzer/cli/commands/table_command.py +235 -235
- tree_sitter_analyzer/cli/info_commands.py +121 -121
- tree_sitter_analyzer/cli_main.py +307 -303
- tree_sitter_analyzer/core/analysis_engine.py +584 -576
- tree_sitter_analyzer/core/cache_service.py +6 -5
- tree_sitter_analyzer/core/query.py +502 -502
- tree_sitter_analyzer/encoding_utils.py +6 -2
- tree_sitter_analyzer/exceptions.py +400 -406
- tree_sitter_analyzer/formatters/java_formatter.py +291 -291
- tree_sitter_analyzer/formatters/python_formatter.py +259 -259
- tree_sitter_analyzer/interfaces/cli.py +1 -1
- tree_sitter_analyzer/interfaces/cli_adapter.py +3 -3
- tree_sitter_analyzer/interfaces/mcp_server.py +426 -425
- tree_sitter_analyzer/language_detector.py +398 -398
- tree_sitter_analyzer/language_loader.py +224 -224
- tree_sitter_analyzer/languages/java_plugin.py +1202 -1202
- tree_sitter_analyzer/mcp/resources/project_stats_resource.py +559 -555
- tree_sitter_analyzer/mcp/server.py +30 -9
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +21 -4
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +22 -4
- tree_sitter_analyzer/mcp/utils/error_handler.py +569 -567
- tree_sitter_analyzer/models.py +470 -470
- tree_sitter_analyzer/project_detector.py +330 -317
- tree_sitter_analyzer/security/__init__.py +22 -22
- tree_sitter_analyzer/security/boundary_manager.py +243 -237
- tree_sitter_analyzer/security/regex_checker.py +297 -292
- tree_sitter_analyzer/table_formatter.py +703 -652
- tree_sitter_analyzer/utils.py +53 -22
- {tree_sitter_analyzer-0.9.2.dist-info → tree_sitter_analyzer-0.9.4.dist-info}/METADATA +13 -13
- {tree_sitter_analyzer-0.9.2.dist-info → tree_sitter_analyzer-0.9.4.dist-info}/RECORD +37 -37
- {tree_sitter_analyzer-0.9.2.dist-info → tree_sitter_analyzer-0.9.4.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-0.9.2.dist-info → tree_sitter_analyzer-0.9.4.dist-info}/entry_points.txt +0 -0
|
@@ -1,259 +1,259 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Python-specific table formatter.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
from .base_formatter import BaseTableFormatter
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class PythonTableFormatter(BaseTableFormatter):
|
|
12
|
-
"""Table formatter specialized for Python"""
|
|
13
|
-
|
|
14
|
-
def _format_full_table(self, data: dict[str, Any]) -> str:
|
|
15
|
-
"""Full table format for Python"""
|
|
16
|
-
lines = []
|
|
17
|
-
|
|
18
|
-
# Header - Python (multi-class supported)
|
|
19
|
-
classes = data.get("classes", [])
|
|
20
|
-
if len(classes) > 1:
|
|
21
|
-
# If multiple classes exist, use filename
|
|
22
|
-
file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
|
|
23
|
-
lines.append(f"# {file_name}")
|
|
24
|
-
else:
|
|
25
|
-
# Single class: use class name
|
|
26
|
-
class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
|
|
27
|
-
lines.append(f"# {class_name}")
|
|
28
|
-
lines.append("")
|
|
29
|
-
|
|
30
|
-
# Imports
|
|
31
|
-
imports = data.get("imports", [])
|
|
32
|
-
if imports:
|
|
33
|
-
lines.append("## Imports")
|
|
34
|
-
lines.append("```python")
|
|
35
|
-
for imp in imports:
|
|
36
|
-
lines.append(str(imp.get("statement", "")))
|
|
37
|
-
lines.append("```")
|
|
38
|
-
lines.append("")
|
|
39
|
-
|
|
40
|
-
# Classes - Python (multi-class aware)
|
|
41
|
-
if len(classes) > 1:
|
|
42
|
-
lines.append("## Classes")
|
|
43
|
-
lines.append("| Class | Type | Visibility | Lines | Methods | Fields |")
|
|
44
|
-
lines.append("|-------|------|------------|-------|---------|--------|")
|
|
45
|
-
|
|
46
|
-
for class_info in classes:
|
|
47
|
-
name = str(class_info.get("name", "Unknown"))
|
|
48
|
-
class_type = str(class_info.get("type", "class"))
|
|
49
|
-
visibility = str(class_info.get("visibility", "public"))
|
|
50
|
-
line_range = class_info.get("line_range", {})
|
|
51
|
-
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
52
|
-
|
|
53
|
-
# Count methods/fields within the class range
|
|
54
|
-
class_methods = [
|
|
55
|
-
m
|
|
56
|
-
for m in data.get("methods", [])
|
|
57
|
-
if line_range.get("start", 0)
|
|
58
|
-
<= m.get("line_range", {}).get("start", 0)
|
|
59
|
-
<= line_range.get("end", 0)
|
|
60
|
-
]
|
|
61
|
-
class_fields = [
|
|
62
|
-
f
|
|
63
|
-
for f in data.get("fields", [])
|
|
64
|
-
if line_range.get("start", 0)
|
|
65
|
-
<= f.get("line_range", {}).get("start", 0)
|
|
66
|
-
<= line_range.get("end", 0)
|
|
67
|
-
]
|
|
68
|
-
|
|
69
|
-
lines.append(
|
|
70
|
-
f"| {name} | {class_type} | {visibility} | {lines_str} | {len(class_methods)} | {len(class_fields)} |"
|
|
71
|
-
)
|
|
72
|
-
else:
|
|
73
|
-
# Single class details
|
|
74
|
-
lines.append("## Class Info")
|
|
75
|
-
lines.append("| Property | Value |")
|
|
76
|
-
lines.append("|----------|-------|")
|
|
77
|
-
|
|
78
|
-
class_info = data.get("classes", [{}])[0] if data.get("classes") else {}
|
|
79
|
-
stats = data.get("statistics") or {}
|
|
80
|
-
|
|
81
|
-
lines.append("| Package | (default) |")
|
|
82
|
-
lines.append(f"| Type | {str(class_info.get('type', 'class'))} |")
|
|
83
|
-
lines.append(
|
|
84
|
-
f"| Visibility | {str(class_info.get('visibility', 'public'))} |"
|
|
85
|
-
)
|
|
86
|
-
lines.append(
|
|
87
|
-
f"| Lines | {class_info.get('line_range', {}).get('start', 0)}-{class_info.get('line_range', {}).get('end', 0)} |"
|
|
88
|
-
)
|
|
89
|
-
lines.append(f"| Total Methods | {stats.get('method_count', 0)} |")
|
|
90
|
-
lines.append(f"| Total Fields | {stats.get('field_count', 0)} |")
|
|
91
|
-
|
|
92
|
-
lines.append("")
|
|
93
|
-
|
|
94
|
-
# Fields
|
|
95
|
-
fields = data.get("fields", [])
|
|
96
|
-
if fields:
|
|
97
|
-
lines.append("## Fields")
|
|
98
|
-
lines.append("| Name | Type | Vis | Modifiers | Line | Doc |")
|
|
99
|
-
lines.append("|------|------|-----|-----------|------|-----|")
|
|
100
|
-
|
|
101
|
-
for field in fields:
|
|
102
|
-
name = str(field.get("name", ""))
|
|
103
|
-
field_type = str(field.get("type", ""))
|
|
104
|
-
visibility = self._convert_visibility(str(field.get("visibility", "")))
|
|
105
|
-
modifiers = ",".join([str(m) for m in field.get("modifiers", [])])
|
|
106
|
-
line = field.get("line_range", {}).get("start", 0)
|
|
107
|
-
doc = str(field.get("javadoc", "")) or "-"
|
|
108
|
-
doc = doc.replace("\n", " ").replace("|", "\\|")[:50]
|
|
109
|
-
|
|
110
|
-
lines.append(
|
|
111
|
-
f"| {name} | {field_type} | {visibility} | {modifiers} | {line} | {doc} |"
|
|
112
|
-
)
|
|
113
|
-
lines.append("")
|
|
114
|
-
|
|
115
|
-
# Methods - Python (no constructor separation)
|
|
116
|
-
methods = data.get("methods", [])
|
|
117
|
-
if methods:
|
|
118
|
-
lines.append("## Methods")
|
|
119
|
-
lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
|
|
120
|
-
lines.append("|--------|-----------|-----|-------|------|----|----|")
|
|
121
|
-
|
|
122
|
-
for method in methods:
|
|
123
|
-
lines.append(self._format_method_row(method))
|
|
124
|
-
lines.append("")
|
|
125
|
-
|
|
126
|
-
# Trim trailing blank lines
|
|
127
|
-
while lines and lines[-1] == "":
|
|
128
|
-
lines.pop()
|
|
129
|
-
|
|
130
|
-
return "\n".join(lines)
|
|
131
|
-
|
|
132
|
-
def _format_compact_table(self, data: dict[str, Any]) -> str:
|
|
133
|
-
"""Compact table format for Python"""
|
|
134
|
-
lines = []
|
|
135
|
-
|
|
136
|
-
# Header
|
|
137
|
-
classes = data.get("classes", [])
|
|
138
|
-
if len(classes) > 1:
|
|
139
|
-
file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
|
|
140
|
-
lines.append(f"# {file_name}")
|
|
141
|
-
else:
|
|
142
|
-
class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
|
|
143
|
-
lines.append(f"# {class_name}")
|
|
144
|
-
lines.append("")
|
|
145
|
-
|
|
146
|
-
# Info
|
|
147
|
-
stats = data.get("statistics") or {}
|
|
148
|
-
lines.append("## Info")
|
|
149
|
-
lines.append("| Property | Value |")
|
|
150
|
-
lines.append("|----------|-------|")
|
|
151
|
-
lines.append(f"| Classes | {len(classes)} |")
|
|
152
|
-
lines.append(f"| Methods | {stats.get('method_count', 0)} |")
|
|
153
|
-
lines.append(f"| Fields | {stats.get('field_count', 0)} |")
|
|
154
|
-
lines.append("")
|
|
155
|
-
|
|
156
|
-
# Methods (compact)
|
|
157
|
-
methods = data.get("methods", [])
|
|
158
|
-
if methods:
|
|
159
|
-
lines.append("## Methods")
|
|
160
|
-
lines.append("| Method | Sig | V | L | Cx | Doc |")
|
|
161
|
-
lines.append("|--------|-----|---|---|----|----|")
|
|
162
|
-
|
|
163
|
-
for method in methods:
|
|
164
|
-
name = str(method.get("name", ""))
|
|
165
|
-
signature = self._create_compact_signature(method)
|
|
166
|
-
visibility = self._convert_visibility(str(method.get("visibility", "")))
|
|
167
|
-
line_range = method.get("line_range", {})
|
|
168
|
-
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
169
|
-
complexity = method.get("complexity_score", 0)
|
|
170
|
-
doc = self._clean_csv_text(
|
|
171
|
-
self._extract_doc_summary(str(method.get("javadoc", "")))
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
lines.append(
|
|
175
|
-
f"| {name} | {signature} | {visibility} | {lines_str} | {complexity} | {doc} |"
|
|
176
|
-
)
|
|
177
|
-
lines.append("")
|
|
178
|
-
|
|
179
|
-
# Trim trailing blank lines
|
|
180
|
-
while lines and lines[-1] == "":
|
|
181
|
-
lines.pop()
|
|
182
|
-
|
|
183
|
-
return "\n".join(lines)
|
|
184
|
-
|
|
185
|
-
def _format_method_row(self, method: dict[str, Any]) -> str:
|
|
186
|
-
"""Format a method table row for Python"""
|
|
187
|
-
name = str(method.get("name", ""))
|
|
188
|
-
signature = self._create_full_signature(method)
|
|
189
|
-
visibility = self._convert_visibility(str(method.get("visibility", "")))
|
|
190
|
-
line_range = method.get("line_range", {})
|
|
191
|
-
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
192
|
-
cols_str = "5-6" # default placeholder
|
|
193
|
-
complexity = method.get("complexity_score", 0)
|
|
194
|
-
doc = self._clean_csv_text(
|
|
195
|
-
self._extract_doc_summary(str(method.get("javadoc", "")))
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
return f"| {name} | {signature} | {visibility} | {lines_str} | {cols_str} | {complexity} | {doc} |"
|
|
199
|
-
|
|
200
|
-
def _create_compact_signature(self, method: dict[str, Any]) -> str:
|
|
201
|
-
"""Create compact method signature for Python"""
|
|
202
|
-
params = method.get("parameters", [])
|
|
203
|
-
param_types = []
|
|
204
|
-
|
|
205
|
-
for p in params:
|
|
206
|
-
if isinstance(p, dict):
|
|
207
|
-
param_types.append(self._shorten_type(p.get("type", "Any")))
|
|
208
|
-
else:
|
|
209
|
-
param_types.append("Any")
|
|
210
|
-
|
|
211
|
-
params_str = ",".join(param_types)
|
|
212
|
-
return_type = self._shorten_type(method.get("return_type", "Any"))
|
|
213
|
-
|
|
214
|
-
return f"({params_str}):{return_type}"
|
|
215
|
-
|
|
216
|
-
def _shorten_type(self, type_name: Any) -> str:
|
|
217
|
-
"""Shorten type name for Python tables"""
|
|
218
|
-
if type_name is None:
|
|
219
|
-
return "Any"
|
|
220
|
-
|
|
221
|
-
if not isinstance(type_name, str):
|
|
222
|
-
type_name = str(type_name)
|
|
223
|
-
|
|
224
|
-
type_mapping = {
|
|
225
|
-
"str": "s",
|
|
226
|
-
"int": "i",
|
|
227
|
-
"float": "f",
|
|
228
|
-
"bool": "b",
|
|
229
|
-
"None": "N",
|
|
230
|
-
"Any": "A",
|
|
231
|
-
"List": "L",
|
|
232
|
-
"Dict": "D",
|
|
233
|
-
"Optional": "O",
|
|
234
|
-
"Union": "U",
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
# List[str] -> L[s]
|
|
238
|
-
if "List[" in type_name:
|
|
239
|
-
result = (
|
|
240
|
-
type_name.replace("List[", "L[").replace("str", "s").replace("int", "i")
|
|
241
|
-
)
|
|
242
|
-
return str(result)
|
|
243
|
-
|
|
244
|
-
# Dict[str, int] -> D[s,i]
|
|
245
|
-
if "Dict[" in type_name:
|
|
246
|
-
result = (
|
|
247
|
-
type_name.replace("Dict[", "D[").replace("str", "s").replace("int", "i")
|
|
248
|
-
)
|
|
249
|
-
return str(result)
|
|
250
|
-
|
|
251
|
-
# Optional[str] -> O[s]
|
|
252
|
-
if "Optional[" in type_name:
|
|
253
|
-
result = type_name.replace("Optional[", "O[").replace("str", "s")
|
|
254
|
-
return str(result)
|
|
255
|
-
|
|
256
|
-
result = type_mapping.get(
|
|
257
|
-
type_name, type_name[:3] if len(type_name) > 3 else type_name
|
|
258
|
-
)
|
|
259
|
-
return str(result)
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Python-specific table formatter.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .base_formatter import BaseTableFormatter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PythonTableFormatter(BaseTableFormatter):
|
|
12
|
+
"""Table formatter specialized for Python"""
|
|
13
|
+
|
|
14
|
+
def _format_full_table(self, data: dict[str, Any]) -> str:
|
|
15
|
+
"""Full table format for Python"""
|
|
16
|
+
lines = []
|
|
17
|
+
|
|
18
|
+
# Header - Python (multi-class supported)
|
|
19
|
+
classes = data.get("classes", [])
|
|
20
|
+
if len(classes) > 1:
|
|
21
|
+
# If multiple classes exist, use filename
|
|
22
|
+
file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
|
|
23
|
+
lines.append(f"# {file_name}")
|
|
24
|
+
else:
|
|
25
|
+
# Single class: use class name
|
|
26
|
+
class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
|
|
27
|
+
lines.append(f"# {class_name}")
|
|
28
|
+
lines.append("")
|
|
29
|
+
|
|
30
|
+
# Imports
|
|
31
|
+
imports = data.get("imports", [])
|
|
32
|
+
if imports:
|
|
33
|
+
lines.append("## Imports")
|
|
34
|
+
lines.append("```python")
|
|
35
|
+
for imp in imports:
|
|
36
|
+
lines.append(str(imp.get("statement", "")))
|
|
37
|
+
lines.append("```")
|
|
38
|
+
lines.append("")
|
|
39
|
+
|
|
40
|
+
# Classes - Python (multi-class aware)
|
|
41
|
+
if len(classes) > 1:
|
|
42
|
+
lines.append("## Classes")
|
|
43
|
+
lines.append("| Class | Type | Visibility | Lines | Methods | Fields |")
|
|
44
|
+
lines.append("|-------|------|------------|-------|---------|--------|")
|
|
45
|
+
|
|
46
|
+
for class_info in classes:
|
|
47
|
+
name = str(class_info.get("name", "Unknown"))
|
|
48
|
+
class_type = str(class_info.get("type", "class"))
|
|
49
|
+
visibility = str(class_info.get("visibility", "public"))
|
|
50
|
+
line_range = class_info.get("line_range", {})
|
|
51
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
52
|
+
|
|
53
|
+
# Count methods/fields within the class range
|
|
54
|
+
class_methods = [
|
|
55
|
+
m
|
|
56
|
+
for m in data.get("methods", [])
|
|
57
|
+
if line_range.get("start", 0)
|
|
58
|
+
<= m.get("line_range", {}).get("start", 0)
|
|
59
|
+
<= line_range.get("end", 0)
|
|
60
|
+
]
|
|
61
|
+
class_fields = [
|
|
62
|
+
f
|
|
63
|
+
for f in data.get("fields", [])
|
|
64
|
+
if line_range.get("start", 0)
|
|
65
|
+
<= f.get("line_range", {}).get("start", 0)
|
|
66
|
+
<= line_range.get("end", 0)
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
lines.append(
|
|
70
|
+
f"| {name} | {class_type} | {visibility} | {lines_str} | {len(class_methods)} | {len(class_fields)} |"
|
|
71
|
+
)
|
|
72
|
+
else:
|
|
73
|
+
# Single class details
|
|
74
|
+
lines.append("## Class Info")
|
|
75
|
+
lines.append("| Property | Value |")
|
|
76
|
+
lines.append("|----------|-------|")
|
|
77
|
+
|
|
78
|
+
class_info = data.get("classes", [{}])[0] if data.get("classes") else {}
|
|
79
|
+
stats = data.get("statistics") or {}
|
|
80
|
+
|
|
81
|
+
lines.append("| Package | (default) |")
|
|
82
|
+
lines.append(f"| Type | {str(class_info.get('type', 'class'))} |")
|
|
83
|
+
lines.append(
|
|
84
|
+
f"| Visibility | {str(class_info.get('visibility', 'public'))} |"
|
|
85
|
+
)
|
|
86
|
+
lines.append(
|
|
87
|
+
f"| Lines | {class_info.get('line_range', {}).get('start', 0)}-{class_info.get('line_range', {}).get('end', 0)} |"
|
|
88
|
+
)
|
|
89
|
+
lines.append(f"| Total Methods | {stats.get('method_count', 0)} |")
|
|
90
|
+
lines.append(f"| Total Fields | {stats.get('field_count', 0)} |")
|
|
91
|
+
|
|
92
|
+
lines.append("")
|
|
93
|
+
|
|
94
|
+
# Fields
|
|
95
|
+
fields = data.get("fields", [])
|
|
96
|
+
if fields:
|
|
97
|
+
lines.append("## Fields")
|
|
98
|
+
lines.append("| Name | Type | Vis | Modifiers | Line | Doc |")
|
|
99
|
+
lines.append("|------|------|-----|-----------|------|-----|")
|
|
100
|
+
|
|
101
|
+
for field in fields:
|
|
102
|
+
name = str(field.get("name", ""))
|
|
103
|
+
field_type = str(field.get("type", ""))
|
|
104
|
+
visibility = self._convert_visibility(str(field.get("visibility", "")))
|
|
105
|
+
modifiers = ",".join([str(m) for m in field.get("modifiers", [])])
|
|
106
|
+
line = field.get("line_range", {}).get("start", 0)
|
|
107
|
+
doc = str(field.get("javadoc", "")) or "-"
|
|
108
|
+
doc = doc.replace("\n", " ").replace("|", "\\|")[:50]
|
|
109
|
+
|
|
110
|
+
lines.append(
|
|
111
|
+
f"| {name} | {field_type} | {visibility} | {modifiers} | {line} | {doc} |"
|
|
112
|
+
)
|
|
113
|
+
lines.append("")
|
|
114
|
+
|
|
115
|
+
# Methods - Python (no constructor separation)
|
|
116
|
+
methods = data.get("methods", [])
|
|
117
|
+
if methods:
|
|
118
|
+
lines.append("## Methods")
|
|
119
|
+
lines.append("| Method | Signature | Vis | Lines | Cols | Cx | Doc |")
|
|
120
|
+
lines.append("|--------|-----------|-----|-------|------|----|----|")
|
|
121
|
+
|
|
122
|
+
for method in methods:
|
|
123
|
+
lines.append(self._format_method_row(method))
|
|
124
|
+
lines.append("")
|
|
125
|
+
|
|
126
|
+
# Trim trailing blank lines
|
|
127
|
+
while lines and lines[-1] == "":
|
|
128
|
+
lines.pop()
|
|
129
|
+
|
|
130
|
+
return "\n".join(lines)
|
|
131
|
+
|
|
132
|
+
def _format_compact_table(self, data: dict[str, Any]) -> str:
|
|
133
|
+
"""Compact table format for Python"""
|
|
134
|
+
lines = []
|
|
135
|
+
|
|
136
|
+
# Header
|
|
137
|
+
classes = data.get("classes", [])
|
|
138
|
+
if len(classes) > 1:
|
|
139
|
+
file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
|
|
140
|
+
lines.append(f"# {file_name}")
|
|
141
|
+
else:
|
|
142
|
+
class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
|
|
143
|
+
lines.append(f"# {class_name}")
|
|
144
|
+
lines.append("")
|
|
145
|
+
|
|
146
|
+
# Info
|
|
147
|
+
stats = data.get("statistics") or {}
|
|
148
|
+
lines.append("## Info")
|
|
149
|
+
lines.append("| Property | Value |")
|
|
150
|
+
lines.append("|----------|-------|")
|
|
151
|
+
lines.append(f"| Classes | {len(classes)} |")
|
|
152
|
+
lines.append(f"| Methods | {stats.get('method_count', 0)} |")
|
|
153
|
+
lines.append(f"| Fields | {stats.get('field_count', 0)} |")
|
|
154
|
+
lines.append("")
|
|
155
|
+
|
|
156
|
+
# Methods (compact)
|
|
157
|
+
methods = data.get("methods", [])
|
|
158
|
+
if methods:
|
|
159
|
+
lines.append("## Methods")
|
|
160
|
+
lines.append("| Method | Sig | V | L | Cx | Doc |")
|
|
161
|
+
lines.append("|--------|-----|---|---|----|----|")
|
|
162
|
+
|
|
163
|
+
for method in methods:
|
|
164
|
+
name = str(method.get("name", ""))
|
|
165
|
+
signature = self._create_compact_signature(method)
|
|
166
|
+
visibility = self._convert_visibility(str(method.get("visibility", "")))
|
|
167
|
+
line_range = method.get("line_range", {})
|
|
168
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
169
|
+
complexity = method.get("complexity_score", 0)
|
|
170
|
+
doc = self._clean_csv_text(
|
|
171
|
+
self._extract_doc_summary(str(method.get("javadoc", "")))
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
lines.append(
|
|
175
|
+
f"| {name} | {signature} | {visibility} | {lines_str} | {complexity} | {doc} |"
|
|
176
|
+
)
|
|
177
|
+
lines.append("")
|
|
178
|
+
|
|
179
|
+
# Trim trailing blank lines
|
|
180
|
+
while lines and lines[-1] == "":
|
|
181
|
+
lines.pop()
|
|
182
|
+
|
|
183
|
+
return "\n".join(lines)
|
|
184
|
+
|
|
185
|
+
def _format_method_row(self, method: dict[str, Any]) -> str:
|
|
186
|
+
"""Format a method table row for Python"""
|
|
187
|
+
name = str(method.get("name", ""))
|
|
188
|
+
signature = self._create_full_signature(method)
|
|
189
|
+
visibility = self._convert_visibility(str(method.get("visibility", "")))
|
|
190
|
+
line_range = method.get("line_range", {})
|
|
191
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
192
|
+
cols_str = "5-6" # default placeholder
|
|
193
|
+
complexity = method.get("complexity_score", 0)
|
|
194
|
+
doc = self._clean_csv_text(
|
|
195
|
+
self._extract_doc_summary(str(method.get("javadoc", "")))
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
return f"| {name} | {signature} | {visibility} | {lines_str} | {cols_str} | {complexity} | {doc} |"
|
|
199
|
+
|
|
200
|
+
def _create_compact_signature(self, method: dict[str, Any]) -> str:
|
|
201
|
+
"""Create compact method signature for Python"""
|
|
202
|
+
params = method.get("parameters", [])
|
|
203
|
+
param_types = []
|
|
204
|
+
|
|
205
|
+
for p in params:
|
|
206
|
+
if isinstance(p, dict):
|
|
207
|
+
param_types.append(self._shorten_type(p.get("type", "Any")))
|
|
208
|
+
else:
|
|
209
|
+
param_types.append("Any")
|
|
210
|
+
|
|
211
|
+
params_str = ",".join(param_types)
|
|
212
|
+
return_type = self._shorten_type(method.get("return_type", "Any"))
|
|
213
|
+
|
|
214
|
+
return f"({params_str}):{return_type}"
|
|
215
|
+
|
|
216
|
+
def _shorten_type(self, type_name: Any) -> str:
|
|
217
|
+
"""Shorten type name for Python tables"""
|
|
218
|
+
if type_name is None:
|
|
219
|
+
return "Any"
|
|
220
|
+
|
|
221
|
+
if not isinstance(type_name, str):
|
|
222
|
+
type_name = str(type_name)
|
|
223
|
+
|
|
224
|
+
type_mapping = {
|
|
225
|
+
"str": "s",
|
|
226
|
+
"int": "i",
|
|
227
|
+
"float": "f",
|
|
228
|
+
"bool": "b",
|
|
229
|
+
"None": "N",
|
|
230
|
+
"Any": "A",
|
|
231
|
+
"List": "L",
|
|
232
|
+
"Dict": "D",
|
|
233
|
+
"Optional": "O",
|
|
234
|
+
"Union": "U",
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
# List[str] -> L[s]
|
|
238
|
+
if "List[" in type_name:
|
|
239
|
+
result = (
|
|
240
|
+
type_name.replace("List[", "L[").replace("str", "s").replace("int", "i")
|
|
241
|
+
)
|
|
242
|
+
return str(result)
|
|
243
|
+
|
|
244
|
+
# Dict[str, int] -> D[s,i]
|
|
245
|
+
if "Dict[" in type_name:
|
|
246
|
+
result = (
|
|
247
|
+
type_name.replace("Dict[", "D[").replace("str", "s").replace("int", "i")
|
|
248
|
+
)
|
|
249
|
+
return str(result)
|
|
250
|
+
|
|
251
|
+
# Optional[str] -> O[s]
|
|
252
|
+
if "Optional[" in type_name:
|
|
253
|
+
result = type_name.replace("Optional[", "O[").replace("str", "s")
|
|
254
|
+
return str(result)
|
|
255
|
+
|
|
256
|
+
result = type_mapping.get(
|
|
257
|
+
type_name, type_name[:3] if len(type_name) > 3 else type_name
|
|
258
|
+
)
|
|
259
|
+
return str(result)
|
|
@@ -54,7 +54,7 @@ For more information, visit: https://github.com/aimasteracc/tree-sitter-analyzer
|
|
|
54
54
|
|
|
55
55
|
# Global options
|
|
56
56
|
parser.add_argument(
|
|
57
|
-
"--version", action="version", version="tree-sitter-analyzer 0.
|
|
57
|
+
"--version", action="version", version="tree-sitter-analyzer 0.9.3"
|
|
58
58
|
)
|
|
59
59
|
parser.add_argument(
|
|
60
60
|
"--verbose", "-v", action="store_true", help="Enable verbose output"
|
|
@@ -53,7 +53,7 @@ class CLIAdapter:
|
|
|
53
53
|
"""
|
|
54
54
|
try:
|
|
55
55
|
self._engine = UnifiedAnalysisEngine()
|
|
56
|
-
logger.
|
|
56
|
+
logger.debug("CLIAdapter initialized successfully")
|
|
57
57
|
except Exception as e:
|
|
58
58
|
logger.error(f"Failed to initialize CLIAdapter: {e}")
|
|
59
59
|
raise
|
|
@@ -111,7 +111,7 @@ class CLIAdapter:
|
|
|
111
111
|
|
|
112
112
|
# パフォーマンスログ
|
|
113
113
|
elapsed_time = time.time() - start_time
|
|
114
|
-
logger.
|
|
114
|
+
logger.debug(f"CLI analysis completed: {file_path} in {elapsed_time:.3f}s")
|
|
115
115
|
|
|
116
116
|
return result
|
|
117
117
|
|
|
@@ -251,7 +251,7 @@ class CLIAdapter:
|
|
|
251
251
|
>>> adapter.clear_cache()
|
|
252
252
|
"""
|
|
253
253
|
self._engine.clear_cache()
|
|
254
|
-
logger.
|
|
254
|
+
logger.debug("CLI adapter cache cleared")
|
|
255
255
|
|
|
256
256
|
def get_cache_stats(self) -> dict[str, Any]:
|
|
257
257
|
"""
|