tree-sitter-analyzer 1.8.4__py3-none-any.whl → 1.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tree-sitter-analyzer might be problematic. Click here for more details.
- tree_sitter_analyzer/__init__.py +1 -1
- tree_sitter_analyzer/api.py +4 -4
- tree_sitter_analyzer/cli/argument_validator.py +29 -17
- tree_sitter_analyzer/cli/commands/advanced_command.py +7 -5
- tree_sitter_analyzer/cli/commands/structure_command.py +7 -5
- tree_sitter_analyzer/cli/commands/summary_command.py +10 -6
- tree_sitter_analyzer/cli/commands/table_command.py +8 -7
- tree_sitter_analyzer/cli/info_commands.py +1 -1
- tree_sitter_analyzer/cli_main.py +3 -2
- tree_sitter_analyzer/core/analysis_engine.py +5 -5
- tree_sitter_analyzer/core/cache_service.py +3 -1
- tree_sitter_analyzer/core/query.py +17 -5
- tree_sitter_analyzer/core/query_service.py +1 -1
- tree_sitter_analyzer/encoding_utils.py +3 -3
- tree_sitter_analyzer/exceptions.py +61 -50
- tree_sitter_analyzer/file_handler.py +3 -0
- tree_sitter_analyzer/formatters/base_formatter.py +10 -5
- tree_sitter_analyzer/formatters/formatter_registry.py +83 -68
- tree_sitter_analyzer/formatters/html_formatter.py +90 -54
- tree_sitter_analyzer/formatters/javascript_formatter.py +21 -16
- tree_sitter_analyzer/formatters/language_formatter_factory.py +7 -6
- tree_sitter_analyzer/formatters/markdown_formatter.py +247 -124
- tree_sitter_analyzer/formatters/python_formatter.py +61 -38
- tree_sitter_analyzer/formatters/typescript_formatter.py +113 -45
- tree_sitter_analyzer/interfaces/mcp_server.py +2 -2
- tree_sitter_analyzer/language_detector.py +6 -6
- tree_sitter_analyzer/language_loader.py +3 -1
- tree_sitter_analyzer/languages/css_plugin.py +120 -61
- tree_sitter_analyzer/languages/html_plugin.py +159 -62
- tree_sitter_analyzer/languages/java_plugin.py +42 -34
- tree_sitter_analyzer/languages/javascript_plugin.py +59 -30
- tree_sitter_analyzer/languages/markdown_plugin.py +402 -368
- tree_sitter_analyzer/languages/python_plugin.py +111 -64
- tree_sitter_analyzer/languages/typescript_plugin.py +241 -132
- tree_sitter_analyzer/mcp/server.py +22 -18
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +13 -8
- tree_sitter_analyzer/mcp/tools/base_tool.py +2 -2
- tree_sitter_analyzer/mcp/tools/fd_rg_utils.py +232 -26
- tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +31 -23
- tree_sitter_analyzer/mcp/tools/list_files_tool.py +21 -19
- tree_sitter_analyzer/mcp/tools/query_tool.py +17 -18
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +30 -31
- tree_sitter_analyzer/mcp/tools/search_content_tool.py +131 -77
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +29 -16
- tree_sitter_analyzer/mcp/utils/file_output_factory.py +64 -51
- tree_sitter_analyzer/mcp/utils/file_output_manager.py +34 -24
- tree_sitter_analyzer/mcp/utils/gitignore_detector.py +8 -4
- tree_sitter_analyzer/models.py +7 -5
- tree_sitter_analyzer/plugins/base.py +9 -7
- tree_sitter_analyzer/plugins/manager.py +1 -0
- tree_sitter_analyzer/queries/css.py +2 -21
- tree_sitter_analyzer/queries/html.py +2 -15
- tree_sitter_analyzer/queries/markdown.py +30 -41
- tree_sitter_analyzer/queries/python.py +20 -5
- tree_sitter_analyzer/query_loader.py +5 -5
- tree_sitter_analyzer/security/validator.py +114 -86
- tree_sitter_analyzer/utils/__init__.py +58 -28
- tree_sitter_analyzer/utils/tree_sitter_compat.py +72 -65
- tree_sitter_analyzer/utils.py +26 -15
- {tree_sitter_analyzer-1.8.4.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/METADATA +1 -1
- tree_sitter_analyzer-1.9.0.dist-info/RECORD +109 -0
- tree_sitter_analyzer-1.8.4.dist-info/RECORD +0 -109
- {tree_sitter_analyzer-1.8.4.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-1.8.4.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/entry_points.txt +0 -0
|
@@ -10,13 +10,17 @@ import json
|
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
12
|
from ..models import CodeElement, MarkupElement, StyleElement
|
|
13
|
-
from .formatter_registry import IFormatter
|
|
14
13
|
from .base_formatter import BaseFormatter
|
|
14
|
+
from .formatter_registry import IFormatter
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class HtmlFormatter(BaseFormatter, IFormatter):
|
|
18
18
|
"""HTML-specific formatter for MarkupElement and StyleElement"""
|
|
19
19
|
|
|
20
|
+
def __init__(self):
|
|
21
|
+
"""Initialize HTML formatter"""
|
|
22
|
+
pass
|
|
23
|
+
|
|
20
24
|
@staticmethod
|
|
21
25
|
def get_format_name() -> str:
|
|
22
26
|
return "html"
|
|
@@ -34,7 +38,7 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
34
38
|
markup_elements = []
|
|
35
39
|
style_elements = []
|
|
36
40
|
other_elements = []
|
|
37
|
-
|
|
41
|
+
|
|
38
42
|
for e in elements:
|
|
39
43
|
if isinstance(e, MarkupElement):
|
|
40
44
|
markup_elements.append(e)
|
|
@@ -42,10 +46,10 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
42
46
|
style_elements.append(e)
|
|
43
47
|
elif isinstance(e, dict):
|
|
44
48
|
# Convert dictionary to appropriate element type based on content
|
|
45
|
-
element_type = e.get(
|
|
46
|
-
if
|
|
49
|
+
element_type = e.get("type", e.get("element_type", "unknown"))
|
|
50
|
+
if "tag_name" in e or element_type in ["tag", "element", "markup"]:
|
|
47
51
|
markup_elements.append(self._dict_to_markup_element(e))
|
|
48
|
-
elif
|
|
52
|
+
elif "selector" in e or element_type in ["rule", "style"]:
|
|
49
53
|
style_elements.append(self._dict_to_style_element(e))
|
|
50
54
|
else:
|
|
51
55
|
other_elements.append(e)
|
|
@@ -71,11 +75,11 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
71
75
|
elements = analysis_result.get("elements", [])
|
|
72
76
|
if not elements:
|
|
73
77
|
return "No HTML elements found."
|
|
74
|
-
|
|
78
|
+
|
|
75
79
|
markup_count = sum(1 for e in elements if isinstance(e, MarkupElement))
|
|
76
80
|
style_count = sum(1 for e in elements if isinstance(e, StyleElement))
|
|
77
81
|
other_count = len(elements) - markup_count - style_count
|
|
78
|
-
|
|
82
|
+
|
|
79
83
|
lines = []
|
|
80
84
|
lines.append("# HTML Analysis Summary")
|
|
81
85
|
lines.append("")
|
|
@@ -83,7 +87,7 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
83
87
|
lines.append(f"- Markup Elements: {markup_count}")
|
|
84
88
|
lines.append(f"- Style Elements: {style_count}")
|
|
85
89
|
lines.append(f"- Other Elements: {other_count}")
|
|
86
|
-
|
|
90
|
+
|
|
87
91
|
return "\n".join(lines)
|
|
88
92
|
|
|
89
93
|
def format_structure(self, analysis_result: dict[str, Any]) -> str:
|
|
@@ -91,20 +95,24 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
91
95
|
elements = analysis_result.get("elements", [])
|
|
92
96
|
return self.format(elements)
|
|
93
97
|
|
|
94
|
-
def format_advanced(
|
|
98
|
+
def format_advanced(
|
|
99
|
+
self, analysis_result: dict[str, Any], output_format: str = "json"
|
|
100
|
+
) -> str:
|
|
95
101
|
"""Format advanced analysis output"""
|
|
96
102
|
elements = analysis_result.get("elements", [])
|
|
97
|
-
|
|
103
|
+
|
|
98
104
|
if output_format == "json":
|
|
99
105
|
formatter = HtmlJsonFormatter()
|
|
100
106
|
return formatter.format(elements)
|
|
101
107
|
else:
|
|
102
108
|
return self.format(elements)
|
|
103
109
|
|
|
104
|
-
def format_table(
|
|
110
|
+
def format_table(
|
|
111
|
+
self, analysis_result: dict[str, Any], table_type: str = "full"
|
|
112
|
+
) -> str:
|
|
105
113
|
"""Format table output"""
|
|
106
114
|
elements = analysis_result.get("elements", [])
|
|
107
|
-
|
|
115
|
+
|
|
108
116
|
if table_type == "compact":
|
|
109
117
|
formatter = HtmlCompactFormatter()
|
|
110
118
|
return formatter.format(elements)
|
|
@@ -131,7 +139,9 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
131
139
|
|
|
132
140
|
# Format each group
|
|
133
141
|
for element_class, group_elements in element_groups.items():
|
|
134
|
-
lines.append(
|
|
142
|
+
lines.append(
|
|
143
|
+
f"### {element_class.title()} Elements ({len(group_elements)})"
|
|
144
|
+
)
|
|
135
145
|
lines.append("")
|
|
136
146
|
lines.append("| Tag | Name | Lines | Attributes | Children |")
|
|
137
147
|
lines.append("|-----|------|-------|------------|----------|")
|
|
@@ -140,13 +150,13 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
140
150
|
tag_name = element.tag_name or "unknown"
|
|
141
151
|
name = element.name or tag_name
|
|
142
152
|
lines_str = f"{element.start_line}-{element.end_line}"
|
|
143
|
-
|
|
153
|
+
|
|
144
154
|
# Format attributes
|
|
145
155
|
attrs = []
|
|
146
156
|
attributes = element.attributes or {}
|
|
147
157
|
for key, value in attributes.items():
|
|
148
158
|
if value:
|
|
149
|
-
attrs.append(f
|
|
159
|
+
attrs.append(f'{key}="{value}"')
|
|
150
160
|
else:
|
|
151
161
|
attrs.append(key)
|
|
152
162
|
attrs_str = ", ".join(attrs) if attrs else "-"
|
|
@@ -156,7 +166,9 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
156
166
|
# Count children
|
|
157
167
|
children_count = len(element.children)
|
|
158
168
|
|
|
159
|
-
lines.append(
|
|
169
|
+
lines.append(
|
|
170
|
+
f"| `{tag_name}` | {name} | {lines_str} | {attrs_str} | {children_count} |"
|
|
171
|
+
)
|
|
160
172
|
|
|
161
173
|
lines.append("")
|
|
162
174
|
|
|
@@ -176,7 +188,7 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
176
188
|
lines = []
|
|
177
189
|
indent = " " * depth
|
|
178
190
|
tag_name = element.tag_name or "unknown"
|
|
179
|
-
|
|
191
|
+
|
|
180
192
|
# Format element info
|
|
181
193
|
attrs_info = ""
|
|
182
194
|
attributes = element.attributes or {}
|
|
@@ -184,11 +196,13 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
184
196
|
key_attrs = []
|
|
185
197
|
for key, value in attributes.items():
|
|
186
198
|
if key in ["id", "class", "name"]:
|
|
187
|
-
key_attrs.append(f
|
|
199
|
+
key_attrs.append(f'{key}="{value}"' if value else key)
|
|
188
200
|
if key_attrs:
|
|
189
201
|
attrs_info = f" ({', '.join(key_attrs)})"
|
|
190
202
|
|
|
191
|
-
lines.append(
|
|
203
|
+
lines.append(
|
|
204
|
+
f"{indent}- `{tag_name}`{attrs_info} [{element.start_line}-{element.end_line}]"
|
|
205
|
+
)
|
|
192
206
|
|
|
193
207
|
# Format children
|
|
194
208
|
for child in element.children:
|
|
@@ -220,7 +234,7 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
220
234
|
for element in group_elements:
|
|
221
235
|
selector = element.selector or element.name
|
|
222
236
|
lines_str = f"{element.start_line}-{element.end_line}"
|
|
223
|
-
|
|
237
|
+
|
|
224
238
|
# Format properties
|
|
225
239
|
props = []
|
|
226
240
|
properties = element.properties or {}
|
|
@@ -246,7 +260,9 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
246
260
|
|
|
247
261
|
for element in elements:
|
|
248
262
|
if isinstance(element, dict):
|
|
249
|
-
element_type = element.get(
|
|
263
|
+
element_type = element.get(
|
|
264
|
+
"element_type", element.get("type", "unknown")
|
|
265
|
+
)
|
|
250
266
|
name = element.get("name", "unknown")
|
|
251
267
|
start_line = element.get("start_line", 0)
|
|
252
268
|
end_line = element.get("end_line", 0)
|
|
@@ -257,7 +273,7 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
257
273
|
start_line = getattr(element, "start_line", 0)
|
|
258
274
|
end_line = getattr(element, "end_line", 0)
|
|
259
275
|
language = getattr(element, "language", "unknown")
|
|
260
|
-
|
|
276
|
+
|
|
261
277
|
lines_str = f"{start_line}-{end_line}"
|
|
262
278
|
lines.append(f"| {element_type} | {name} | {lines_str} | {language} |")
|
|
263
279
|
|
|
@@ -266,34 +282,36 @@ class HtmlFormatter(BaseFormatter, IFormatter):
|
|
|
266
282
|
|
|
267
283
|
def _dict_to_markup_element(self, data: dict):
|
|
268
284
|
"""Convert dictionary to MarkupElement-like object"""
|
|
285
|
+
|
|
269
286
|
# Create a mock MarkupElement-like object
|
|
270
287
|
class MockMarkupElement:
|
|
271
288
|
def __init__(self, data):
|
|
272
|
-
self.name = data.get(
|
|
273
|
-
self.tag_name = data.get(
|
|
274
|
-
self.element_class = data.get(
|
|
275
|
-
self.start_line = data.get(
|
|
276
|
-
self.end_line = data.get(
|
|
277
|
-
self.attributes = data.get(
|
|
289
|
+
self.name = data.get("name", "unknown")
|
|
290
|
+
self.tag_name = data.get("tag_name", data.get("name", "unknown"))
|
|
291
|
+
self.element_class = data.get("element_class", "unknown")
|
|
292
|
+
self.start_line = data.get("start_line", 0)
|
|
293
|
+
self.end_line = data.get("end_line", 0)
|
|
294
|
+
self.attributes = data.get("attributes", {})
|
|
278
295
|
self.children = []
|
|
279
296
|
self.parent = None
|
|
280
|
-
self.language = data.get(
|
|
281
|
-
|
|
297
|
+
self.language = data.get("language", "html")
|
|
298
|
+
|
|
282
299
|
return MockMarkupElement(data)
|
|
283
300
|
|
|
284
301
|
def _dict_to_style_element(self, data: dict):
|
|
285
302
|
"""Convert dictionary to StyleElement-like object"""
|
|
303
|
+
|
|
286
304
|
# Create a mock StyleElement-like object
|
|
287
305
|
class MockStyleElement:
|
|
288
306
|
def __init__(self, data):
|
|
289
|
-
self.name = data.get(
|
|
290
|
-
self.selector = data.get(
|
|
291
|
-
self.element_class = data.get(
|
|
292
|
-
self.start_line = data.get(
|
|
293
|
-
self.end_line = data.get(
|
|
294
|
-
self.properties = data.get(
|
|
295
|
-
self.language = data.get(
|
|
296
|
-
|
|
307
|
+
self.name = data.get("name", "unknown")
|
|
308
|
+
self.selector = data.get("selector", data.get("name", "unknown"))
|
|
309
|
+
self.element_class = data.get("element_class", "unknown")
|
|
310
|
+
self.start_line = data.get("start_line", 0)
|
|
311
|
+
self.end_line = data.get("end_line", 0)
|
|
312
|
+
self.properties = data.get("properties", {})
|
|
313
|
+
self.language = data.get("language", "css")
|
|
314
|
+
|
|
297
315
|
return MockStyleElement(data)
|
|
298
316
|
|
|
299
317
|
|
|
@@ -311,26 +329,38 @@ class HtmlJsonFormatter(IFormatter):
|
|
|
311
329
|
"total_elements": len(elements),
|
|
312
330
|
"markup_elements": [],
|
|
313
331
|
"style_elements": [],
|
|
314
|
-
"other_elements": []
|
|
332
|
+
"other_elements": [],
|
|
315
333
|
}
|
|
316
334
|
}
|
|
317
335
|
|
|
318
336
|
for element in elements:
|
|
319
337
|
if isinstance(element, MarkupElement):
|
|
320
|
-
result["html_analysis"]["markup_elements"].append(
|
|
338
|
+
result["html_analysis"]["markup_elements"].append(
|
|
339
|
+
self._markup_to_dict(element)
|
|
340
|
+
)
|
|
321
341
|
elif isinstance(element, StyleElement):
|
|
322
|
-
result["html_analysis"]["style_elements"].append(
|
|
342
|
+
result["html_analysis"]["style_elements"].append(
|
|
343
|
+
self._style_to_dict(element)
|
|
344
|
+
)
|
|
323
345
|
elif isinstance(element, dict):
|
|
324
346
|
# Handle dictionary format
|
|
325
|
-
element_type = element.get(
|
|
326
|
-
|
|
347
|
+
element_type = element.get(
|
|
348
|
+
"element_type", element.get("type", "unknown")
|
|
349
|
+
)
|
|
350
|
+
if "tag_name" in element or element_type in [
|
|
351
|
+
"tag",
|
|
352
|
+
"element",
|
|
353
|
+
"markup",
|
|
354
|
+
]:
|
|
327
355
|
result["html_analysis"]["markup_elements"].append(element)
|
|
328
|
-
elif "selector" in element or element_type in [
|
|
356
|
+
elif "selector" in element or element_type in ["rule", "style"]:
|
|
329
357
|
result["html_analysis"]["style_elements"].append(element)
|
|
330
358
|
else:
|
|
331
359
|
result["html_analysis"]["other_elements"].append(element)
|
|
332
360
|
else:
|
|
333
|
-
result["html_analysis"]["other_elements"].append(
|
|
361
|
+
result["html_analysis"]["other_elements"].append(
|
|
362
|
+
self._element_to_dict(element)
|
|
363
|
+
)
|
|
334
364
|
|
|
335
365
|
return json.dumps(result, indent=2, ensure_ascii=False)
|
|
336
366
|
|
|
@@ -345,7 +375,7 @@ class HtmlJsonFormatter(IFormatter):
|
|
|
345
375
|
"attributes": element.attributes,
|
|
346
376
|
"children_count": len(element.children),
|
|
347
377
|
"children": [self._markup_to_dict(child) for child in element.children],
|
|
348
|
-
"language": element.language
|
|
378
|
+
"language": element.language,
|
|
349
379
|
}
|
|
350
380
|
|
|
351
381
|
def _style_to_dict(self, element: StyleElement) -> dict[str, Any]:
|
|
@@ -357,7 +387,7 @@ class HtmlJsonFormatter(IFormatter):
|
|
|
357
387
|
"start_line": element.start_line,
|
|
358
388
|
"end_line": element.end_line,
|
|
359
389
|
"properties": element.properties,
|
|
360
|
-
"language": element.language
|
|
390
|
+
"language": element.language,
|
|
361
391
|
}
|
|
362
392
|
|
|
363
393
|
def _element_to_dict(self, element: CodeElement) -> dict[str, Any]:
|
|
@@ -367,7 +397,7 @@ class HtmlJsonFormatter(IFormatter):
|
|
|
367
397
|
"type": getattr(element, "element_type", "unknown"),
|
|
368
398
|
"start_line": element.start_line,
|
|
369
399
|
"end_line": element.end_line,
|
|
370
|
-
"language": element.language
|
|
400
|
+
"language": element.language,
|
|
371
401
|
}
|
|
372
402
|
|
|
373
403
|
|
|
@@ -416,12 +446,18 @@ class HtmlCompactFormatter(IFormatter):
|
|
|
416
446
|
end_line = element.end_line
|
|
417
447
|
elif isinstance(element, dict):
|
|
418
448
|
# Handle dictionary format
|
|
419
|
-
element_type = element.get(
|
|
449
|
+
element_type = element.get(
|
|
450
|
+
"element_type", element.get("type", "unknown")
|
|
451
|
+
)
|
|
420
452
|
name = element.get("name", "unknown")
|
|
421
453
|
start_line = element.get("start_line", 0)
|
|
422
454
|
end_line = element.get("end_line", 0)
|
|
423
|
-
|
|
424
|
-
if "tag_name" in element or element_type in [
|
|
455
|
+
|
|
456
|
+
if "tag_name" in element or element_type in [
|
|
457
|
+
"tag",
|
|
458
|
+
"element",
|
|
459
|
+
"markup",
|
|
460
|
+
]:
|
|
425
461
|
symbol = "🏷️"
|
|
426
462
|
tag_name = element.get("tag_name", name)
|
|
427
463
|
info = f"<{tag_name}>"
|
|
@@ -430,7 +466,7 @@ class HtmlCompactFormatter(IFormatter):
|
|
|
430
466
|
info += f" #{attributes['id']}"
|
|
431
467
|
if attributes.get("class"):
|
|
432
468
|
info += f" .{attributes['class']}"
|
|
433
|
-
elif "selector" in element or element_type in [
|
|
469
|
+
elif "selector" in element or element_type in ["rule", "style"]:
|
|
434
470
|
symbol = "🎨"
|
|
435
471
|
info = element.get("selector", name)
|
|
436
472
|
else:
|
|
@@ -452,11 +488,11 @@ class HtmlCompactFormatter(IFormatter):
|
|
|
452
488
|
def register_html_formatters() -> None:
|
|
453
489
|
"""Register HTML-specific formatters"""
|
|
454
490
|
from .formatter_registry import FormatterRegistry
|
|
455
|
-
|
|
491
|
+
|
|
456
492
|
FormatterRegistry.register_formatter(HtmlFormatter)
|
|
457
493
|
FormatterRegistry.register_formatter(HtmlJsonFormatter)
|
|
458
494
|
FormatterRegistry.register_formatter(HtmlCompactFormatter)
|
|
459
495
|
|
|
460
496
|
|
|
461
497
|
# Auto-register when module is imported
|
|
462
|
-
register_html_formatters()
|
|
498
|
+
register_html_formatters()
|
|
@@ -20,21 +20,23 @@ class JavaScriptTableFormatter(BaseTableFormatter):
|
|
|
20
20
|
# Handle None data
|
|
21
21
|
if data is None:
|
|
22
22
|
return "# No data available\n"
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
# Ensure data is a dictionary
|
|
25
25
|
if not isinstance(data, dict):
|
|
26
26
|
return f"# Invalid data type: {type(data)}\n"
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
if format_type:
|
|
29
29
|
# Check for supported format types
|
|
30
|
-
supported_formats = [
|
|
30
|
+
supported_formats = ["full", "compact", "csv", "json"]
|
|
31
31
|
if format_type not in supported_formats:
|
|
32
|
-
raise ValueError(
|
|
33
|
-
|
|
32
|
+
raise ValueError(
|
|
33
|
+
f"Unsupported format type: {format_type}. Supported formats: {supported_formats}"
|
|
34
|
+
)
|
|
35
|
+
|
|
34
36
|
# Handle json format separately
|
|
35
|
-
if format_type ==
|
|
37
|
+
if format_type == "json":
|
|
36
38
|
return self._format_json(data)
|
|
37
|
-
|
|
39
|
+
|
|
38
40
|
# Temporarily change format type for this call
|
|
39
41
|
original_format = self.format_type
|
|
40
42
|
self.format_type = format_type
|
|
@@ -47,10 +49,10 @@ class JavaScriptTableFormatter(BaseTableFormatter):
|
|
|
47
49
|
"""Full table format for JavaScript"""
|
|
48
50
|
if data is None:
|
|
49
51
|
return "# No data available\n"
|
|
50
|
-
|
|
52
|
+
|
|
51
53
|
if not isinstance(data, dict):
|
|
52
54
|
return f"# Invalid data type: {type(data)}\n"
|
|
53
|
-
|
|
55
|
+
|
|
54
56
|
lines = []
|
|
55
57
|
|
|
56
58
|
# Header - JavaScript (module/file based)
|
|
@@ -479,10 +481,12 @@ class JavaScriptTableFormatter(BaseTableFormatter):
|
|
|
479
481
|
return "array"
|
|
480
482
|
elif value_str.startswith("{") and value_str.endswith("}"):
|
|
481
483
|
return "object"
|
|
482
|
-
elif (
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
484
|
+
elif (
|
|
485
|
+
value_str.startswith("function")
|
|
486
|
+
or value_str.startswith("async function")
|
|
487
|
+
or value_str.startswith("new Function")
|
|
488
|
+
or "=>" in value_str
|
|
489
|
+
):
|
|
486
490
|
return "function"
|
|
487
491
|
elif value_str.startswith("class"):
|
|
488
492
|
return "class"
|
|
@@ -548,19 +552,20 @@ class JavaScriptTableFormatter(BaseTableFormatter):
|
|
|
548
552
|
"""Get class information as formatted string"""
|
|
549
553
|
if cls is None:
|
|
550
554
|
return "Unknown (0 methods)"
|
|
551
|
-
|
|
555
|
+
|
|
552
556
|
if not isinstance(cls, dict):
|
|
553
557
|
return f"{str(cls)} (0 methods)"
|
|
554
|
-
|
|
558
|
+
|
|
555
559
|
name = str(cls.get("name", "Unknown"))
|
|
556
560
|
methods = cls.get("methods", [])
|
|
557
561
|
method_count = len(methods) if isinstance(methods, list) else 0
|
|
558
|
-
|
|
562
|
+
|
|
559
563
|
return f"{name} ({method_count} methods)"
|
|
560
564
|
|
|
561
565
|
def _format_json(self, data: dict[str, Any]) -> str:
|
|
562
566
|
"""Format data as JSON"""
|
|
563
567
|
import json
|
|
568
|
+
|
|
564
569
|
try:
|
|
565
570
|
return json.dumps(data, indent=2, ensure_ascii=False)
|
|
566
571
|
except (TypeError, ValueError) as e:
|
|
@@ -3,20 +3,19 @@
|
|
|
3
3
|
Factory for creating language-specific formatters for different output types.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from typing import Dict, Type, Any
|
|
7
6
|
from .base_formatter import BaseFormatter
|
|
8
|
-
from .markdown_formatter import MarkdownFormatter
|
|
9
7
|
from .html_formatter import HtmlFormatter
|
|
8
|
+
from .markdown_formatter import MarkdownFormatter
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class LanguageFormatterFactory:
|
|
13
12
|
"""Factory for creating language-specific formatters"""
|
|
14
13
|
|
|
15
|
-
_formatters:
|
|
14
|
+
_formatters: dict[str, type[BaseFormatter]] = {
|
|
16
15
|
"markdown": MarkdownFormatter,
|
|
17
16
|
"md": MarkdownFormatter, # Alias
|
|
18
17
|
"html": HtmlFormatter,
|
|
19
|
-
"css": HtmlFormatter,
|
|
18
|
+
"css": HtmlFormatter, # CSS files also use HTML formatter
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
@classmethod
|
|
@@ -39,7 +38,9 @@ class LanguageFormatterFactory:
|
|
|
39
38
|
return formatter_class()
|
|
40
39
|
|
|
41
40
|
@classmethod
|
|
42
|
-
def register_formatter(
|
|
41
|
+
def register_formatter(
|
|
42
|
+
cls, language: str, formatter_class: type[BaseFormatter]
|
|
43
|
+
) -> None:
|
|
43
44
|
"""
|
|
44
45
|
Register new language formatter
|
|
45
46
|
|
|
@@ -83,4 +84,4 @@ def create_language_formatter(language: str) -> BaseFormatter:
|
|
|
83
84
|
Returns:
|
|
84
85
|
Language formatter or None if not supported
|
|
85
86
|
"""
|
|
86
|
-
return LanguageFormatterFactory.create_formatter(language)
|
|
87
|
+
return LanguageFormatterFactory.create_formatter(language)
|