tree-sitter-analyzer 1.9.17.1__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.
- tree_sitter_analyzer/__init__.py +132 -0
- tree_sitter_analyzer/__main__.py +11 -0
- tree_sitter_analyzer/api.py +853 -0
- tree_sitter_analyzer/cli/__init__.py +39 -0
- tree_sitter_analyzer/cli/__main__.py +12 -0
- tree_sitter_analyzer/cli/argument_validator.py +89 -0
- tree_sitter_analyzer/cli/commands/__init__.py +26 -0
- tree_sitter_analyzer/cli/commands/advanced_command.py +226 -0
- tree_sitter_analyzer/cli/commands/base_command.py +181 -0
- tree_sitter_analyzer/cli/commands/default_command.py +18 -0
- tree_sitter_analyzer/cli/commands/find_and_grep_cli.py +188 -0
- tree_sitter_analyzer/cli/commands/list_files_cli.py +133 -0
- tree_sitter_analyzer/cli/commands/partial_read_command.py +139 -0
- tree_sitter_analyzer/cli/commands/query_command.py +109 -0
- tree_sitter_analyzer/cli/commands/search_content_cli.py +161 -0
- tree_sitter_analyzer/cli/commands/structure_command.py +156 -0
- tree_sitter_analyzer/cli/commands/summary_command.py +116 -0
- tree_sitter_analyzer/cli/commands/table_command.py +414 -0
- tree_sitter_analyzer/cli/info_commands.py +124 -0
- tree_sitter_analyzer/cli_main.py +472 -0
- tree_sitter_analyzer/constants.py +85 -0
- tree_sitter_analyzer/core/__init__.py +15 -0
- tree_sitter_analyzer/core/analysis_engine.py +580 -0
- tree_sitter_analyzer/core/cache_service.py +333 -0
- tree_sitter_analyzer/core/engine.py +585 -0
- tree_sitter_analyzer/core/parser.py +293 -0
- tree_sitter_analyzer/core/query.py +605 -0
- tree_sitter_analyzer/core/query_filter.py +200 -0
- tree_sitter_analyzer/core/query_service.py +340 -0
- tree_sitter_analyzer/encoding_utils.py +530 -0
- tree_sitter_analyzer/exceptions.py +747 -0
- tree_sitter_analyzer/file_handler.py +246 -0
- tree_sitter_analyzer/formatters/__init__.py +1 -0
- tree_sitter_analyzer/formatters/base_formatter.py +201 -0
- tree_sitter_analyzer/formatters/csharp_formatter.py +367 -0
- tree_sitter_analyzer/formatters/formatter_config.py +197 -0
- tree_sitter_analyzer/formatters/formatter_factory.py +84 -0
- tree_sitter_analyzer/formatters/formatter_registry.py +377 -0
- tree_sitter_analyzer/formatters/formatter_selector.py +96 -0
- tree_sitter_analyzer/formatters/go_formatter.py +368 -0
- tree_sitter_analyzer/formatters/html_formatter.py +498 -0
- tree_sitter_analyzer/formatters/java_formatter.py +423 -0
- tree_sitter_analyzer/formatters/javascript_formatter.py +611 -0
- tree_sitter_analyzer/formatters/kotlin_formatter.py +268 -0
- tree_sitter_analyzer/formatters/language_formatter_factory.py +123 -0
- tree_sitter_analyzer/formatters/legacy_formatter_adapters.py +228 -0
- tree_sitter_analyzer/formatters/markdown_formatter.py +725 -0
- tree_sitter_analyzer/formatters/php_formatter.py +301 -0
- tree_sitter_analyzer/formatters/python_formatter.py +830 -0
- tree_sitter_analyzer/formatters/ruby_formatter.py +278 -0
- tree_sitter_analyzer/formatters/rust_formatter.py +233 -0
- tree_sitter_analyzer/formatters/sql_formatter_wrapper.py +689 -0
- tree_sitter_analyzer/formatters/sql_formatters.py +536 -0
- tree_sitter_analyzer/formatters/typescript_formatter.py +543 -0
- tree_sitter_analyzer/formatters/yaml_formatter.py +462 -0
- tree_sitter_analyzer/interfaces/__init__.py +9 -0
- tree_sitter_analyzer/interfaces/cli.py +535 -0
- tree_sitter_analyzer/interfaces/cli_adapter.py +359 -0
- tree_sitter_analyzer/interfaces/mcp_adapter.py +224 -0
- tree_sitter_analyzer/interfaces/mcp_server.py +428 -0
- tree_sitter_analyzer/language_detector.py +553 -0
- tree_sitter_analyzer/language_loader.py +271 -0
- tree_sitter_analyzer/languages/__init__.py +10 -0
- tree_sitter_analyzer/languages/csharp_plugin.py +1076 -0
- tree_sitter_analyzer/languages/css_plugin.py +449 -0
- tree_sitter_analyzer/languages/go_plugin.py +836 -0
- tree_sitter_analyzer/languages/html_plugin.py +496 -0
- tree_sitter_analyzer/languages/java_plugin.py +1299 -0
- tree_sitter_analyzer/languages/javascript_plugin.py +1622 -0
- tree_sitter_analyzer/languages/kotlin_plugin.py +656 -0
- tree_sitter_analyzer/languages/markdown_plugin.py +1928 -0
- tree_sitter_analyzer/languages/php_plugin.py +862 -0
- tree_sitter_analyzer/languages/python_plugin.py +1636 -0
- tree_sitter_analyzer/languages/ruby_plugin.py +757 -0
- tree_sitter_analyzer/languages/rust_plugin.py +673 -0
- tree_sitter_analyzer/languages/sql_plugin.py +2444 -0
- tree_sitter_analyzer/languages/typescript_plugin.py +1892 -0
- tree_sitter_analyzer/languages/yaml_plugin.py +695 -0
- tree_sitter_analyzer/legacy_table_formatter.py +860 -0
- tree_sitter_analyzer/mcp/__init__.py +34 -0
- tree_sitter_analyzer/mcp/resources/__init__.py +43 -0
- tree_sitter_analyzer/mcp/resources/code_file_resource.py +208 -0
- tree_sitter_analyzer/mcp/resources/project_stats_resource.py +586 -0
- tree_sitter_analyzer/mcp/server.py +869 -0
- tree_sitter_analyzer/mcp/tools/__init__.py +28 -0
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +779 -0
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +291 -0
- tree_sitter_analyzer/mcp/tools/base_tool.py +139 -0
- tree_sitter_analyzer/mcp/tools/fd_rg_utils.py +816 -0
- tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +686 -0
- tree_sitter_analyzer/mcp/tools/list_files_tool.py +413 -0
- tree_sitter_analyzer/mcp/tools/output_format_validator.py +148 -0
- tree_sitter_analyzer/mcp/tools/query_tool.py +443 -0
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +464 -0
- tree_sitter_analyzer/mcp/tools/search_content_tool.py +836 -0
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +572 -0
- tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +653 -0
- tree_sitter_analyzer/mcp/utils/__init__.py +113 -0
- tree_sitter_analyzer/mcp/utils/error_handler.py +569 -0
- tree_sitter_analyzer/mcp/utils/file_output_factory.py +217 -0
- tree_sitter_analyzer/mcp/utils/file_output_manager.py +322 -0
- tree_sitter_analyzer/mcp/utils/gitignore_detector.py +358 -0
- tree_sitter_analyzer/mcp/utils/path_resolver.py +414 -0
- tree_sitter_analyzer/mcp/utils/search_cache.py +343 -0
- tree_sitter_analyzer/models.py +840 -0
- tree_sitter_analyzer/mypy_current_errors.txt +2 -0
- tree_sitter_analyzer/output_manager.py +255 -0
- tree_sitter_analyzer/platform_compat/__init__.py +3 -0
- tree_sitter_analyzer/platform_compat/adapter.py +324 -0
- tree_sitter_analyzer/platform_compat/compare.py +224 -0
- tree_sitter_analyzer/platform_compat/detector.py +67 -0
- tree_sitter_analyzer/platform_compat/fixtures.py +228 -0
- tree_sitter_analyzer/platform_compat/profiles.py +217 -0
- tree_sitter_analyzer/platform_compat/record.py +55 -0
- tree_sitter_analyzer/platform_compat/recorder.py +155 -0
- tree_sitter_analyzer/platform_compat/report.py +92 -0
- tree_sitter_analyzer/plugins/__init__.py +280 -0
- tree_sitter_analyzer/plugins/base.py +647 -0
- tree_sitter_analyzer/plugins/manager.py +384 -0
- tree_sitter_analyzer/project_detector.py +328 -0
- tree_sitter_analyzer/queries/__init__.py +27 -0
- tree_sitter_analyzer/queries/csharp.py +216 -0
- tree_sitter_analyzer/queries/css.py +615 -0
- tree_sitter_analyzer/queries/go.py +275 -0
- tree_sitter_analyzer/queries/html.py +543 -0
- tree_sitter_analyzer/queries/java.py +402 -0
- tree_sitter_analyzer/queries/javascript.py +724 -0
- tree_sitter_analyzer/queries/kotlin.py +192 -0
- tree_sitter_analyzer/queries/markdown.py +258 -0
- tree_sitter_analyzer/queries/php.py +95 -0
- tree_sitter_analyzer/queries/python.py +859 -0
- tree_sitter_analyzer/queries/ruby.py +92 -0
- tree_sitter_analyzer/queries/rust.py +223 -0
- tree_sitter_analyzer/queries/sql.py +555 -0
- tree_sitter_analyzer/queries/typescript.py +871 -0
- tree_sitter_analyzer/queries/yaml.py +236 -0
- tree_sitter_analyzer/query_loader.py +272 -0
- tree_sitter_analyzer/security/__init__.py +22 -0
- tree_sitter_analyzer/security/boundary_manager.py +277 -0
- tree_sitter_analyzer/security/regex_checker.py +297 -0
- tree_sitter_analyzer/security/validator.py +599 -0
- tree_sitter_analyzer/table_formatter.py +782 -0
- tree_sitter_analyzer/utils/__init__.py +53 -0
- tree_sitter_analyzer/utils/logging.py +433 -0
- tree_sitter_analyzer/utils/tree_sitter_compat.py +289 -0
- tree_sitter_analyzer-1.9.17.1.dist-info/METADATA +485 -0
- tree_sitter_analyzer-1.9.17.1.dist-info/RECORD +149 -0
- tree_sitter_analyzer-1.9.17.1.dist-info/WHEEL +4 -0
- tree_sitter_analyzer-1.9.17.1.dist-info/entry_points.txt +25 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Kotlin-specific table formatter.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .base_formatter import BaseTableFormatter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class KotlinTableFormatter(BaseTableFormatter):
|
|
12
|
+
"""Table formatter specialized for Kotlin"""
|
|
13
|
+
|
|
14
|
+
def _format_full_table(self, data: dict[str, Any]) -> str:
|
|
15
|
+
"""Full table format for Kotlin"""
|
|
16
|
+
lines = []
|
|
17
|
+
|
|
18
|
+
# Header - Kotlin
|
|
19
|
+
package_name = (data.get("package") or {}).get("name", "default")
|
|
20
|
+
file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
|
|
21
|
+
if package_name != "default":
|
|
22
|
+
lines.append(f"# {package_name}.{file_name}")
|
|
23
|
+
else:
|
|
24
|
+
lines.append(f"# {file_name}")
|
|
25
|
+
lines.append("")
|
|
26
|
+
|
|
27
|
+
# Imports
|
|
28
|
+
imports = data.get("imports", [])
|
|
29
|
+
if imports:
|
|
30
|
+
lines.append("## Imports")
|
|
31
|
+
lines.append("```kotlin")
|
|
32
|
+
for imp in imports:
|
|
33
|
+
lines.append(str(imp.get("statement", "")))
|
|
34
|
+
lines.append("```")
|
|
35
|
+
lines.append("")
|
|
36
|
+
|
|
37
|
+
# Classes/Objects/Interfaces
|
|
38
|
+
classes = data.get("classes", [])
|
|
39
|
+
if classes:
|
|
40
|
+
lines.append("## Classes & Objects")
|
|
41
|
+
lines.append("| Name | Type | Visibility | Lines | Props | Methods |")
|
|
42
|
+
lines.append("|------|------|------------|-------|-------|---------|")
|
|
43
|
+
|
|
44
|
+
for cls in classes:
|
|
45
|
+
name = str(cls.get("name", "Unknown"))
|
|
46
|
+
cls_type = str(cls.get("type", "class"))
|
|
47
|
+
visibility = str(cls.get("visibility", "public"))
|
|
48
|
+
line_range = cls.get("line_range", {})
|
|
49
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
50
|
+
|
|
51
|
+
# Count props/methods within
|
|
52
|
+
class_props = len(
|
|
53
|
+
[
|
|
54
|
+
p
|
|
55
|
+
for p in data.get("fields", [])
|
|
56
|
+
if line_range.get("start", 0)
|
|
57
|
+
<= p.get("line_range", {}).get("start", 0)
|
|
58
|
+
<= line_range.get("end", 0)
|
|
59
|
+
]
|
|
60
|
+
)
|
|
61
|
+
class_methods = len(
|
|
62
|
+
[
|
|
63
|
+
m
|
|
64
|
+
for m in data.get("methods", [])
|
|
65
|
+
if line_range.get("start", 0)
|
|
66
|
+
<= m.get("line_range", {}).get("start", 0)
|
|
67
|
+
<= line_range.get("end", 0)
|
|
68
|
+
]
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
lines.append(
|
|
72
|
+
f"| {name} | {cls_type} | {visibility} | {lines_str} | {class_props} | {class_methods} |"
|
|
73
|
+
)
|
|
74
|
+
lines.append("")
|
|
75
|
+
|
|
76
|
+
# Top-level Functions
|
|
77
|
+
# We want to list all functions, but maybe group them or just list them.
|
|
78
|
+
# BaseTableFormatter lists all methods in data.get("methods") usually.
|
|
79
|
+
fns = data.get("methods", [])
|
|
80
|
+
if fns:
|
|
81
|
+
lines.append("## Functions")
|
|
82
|
+
lines.append("| Function | Signature | Vis | Lines | Suspend | Doc |")
|
|
83
|
+
lines.append("|----------|-----------|-----|-------|---------|-----|")
|
|
84
|
+
|
|
85
|
+
for fn in fns:
|
|
86
|
+
lines.append(self._format_fn_row(fn))
|
|
87
|
+
lines.append("")
|
|
88
|
+
|
|
89
|
+
# Top-level Properties
|
|
90
|
+
props = data.get("fields", []) # Mapped to fields
|
|
91
|
+
if props:
|
|
92
|
+
lines.append("## Properties")
|
|
93
|
+
lines.append("| Name | Type | Vis | Kind | Line | Doc |")
|
|
94
|
+
lines.append("|------|------|-----|------|------|-----|")
|
|
95
|
+
|
|
96
|
+
for prop in props:
|
|
97
|
+
lines.append(self._format_prop_row(prop))
|
|
98
|
+
lines.append("")
|
|
99
|
+
|
|
100
|
+
return "\n".join(lines)
|
|
101
|
+
|
|
102
|
+
def _format_compact_table(self, data: dict[str, Any]) -> str:
|
|
103
|
+
"""Compact table format for Kotlin"""
|
|
104
|
+
lines = []
|
|
105
|
+
|
|
106
|
+
# Header
|
|
107
|
+
package_name = (data.get("package") or {}).get("name", "default")
|
|
108
|
+
file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
|
|
109
|
+
if package_name != "default":
|
|
110
|
+
lines.append(f"# {package_name}.{file_name}")
|
|
111
|
+
else:
|
|
112
|
+
lines.append(f"# {file_name}")
|
|
113
|
+
lines.append("")
|
|
114
|
+
|
|
115
|
+
# Info
|
|
116
|
+
stats = data.get("statistics") or {}
|
|
117
|
+
lines.append("## Info")
|
|
118
|
+
lines.append("| Property | Value |")
|
|
119
|
+
lines.append("|----------|-------|")
|
|
120
|
+
lines.append(f"| Package | {package_name} |")
|
|
121
|
+
lines.append(f"| Classes | {len(data.get('classes', []))} |")
|
|
122
|
+
lines.append(f"| Functions | {stats.get('method_count', 0)} |")
|
|
123
|
+
lines.append(f"| Properties | {stats.get('field_count', 0)} |")
|
|
124
|
+
lines.append("")
|
|
125
|
+
|
|
126
|
+
# Functions (compact)
|
|
127
|
+
fns = data.get("methods", [])
|
|
128
|
+
if fns:
|
|
129
|
+
lines.append("## Functions")
|
|
130
|
+
lines.append("| Fn | Sig | V | S | L | Doc |")
|
|
131
|
+
lines.append("|----|-----|---|---|---|-----|")
|
|
132
|
+
|
|
133
|
+
for fn in fns:
|
|
134
|
+
name = str(fn.get("name", ""))
|
|
135
|
+
signature = self._create_compact_signature(fn)
|
|
136
|
+
visibility = self._convert_visibility(str(fn.get("visibility", "")))
|
|
137
|
+
is_suspend = "Y" if fn.get("is_suspend", False) else "-"
|
|
138
|
+
line_range = fn.get("line_range", {})
|
|
139
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
140
|
+
doc = self._clean_csv_text(
|
|
141
|
+
self._extract_doc_summary(str(fn.get("docstring", "") or ""))
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
lines.append(
|
|
145
|
+
f"| {name} | {signature} | {visibility} | {is_suspend} | {lines_str} | {doc} |"
|
|
146
|
+
)
|
|
147
|
+
lines.append("")
|
|
148
|
+
|
|
149
|
+
return "\n".join(lines)
|
|
150
|
+
|
|
151
|
+
def _format_fn_row(self, fn: dict[str, Any]) -> str:
|
|
152
|
+
"""Format a function table row for Kotlin"""
|
|
153
|
+
name = str(fn.get("name", ""))
|
|
154
|
+
signature = self._create_full_signature(fn)
|
|
155
|
+
visibility = self._convert_visibility(str(fn.get("visibility", "")))
|
|
156
|
+
is_suspend = "Yes" if fn.get("is_suspend", False) else "-"
|
|
157
|
+
line_range = fn.get("line_range", {})
|
|
158
|
+
lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
|
|
159
|
+
doc = self._clean_csv_text(
|
|
160
|
+
self._extract_doc_summary(str(fn.get("docstring", "") or ""))
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
return f"| {name} | {signature} | {visibility} | {lines_str} | {is_suspend} | {doc} |"
|
|
164
|
+
|
|
165
|
+
def _format_prop_row(self, prop: dict[str, Any]) -> str:
|
|
166
|
+
"""Format a property table row for Kotlin"""
|
|
167
|
+
name = str(prop.get("name", ""))
|
|
168
|
+
prop_type = str(prop.get("type", ""))
|
|
169
|
+
visibility = self._convert_visibility(str(prop.get("visibility", "")))
|
|
170
|
+
# Check val/var if extracted
|
|
171
|
+
kind = (
|
|
172
|
+
"val"
|
|
173
|
+
if prop.get("is_val", False)
|
|
174
|
+
else ("var" if prop.get("is_var", False) else "-")
|
|
175
|
+
)
|
|
176
|
+
line = prop.get("line_range", {}).get("start", 0)
|
|
177
|
+
doc = self._clean_csv_text(
|
|
178
|
+
self._extract_doc_summary(str(prop.get("docstring", "") or ""))
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
return f"| {name} | {prop_type} | {visibility} | {kind} | {line} | {doc} |"
|
|
182
|
+
|
|
183
|
+
def _create_full_signature(self, fn: dict[str, Any]) -> str:
|
|
184
|
+
"""Create full function signature for Kotlin"""
|
|
185
|
+
# Kotlin: fun name(p1: T1, p2: T2): R
|
|
186
|
+
params = fn.get("parameters", [])
|
|
187
|
+
params_str_list = []
|
|
188
|
+
for p in params:
|
|
189
|
+
if isinstance(p, dict):
|
|
190
|
+
# "name: type" is expected
|
|
191
|
+
params_str_list.append(f"{p.get('name')}: {p.get('type')}")
|
|
192
|
+
else:
|
|
193
|
+
params_str_list.append(str(p))
|
|
194
|
+
|
|
195
|
+
params_str = ", ".join(params_str_list)
|
|
196
|
+
return_type = fn.get("return_type", "")
|
|
197
|
+
ret_str = f": {return_type}" if return_type and return_type != "Unit" else ""
|
|
198
|
+
|
|
199
|
+
return f"fun({params_str}){ret_str}"
|
|
200
|
+
|
|
201
|
+
def _create_compact_signature(self, fn: dict[str, Any]) -> str:
|
|
202
|
+
"""Create compact function signature for Kotlin"""
|
|
203
|
+
params = fn.get("parameters", [])
|
|
204
|
+
params_summary = f"({len(params)})"
|
|
205
|
+
return_type = fn.get("return_type", "")
|
|
206
|
+
ret_str = f":{return_type}" if return_type and return_type != "Unit" else ""
|
|
207
|
+
|
|
208
|
+
return f"{params_summary}{ret_str}"
|
|
209
|
+
|
|
210
|
+
def _convert_visibility(self, visibility: str) -> str:
|
|
211
|
+
"""Convert visibility to short symbol"""
|
|
212
|
+
if visibility == "public":
|
|
213
|
+
return "pub"
|
|
214
|
+
elif visibility == "private":
|
|
215
|
+
return "priv"
|
|
216
|
+
elif visibility == "protected":
|
|
217
|
+
return "prot"
|
|
218
|
+
elif visibility == "internal":
|
|
219
|
+
return "int"
|
|
220
|
+
return visibility
|
|
221
|
+
|
|
222
|
+
def format_table(
|
|
223
|
+
self, analysis_result: dict[str, Any], table_type: str = "full"
|
|
224
|
+
) -> str:
|
|
225
|
+
"""Format table output for Kotlin"""
|
|
226
|
+
# Set the format type based on table_type parameter
|
|
227
|
+
original_format_type = self.format_type
|
|
228
|
+
self.format_type = table_type
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
# Handle json format separately
|
|
232
|
+
if table_type == "json":
|
|
233
|
+
return self._format_json(analysis_result)
|
|
234
|
+
# Use the existing format_structure method
|
|
235
|
+
return self.format_structure(analysis_result)
|
|
236
|
+
finally:
|
|
237
|
+
# Restore original format type
|
|
238
|
+
self.format_type = original_format_type
|
|
239
|
+
|
|
240
|
+
def format_summary(self, analysis_result: dict[str, Any]) -> str:
|
|
241
|
+
"""Format summary output for Kotlin"""
|
|
242
|
+
return self._format_compact_table(analysis_result)
|
|
243
|
+
|
|
244
|
+
def format_structure(self, analysis_result: dict[str, Any]) -> str:
|
|
245
|
+
"""Format structure analysis output for Kotlin"""
|
|
246
|
+
if self.format_type == "compact":
|
|
247
|
+
return self._format_compact_table(analysis_result)
|
|
248
|
+
return self._format_full_table(analysis_result)
|
|
249
|
+
|
|
250
|
+
def format_advanced(
|
|
251
|
+
self, analysis_result: dict[str, Any], output_format: str = "json"
|
|
252
|
+
) -> str:
|
|
253
|
+
"""Format advanced analysis output for Kotlin"""
|
|
254
|
+
if output_format == "json":
|
|
255
|
+
return self._format_json(analysis_result)
|
|
256
|
+
elif output_format == "csv":
|
|
257
|
+
return self._format_csv(analysis_result)
|
|
258
|
+
else:
|
|
259
|
+
return self._format_full_table(analysis_result)
|
|
260
|
+
|
|
261
|
+
def _format_json(self, data: dict[str, Any]) -> str:
|
|
262
|
+
"""Format data as JSON"""
|
|
263
|
+
import json
|
|
264
|
+
|
|
265
|
+
try:
|
|
266
|
+
return json.dumps(data, indent=2, ensure_ascii=False)
|
|
267
|
+
except (TypeError, ValueError) as e:
|
|
268
|
+
return f"# JSON serialization error: {e}\n"
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Factory for creating language-specific formatters for different output types.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .base_formatter import BaseFormatter
|
|
7
|
+
from .csharp_formatter import CSharpTableFormatter
|
|
8
|
+
from .go_formatter import GoTableFormatter
|
|
9
|
+
from .html_formatter import HtmlFormatter
|
|
10
|
+
from .java_formatter import JavaTableFormatter
|
|
11
|
+
from .javascript_formatter import JavaScriptTableFormatter
|
|
12
|
+
from .kotlin_formatter import KotlinTableFormatter
|
|
13
|
+
from .markdown_formatter import MarkdownFormatter
|
|
14
|
+
from .php_formatter import PHPTableFormatter
|
|
15
|
+
from .python_formatter import PythonTableFormatter
|
|
16
|
+
from .ruby_formatter import RubyTableFormatter
|
|
17
|
+
from .rust_formatter import RustTableFormatter
|
|
18
|
+
from .sql_formatter_wrapper import SQLFormatterWrapper
|
|
19
|
+
from .typescript_formatter import TypeScriptTableFormatter
|
|
20
|
+
from .yaml_formatter import YAMLFormatter
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class LanguageFormatterFactory:
|
|
24
|
+
"""Factory for creating language-specific formatters"""
|
|
25
|
+
|
|
26
|
+
_formatters: dict[str, type[BaseFormatter]] = {
|
|
27
|
+
"markdown": MarkdownFormatter,
|
|
28
|
+
"md": MarkdownFormatter, # Alias
|
|
29
|
+
"html": HtmlFormatter,
|
|
30
|
+
"css": HtmlFormatter, # CSS files also use HTML formatter
|
|
31
|
+
"sql": SQLFormatterWrapper, # SQL-specific formatter
|
|
32
|
+
"python": PythonTableFormatter, # Python files use Python formatter
|
|
33
|
+
"py": PythonTableFormatter, # Python alias
|
|
34
|
+
"java": JavaTableFormatter, # Java files use Java formatter
|
|
35
|
+
"kotlin": KotlinTableFormatter, # Kotlin files use Kotlin formatter
|
|
36
|
+
"kt": KotlinTableFormatter, # Kotlin alias
|
|
37
|
+
"kts": KotlinTableFormatter, # Kotlin script alias
|
|
38
|
+
"javascript": JavaScriptTableFormatter, # JavaScript files use JavaScript formatter
|
|
39
|
+
"js": JavaScriptTableFormatter, # JavaScript alias
|
|
40
|
+
"typescript": TypeScriptTableFormatter, # TypeScript files use TypeScript formatter
|
|
41
|
+
"ts": TypeScriptTableFormatter, # TypeScript alias
|
|
42
|
+
"csharp": CSharpTableFormatter, # C# files use C# formatter
|
|
43
|
+
"cs": CSharpTableFormatter, # C# alias
|
|
44
|
+
"php": PHPTableFormatter, # PHP files use PHP formatter
|
|
45
|
+
"ruby": RubyTableFormatter, # Ruby files use Ruby formatter
|
|
46
|
+
"rb": RubyTableFormatter, # Ruby alias
|
|
47
|
+
"rust": RustTableFormatter, # Rust files use Rust formatter
|
|
48
|
+
"rs": RustTableFormatter, # Rust alias
|
|
49
|
+
"go": GoTableFormatter, # Go files use Go formatter
|
|
50
|
+
"yaml": YAMLFormatter, # YAML files use YAML formatter
|
|
51
|
+
"yml": YAMLFormatter, # YAML alias
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def create_formatter(cls, language: str) -> BaseFormatter:
|
|
56
|
+
"""
|
|
57
|
+
Create formatter for specified language
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
language: Programming language name
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Language-specific formatter
|
|
64
|
+
"""
|
|
65
|
+
formatter_class = cls._formatters.get(language.lower())
|
|
66
|
+
|
|
67
|
+
if formatter_class is None:
|
|
68
|
+
raise ValueError(f"Unsupported language: {language}")
|
|
69
|
+
|
|
70
|
+
return formatter_class()
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def register_formatter(
|
|
74
|
+
cls, language: str, formatter_class: type[BaseFormatter]
|
|
75
|
+
) -> None:
|
|
76
|
+
"""
|
|
77
|
+
Register new language formatter
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
language: Programming language name
|
|
81
|
+
formatter_class: Formatter class
|
|
82
|
+
"""
|
|
83
|
+
cls._formatters[language.lower()] = formatter_class
|
|
84
|
+
|
|
85
|
+
@classmethod
|
|
86
|
+
def get_supported_languages(cls) -> list[str]:
|
|
87
|
+
"""
|
|
88
|
+
Get list of supported languages
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
List of supported languages
|
|
92
|
+
"""
|
|
93
|
+
return list(cls._formatters.keys())
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def supports_language(cls, language: str) -> bool:
|
|
97
|
+
"""
|
|
98
|
+
Check if language is supported
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
language: Programming language name
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
True if language is supported
|
|
105
|
+
"""
|
|
106
|
+
return language.lower() in cls._formatters
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def create_language_formatter(language: str) -> BaseFormatter | None:
|
|
110
|
+
"""
|
|
111
|
+
Create language formatter (function for compatibility)
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
language: Programming language name
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Language formatter or None if not supported
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
return LanguageFormatterFactory.create_formatter(language)
|
|
121
|
+
except ValueError:
|
|
122
|
+
# Return None for unsupported languages instead of raising exception
|
|
123
|
+
return None
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Legacy Formatter Adapters
|
|
4
|
+
|
|
5
|
+
Adapters to integrate the legacy v1.6.1.4 TableFormatter with the v1.9.4 FormatterRegistry system.
|
|
6
|
+
This ensures backward compatibility while maintaining the new architecture.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
from ..constants import (
|
|
16
|
+
ELEMENT_TYPE_CLASS,
|
|
17
|
+
ELEMENT_TYPE_FUNCTION,
|
|
18
|
+
ELEMENT_TYPE_IMPORT,
|
|
19
|
+
ELEMENT_TYPE_PACKAGE,
|
|
20
|
+
ELEMENT_TYPE_VARIABLE,
|
|
21
|
+
get_element_type,
|
|
22
|
+
is_element_of_type,
|
|
23
|
+
)
|
|
24
|
+
from ..legacy_table_formatter import LegacyTableFormatter
|
|
25
|
+
from ..models import CodeElement
|
|
26
|
+
from .formatter_registry import IFormatter
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class LegacyFormatterAdapter(IFormatter):
|
|
32
|
+
"""
|
|
33
|
+
Base adapter class for legacy table formatters.
|
|
34
|
+
|
|
35
|
+
Converts CodeElement lists to the legacy data structure format
|
|
36
|
+
and delegates formatting to LegacyTableFormatter.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def get_format_name() -> str:
|
|
41
|
+
"""Return the format name this formatter supports"""
|
|
42
|
+
# This will be overridden in subclasses
|
|
43
|
+
return "legacy"
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self, format_type: str, language: str = "java", include_javadoc: bool = False
|
|
47
|
+
):
|
|
48
|
+
"""
|
|
49
|
+
Initialize the legacy formatter adapter.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
format_type: Format type (full, compact, csv)
|
|
53
|
+
language: Programming language for syntax highlighting
|
|
54
|
+
include_javadoc: Whether to include JavaDoc/documentation
|
|
55
|
+
"""
|
|
56
|
+
self.format_type = format_type
|
|
57
|
+
self.language = language
|
|
58
|
+
self.include_javadoc = include_javadoc
|
|
59
|
+
self.formatter = LegacyTableFormatter(
|
|
60
|
+
format_type=format_type, language=language, include_javadoc=include_javadoc
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def format(self, elements: list[CodeElement]) -> str:
|
|
64
|
+
"""
|
|
65
|
+
Format CodeElement list using legacy formatter.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
elements: List of CodeElement objects to format
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Formatted string in legacy v1.6.1.4 format
|
|
72
|
+
"""
|
|
73
|
+
# Convert CodeElement list to legacy data structure
|
|
74
|
+
legacy_data = self._convert_to_legacy_format(elements)
|
|
75
|
+
|
|
76
|
+
# Use legacy formatter
|
|
77
|
+
result = self.formatter.format_structure(legacy_data)
|
|
78
|
+
|
|
79
|
+
# Ensure Unix-style line endings for consistency
|
|
80
|
+
result = result.replace("\r\n", "\n").replace("\r", "\n")
|
|
81
|
+
|
|
82
|
+
return result
|
|
83
|
+
|
|
84
|
+
def _convert_to_legacy_format(self, elements: list[CodeElement]) -> dict[str, Any]:
|
|
85
|
+
"""
|
|
86
|
+
Convert CodeElement list to legacy data structure format.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
elements: List of CodeElement objects
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Dictionary in legacy format expected by LegacyTableFormatter
|
|
93
|
+
"""
|
|
94
|
+
# Extract file_path from first element if available
|
|
95
|
+
file_path = "Unknown"
|
|
96
|
+
if elements and hasattr(elements[0], "file_path"):
|
|
97
|
+
file_path = elements[0].file_path or "Unknown"
|
|
98
|
+
|
|
99
|
+
# Initialize legacy data structure
|
|
100
|
+
legacy_data: dict[str, Any] = {
|
|
101
|
+
"file_path": file_path,
|
|
102
|
+
"package": {"name": "unknown"},
|
|
103
|
+
"imports": [],
|
|
104
|
+
"classes": [],
|
|
105
|
+
"methods": [],
|
|
106
|
+
"fields": [],
|
|
107
|
+
"statistics": {"method_count": 0, "field_count": 0, "class_count": 0},
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# Process elements by type
|
|
111
|
+
package_name = "unknown"
|
|
112
|
+
for element in elements:
|
|
113
|
+
# Use is_element_of_type helper for accurate type checking
|
|
114
|
+
# Also handle legacy "method" and "field" type names
|
|
115
|
+
element_type = get_element_type(element)
|
|
116
|
+
|
|
117
|
+
if is_element_of_type(element, ELEMENT_TYPE_PACKAGE):
|
|
118
|
+
package_name = element.name
|
|
119
|
+
legacy_data["package"]["name"] = package_name
|
|
120
|
+
elif is_element_of_type(element, ELEMENT_TYPE_CLASS):
|
|
121
|
+
legacy_data["classes"].append(self._convert_class_element(element))
|
|
122
|
+
elif (
|
|
123
|
+
is_element_of_type(element, ELEMENT_TYPE_FUNCTION)
|
|
124
|
+
or element_type == "method"
|
|
125
|
+
):
|
|
126
|
+
legacy_data["methods"].append(self._convert_method_element(element))
|
|
127
|
+
elif (
|
|
128
|
+
is_element_of_type(element, ELEMENT_TYPE_VARIABLE)
|
|
129
|
+
or element_type == "field"
|
|
130
|
+
):
|
|
131
|
+
legacy_data["fields"].append(self._convert_field_element(element))
|
|
132
|
+
elif is_element_of_type(element, ELEMENT_TYPE_IMPORT):
|
|
133
|
+
legacy_data["imports"].append(self._convert_import_element(element))
|
|
134
|
+
|
|
135
|
+
# Update statistics
|
|
136
|
+
legacy_data["statistics"]["method_count"] = len(legacy_data["methods"])
|
|
137
|
+
legacy_data["statistics"]["field_count"] = len(legacy_data["fields"])
|
|
138
|
+
legacy_data["statistics"]["class_count"] = len(legacy_data["classes"])
|
|
139
|
+
|
|
140
|
+
# If no classes found, create a default one for proper formatting
|
|
141
|
+
if not legacy_data["classes"] and (
|
|
142
|
+
legacy_data["methods"] or legacy_data["fields"]
|
|
143
|
+
):
|
|
144
|
+
legacy_data["classes"] = [
|
|
145
|
+
{
|
|
146
|
+
"name": "Unknown",
|
|
147
|
+
"type": "class",
|
|
148
|
+
"visibility": "public",
|
|
149
|
+
"line_range": {"start": 1, "end": 100},
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
return legacy_data
|
|
154
|
+
|
|
155
|
+
def _convert_class_element(self, element: CodeElement) -> dict[str, Any]:
|
|
156
|
+
"""Convert class CodeElement to legacy format"""
|
|
157
|
+
return {
|
|
158
|
+
"name": element.name,
|
|
159
|
+
"type": getattr(element, "class_type", "class"),
|
|
160
|
+
"visibility": getattr(element, "visibility", "public"),
|
|
161
|
+
"line_range": {"start": element.start_line, "end": element.end_line},
|
|
162
|
+
"modifiers": getattr(element, "modifiers", []),
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
def _convert_method_element(self, element: CodeElement) -> dict[str, Any]:
|
|
166
|
+
"""Convert method CodeElement to legacy format"""
|
|
167
|
+
return {
|
|
168
|
+
"name": element.name,
|
|
169
|
+
"visibility": getattr(element, "visibility", "public"),
|
|
170
|
+
"return_type": getattr(element, "return_type", "void"),
|
|
171
|
+
"parameters": getattr(element, "parameters", []),
|
|
172
|
+
"line_range": {"start": element.start_line, "end": element.end_line},
|
|
173
|
+
"is_constructor": getattr(element, "is_constructor", False),
|
|
174
|
+
"is_static": getattr(element, "is_static", False),
|
|
175
|
+
"modifiers": getattr(element, "modifiers", []),
|
|
176
|
+
"complexity_score": getattr(element, "complexity_score", 0),
|
|
177
|
+
"javadoc": getattr(element, "documentation", ""),
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
def _convert_field_element(self, element: CodeElement) -> dict[str, Any]:
|
|
181
|
+
"""Convert field CodeElement to legacy format"""
|
|
182
|
+
return {
|
|
183
|
+
"name": element.name,
|
|
184
|
+
"type": getattr(element, "field_type", "Object"),
|
|
185
|
+
"visibility": getattr(element, "visibility", "private"),
|
|
186
|
+
"line_range": {"start": element.start_line, "end": element.end_line},
|
|
187
|
+
"modifiers": getattr(element, "modifiers", []),
|
|
188
|
+
"javadoc": getattr(element, "documentation", ""),
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
def _convert_import_element(self, element: CodeElement) -> dict[str, Any]:
|
|
192
|
+
"""Convert import CodeElement to legacy format"""
|
|
193
|
+
return {
|
|
194
|
+
"statement": getattr(element, "import_statement", f"import {element.name}")
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class LegacyFullFormatter(LegacyFormatterAdapter):
|
|
199
|
+
"""Legacy full formatter producing Markdown tables"""
|
|
200
|
+
|
|
201
|
+
def __init__(self, language: str = "java", include_javadoc: bool = False):
|
|
202
|
+
super().__init__("full", language, include_javadoc)
|
|
203
|
+
|
|
204
|
+
@staticmethod
|
|
205
|
+
def get_format_name() -> str:
|
|
206
|
+
return "full"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class LegacyCompactFormatter(LegacyFormatterAdapter):
|
|
210
|
+
"""Legacy compact formatter with complexity scores"""
|
|
211
|
+
|
|
212
|
+
def __init__(self, language: str = "java", include_javadoc: bool = False):
|
|
213
|
+
super().__init__("compact", language, include_javadoc)
|
|
214
|
+
|
|
215
|
+
@staticmethod
|
|
216
|
+
def get_format_name() -> str:
|
|
217
|
+
return "compact"
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class LegacyCsvFormatter(LegacyFormatterAdapter):
|
|
221
|
+
"""Legacy CSV formatter with simple structure"""
|
|
222
|
+
|
|
223
|
+
def __init__(self, language: str = "java", include_javadoc: bool = False):
|
|
224
|
+
super().__init__("csv", language, include_javadoc)
|
|
225
|
+
|
|
226
|
+
@staticmethod
|
|
227
|
+
def get_format_name() -> str:
|
|
228
|
+
return "csv"
|