tree-sitter-analyzer 1.8.3__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.

Files changed (64) hide show
  1. tree_sitter_analyzer/__init__.py +1 -1
  2. tree_sitter_analyzer/api.py +4 -4
  3. tree_sitter_analyzer/cli/argument_validator.py +29 -17
  4. tree_sitter_analyzer/cli/commands/advanced_command.py +7 -5
  5. tree_sitter_analyzer/cli/commands/structure_command.py +7 -5
  6. tree_sitter_analyzer/cli/commands/summary_command.py +10 -6
  7. tree_sitter_analyzer/cli/commands/table_command.py +8 -7
  8. tree_sitter_analyzer/cli/info_commands.py +1 -1
  9. tree_sitter_analyzer/cli_main.py +3 -2
  10. tree_sitter_analyzer/core/analysis_engine.py +5 -5
  11. tree_sitter_analyzer/core/cache_service.py +3 -1
  12. tree_sitter_analyzer/core/query.py +17 -5
  13. tree_sitter_analyzer/core/query_service.py +1 -1
  14. tree_sitter_analyzer/encoding_utils.py +3 -3
  15. tree_sitter_analyzer/exceptions.py +61 -50
  16. tree_sitter_analyzer/file_handler.py +3 -0
  17. tree_sitter_analyzer/formatters/base_formatter.py +10 -5
  18. tree_sitter_analyzer/formatters/formatter_registry.py +83 -68
  19. tree_sitter_analyzer/formatters/html_formatter.py +90 -54
  20. tree_sitter_analyzer/formatters/javascript_formatter.py +21 -16
  21. tree_sitter_analyzer/formatters/language_formatter_factory.py +7 -6
  22. tree_sitter_analyzer/formatters/markdown_formatter.py +247 -124
  23. tree_sitter_analyzer/formatters/python_formatter.py +61 -38
  24. tree_sitter_analyzer/formatters/typescript_formatter.py +113 -45
  25. tree_sitter_analyzer/interfaces/mcp_server.py +2 -2
  26. tree_sitter_analyzer/language_detector.py +6 -6
  27. tree_sitter_analyzer/language_loader.py +3 -1
  28. tree_sitter_analyzer/languages/css_plugin.py +120 -61
  29. tree_sitter_analyzer/languages/html_plugin.py +159 -62
  30. tree_sitter_analyzer/languages/java_plugin.py +42 -34
  31. tree_sitter_analyzer/languages/javascript_plugin.py +59 -30
  32. tree_sitter_analyzer/languages/markdown_plugin.py +402 -368
  33. tree_sitter_analyzer/languages/python_plugin.py +111 -64
  34. tree_sitter_analyzer/languages/typescript_plugin.py +241 -132
  35. tree_sitter_analyzer/mcp/server.py +22 -18
  36. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +13 -8
  37. tree_sitter_analyzer/mcp/tools/base_tool.py +2 -2
  38. tree_sitter_analyzer/mcp/tools/fd_rg_utils.py +232 -26
  39. tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +31 -23
  40. tree_sitter_analyzer/mcp/tools/list_files_tool.py +21 -19
  41. tree_sitter_analyzer/mcp/tools/query_tool.py +17 -18
  42. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +30 -31
  43. tree_sitter_analyzer/mcp/tools/search_content_tool.py +131 -77
  44. tree_sitter_analyzer/mcp/tools/table_format_tool.py +29 -16
  45. tree_sitter_analyzer/mcp/utils/file_output_factory.py +64 -51
  46. tree_sitter_analyzer/mcp/utils/file_output_manager.py +34 -24
  47. tree_sitter_analyzer/mcp/utils/gitignore_detector.py +8 -4
  48. tree_sitter_analyzer/models.py +7 -5
  49. tree_sitter_analyzer/plugins/base.py +9 -7
  50. tree_sitter_analyzer/plugins/manager.py +1 -0
  51. tree_sitter_analyzer/queries/css.py +2 -21
  52. tree_sitter_analyzer/queries/html.py +2 -15
  53. tree_sitter_analyzer/queries/markdown.py +30 -41
  54. tree_sitter_analyzer/queries/python.py +20 -5
  55. tree_sitter_analyzer/query_loader.py +5 -5
  56. tree_sitter_analyzer/security/validator.py +114 -86
  57. tree_sitter_analyzer/utils/__init__.py +58 -28
  58. tree_sitter_analyzer/utils/tree_sitter_compat.py +72 -65
  59. tree_sitter_analyzer/utils.py +83 -25
  60. {tree_sitter_analyzer-1.8.3.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/METADATA +19 -5
  61. tree_sitter_analyzer-1.9.0.dist-info/RECORD +109 -0
  62. tree_sitter_analyzer-1.8.3.dist-info/RECORD +0 -109
  63. {tree_sitter_analyzer-1.8.3.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/WHEEL +0 -0
  64. {tree_sitter_analyzer-1.8.3.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/entry_points.txt +0 -0
@@ -8,7 +8,6 @@ Provides extensible formatter architecture following the Registry pattern.
8
8
 
9
9
  import logging
10
10
  from abc import ABC, abstractmethod
11
- from typing import Any
12
11
 
13
12
  from ..models import CodeElement
14
13
 
@@ -18,7 +17,7 @@ logger = logging.getLogger(__name__)
18
17
  class IFormatter(ABC):
19
18
  """
20
19
  Interface for code element formatters.
21
-
20
+
22
21
  All formatters must implement this interface to be compatible
23
22
  with the FormatterRegistry system.
24
23
  """
@@ -28,7 +27,7 @@ class IFormatter(ABC):
28
27
  def get_format_name() -> str:
29
28
  """
30
29
  Return the format name this formatter supports.
31
-
30
+
32
31
  Returns:
33
32
  Format name (e.g., "json", "csv", "markdown")
34
33
  """
@@ -38,10 +37,10 @@ class IFormatter(ABC):
38
37
  def format(self, elements: list[CodeElement]) -> str:
39
38
  """
40
39
  Format a list of CodeElements into a string representation.
41
-
40
+
42
41
  Args:
43
42
  elements: List of CodeElement objects to format
44
-
43
+
45
44
  Returns:
46
45
  Formatted string representation
47
46
  """
@@ -51,7 +50,7 @@ class IFormatter(ABC):
51
50
  class FormatterRegistry:
52
51
  """
53
52
  Registry for managing and providing formatter instances.
54
-
53
+
55
54
  Implements the Registry pattern to allow dynamic registration
56
55
  and retrieval of formatters by format name.
57
56
  """
@@ -62,23 +61,23 @@ class FormatterRegistry:
62
61
  def register_formatter(cls, formatter_class: type[IFormatter]) -> None:
63
62
  """
64
63
  Register a formatter class in the registry.
65
-
64
+
66
65
  Args:
67
66
  formatter_class: Formatter class implementing IFormatter
68
-
67
+
69
68
  Raises:
70
69
  ValueError: If formatter_class doesn't implement IFormatter
71
70
  """
72
71
  if not issubclass(formatter_class, IFormatter):
73
- raise ValueError(f"Formatter class must implement IFormatter interface")
74
-
72
+ raise ValueError("Formatter class must implement IFormatter interface")
73
+
75
74
  format_name = formatter_class.get_format_name()
76
75
  if not format_name:
77
76
  raise ValueError("Formatter must provide a non-empty format name")
78
-
77
+
79
78
  if format_name in cls._formatters:
80
79
  logger.warning(f"Overriding existing formatter for format: {format_name}")
81
-
80
+
82
81
  cls._formatters[format_name] = formatter_class
83
82
  logger.debug(f"Registered formatter for format: {format_name}")
84
83
 
@@ -86,13 +85,13 @@ class FormatterRegistry:
86
85
  def get_formatter(cls, format_name: str) -> IFormatter:
87
86
  """
88
87
  Get a formatter instance for the specified format.
89
-
88
+
90
89
  Args:
91
90
  format_name: Name of the format to get formatter for
92
-
91
+
93
92
  Returns:
94
93
  Formatter instance
95
-
94
+
96
95
  Raises:
97
96
  ValueError: If format is not supported
98
97
  """
@@ -102,7 +101,7 @@ class FormatterRegistry:
102
101
  f"Unsupported format: {format_name}. "
103
102
  f"Available formats: {available_formats}"
104
103
  )
105
-
104
+
106
105
  formatter_class = cls._formatters[format_name]
107
106
  return formatter_class()
108
107
 
@@ -110,7 +109,7 @@ class FormatterRegistry:
110
109
  def get_available_formats(cls) -> list[str]:
111
110
  """
112
111
  Get list of all available format names.
113
-
112
+
114
113
  Returns:
115
114
  List of available format names
116
115
  """
@@ -120,10 +119,10 @@ class FormatterRegistry:
120
119
  def is_format_supported(cls, format_name: str) -> bool:
121
120
  """
122
121
  Check if a format is supported.
123
-
122
+
124
123
  Args:
125
124
  format_name: Format name to check
126
-
125
+
127
126
  Returns:
128
127
  True if format is supported
129
128
  """
@@ -133,10 +132,10 @@ class FormatterRegistry:
133
132
  def unregister_formatter(cls, format_name: str) -> bool:
134
133
  """
135
134
  Unregister a formatter for the specified format.
136
-
135
+
137
136
  Args:
138
137
  format_name: Format name to unregister
139
-
138
+
140
139
  Returns:
141
140
  True if formatter was unregistered, False if not found
142
141
  """
@@ -150,7 +149,7 @@ class FormatterRegistry:
150
149
  def clear_registry(cls) -> None:
151
150
  """
152
151
  Clear all registered formatters.
153
-
152
+
154
153
  This method is primarily for testing purposes.
155
154
  """
156
155
  cls._formatters.clear()
@@ -159,6 +158,7 @@ class FormatterRegistry:
159
158
 
160
159
  # Built-in formatter implementations
161
160
 
161
+
162
162
  class JsonFormatter(IFormatter):
163
163
  """JSON formatter for CodeElement lists"""
164
164
 
@@ -169,7 +169,7 @@ class JsonFormatter(IFormatter):
169
169
  def format(self, elements: list[CodeElement]) -> str:
170
170
  """Format elements as JSON"""
171
171
  import json
172
-
172
+
173
173
  result = []
174
174
  for element in elements:
175
175
  element_dict = {
@@ -179,7 +179,7 @@ class JsonFormatter(IFormatter):
179
179
  "end_line": element.end_line,
180
180
  "language": element.language,
181
181
  }
182
-
182
+
183
183
  # Add type-specific attributes
184
184
  if hasattr(element, "parameters"):
185
185
  element_dict["parameters"] = getattr(element, "parameters", [])
@@ -195,9 +195,9 @@ class JsonFormatter(IFormatter):
195
195
  element_dict["selector"] = getattr(element, "selector", "")
196
196
  if hasattr(element, "element_class"):
197
197
  element_dict["element_class"] = getattr(element, "element_class", "")
198
-
198
+
199
199
  result.append(element_dict)
200
-
200
+
201
201
  return json.dumps(result, indent=2, ensure_ascii=False)
202
202
 
203
203
 
@@ -212,30 +212,41 @@ class CsvFormatter(IFormatter):
212
212
  """Format elements as CSV"""
213
213
  import csv
214
214
  import io
215
-
215
+
216
216
  output = io.StringIO()
217
217
  writer = csv.writer(output, lineterminator="\n")
218
-
218
+
219
219
  # Write header
220
- writer.writerow([
221
- "Type", "Name", "Start Line", "End Line", "Language",
222
- "Visibility", "Parameters", "Return Type", "Modifiers"
223
- ])
224
-
220
+ writer.writerow(
221
+ [
222
+ "Type",
223
+ "Name",
224
+ "Start Line",
225
+ "End Line",
226
+ "Language",
227
+ "Visibility",
228
+ "Parameters",
229
+ "Return Type",
230
+ "Modifiers",
231
+ ]
232
+ )
233
+
225
234
  # Write data rows
226
235
  for element in elements:
227
- writer.writerow([
228
- getattr(element, "element_type", "unknown"),
229
- element.name,
230
- element.start_line,
231
- element.end_line,
232
- element.language,
233
- getattr(element, "visibility", ""),
234
- str(getattr(element, "parameters", [])),
235
- getattr(element, "return_type", ""),
236
- str(getattr(element, "modifiers", []))
237
- ])
238
-
236
+ writer.writerow(
237
+ [
238
+ getattr(element, "element_type", "unknown"),
239
+ element.name,
240
+ element.start_line,
241
+ element.end_line,
242
+ element.language,
243
+ getattr(element, "visibility", ""),
244
+ str(getattr(element, "parameters", [])),
245
+ getattr(element, "return_type", ""),
246
+ str(getattr(element, "modifiers", [])),
247
+ ]
248
+ )
249
+
239
250
  csv_content = output.getvalue()
240
251
  output.close()
241
252
  return csv_content.rstrip("\n")
@@ -252,13 +263,13 @@ class FullFormatter(IFormatter):
252
263
  """Format elements as full table"""
253
264
  if not elements:
254
265
  return "No elements found."
255
-
266
+
256
267
  lines = []
257
268
  lines.append("=" * 80)
258
269
  lines.append("CODE STRUCTURE ANALYSIS")
259
270
  lines.append("=" * 80)
260
271
  lines.append("")
261
-
272
+
262
273
  # Group elements by type
263
274
  element_groups: dict[str, list[CodeElement]] = {}
264
275
  for element in elements:
@@ -266,32 +277,36 @@ class FullFormatter(IFormatter):
266
277
  if element_type not in element_groups:
267
278
  element_groups[element_type] = []
268
279
  element_groups[element_type].append(element)
269
-
280
+
270
281
  # Format each group
271
282
  for element_type, group_elements in element_groups.items():
272
283
  lines.append(f"{element_type.upper()}S ({len(group_elements)})")
273
284
  lines.append("-" * 40)
274
-
285
+
275
286
  for element in group_elements:
276
287
  lines.append(f" {element.name}")
277
288
  lines.append(f" Lines: {element.start_line}-{element.end_line}")
278
289
  lines.append(f" Language: {element.language}")
279
-
290
+
280
291
  if hasattr(element, "visibility"):
281
- lines.append(f" Visibility: {getattr(element, 'visibility', 'unknown')}")
292
+ lines.append(
293
+ f" Visibility: {getattr(element, 'visibility', 'unknown')}"
294
+ )
282
295
  if hasattr(element, "parameters"):
283
296
  params = getattr(element, "parameters", [])
284
297
  if params:
285
- lines.append(f" Parameters: {', '.join(str(p) for p in params)}")
298
+ lines.append(
299
+ f" Parameters: {', '.join(str(p) for p in params)}"
300
+ )
286
301
  if hasattr(element, "return_type"):
287
302
  ret_type = getattr(element, "return_type", None)
288
303
  if ret_type:
289
304
  lines.append(f" Return Type: {ret_type}")
290
-
305
+
291
306
  lines.append("")
292
-
307
+
293
308
  lines.append("")
294
-
309
+
295
310
  return "\n".join(lines)
296
311
 
297
312
 
@@ -306,29 +321,24 @@ class CompactFormatter(IFormatter):
306
321
  """Format elements in compact format"""
307
322
  if not elements:
308
323
  return "No elements found."
309
-
324
+
310
325
  lines = []
311
326
  lines.append("CODE ELEMENTS")
312
327
  lines.append("-" * 20)
313
-
328
+
314
329
  for element in elements:
315
330
  element_type = getattr(element, "element_type", "unknown")
316
331
  visibility = getattr(element, "visibility", "")
317
332
  vis_symbol = self._get_visibility_symbol(visibility)
318
-
333
+
319
334
  line = f"{vis_symbol} {element.name} ({element_type}) [{element.start_line}-{element.end_line}]"
320
335
  lines.append(line)
321
-
336
+
322
337
  return "\n".join(lines)
323
338
 
324
339
  def _get_visibility_symbol(self, visibility: str) -> str:
325
340
  """Get symbol for visibility"""
326
- mapping = {
327
- "public": "+",
328
- "private": "-",
329
- "protected": "#",
330
- "package": "~"
331
- }
341
+ mapping = {"public": "+", "private": "-", "protected": "#", "package": "~"}
332
342
  return mapping.get(visibility, "?")
333
343
 
334
344
 
@@ -339,10 +349,15 @@ def register_builtin_formatters() -> None:
339
349
  FormatterRegistry.register_formatter(CsvFormatter)
340
350
  FormatterRegistry.register_formatter(FullFormatter)
341
351
  FormatterRegistry.register_formatter(CompactFormatter)
342
-
352
+
343
353
  # Register HTML formatters if available
344
354
  try:
345
- from .html_formatter import HtmlFormatter, HtmlJsonFormatter, HtmlCompactFormatter
355
+ from .html_formatter import (
356
+ HtmlCompactFormatter,
357
+ HtmlFormatter,
358
+ HtmlJsonFormatter,
359
+ )
360
+
346
361
  FormatterRegistry.register_formatter(HtmlFormatter)
347
362
  FormatterRegistry.register_formatter(HtmlJsonFormatter)
348
363
  FormatterRegistry.register_formatter(HtmlCompactFormatter)
@@ -352,4 +367,4 @@ def register_builtin_formatters() -> None:
352
367
 
353
368
 
354
369
  # Auto-register built-in formatters when module is imported
355
- register_builtin_formatters()
370
+ register_builtin_formatters()