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,498 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
HTML Formatter
|
|
4
|
+
|
|
5
|
+
Specialized formatter for HTML/CSS code elements including MarkupElement and StyleElement.
|
|
6
|
+
Provides HTML-specific formatting with element classification and hierarchy display.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from ..models import CodeElement, MarkupElement, StyleElement
|
|
13
|
+
from .base_formatter import BaseFormatter
|
|
14
|
+
from .formatter_registry import IFormatter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class HtmlFormatter(BaseFormatter, IFormatter):
|
|
18
|
+
"""HTML-specific formatter for MarkupElement and StyleElement"""
|
|
19
|
+
|
|
20
|
+
def __init__(self) -> None:
|
|
21
|
+
"""Initialize HTML formatter"""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def get_format_name() -> str:
|
|
26
|
+
return "html"
|
|
27
|
+
|
|
28
|
+
def format(self, elements: list[CodeElement]) -> str:
|
|
29
|
+
"""Format HTML elements with hierarchy and classification"""
|
|
30
|
+
if not elements:
|
|
31
|
+
return "No HTML elements found."
|
|
32
|
+
|
|
33
|
+
lines = []
|
|
34
|
+
lines.append("# HTML Structure Analysis")
|
|
35
|
+
lines.append("")
|
|
36
|
+
|
|
37
|
+
# Handle both CodeElement objects and dictionaries
|
|
38
|
+
markup_elements = []
|
|
39
|
+
style_elements = []
|
|
40
|
+
other_elements: list[dict[str, Any]] = []
|
|
41
|
+
|
|
42
|
+
for e in elements:
|
|
43
|
+
if isinstance(e, MarkupElement):
|
|
44
|
+
markup_elements.append(e)
|
|
45
|
+
elif isinstance(e, StyleElement):
|
|
46
|
+
style_elements.append(e)
|
|
47
|
+
elif isinstance(e, dict):
|
|
48
|
+
# Convert dictionary to appropriate element type based on content
|
|
49
|
+
element_type = e.get("type", e.get("element_type", "unknown"))
|
|
50
|
+
if "tag_name" in e or element_type in ["tag", "element", "markup"]:
|
|
51
|
+
markup_elements.append(self._dict_to_markup_element(e))
|
|
52
|
+
elif "selector" in e or element_type in ["rule", "style"]:
|
|
53
|
+
style_elements.append(self._dict_to_style_element(e))
|
|
54
|
+
else:
|
|
55
|
+
other_elements.append(e)
|
|
56
|
+
else:
|
|
57
|
+
other_elements.append(self._element_to_dict(e))
|
|
58
|
+
|
|
59
|
+
# Format markup elements
|
|
60
|
+
if markup_elements:
|
|
61
|
+
lines.extend(self._format_markup_elements(markup_elements))
|
|
62
|
+
|
|
63
|
+
# Format style elements
|
|
64
|
+
if style_elements:
|
|
65
|
+
lines.extend(self._format_style_elements(style_elements))
|
|
66
|
+
|
|
67
|
+
# Format other elements
|
|
68
|
+
if other_elements:
|
|
69
|
+
lines.extend(self._format_other_elements(other_elements))
|
|
70
|
+
|
|
71
|
+
return "\n".join(lines)
|
|
72
|
+
|
|
73
|
+
def format_summary(self, analysis_result: dict[str, Any]) -> str:
|
|
74
|
+
"""Format summary output for HTML elements"""
|
|
75
|
+
elements = analysis_result.get("elements", [])
|
|
76
|
+
if not elements:
|
|
77
|
+
return "No HTML elements found."
|
|
78
|
+
|
|
79
|
+
markup_count = sum(1 for e in elements if isinstance(e, MarkupElement))
|
|
80
|
+
style_count = sum(1 for e in elements if isinstance(e, StyleElement))
|
|
81
|
+
other_count = len(elements) - markup_count - style_count
|
|
82
|
+
|
|
83
|
+
lines = []
|
|
84
|
+
lines.append("# HTML Analysis Summary")
|
|
85
|
+
lines.append("")
|
|
86
|
+
lines.append(f"**Total Elements:** {len(elements)}")
|
|
87
|
+
lines.append(f"- Markup Elements: {markup_count}")
|
|
88
|
+
lines.append(f"- Style Elements: {style_count}")
|
|
89
|
+
lines.append(f"- Other Elements: {other_count}")
|
|
90
|
+
|
|
91
|
+
return "\n".join(lines)
|
|
92
|
+
|
|
93
|
+
def format_structure(self, analysis_result: dict[str, Any]) -> str:
|
|
94
|
+
"""Format structure analysis output"""
|
|
95
|
+
elements = analysis_result.get("elements", [])
|
|
96
|
+
return self.format(elements)
|
|
97
|
+
|
|
98
|
+
def format_advanced(
|
|
99
|
+
self, analysis_result: dict[str, Any], output_format: str = "json"
|
|
100
|
+
) -> str:
|
|
101
|
+
"""Format advanced analysis output"""
|
|
102
|
+
elements = analysis_result.get("elements", [])
|
|
103
|
+
|
|
104
|
+
if output_format == "json":
|
|
105
|
+
formatter = HtmlJsonFormatter()
|
|
106
|
+
return formatter.format(elements)
|
|
107
|
+
else:
|
|
108
|
+
return self.format(elements)
|
|
109
|
+
|
|
110
|
+
def format_table(
|
|
111
|
+
self, analysis_result: dict[str, Any], table_type: str = "full"
|
|
112
|
+
) -> str:
|
|
113
|
+
"""Format table output"""
|
|
114
|
+
elements = analysis_result.get("elements", [])
|
|
115
|
+
|
|
116
|
+
if table_type == "compact":
|
|
117
|
+
formatter: IFormatter = HtmlCompactFormatter()
|
|
118
|
+
return formatter.format(elements)
|
|
119
|
+
elif table_type == "json":
|
|
120
|
+
formatter = HtmlJsonFormatter()
|
|
121
|
+
return formatter.format(elements)
|
|
122
|
+
else:
|
|
123
|
+
# Default to full format (including "html" and "full")
|
|
124
|
+
return self.format(elements)
|
|
125
|
+
|
|
126
|
+
def _format_markup_elements(self, elements: list[MarkupElement]) -> list[str]:
|
|
127
|
+
"""Format MarkupElement list with hierarchy"""
|
|
128
|
+
lines = []
|
|
129
|
+
lines.append("## HTML Elements")
|
|
130
|
+
lines.append("")
|
|
131
|
+
|
|
132
|
+
# Group by element class
|
|
133
|
+
element_groups: dict[str, list[MarkupElement]] = {}
|
|
134
|
+
for element in elements:
|
|
135
|
+
element_class = element.element_class or "unknown"
|
|
136
|
+
if element_class not in element_groups:
|
|
137
|
+
element_groups[element_class] = []
|
|
138
|
+
element_groups[element_class].append(element)
|
|
139
|
+
|
|
140
|
+
# Format each group
|
|
141
|
+
for element_class, group_elements in element_groups.items():
|
|
142
|
+
lines.append(
|
|
143
|
+
f"### {element_class.title()} Elements ({len(group_elements)})"
|
|
144
|
+
)
|
|
145
|
+
lines.append("")
|
|
146
|
+
lines.append("| Tag | Name | Lines | Attributes | Children |")
|
|
147
|
+
lines.append("|-----|------|-------|------------|----------|")
|
|
148
|
+
|
|
149
|
+
for element in group_elements:
|
|
150
|
+
tag_name = element.tag_name or "unknown"
|
|
151
|
+
name = element.name or tag_name
|
|
152
|
+
lines_str = f"{element.start_line}-{element.end_line}"
|
|
153
|
+
|
|
154
|
+
# Format attributes
|
|
155
|
+
attrs = []
|
|
156
|
+
attributes = element.attributes or {}
|
|
157
|
+
for key, value in attributes.items():
|
|
158
|
+
if value:
|
|
159
|
+
attrs.append(f'{key}="{value}"')
|
|
160
|
+
else:
|
|
161
|
+
attrs.append(key)
|
|
162
|
+
attrs_str = ", ".join(attrs) if attrs else "-"
|
|
163
|
+
if len(attrs_str) > 30:
|
|
164
|
+
attrs_str = attrs_str[:27] + "..."
|
|
165
|
+
|
|
166
|
+
# Count children
|
|
167
|
+
children_count = len(element.children)
|
|
168
|
+
|
|
169
|
+
lines.append(
|
|
170
|
+
f"| `{tag_name}` | {name} | {lines_str} | {attrs_str} | {children_count} |"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
lines.append("")
|
|
174
|
+
|
|
175
|
+
# Show hierarchy for root elements
|
|
176
|
+
root_elements = [e for e in elements if e.parent is None]
|
|
177
|
+
if root_elements and len(root_elements) < len(elements):
|
|
178
|
+
lines.append("### Element Hierarchy")
|
|
179
|
+
lines.append("")
|
|
180
|
+
for root in root_elements:
|
|
181
|
+
lines.extend(self._format_element_tree(root, 0))
|
|
182
|
+
lines.append("")
|
|
183
|
+
|
|
184
|
+
return lines
|
|
185
|
+
|
|
186
|
+
def _format_element_tree(self, element: MarkupElement, depth: int) -> list[str]:
|
|
187
|
+
"""Format element tree hierarchy"""
|
|
188
|
+
lines = []
|
|
189
|
+
indent = " " * depth
|
|
190
|
+
tag_name = element.tag_name or "unknown"
|
|
191
|
+
|
|
192
|
+
# Format element info
|
|
193
|
+
attrs_info = ""
|
|
194
|
+
attributes = element.attributes or {}
|
|
195
|
+
if attributes:
|
|
196
|
+
key_attrs = []
|
|
197
|
+
for key, value in attributes.items():
|
|
198
|
+
if key in ["id", "class", "name"]:
|
|
199
|
+
key_attrs.append(f'{key}="{value}"' if value else key)
|
|
200
|
+
if key_attrs:
|
|
201
|
+
attrs_info = f" ({', '.join(key_attrs)})"
|
|
202
|
+
|
|
203
|
+
lines.append(
|
|
204
|
+
f"{indent}- `{tag_name}`{attrs_info} [{element.start_line}-{element.end_line}]"
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# Format children
|
|
208
|
+
for child in element.children:
|
|
209
|
+
lines.extend(self._format_element_tree(child, depth + 1))
|
|
210
|
+
|
|
211
|
+
return lines
|
|
212
|
+
|
|
213
|
+
def _format_style_elements(self, elements: list[StyleElement]) -> list[str]:
|
|
214
|
+
"""Format StyleElement list"""
|
|
215
|
+
lines = []
|
|
216
|
+
lines.append("## CSS Rules")
|
|
217
|
+
lines.append("")
|
|
218
|
+
|
|
219
|
+
# Group by element class
|
|
220
|
+
element_groups: dict[str, list[StyleElement]] = {}
|
|
221
|
+
for element in elements:
|
|
222
|
+
element_class = element.element_class or "unknown"
|
|
223
|
+
if element_class not in element_groups:
|
|
224
|
+
element_groups[element_class] = []
|
|
225
|
+
element_groups[element_class].append(element)
|
|
226
|
+
|
|
227
|
+
# Format each group
|
|
228
|
+
for element_class, group_elements in element_groups.items():
|
|
229
|
+
lines.append(f"### {element_class.title()} Rules ({len(group_elements)})")
|
|
230
|
+
lines.append("")
|
|
231
|
+
lines.append("| Selector | Properties | Lines |")
|
|
232
|
+
lines.append("|----------|------------|-------|")
|
|
233
|
+
|
|
234
|
+
for element in group_elements:
|
|
235
|
+
selector = element.selector or element.name
|
|
236
|
+
lines_str = f"{element.start_line}-{element.end_line}"
|
|
237
|
+
|
|
238
|
+
# Format properties
|
|
239
|
+
props = []
|
|
240
|
+
properties = element.properties or {}
|
|
241
|
+
for key, value in properties.items():
|
|
242
|
+
props.append(f"{key}: {value}")
|
|
243
|
+
props_str = "; ".join(props) if props else "-"
|
|
244
|
+
if len(props_str) > 40:
|
|
245
|
+
props_str = props_str[:37] + "..."
|
|
246
|
+
|
|
247
|
+
lines.append(f"| `{selector}` | {props_str} | {lines_str} |")
|
|
248
|
+
|
|
249
|
+
lines.append("")
|
|
250
|
+
|
|
251
|
+
return lines
|
|
252
|
+
|
|
253
|
+
def _format_other_elements(self, elements: list) -> list[str]:
|
|
254
|
+
"""Format other code elements"""
|
|
255
|
+
lines = []
|
|
256
|
+
lines.append("## Other Elements")
|
|
257
|
+
lines.append("")
|
|
258
|
+
lines.append("| Type | Name | Lines | Language |")
|
|
259
|
+
lines.append("|------|------|-------|----------|")
|
|
260
|
+
|
|
261
|
+
for element in elements:
|
|
262
|
+
if isinstance(element, dict):
|
|
263
|
+
element_type = element.get(
|
|
264
|
+
"element_type", element.get("type", "unknown")
|
|
265
|
+
)
|
|
266
|
+
name = element.get("name", "unknown")
|
|
267
|
+
start_line = element.get("start_line", 0)
|
|
268
|
+
end_line = element.get("end_line", 0)
|
|
269
|
+
language = element.get("language", "unknown")
|
|
270
|
+
else:
|
|
271
|
+
element_type = getattr(element, "element_type", "unknown")
|
|
272
|
+
name = getattr(element, "name", "unknown")
|
|
273
|
+
start_line = getattr(element, "start_line", 0)
|
|
274
|
+
end_line = getattr(element, "end_line", 0)
|
|
275
|
+
language = getattr(element, "language", "unknown")
|
|
276
|
+
|
|
277
|
+
lines_str = f"{start_line}-{end_line}"
|
|
278
|
+
lines.append(f"| {element_type} | {name} | {lines_str} | {language} |")
|
|
279
|
+
|
|
280
|
+
lines.append("")
|
|
281
|
+
return lines
|
|
282
|
+
|
|
283
|
+
def _dict_to_markup_element(self, data: dict) -> Any:
|
|
284
|
+
"""Convert dictionary to MarkupElement-like object"""
|
|
285
|
+
|
|
286
|
+
# Create a mock MarkupElement-like object
|
|
287
|
+
class MockMarkupElement:
|
|
288
|
+
def __init__(self, data: dict[str, Any]) -> None:
|
|
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", {})
|
|
295
|
+
self.children: list[MockMarkupElement] = []
|
|
296
|
+
self.parent = None
|
|
297
|
+
self.language = data.get("language", "html")
|
|
298
|
+
|
|
299
|
+
return MockMarkupElement(data)
|
|
300
|
+
|
|
301
|
+
def _dict_to_style_element(self, data: dict) -> Any:
|
|
302
|
+
"""Convert dictionary to StyleElement-like object"""
|
|
303
|
+
|
|
304
|
+
# Create a mock StyleElement-like object
|
|
305
|
+
class MockStyleElement:
|
|
306
|
+
def __init__(self, data: dict[str, Any]) -> None:
|
|
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
|
+
|
|
315
|
+
return MockStyleElement(data)
|
|
316
|
+
|
|
317
|
+
def _element_to_dict(self, element: CodeElement) -> dict[str, Any]:
|
|
318
|
+
"""Convert generic CodeElement to dictionary"""
|
|
319
|
+
return {
|
|
320
|
+
"name": element.name,
|
|
321
|
+
"type": getattr(element, "element_type", "unknown"),
|
|
322
|
+
"start_line": element.start_line,
|
|
323
|
+
"end_line": element.end_line,
|
|
324
|
+
"language": element.language,
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class HtmlJsonFormatter(IFormatter):
|
|
329
|
+
"""JSON formatter specifically for HTML elements"""
|
|
330
|
+
|
|
331
|
+
@staticmethod
|
|
332
|
+
def get_format_name() -> str:
|
|
333
|
+
return "html_json"
|
|
334
|
+
|
|
335
|
+
def format(self, elements: list[CodeElement]) -> str:
|
|
336
|
+
"""Format HTML elements as JSON with hierarchy"""
|
|
337
|
+
result: dict[str, Any] = {
|
|
338
|
+
"html_analysis": {
|
|
339
|
+
"total_elements": len(elements),
|
|
340
|
+
"markup_elements": [],
|
|
341
|
+
"style_elements": [],
|
|
342
|
+
"other_elements": [],
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
for element in elements:
|
|
347
|
+
if isinstance(element, MarkupElement):
|
|
348
|
+
result["html_analysis"]["markup_elements"].append(
|
|
349
|
+
self._markup_to_dict(element)
|
|
350
|
+
)
|
|
351
|
+
elif isinstance(element, StyleElement):
|
|
352
|
+
result["html_analysis"]["style_elements"].append(
|
|
353
|
+
self._style_to_dict(element)
|
|
354
|
+
)
|
|
355
|
+
elif isinstance(element, dict):
|
|
356
|
+
# Handle dictionary format
|
|
357
|
+
element_type = element.get(
|
|
358
|
+
"element_type", element.get("type", "unknown")
|
|
359
|
+
)
|
|
360
|
+
if "tag_name" in element or element_type in [
|
|
361
|
+
"tag",
|
|
362
|
+
"element",
|
|
363
|
+
"markup",
|
|
364
|
+
]:
|
|
365
|
+
result["html_analysis"]["markup_elements"].append(element)
|
|
366
|
+
elif "selector" in element or element_type in ["rule", "style"]:
|
|
367
|
+
result["html_analysis"]["style_elements"].append(element)
|
|
368
|
+
else:
|
|
369
|
+
result["html_analysis"]["other_elements"].append(element)
|
|
370
|
+
else:
|
|
371
|
+
result["html_analysis"]["other_elements"].append(
|
|
372
|
+
self._element_to_dict(element)
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
return json.dumps(result, indent=2, ensure_ascii=False)
|
|
376
|
+
|
|
377
|
+
def _markup_to_dict(self, element: MarkupElement) -> dict[str, Any]:
|
|
378
|
+
"""Convert MarkupElement to dictionary"""
|
|
379
|
+
return {
|
|
380
|
+
"name": element.name,
|
|
381
|
+
"tag_name": element.tag_name,
|
|
382
|
+
"element_class": element.element_class,
|
|
383
|
+
"start_line": element.start_line,
|
|
384
|
+
"end_line": element.end_line,
|
|
385
|
+
"attributes": element.attributes,
|
|
386
|
+
"children_count": len(element.children),
|
|
387
|
+
"children": [self._markup_to_dict(child) for child in element.children],
|
|
388
|
+
"language": element.language,
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
def _style_to_dict(self, element: StyleElement) -> dict[str, Any]:
|
|
392
|
+
"""Convert StyleElement to dictionary"""
|
|
393
|
+
return {
|
|
394
|
+
"name": element.name,
|
|
395
|
+
"selector": element.selector,
|
|
396
|
+
"element_class": element.element_class,
|
|
397
|
+
"start_line": element.start_line,
|
|
398
|
+
"end_line": element.end_line,
|
|
399
|
+
"properties": element.properties,
|
|
400
|
+
"language": element.language,
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
def _element_to_dict(self, element: CodeElement) -> dict[str, Any]:
|
|
404
|
+
"""Convert generic CodeElement to dictionary"""
|
|
405
|
+
return {
|
|
406
|
+
"name": element.name,
|
|
407
|
+
"type": getattr(element, "element_type", "unknown"),
|
|
408
|
+
"start_line": element.start_line,
|
|
409
|
+
"end_line": element.end_line,
|
|
410
|
+
"language": element.language,
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
class HtmlCompactFormatter(IFormatter):
|
|
415
|
+
"""Compact formatter for HTML elements"""
|
|
416
|
+
|
|
417
|
+
@staticmethod
|
|
418
|
+
def get_format_name() -> str:
|
|
419
|
+
return "html_compact"
|
|
420
|
+
|
|
421
|
+
def format(self, elements: list[CodeElement]) -> str:
|
|
422
|
+
"""Format HTML elements in compact format"""
|
|
423
|
+
if not elements:
|
|
424
|
+
return "No HTML elements found."
|
|
425
|
+
|
|
426
|
+
lines = []
|
|
427
|
+
lines.append("HTML ELEMENTS")
|
|
428
|
+
lines.append("-" * 20)
|
|
429
|
+
|
|
430
|
+
markup_count = sum(1 for e in elements if isinstance(e, MarkupElement))
|
|
431
|
+
style_count = sum(1 for e in elements if isinstance(e, StyleElement))
|
|
432
|
+
other_count = len(elements) - markup_count - style_count
|
|
433
|
+
|
|
434
|
+
lines.append(f"Total: {len(elements)} elements")
|
|
435
|
+
lines.append(f" Markup: {markup_count}")
|
|
436
|
+
lines.append(f" Style: {style_count}")
|
|
437
|
+
lines.append(f" Other: {other_count}")
|
|
438
|
+
lines.append("")
|
|
439
|
+
|
|
440
|
+
for element in elements:
|
|
441
|
+
if isinstance(element, MarkupElement):
|
|
442
|
+
symbol = "🏷️"
|
|
443
|
+
info = f"<{element.tag_name}>"
|
|
444
|
+
if element.attributes.get("id"):
|
|
445
|
+
info += f" #{element.attributes['id']}"
|
|
446
|
+
if element.attributes.get("class"):
|
|
447
|
+
info += f" .{element.attributes['class']}"
|
|
448
|
+
name = element.name
|
|
449
|
+
start_line = element.start_line
|
|
450
|
+
end_line = element.end_line
|
|
451
|
+
elif isinstance(element, StyleElement):
|
|
452
|
+
symbol = "🎨"
|
|
453
|
+
info = element.selector
|
|
454
|
+
name = element.name
|
|
455
|
+
start_line = element.start_line
|
|
456
|
+
end_line = element.end_line
|
|
457
|
+
elif isinstance(element, dict):
|
|
458
|
+
# Handle dictionary format
|
|
459
|
+
element_type = element.get(
|
|
460
|
+
"element_type", element.get("type", "unknown")
|
|
461
|
+
)
|
|
462
|
+
name = element.get("name", "unknown")
|
|
463
|
+
start_line = element.get("start_line", 0)
|
|
464
|
+
end_line = element.get("end_line", 0)
|
|
465
|
+
|
|
466
|
+
if "tag_name" in element or element_type in [
|
|
467
|
+
"tag",
|
|
468
|
+
"element",
|
|
469
|
+
"markup",
|
|
470
|
+
]:
|
|
471
|
+
symbol = "🏷️"
|
|
472
|
+
tag_name = element.get("tag_name", name)
|
|
473
|
+
info = f"<{tag_name}>"
|
|
474
|
+
attributes = element.get("attributes", {})
|
|
475
|
+
if attributes.get("id"):
|
|
476
|
+
info += f" #{attributes['id']}"
|
|
477
|
+
if attributes.get("class"):
|
|
478
|
+
info += f" .{attributes['class']}"
|
|
479
|
+
elif "selector" in element or element_type in ["rule", "style"]:
|
|
480
|
+
symbol = "🎨"
|
|
481
|
+
info = str(element.get("selector", name))
|
|
482
|
+
else:
|
|
483
|
+
symbol = "📄"
|
|
484
|
+
info = str(element_type)
|
|
485
|
+
else:
|
|
486
|
+
symbol = "📄"
|
|
487
|
+
info = getattr(element, "element_type", "unknown")
|
|
488
|
+
name = getattr(element, "name", "unknown")
|
|
489
|
+
start_line = getattr(element, "start_line", 0)
|
|
490
|
+
end_line = getattr(element, "end_line", 0)
|
|
491
|
+
|
|
492
|
+
lines.append(f"{symbol} {name} {info} [{start_line}-{end_line}]")
|
|
493
|
+
|
|
494
|
+
return "\n".join(lines)
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
# HTML formatters are registered via formatter_registry.py
|
|
498
|
+
# to avoid duplicate registration warnings
|