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.
Files changed (149) hide show
  1. tree_sitter_analyzer/__init__.py +132 -0
  2. tree_sitter_analyzer/__main__.py +11 -0
  3. tree_sitter_analyzer/api.py +853 -0
  4. tree_sitter_analyzer/cli/__init__.py +39 -0
  5. tree_sitter_analyzer/cli/__main__.py +12 -0
  6. tree_sitter_analyzer/cli/argument_validator.py +89 -0
  7. tree_sitter_analyzer/cli/commands/__init__.py +26 -0
  8. tree_sitter_analyzer/cli/commands/advanced_command.py +226 -0
  9. tree_sitter_analyzer/cli/commands/base_command.py +181 -0
  10. tree_sitter_analyzer/cli/commands/default_command.py +18 -0
  11. tree_sitter_analyzer/cli/commands/find_and_grep_cli.py +188 -0
  12. tree_sitter_analyzer/cli/commands/list_files_cli.py +133 -0
  13. tree_sitter_analyzer/cli/commands/partial_read_command.py +139 -0
  14. tree_sitter_analyzer/cli/commands/query_command.py +109 -0
  15. tree_sitter_analyzer/cli/commands/search_content_cli.py +161 -0
  16. tree_sitter_analyzer/cli/commands/structure_command.py +156 -0
  17. tree_sitter_analyzer/cli/commands/summary_command.py +116 -0
  18. tree_sitter_analyzer/cli/commands/table_command.py +414 -0
  19. tree_sitter_analyzer/cli/info_commands.py +124 -0
  20. tree_sitter_analyzer/cli_main.py +472 -0
  21. tree_sitter_analyzer/constants.py +85 -0
  22. tree_sitter_analyzer/core/__init__.py +15 -0
  23. tree_sitter_analyzer/core/analysis_engine.py +580 -0
  24. tree_sitter_analyzer/core/cache_service.py +333 -0
  25. tree_sitter_analyzer/core/engine.py +585 -0
  26. tree_sitter_analyzer/core/parser.py +293 -0
  27. tree_sitter_analyzer/core/query.py +605 -0
  28. tree_sitter_analyzer/core/query_filter.py +200 -0
  29. tree_sitter_analyzer/core/query_service.py +340 -0
  30. tree_sitter_analyzer/encoding_utils.py +530 -0
  31. tree_sitter_analyzer/exceptions.py +747 -0
  32. tree_sitter_analyzer/file_handler.py +246 -0
  33. tree_sitter_analyzer/formatters/__init__.py +1 -0
  34. tree_sitter_analyzer/formatters/base_formatter.py +201 -0
  35. tree_sitter_analyzer/formatters/csharp_formatter.py +367 -0
  36. tree_sitter_analyzer/formatters/formatter_config.py +197 -0
  37. tree_sitter_analyzer/formatters/formatter_factory.py +84 -0
  38. tree_sitter_analyzer/formatters/formatter_registry.py +377 -0
  39. tree_sitter_analyzer/formatters/formatter_selector.py +96 -0
  40. tree_sitter_analyzer/formatters/go_formatter.py +368 -0
  41. tree_sitter_analyzer/formatters/html_formatter.py +498 -0
  42. tree_sitter_analyzer/formatters/java_formatter.py +423 -0
  43. tree_sitter_analyzer/formatters/javascript_formatter.py +611 -0
  44. tree_sitter_analyzer/formatters/kotlin_formatter.py +268 -0
  45. tree_sitter_analyzer/formatters/language_formatter_factory.py +123 -0
  46. tree_sitter_analyzer/formatters/legacy_formatter_adapters.py +228 -0
  47. tree_sitter_analyzer/formatters/markdown_formatter.py +725 -0
  48. tree_sitter_analyzer/formatters/php_formatter.py +301 -0
  49. tree_sitter_analyzer/formatters/python_formatter.py +830 -0
  50. tree_sitter_analyzer/formatters/ruby_formatter.py +278 -0
  51. tree_sitter_analyzer/formatters/rust_formatter.py +233 -0
  52. tree_sitter_analyzer/formatters/sql_formatter_wrapper.py +689 -0
  53. tree_sitter_analyzer/formatters/sql_formatters.py +536 -0
  54. tree_sitter_analyzer/formatters/typescript_formatter.py +543 -0
  55. tree_sitter_analyzer/formatters/yaml_formatter.py +462 -0
  56. tree_sitter_analyzer/interfaces/__init__.py +9 -0
  57. tree_sitter_analyzer/interfaces/cli.py +535 -0
  58. tree_sitter_analyzer/interfaces/cli_adapter.py +359 -0
  59. tree_sitter_analyzer/interfaces/mcp_adapter.py +224 -0
  60. tree_sitter_analyzer/interfaces/mcp_server.py +428 -0
  61. tree_sitter_analyzer/language_detector.py +553 -0
  62. tree_sitter_analyzer/language_loader.py +271 -0
  63. tree_sitter_analyzer/languages/__init__.py +10 -0
  64. tree_sitter_analyzer/languages/csharp_plugin.py +1076 -0
  65. tree_sitter_analyzer/languages/css_plugin.py +449 -0
  66. tree_sitter_analyzer/languages/go_plugin.py +836 -0
  67. tree_sitter_analyzer/languages/html_plugin.py +496 -0
  68. tree_sitter_analyzer/languages/java_plugin.py +1299 -0
  69. tree_sitter_analyzer/languages/javascript_plugin.py +1622 -0
  70. tree_sitter_analyzer/languages/kotlin_plugin.py +656 -0
  71. tree_sitter_analyzer/languages/markdown_plugin.py +1928 -0
  72. tree_sitter_analyzer/languages/php_plugin.py +862 -0
  73. tree_sitter_analyzer/languages/python_plugin.py +1636 -0
  74. tree_sitter_analyzer/languages/ruby_plugin.py +757 -0
  75. tree_sitter_analyzer/languages/rust_plugin.py +673 -0
  76. tree_sitter_analyzer/languages/sql_plugin.py +2444 -0
  77. tree_sitter_analyzer/languages/typescript_plugin.py +1892 -0
  78. tree_sitter_analyzer/languages/yaml_plugin.py +695 -0
  79. tree_sitter_analyzer/legacy_table_formatter.py +860 -0
  80. tree_sitter_analyzer/mcp/__init__.py +34 -0
  81. tree_sitter_analyzer/mcp/resources/__init__.py +43 -0
  82. tree_sitter_analyzer/mcp/resources/code_file_resource.py +208 -0
  83. tree_sitter_analyzer/mcp/resources/project_stats_resource.py +586 -0
  84. tree_sitter_analyzer/mcp/server.py +869 -0
  85. tree_sitter_analyzer/mcp/tools/__init__.py +28 -0
  86. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +779 -0
  87. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +291 -0
  88. tree_sitter_analyzer/mcp/tools/base_tool.py +139 -0
  89. tree_sitter_analyzer/mcp/tools/fd_rg_utils.py +816 -0
  90. tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +686 -0
  91. tree_sitter_analyzer/mcp/tools/list_files_tool.py +413 -0
  92. tree_sitter_analyzer/mcp/tools/output_format_validator.py +148 -0
  93. tree_sitter_analyzer/mcp/tools/query_tool.py +443 -0
  94. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +464 -0
  95. tree_sitter_analyzer/mcp/tools/search_content_tool.py +836 -0
  96. tree_sitter_analyzer/mcp/tools/table_format_tool.py +572 -0
  97. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +653 -0
  98. tree_sitter_analyzer/mcp/utils/__init__.py +113 -0
  99. tree_sitter_analyzer/mcp/utils/error_handler.py +569 -0
  100. tree_sitter_analyzer/mcp/utils/file_output_factory.py +217 -0
  101. tree_sitter_analyzer/mcp/utils/file_output_manager.py +322 -0
  102. tree_sitter_analyzer/mcp/utils/gitignore_detector.py +358 -0
  103. tree_sitter_analyzer/mcp/utils/path_resolver.py +414 -0
  104. tree_sitter_analyzer/mcp/utils/search_cache.py +343 -0
  105. tree_sitter_analyzer/models.py +840 -0
  106. tree_sitter_analyzer/mypy_current_errors.txt +2 -0
  107. tree_sitter_analyzer/output_manager.py +255 -0
  108. tree_sitter_analyzer/platform_compat/__init__.py +3 -0
  109. tree_sitter_analyzer/platform_compat/adapter.py +324 -0
  110. tree_sitter_analyzer/platform_compat/compare.py +224 -0
  111. tree_sitter_analyzer/platform_compat/detector.py +67 -0
  112. tree_sitter_analyzer/platform_compat/fixtures.py +228 -0
  113. tree_sitter_analyzer/platform_compat/profiles.py +217 -0
  114. tree_sitter_analyzer/platform_compat/record.py +55 -0
  115. tree_sitter_analyzer/platform_compat/recorder.py +155 -0
  116. tree_sitter_analyzer/platform_compat/report.py +92 -0
  117. tree_sitter_analyzer/plugins/__init__.py +280 -0
  118. tree_sitter_analyzer/plugins/base.py +647 -0
  119. tree_sitter_analyzer/plugins/manager.py +384 -0
  120. tree_sitter_analyzer/project_detector.py +328 -0
  121. tree_sitter_analyzer/queries/__init__.py +27 -0
  122. tree_sitter_analyzer/queries/csharp.py +216 -0
  123. tree_sitter_analyzer/queries/css.py +615 -0
  124. tree_sitter_analyzer/queries/go.py +275 -0
  125. tree_sitter_analyzer/queries/html.py +543 -0
  126. tree_sitter_analyzer/queries/java.py +402 -0
  127. tree_sitter_analyzer/queries/javascript.py +724 -0
  128. tree_sitter_analyzer/queries/kotlin.py +192 -0
  129. tree_sitter_analyzer/queries/markdown.py +258 -0
  130. tree_sitter_analyzer/queries/php.py +95 -0
  131. tree_sitter_analyzer/queries/python.py +859 -0
  132. tree_sitter_analyzer/queries/ruby.py +92 -0
  133. tree_sitter_analyzer/queries/rust.py +223 -0
  134. tree_sitter_analyzer/queries/sql.py +555 -0
  135. tree_sitter_analyzer/queries/typescript.py +871 -0
  136. tree_sitter_analyzer/queries/yaml.py +236 -0
  137. tree_sitter_analyzer/query_loader.py +272 -0
  138. tree_sitter_analyzer/security/__init__.py +22 -0
  139. tree_sitter_analyzer/security/boundary_manager.py +277 -0
  140. tree_sitter_analyzer/security/regex_checker.py +297 -0
  141. tree_sitter_analyzer/security/validator.py +599 -0
  142. tree_sitter_analyzer/table_formatter.py +782 -0
  143. tree_sitter_analyzer/utils/__init__.py +53 -0
  144. tree_sitter_analyzer/utils/logging.py +433 -0
  145. tree_sitter_analyzer/utils/tree_sitter_compat.py +289 -0
  146. tree_sitter_analyzer-1.9.17.1.dist-info/METADATA +485 -0
  147. tree_sitter_analyzer-1.9.17.1.dist-info/RECORD +149 -0
  148. tree_sitter_analyzer-1.9.17.1.dist-info/WHEEL +4 -0
  149. tree_sitter_analyzer-1.9.17.1.dist-info/entry_points.txt +25 -0
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Ruby-specific table formatter.
4
+ """
5
+
6
+ from typing import Any
7
+
8
+ from .base_formatter import BaseTableFormatter
9
+
10
+
11
+ class RubyTableFormatter(BaseTableFormatter):
12
+ """Table formatter specialized for Ruby"""
13
+
14
+ def _format_full_table(self, data: dict[str, Any]) -> str:
15
+ """Full table format for Ruby"""
16
+ lines = []
17
+
18
+ # Header - Ruby (multi-class supported)
19
+ classes = data.get("classes", [])
20
+
21
+ if len(classes) > 1:
22
+ # If multiple classes exist, use filename
23
+ file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
24
+ lines.append(f"# {file_name}")
25
+ else:
26
+ # Single class: use class name
27
+ class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
28
+ lines.append(f"# {class_name}")
29
+ lines.append("")
30
+
31
+ # Require statements (imports)
32
+ imports = data.get("imports", [])
33
+ if imports:
34
+ lines.append("## Imports")
35
+ lines.append("```ruby")
36
+ for imp in imports:
37
+ import_text = imp.get("raw_text", "").strip()
38
+ if import_text:
39
+ lines.append(import_text)
40
+ lines.append("```")
41
+ lines.append("")
42
+
43
+ # Class Info - Ruby (multi-class aware)
44
+ if len(classes) > 1:
45
+ lines.append("## Classes Overview")
46
+ lines.append("| Class | Type | Lines | Methods | Constants |")
47
+ lines.append("|-------|------|-------|---------|-----------|")
48
+
49
+ for class_info in classes:
50
+ name = str(class_info.get("name", "Unknown"))
51
+ class_type = str(class_info.get("class_type", "class"))
52
+ line_range = class_info.get("line_range", {})
53
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
54
+
55
+ # Count methods/constants within the class range
56
+ class_methods = [
57
+ m
58
+ for m in data.get("methods", [])
59
+ if line_range.get("start", 0)
60
+ <= m.get("line_range", {}).get("start", 0)
61
+ <= line_range.get("end", 0)
62
+ ]
63
+ class_constants = [
64
+ f
65
+ for f in data.get("fields", [])
66
+ if f.get("is_constant", False)
67
+ and line_range.get("start", 0)
68
+ <= f.get("line_range", {}).get("start", 0)
69
+ <= line_range.get("end", 0)
70
+ ]
71
+
72
+ lines.append(
73
+ f"| {name} | {class_type} | {lines_str} | {len(class_methods)} | {len(class_constants)} |"
74
+ )
75
+ else:
76
+ # Single class details
77
+ lines.append("## Info")
78
+ lines.append("| Property | Value |")
79
+ lines.append("|----------|-------|")
80
+
81
+ class_info = data.get("classes", [{}])[0] if data.get("classes") else {}
82
+ stats = data.get("statistics") or {}
83
+
84
+ lines.append(f"| Type | {str(class_info.get('class_type', 'class'))} |")
85
+ lines.append(f"| Methods | {stats.get('method_count', 0)} |")
86
+ lines.append(
87
+ f"| Constants | {sum(1 for f in data.get('fields', []) if f.get('is_constant', False))} |"
88
+ )
89
+
90
+ lines.append("")
91
+
92
+ # Methods
93
+ methods = data.get("methods", [])
94
+ if methods:
95
+ lines.append("## Methods")
96
+ lines.append("| Name | Type | Lines | Parameters |")
97
+ lines.append("|------|------|-------|------------|")
98
+
99
+ for method in methods:
100
+ name = str(method.get("name", "Unknown"))
101
+ metadata = method.get("metadata", {})
102
+ method_type = metadata.get("method_type", "instance")
103
+ attr_type = metadata.get("attr_type", "")
104
+
105
+ # Determine display type
106
+ if attr_type:
107
+ display_type = attr_type
108
+ elif method_type == "class":
109
+ display_type = "class method"
110
+ else:
111
+ display_type = "instance method"
112
+
113
+ line_range = method.get("line_range", {})
114
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
115
+ params = ", ".join(method.get("parameters", []))
116
+
117
+ lines.append(f"| {name} | {display_type} | {lines_str} | {params} |")
118
+
119
+ lines.append("")
120
+
121
+ # Variables (Constants, Instance Variables, Class Variables)
122
+ fields = data.get("fields", [])
123
+ if fields:
124
+ lines.append("## Variables")
125
+ lines.append("| Name | Type | Visibility | Lines |")
126
+ lines.append("|------|------|------------|-------|")
127
+
128
+ for field in fields:
129
+ name = str(field.get("name", "Unknown"))
130
+ metadata = field.get("metadata", {})
131
+
132
+ # Determine variable type
133
+ if field.get("is_constant", False):
134
+ var_type = "constant"
135
+ elif metadata.get("is_class_variable", False):
136
+ var_type = "class variable"
137
+ elif metadata.get("is_instance_variable", False):
138
+ var_type = "instance variable"
139
+ elif metadata.get("is_global", False):
140
+ var_type = "global variable"
141
+ else:
142
+ var_type = "variable"
143
+
144
+ visibility = str(field.get("visibility", "public"))
145
+ line_range = field.get("line_range", {})
146
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
147
+
148
+ lines.append(f"| {name} | {var_type} | {visibility} | {lines_str} |")
149
+
150
+ lines.append("")
151
+
152
+ return "\n".join(lines)
153
+
154
+ def _format_compact_table(self, data: dict[str, Any]) -> str:
155
+ """Compact table format for Ruby"""
156
+ lines = []
157
+
158
+ # Header
159
+ classes = data.get("classes", [])
160
+
161
+ if len(classes) > 1:
162
+ file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
163
+ lines.append(f"# {file_name}")
164
+ else:
165
+ class_name = classes[0].get("name", "Unknown") if classes else "Unknown"
166
+ lines.append(f"# {class_name}")
167
+ lines.append("")
168
+
169
+ # Statistics
170
+ stats = data.get("statistics") or {}
171
+ lines.append("## Statistics")
172
+ lines.append(f"- Classes: {stats.get('class_count', 0)}")
173
+ lines.append(f"- Methods: {stats.get('method_count', 0)}")
174
+ lines.append(
175
+ f"- Constants: {sum(1 for f in data.get('fields', []) if f.get('is_constant', False))}"
176
+ )
177
+ lines.append(f"- Imports: {len(data.get('imports', []))}")
178
+ lines.append("")
179
+
180
+ # Classes
181
+ if classes:
182
+ lines.append("## Classes")
183
+ for class_info in classes:
184
+ name = str(class_info.get("name", "Unknown"))
185
+ class_type = str(class_info.get("class_type", "class"))
186
+ line_range = class_info.get("line_range", {})
187
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
188
+ lines.append(f"- **{name}** ({class_type}) - Lines {lines_str}")
189
+ lines.append("")
190
+
191
+ # Methods
192
+ methods = data.get("methods", [])
193
+ if methods:
194
+ lines.append("## Methods")
195
+ for method in methods:
196
+ name = str(method.get("name", "Unknown"))
197
+ metadata = method.get("metadata", {})
198
+ method_type = metadata.get("method_type", "instance")
199
+ line_range = method.get("line_range", {})
200
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
201
+
202
+ type_prefix = "." if method_type == "class" else "#"
203
+ lines.append(f"- {type_prefix}{name} - Lines {lines_str}")
204
+ lines.append("")
205
+
206
+ return "\n".join(lines)
207
+
208
+ def _format_csv(self, data: dict[str, Any]) -> str:
209
+ """CSV format for Ruby"""
210
+ lines = []
211
+
212
+ # Header
213
+ lines.append("Type,Name,Additional,Lines")
214
+
215
+ # Classes
216
+ for class_info in data.get("classes", []):
217
+ name = str(class_info.get("name", "Unknown"))
218
+ class_type = str(class_info.get("class_type", "class"))
219
+ line_range = class_info.get("line_range", {})
220
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
221
+ lines.append(f"{class_type},{name},,{lines_str}")
222
+
223
+ # Methods
224
+ for method in data.get("methods", []):
225
+ name = str(method.get("name", "Unknown"))
226
+ metadata = method.get("metadata", {})
227
+ method_type = metadata.get("method_type", "instance")
228
+ attr_type = metadata.get("attr_type", "")
229
+ line_range = method.get("line_range", {})
230
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
231
+
232
+ additional = attr_type if attr_type else method_type
233
+ lines.append(f"method,{name},{additional},{lines_str}")
234
+
235
+ # Variables
236
+ for field in data.get("fields", []):
237
+ name = str(field.get("name", "Unknown"))
238
+ metadata = field.get("metadata", {})
239
+
240
+ # Determine variable type
241
+ if field.get("is_constant", False):
242
+ var_type = "constant"
243
+ elif metadata.get("is_class_variable", False):
244
+ var_type = "class_variable"
245
+ elif metadata.get("is_instance_variable", False):
246
+ var_type = "instance_variable"
247
+ else:
248
+ var_type = "variable"
249
+
250
+ line_range = field.get("line_range", {})
251
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
252
+ lines.append(f"{var_type},{name},,{lines_str}")
253
+
254
+ return "\n".join(lines)
255
+
256
+
257
+ class RubyFullFormatter(RubyTableFormatter):
258
+ """Full table formatter for Ruby"""
259
+
260
+ def format(self, data: dict[str, Any]) -> str:
261
+ """Format data as full table"""
262
+ return self._format_full_table(data)
263
+
264
+
265
+ class RubyCompactFormatter(RubyTableFormatter):
266
+ """Compact table formatter for Ruby"""
267
+
268
+ def format(self, data: dict[str, Any]) -> str:
269
+ """Format data as compact table"""
270
+ return self._format_compact_table(data)
271
+
272
+
273
+ class RubyCSVFormatter(RubyTableFormatter):
274
+ """CSV formatter for Ruby"""
275
+
276
+ def format(self, data: dict[str, Any]) -> str:
277
+ """Format data as CSV"""
278
+ return self._format_csv(data)
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Rust-specific table formatter.
4
+ """
5
+
6
+ from typing import Any
7
+
8
+ from .base_formatter import BaseTableFormatter
9
+
10
+
11
+ class RustTableFormatter(BaseTableFormatter):
12
+ """Table formatter specialized for Rust"""
13
+
14
+ def _format_full_table(self, data: dict[str, Any]) -> str:
15
+ """Full table format for Rust"""
16
+ lines = []
17
+
18
+ # Header - Rust (module-centric)
19
+ file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
20
+ lines.append(f"# {file_name}")
21
+ lines.append("")
22
+
23
+ # Module Info
24
+ modules = data.get("modules", [])
25
+ if modules:
26
+ lines.append("## Modules")
27
+ lines.append("| Name | Visibility | Lines |")
28
+ lines.append("|------|------------|-------|")
29
+ for mod in modules:
30
+ lines.append(
31
+ f"| {mod.get('name')} | {mod.get('visibility')} | {mod.get('line_range', {}).get('start')}-{mod.get('line_range', {}).get('end')} |"
32
+ )
33
+ lines.append("")
34
+
35
+ # Structs (mapped from classes)
36
+ structs = data.get("classes", [])
37
+ if structs:
38
+ lines.append("## Structs")
39
+ lines.append("| Name | Type | Visibility | Lines | Fields | Traits |")
40
+ lines.append("|------|------|------------|-------|--------|--------|")
41
+
42
+ for struct in structs:
43
+ name = str(struct.get("name", "Unknown"))
44
+ struct_type = str(struct.get("type", "struct")) # struct, enum, trait
45
+ visibility = str(struct.get("visibility", "private"))
46
+ line_range = struct.get("line_range", {})
47
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
48
+
49
+ # Count fields
50
+ fields_count = len(
51
+ [
52
+ f
53
+ for f in data.get("fields", [])
54
+ if line_range.get("start", 0)
55
+ <= f.get("line_range", {}).get("start", 0)
56
+ <= line_range.get("end", 0)
57
+ ]
58
+ )
59
+
60
+ # Traits (from interfaces field)
61
+ traits = struct.get("implements_interfaces", [])
62
+ traits_str = ", ".join(traits) if traits else "-"
63
+
64
+ lines.append(
65
+ f"| {name} | {struct_type} | {visibility} | {lines_str} | {fields_count} | {traits_str} |"
66
+ )
67
+ lines.append("")
68
+
69
+ # Functions (mapped from methods)
70
+ fns = data.get("methods", [])
71
+ if fns:
72
+ lines.append("## Functions")
73
+ lines.append("| Function | Signature | Vis | Async | Lines | Doc |")
74
+ lines.append("|----------|-----------|-----|-------|-------|-----|")
75
+
76
+ for fn in fns:
77
+ lines.append(self._format_fn_row(fn))
78
+ lines.append("")
79
+
80
+ # Traits (if mapped separately or included in classes)
81
+ # Note: The extractor maps traits to classes with type="trait"
82
+
83
+ # Impl blocks
84
+ impls = data.get("impls", [])
85
+ if impls:
86
+ lines.append("## Implementations")
87
+ lines.append("| Type | Trait | Lines |")
88
+ lines.append("|------|-------|-------|")
89
+ for impl in impls:
90
+ trait_name = impl.get("trait", "-")
91
+ type_name = impl.get("type", "Unknown")
92
+ line_range = impl.get("line_range", {})
93
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
94
+ lines.append(f"| {type_name} | {trait_name} | {lines_str} |")
95
+ lines.append("")
96
+
97
+ return "\n".join(lines)
98
+
99
+ def _format_compact_table(self, data: dict[str, Any]) -> str:
100
+ """Compact table format for Rust"""
101
+ lines = []
102
+
103
+ # Header
104
+ file_name = data.get("file_path", "Unknown").split("/")[-1].split("\\")[-1]
105
+ lines.append(f"# {file_name}")
106
+ lines.append("")
107
+
108
+ # Info
109
+ stats = data.get("statistics") or {}
110
+ lines.append("## Info")
111
+ lines.append("| Property | Value |")
112
+ lines.append("|----------|-------|")
113
+ lines.append(f"| Structs | {len(data.get('classes', []))} |")
114
+ lines.append(f"| Functions | {stats.get('method_count', 0)} |")
115
+ lines.append(f"| Lines | {stats.get('lines', 0)} |")
116
+ lines.append("")
117
+
118
+ # Functions (compact)
119
+ fns = data.get("methods", [])
120
+ if fns:
121
+ lines.append("## Functions")
122
+ lines.append("| Fn | Sig | V | A | L | Doc |")
123
+ lines.append("|----|-----|---|---|---|-----|")
124
+
125
+ for fn in fns:
126
+ name = str(fn.get("name", ""))
127
+ signature = self._create_compact_signature(fn)
128
+ visibility = self._convert_visibility(str(fn.get("visibility", "")))
129
+ is_async = "Y" if fn.get("is_async", False) else "-"
130
+ line_range = fn.get("line_range", {})
131
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
132
+ doc = self._clean_csv_text(
133
+ self._extract_doc_summary(str(fn.get("docstring", "") or ""))
134
+ )
135
+
136
+ lines.append(
137
+ f"| {name} | {signature} | {visibility} | {is_async} | {lines_str} | {doc} |"
138
+ )
139
+ lines.append("")
140
+
141
+ return "\n".join(lines)
142
+
143
+ def _format_fn_row(self, fn: dict[str, Any]) -> str:
144
+ """Format a function table row for Rust"""
145
+ name = str(fn.get("name", ""))
146
+ signature = self._create_full_signature(fn)
147
+ visibility = self._convert_visibility(str(fn.get("visibility", "")))
148
+ is_async = "Yes" if fn.get("is_async", False) else "-"
149
+ line_range = fn.get("line_range", {})
150
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
151
+ doc = self._clean_csv_text(
152
+ self._extract_doc_summary(str(fn.get("docstring", "") or ""))
153
+ )
154
+
155
+ return f"| {name} | {signature} | {visibility} | {is_async} | {lines_str} | {doc} |"
156
+
157
+ def _create_full_signature(self, fn: dict[str, Any]) -> str:
158
+ """Create full function signature for Rust"""
159
+ params = fn.get("parameters", [])
160
+ # Rust parameters are usually strings like "x: i32", keep them as is or simplify
161
+ params_str = ", ".join([str(p) for p in params])
162
+ return_type = fn.get("return_type", "")
163
+ ret_str = f" -> {return_type}" if return_type and return_type != "()" else ""
164
+
165
+ return f"fn({params_str}){ret_str}"
166
+
167
+ def _create_compact_signature(self, fn: dict[str, Any]) -> str:
168
+ """Create compact function signature for Rust"""
169
+ params = fn.get("parameters", [])
170
+ # Simply count parameters or use short types if available
171
+ params_summary = f"({len(params)})"
172
+ return_type = fn.get("return_type", "")
173
+ ret_str = f"->{return_type}" if return_type and return_type != "()" else ""
174
+
175
+ return f"{params_summary}{ret_str}"
176
+
177
+ def _convert_visibility(self, visibility: str) -> str:
178
+ """Convert visibility to short symbol"""
179
+ if visibility == "pub":
180
+ return "pub"
181
+ elif visibility == "pub(crate)":
182
+ return "crate"
183
+ elif visibility == "private": # Default
184
+ return "priv"
185
+ return visibility
186
+
187
+ def format_table(
188
+ self, analysis_result: dict[str, Any], table_type: str = "full"
189
+ ) -> str:
190
+ """Format table output for Rust"""
191
+ # Set the format type based on table_type parameter
192
+ original_format_type = self.format_type
193
+ self.format_type = table_type
194
+
195
+ try:
196
+ # Handle json format separately
197
+ if table_type == "json":
198
+ return self._format_json(analysis_result)
199
+ # Use the existing format_structure method
200
+ return self.format_structure(analysis_result)
201
+ finally:
202
+ # Restore original format type
203
+ self.format_type = original_format_type
204
+
205
+ def format_summary(self, analysis_result: dict[str, Any]) -> str:
206
+ """Format summary output for Rust"""
207
+ return self._format_compact_table(analysis_result)
208
+
209
+ def format_structure(self, analysis_result: dict[str, Any]) -> str:
210
+ """Format structure analysis output for Rust"""
211
+ if self.format_type == "compact":
212
+ return self._format_compact_table(analysis_result)
213
+ return self._format_full_table(analysis_result)
214
+
215
+ def format_advanced(
216
+ self, analysis_result: dict[str, Any], output_format: str = "json"
217
+ ) -> str:
218
+ """Format advanced analysis output for Rust"""
219
+ if output_format == "json":
220
+ return self._format_json(analysis_result)
221
+ elif output_format == "csv":
222
+ return self._format_csv(analysis_result)
223
+ else:
224
+ return self._format_full_table(analysis_result)
225
+
226
+ def _format_json(self, data: dict[str, Any]) -> str:
227
+ """Format data as JSON"""
228
+ import json
229
+
230
+ try:
231
+ return json.dumps(data, indent=2, ensure_ascii=False)
232
+ except (TypeError, ValueError) as e:
233
+ return f"# JSON serialization error: {e}\n"