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
|
@@ -7,7 +7,7 @@ Supports tree-sitter 0.20+ with query.matches() method only.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
|
-
from typing import Any
|
|
10
|
+
from typing import Any
|
|
11
11
|
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
@@ -15,82 +15,82 @@ logger = logging.getLogger(__name__)
|
|
|
15
15
|
class TreeSitterQueryCompat:
|
|
16
16
|
"""
|
|
17
17
|
Tree-sitter query execution wrapper for modern API.
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
Uses only the modern tree-sitter API (query.matches()).
|
|
20
20
|
"""
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
@staticmethod
|
|
23
23
|
def execute_query(
|
|
24
|
-
language: Any,
|
|
25
|
-
|
|
26
|
-
root_node: Any
|
|
27
|
-
) -> List[Tuple[Any, str]]:
|
|
24
|
+
language: Any, query_string: str, root_node: Any
|
|
25
|
+
) -> list[tuple[Any, str]]:
|
|
28
26
|
"""
|
|
29
27
|
Execute a tree-sitter query using the modern API.
|
|
30
|
-
|
|
28
|
+
|
|
31
29
|
Args:
|
|
32
30
|
language: Tree-sitter language object
|
|
33
31
|
query_string: Query string to execute
|
|
34
32
|
root_node: Root node to query against
|
|
35
|
-
|
|
33
|
+
|
|
36
34
|
Returns:
|
|
37
35
|
List of (node, capture_name) tuples
|
|
38
|
-
|
|
36
|
+
|
|
39
37
|
Raises:
|
|
40
38
|
Exception: If query execution fails
|
|
41
39
|
"""
|
|
42
40
|
try:
|
|
43
41
|
import tree_sitter
|
|
42
|
+
|
|
44
43
|
query = tree_sitter.Query(language, query_string)
|
|
45
|
-
|
|
44
|
+
|
|
46
45
|
# Try newest API first (tree-sitter 0.25+) with QueryCursor
|
|
47
|
-
if hasattr(tree_sitter,
|
|
46
|
+
if hasattr(tree_sitter, "QueryCursor"):
|
|
48
47
|
logger.debug("Using newest tree-sitter API (QueryCursor)")
|
|
49
48
|
return TreeSitterQueryCompat._execute_newest_api(query, root_node)
|
|
50
49
|
# Try modern API (tree-sitter 0.20+)
|
|
51
|
-
elif hasattr(query,
|
|
50
|
+
elif hasattr(query, "matches"):
|
|
52
51
|
logger.debug("Using modern tree-sitter API (matches)")
|
|
53
52
|
return TreeSitterQueryCompat._execute_modern_api(query, root_node)
|
|
54
53
|
# Fall back to legacy API (tree-sitter < 0.20)
|
|
55
|
-
elif hasattr(query,
|
|
54
|
+
elif hasattr(query, "captures"):
|
|
56
55
|
logger.debug("Using legacy tree-sitter API (captures)")
|
|
57
56
|
return TreeSitterQueryCompat._execute_legacy_api(query, root_node)
|
|
58
57
|
# Try very old API with different method signature
|
|
59
58
|
else:
|
|
60
59
|
logger.debug("Using very old tree-sitter API (direct query)")
|
|
61
60
|
return TreeSitterQueryCompat._execute_old_api(query, root_node)
|
|
62
|
-
|
|
61
|
+
|
|
63
62
|
except Exception as e:
|
|
64
63
|
logger.error(f"Tree-sitter query execution failed: {e}")
|
|
65
64
|
# Return empty result instead of raising to prevent complete failure
|
|
66
65
|
logger.debug("Returning empty result due to query execution failure")
|
|
67
66
|
return []
|
|
68
|
-
|
|
67
|
+
|
|
69
68
|
@staticmethod
|
|
70
|
-
def _execute_newest_api(query: Any, root_node: Any) ->
|
|
69
|
+
def _execute_newest_api(query: Any, root_node: Any) -> list[tuple[Any, str]]:
|
|
71
70
|
"""Execute query using newest API (tree-sitter 0.25+) with QueryCursor"""
|
|
72
71
|
captures = []
|
|
73
72
|
try:
|
|
74
73
|
import tree_sitter
|
|
74
|
+
|
|
75
75
|
cursor = tree_sitter.QueryCursor(query)
|
|
76
|
-
|
|
76
|
+
|
|
77
77
|
# Execute query and get matches
|
|
78
78
|
matches = cursor.matches(root_node)
|
|
79
79
|
# matches is a list of tuples: (pattern_index, captures_dict)
|
|
80
|
-
for
|
|
80
|
+
for _pattern_index, captures_dict in matches:
|
|
81
81
|
# captures_dict is {capture_name: [node1, node2, ...]}
|
|
82
82
|
for capture_name, nodes in captures_dict.items():
|
|
83
83
|
for node in nodes:
|
|
84
84
|
captures.append((node, capture_name))
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
except Exception as e:
|
|
87
87
|
logger.error(f"Newest API execution failed: {e}")
|
|
88
88
|
# Don't raise, just return empty result
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
return captures
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
@staticmethod
|
|
93
|
-
def _execute_modern_api(query: Any, root_node: Any) ->
|
|
93
|
+
def _execute_modern_api(query: Any, root_node: Any) -> list[tuple[Any, str]]:
|
|
94
94
|
"""Execute query using modern API (tree-sitter 0.20+)"""
|
|
95
95
|
captures = []
|
|
96
96
|
try:
|
|
@@ -103,9 +103,9 @@ class TreeSitterQueryCompat:
|
|
|
103
103
|
logger.error(f"Modern API execution failed: {e}")
|
|
104
104
|
raise
|
|
105
105
|
return captures
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
@staticmethod
|
|
108
|
-
def _execute_legacy_api(query: Any, root_node: Any) ->
|
|
108
|
+
def _execute_legacy_api(query: Any, root_node: Any) -> list[tuple[Any, str]]:
|
|
109
109
|
"""Execute query using legacy API (tree-sitter < 0.20)"""
|
|
110
110
|
captures = []
|
|
111
111
|
try:
|
|
@@ -117,71 +117,76 @@ class TreeSitterQueryCompat:
|
|
|
117
117
|
logger.error(f"Legacy API execution failed: {e}")
|
|
118
118
|
raise
|
|
119
119
|
return captures
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
@staticmethod
|
|
122
|
-
def _execute_old_api(query: Any, root_node: Any) ->
|
|
122
|
+
def _execute_old_api(query: Any, root_node: Any) -> list[tuple[Any, str]]:
|
|
123
123
|
"""Execute query using very old API (tree-sitter < 0.19)"""
|
|
124
124
|
captures = []
|
|
125
125
|
try:
|
|
126
126
|
# Try different old API patterns
|
|
127
|
-
if
|
|
127
|
+
if callable(query):
|
|
128
128
|
# Some very old versions had callable queries
|
|
129
129
|
query_result = query(root_node)
|
|
130
130
|
if isinstance(query_result, list):
|
|
131
131
|
for item in query_result:
|
|
132
132
|
if isinstance(item, tuple) and len(item) >= 2:
|
|
133
133
|
captures.append((item[0], str(item[1])))
|
|
134
|
-
elif hasattr(item,
|
|
134
|
+
elif hasattr(item, "node") and hasattr(item, "name"):
|
|
135
135
|
captures.append((item.node, item.name))
|
|
136
136
|
else:
|
|
137
137
|
# If no known API is available, return empty result
|
|
138
|
-
logger.warning(
|
|
139
|
-
|
|
138
|
+
logger.warning(
|
|
139
|
+
"No compatible tree-sitter query API found, returning empty result"
|
|
140
|
+
)
|
|
141
|
+
|
|
140
142
|
except Exception as e:
|
|
141
143
|
logger.error(f"Old API execution failed: {e}")
|
|
142
144
|
# Don't raise, just return empty result
|
|
143
|
-
|
|
145
|
+
|
|
144
146
|
return captures
|
|
145
|
-
|
|
147
|
+
|
|
146
148
|
@staticmethod
|
|
147
149
|
def safe_execute_query(
|
|
148
150
|
language: Any,
|
|
149
151
|
query_string: str,
|
|
150
152
|
root_node: Any,
|
|
151
|
-
fallback_result:
|
|
152
|
-
) ->
|
|
153
|
+
fallback_result: list[tuple[Any, str]] | None = None,
|
|
154
|
+
) -> list[tuple[Any, str]]:
|
|
153
155
|
"""
|
|
154
156
|
Safely execute a query with fallback handling.
|
|
155
|
-
|
|
157
|
+
|
|
156
158
|
Args:
|
|
157
159
|
language: Tree-sitter language object
|
|
158
160
|
query_string: Query string to execute
|
|
159
161
|
root_node: Root node to query against
|
|
160
162
|
fallback_result: Result to return if query fails
|
|
161
|
-
|
|
163
|
+
|
|
162
164
|
Returns:
|
|
163
165
|
List of (node, capture_name) tuples or fallback_result
|
|
164
166
|
"""
|
|
165
167
|
try:
|
|
166
|
-
return TreeSitterQueryCompat.execute_query(
|
|
168
|
+
return TreeSitterQueryCompat.execute_query(
|
|
169
|
+
language, query_string, root_node
|
|
170
|
+
)
|
|
167
171
|
except Exception as e:
|
|
168
172
|
logger.debug(f"Query execution failed, using fallback: {e}")
|
|
169
173
|
return fallback_result or []
|
|
170
174
|
|
|
171
175
|
|
|
172
|
-
def create_query_safely(language: Any, query_string: str) ->
|
|
176
|
+
def create_query_safely(language: Any, query_string: str) -> Any | None:
|
|
173
177
|
"""
|
|
174
178
|
Safely create a tree-sitter query object.
|
|
175
|
-
|
|
179
|
+
|
|
176
180
|
Args:
|
|
177
181
|
language: Tree-sitter language object
|
|
178
182
|
query_string: Query string
|
|
179
|
-
|
|
183
|
+
|
|
180
184
|
Returns:
|
|
181
185
|
Query object or None if creation fails
|
|
182
186
|
"""
|
|
183
187
|
try:
|
|
184
188
|
import tree_sitter
|
|
189
|
+
|
|
185
190
|
return tree_sitter.Query(language, query_string)
|
|
186
191
|
except Exception as e:
|
|
187
192
|
logger.debug(f"Query creation failed: {e}")
|
|
@@ -191,37 +196,39 @@ def create_query_safely(language: Any, query_string: str) -> Optional[Any]:
|
|
|
191
196
|
def get_node_text_safe(node: Any, source_code: str, encoding: str = "utf-8") -> str:
|
|
192
197
|
"""
|
|
193
198
|
Safely extract text from a tree-sitter node.
|
|
194
|
-
|
|
199
|
+
|
|
195
200
|
Args:
|
|
196
201
|
node: Tree-sitter node
|
|
197
202
|
source_code: Source code string
|
|
198
203
|
encoding: Text encoding
|
|
199
|
-
|
|
204
|
+
|
|
200
205
|
Returns:
|
|
201
206
|
Node text or empty string if extraction fails
|
|
202
207
|
"""
|
|
203
208
|
try:
|
|
204
209
|
# Try byte-based extraction first
|
|
205
|
-
if hasattr(node,
|
|
210
|
+
if hasattr(node, "start_byte") and hasattr(node, "end_byte"):
|
|
206
211
|
start_byte = node.start_byte
|
|
207
212
|
end_byte = node.end_byte
|
|
208
213
|
source_bytes = source_code.encode(encoding)
|
|
209
214
|
if start_byte <= end_byte <= len(source_bytes):
|
|
210
|
-
return source_bytes[start_byte:end_byte].decode(
|
|
211
|
-
|
|
215
|
+
return source_bytes[start_byte:end_byte].decode(
|
|
216
|
+
encoding, errors="replace"
|
|
217
|
+
)
|
|
218
|
+
|
|
212
219
|
# Fall back to node.text if available
|
|
213
|
-
if hasattr(node,
|
|
220
|
+
if hasattr(node, "text") and node.text:
|
|
214
221
|
if isinstance(node.text, bytes):
|
|
215
|
-
return node.text.decode(encoding, errors=
|
|
222
|
+
return node.text.decode(encoding, errors="replace")
|
|
216
223
|
else:
|
|
217
224
|
return str(node.text)
|
|
218
|
-
|
|
225
|
+
|
|
219
226
|
# Fall back to point-based extraction
|
|
220
|
-
if hasattr(node,
|
|
227
|
+
if hasattr(node, "start_point") and hasattr(node, "end_point"):
|
|
221
228
|
start_point = node.start_point
|
|
222
229
|
end_point = node.end_point
|
|
223
|
-
lines = source_code.split(
|
|
224
|
-
|
|
230
|
+
lines = source_code.split("\n")
|
|
231
|
+
|
|
225
232
|
if start_point[0] < len(lines) and end_point[0] < len(lines):
|
|
226
233
|
if start_point[0] == end_point[0]:
|
|
227
234
|
# Single line
|
|
@@ -242,10 +249,10 @@ def get_node_text_safe(node: Any, source_code: str, encoding: str = "utf-8") ->
|
|
|
242
249
|
result_lines.append(line[:end_col])
|
|
243
250
|
else:
|
|
244
251
|
result_lines.append(line)
|
|
245
|
-
return
|
|
246
|
-
|
|
252
|
+
return "\n".join(result_lines)
|
|
253
|
+
|
|
247
254
|
return ""
|
|
248
|
-
|
|
255
|
+
|
|
249
256
|
except Exception as e:
|
|
250
257
|
logger.debug(f"Node text extraction failed: {e}")
|
|
251
258
|
return ""
|
|
@@ -255,28 +262,28 @@ def log_api_info():
|
|
|
255
262
|
"""Log information about available tree-sitter APIs."""
|
|
256
263
|
try:
|
|
257
264
|
import tree_sitter
|
|
265
|
+
|
|
258
266
|
logger.debug("Tree-sitter library available")
|
|
259
|
-
|
|
267
|
+
|
|
260
268
|
# Check available APIs
|
|
261
269
|
try:
|
|
262
270
|
# Create a dummy query to test available methods
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
271
|
+
# We can't actually test without a language, so just check the class
|
|
272
|
+
|
|
266
273
|
# We can't actually test without a language, so just check the class
|
|
267
274
|
query_class = tree_sitter.Query
|
|
268
|
-
has_matches =
|
|
269
|
-
has_captures =
|
|
270
|
-
|
|
275
|
+
has_matches = "matches" in dir(query_class)
|
|
276
|
+
has_captures = "captures" in dir(query_class)
|
|
277
|
+
|
|
271
278
|
if has_matches:
|
|
272
279
|
logger.debug("Tree-sitter modern API (matches) available")
|
|
273
280
|
elif has_captures:
|
|
274
281
|
logger.debug("Tree-sitter legacy API (captures) available")
|
|
275
282
|
else:
|
|
276
283
|
logger.warning("No compatible tree-sitter API found")
|
|
277
|
-
|
|
284
|
+
|
|
278
285
|
except Exception as e:
|
|
279
286
|
logger.debug(f"API detection failed: {e}")
|
|
280
|
-
|
|
287
|
+
|
|
281
288
|
except ImportError:
|
|
282
|
-
logger.debug("Tree-sitter library not available")
|
|
289
|
+
logger.debug("Tree-sitter library not available")
|
tree_sitter_analyzer/utils.py
CHANGED
|
@@ -33,7 +33,7 @@ def setup_logger(
|
|
|
33
33
|
level = logging.ERROR
|
|
34
34
|
else:
|
|
35
35
|
level = logging.WARNING # Default fallback
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
# Get log level from environment variable (only if set and not empty)
|
|
38
38
|
env_level = os.environ.get("LOG_LEVEL", "").upper()
|
|
39
39
|
if env_level and env_level in ["DEBUG", "INFO", "WARNING", "ERROR"]:
|
|
@@ -48,13 +48,15 @@ def setup_logger(
|
|
|
48
48
|
# If env_level is empty or not recognized, use the passed level parameter
|
|
49
49
|
|
|
50
50
|
logger = logging.getLogger(name)
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# Clear existing handlers if this is a test logger to ensure clean state
|
|
53
53
|
if name.startswith("test_"):
|
|
54
54
|
logger.handlers.clear()
|
|
55
55
|
|
|
56
56
|
# Initialize file logging variables at function scope
|
|
57
|
-
enable_file_log =
|
|
57
|
+
enable_file_log = (
|
|
58
|
+
os.environ.get("TREE_SITTER_ANALYZER_ENABLE_FILE_LOG", "").lower() == "true"
|
|
59
|
+
)
|
|
58
60
|
file_log_level = level # Default to main logger level
|
|
59
61
|
|
|
60
62
|
if not logger.handlers: # Avoid duplicate handlers
|
|
@@ -82,10 +84,17 @@ def setup_logger(
|
|
|
82
84
|
# Use system temporary directory
|
|
83
85
|
temp_dir = tempfile.gettempdir()
|
|
84
86
|
log_path = Path(temp_dir) / "tree_sitter_analyzer.log"
|
|
85
|
-
|
|
87
|
+
|
|
86
88
|
# Determine file log level
|
|
87
|
-
file_log_level_str = os.environ.get(
|
|
88
|
-
|
|
89
|
+
file_log_level_str = os.environ.get(
|
|
90
|
+
"TREE_SITTER_ANALYZER_FILE_LOG_LEVEL", ""
|
|
91
|
+
).upper()
|
|
92
|
+
if file_log_level_str and file_log_level_str in [
|
|
93
|
+
"DEBUG",
|
|
94
|
+
"INFO",
|
|
95
|
+
"WARNING",
|
|
96
|
+
"ERROR",
|
|
97
|
+
]:
|
|
89
98
|
if file_log_level_str == "DEBUG":
|
|
90
99
|
file_log_level = logging.DEBUG
|
|
91
100
|
elif file_log_level_str == "INFO":
|
|
@@ -97,19 +106,21 @@ def setup_logger(
|
|
|
97
106
|
else:
|
|
98
107
|
# Use same level as main logger
|
|
99
108
|
file_log_level = level
|
|
100
|
-
|
|
109
|
+
|
|
101
110
|
file_handler = logging.FileHandler(str(log_path), encoding="utf-8")
|
|
102
111
|
file_handler.setFormatter(formatter)
|
|
103
112
|
file_handler.setLevel(file_log_level)
|
|
104
113
|
logger.addHandler(file_handler)
|
|
105
|
-
|
|
114
|
+
|
|
106
115
|
# Log the file location for debugging purposes
|
|
107
116
|
if hasattr(sys, "stderr") and hasattr(sys.stderr, "write"):
|
|
108
117
|
try:
|
|
109
|
-
sys.stderr.write(
|
|
118
|
+
sys.stderr.write(
|
|
119
|
+
f"[logging_setup] File logging enabled: {log_path}\n"
|
|
120
|
+
)
|
|
110
121
|
except Exception:
|
|
111
122
|
...
|
|
112
|
-
|
|
123
|
+
|
|
113
124
|
except Exception as e:
|
|
114
125
|
# Never let logging configuration break runtime behavior; log to stderr if possible
|
|
115
126
|
if hasattr(sys, "stderr") and hasattr(sys.stderr, "write"):
|
|
@@ -126,9 +137,9 @@ def setup_logger(
|
|
|
126
137
|
if enable_file_log:
|
|
127
138
|
# Use the minimum level to ensure all messages reach their intended handlers
|
|
128
139
|
final_level = min(level, file_log_level)
|
|
129
|
-
|
|
140
|
+
|
|
130
141
|
logger.setLevel(final_level)
|
|
131
|
-
|
|
142
|
+
|
|
132
143
|
# For test loggers, ensure they don't inherit from parent and force level
|
|
133
144
|
if logger.name.startswith("test_"):
|
|
134
145
|
logger.propagate = False
|
|
@@ -162,8 +173,8 @@ class SafeStreamHandler(logging.StreamHandler):
|
|
|
162
173
|
|
|
163
174
|
# Special handling for pytest capture scenarios
|
|
164
175
|
# Check if this is a pytest capture stream that might be problematic
|
|
165
|
-
stream_name = getattr(self.stream,
|
|
166
|
-
if stream_name is None or
|
|
176
|
+
stream_name = getattr(self.stream, "name", "")
|
|
177
|
+
if stream_name is None or "pytest" in str(type(self.stream)).lower():
|
|
167
178
|
# For pytest streams, be extra cautious
|
|
168
179
|
try:
|
|
169
180
|
# Just try to emit without any pre-checks
|
|
@@ -342,7 +353,7 @@ def safe_print(message: str | None, level: str = "info", quiet: bool = False) ->
|
|
|
342
353
|
|
|
343
354
|
# Handle None message by converting to string - always call log function even for None
|
|
344
355
|
msg = str(message) if message is not None else "None"
|
|
345
|
-
|
|
356
|
+
|
|
346
357
|
# Use dynamic lookup to support mocking
|
|
347
358
|
level_lower = level.lower()
|
|
348
359
|
if level_lower == "info":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tree-sitter-analyzer
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.9.0
|
|
4
4
|
Summary: AI-era enterprise-grade code analysis tool with comprehensive HTML/CSS support, dynamic plugin architecture, and MCP integration
|
|
5
5
|
Project-URL: Homepage, https://github.com/aimasteracc/tree-sitter-analyzer
|
|
6
6
|
Project-URL: Documentation, https://github.com/aimasteracc/tree-sitter-analyzer#readme
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
tree_sitter_analyzer/__init__.py,sha256=0MHpJmMcjVenxRRk4tpuSe8gRs2A0STrXYh1G7qo6bI,3067
|
|
2
|
+
tree_sitter_analyzer/__main__.py,sha256=Zl79tpe4UaMu-7yeztc06tgP0CVMRnvGgas4ZQP5SCs,228
|
|
3
|
+
tree_sitter_analyzer/api.py,sha256=y12xDnqvdNJdiG6GyqVdZBunmBLwfIjVgsCy0jjGOds,22129
|
|
4
|
+
tree_sitter_analyzer/cli_main.py,sha256=AmKeZIUCSI8Gshbz_e1Niquf4pFbpPgtOTwQdLbQgcw,11093
|
|
5
|
+
tree_sitter_analyzer/constants.py,sha256=7w3sLFt_6vPaKsxzrc21K1rOKpLGMyyA1203nu3pDOQ,1889
|
|
6
|
+
tree_sitter_analyzer/encoding_utils.py,sha256=NHkqOt7GdrxgMsd3k0rVxSO0mWJZXODw3uwl2Qk9ufc,14803
|
|
7
|
+
tree_sitter_analyzer/exceptions.py,sha256=3Djpca6j9CZ97zYOLP5upp_vzlMFbmfy2ZFpb1htp8k,22948
|
|
8
|
+
tree_sitter_analyzer/file_handler.py,sha256=TTaPZ2u8GvgAoj9-uM03IlKFaZfBEHTHzaDQrGu7qRU,7118
|
|
9
|
+
tree_sitter_analyzer/language_detector.py,sha256=Qw_35aYpZhHoj_IWDbIvJGmFWTRlrAD1-lFWAoxib5w,16116
|
|
10
|
+
tree_sitter_analyzer/language_loader.py,sha256=_5rON5hSlcBehMsAPu334KeqfguHBz0_Hm5hvROtDPo,9012
|
|
11
|
+
tree_sitter_analyzer/models.py,sha256=61RlViv_Q4Kqtzv44JSxc3qCYLrocgzPUmoOSdyPFgA,22165
|
|
12
|
+
tree_sitter_analyzer/output_manager.py,sha256=hRAp6Aa9k05UVvZkOyRCEz2Lf7blx05fWnculHd86RA,8264
|
|
13
|
+
tree_sitter_analyzer/project_detector.py,sha256=-zmtm12EvVD_6TDxS_6KpzuswP2Bpppnxq50kAEDyMA,9430
|
|
14
|
+
tree_sitter_analyzer/query_loader.py,sha256=zBBTkx-5a59-zB8jXvsVNvT1md4t2n_Vfxhw-5ebjPw,10346
|
|
15
|
+
tree_sitter_analyzer/table_formatter.py,sha256=tPKw77LLlQ7k5MMs9_Ez7qsSroNaSzZPoplyPtKHLhA,28577
|
|
16
|
+
tree_sitter_analyzer/utils.py,sha256=zqd92pKu3qBt1hhKvKFOmm6zve3sZ5AT2OJ4ExA2uns,16225
|
|
17
|
+
tree_sitter_analyzer/cli/__init__.py,sha256=O_3URpbdu5Ilb2-r48LjbZuWtOWQu_BhL3pa6C0G3Bk,871
|
|
18
|
+
tree_sitter_analyzer/cli/__main__.py,sha256=Xq8o8-0dPnMDU9WZqmqhzr98rx8rvoffTUHAkAwl-L8,218
|
|
19
|
+
tree_sitter_analyzer/cli/argument_validator.py,sha256=NrTXRazgWzDGEcB1J2Q8VRrBT3v97VRY74wnIMwRBcM,2623
|
|
20
|
+
tree_sitter_analyzer/cli/info_commands.py,sha256=kwnqs1dKKtZDS1WLMLurBwnC_9W0-8oOrDHCE0J5Z2M,4434
|
|
21
|
+
tree_sitter_analyzer/cli/commands/__init__.py,sha256=jpcpM1ptLuxLMBDUv1y_a87k8RAw1otFzeYpWtXvz3Y,671
|
|
22
|
+
tree_sitter_analyzer/cli/commands/advanced_command.py,sha256=w5sTaVjIDrUHlGEU9JZgZXpbcUhBvTwWoOYxsvAQI2U,11466
|
|
23
|
+
tree_sitter_analyzer/cli/commands/base_command.py,sha256=MGlRA6sIcMt6ta-07NOFcPz8-eUwwS2g-JlBVYn105s,6611
|
|
24
|
+
tree_sitter_analyzer/cli/commands/default_command.py,sha256=RAR_eaOK3EndIqU7QL5UAn44mwyhItTN7aUaKL1WmSc,524
|
|
25
|
+
tree_sitter_analyzer/cli/commands/find_and_grep_cli.py,sha256=Kg5H11FB7dEOS9Ors41T89roJjuwJ4t26n_Dv2ra5Og,6290
|
|
26
|
+
tree_sitter_analyzer/cli/commands/list_files_cli.py,sha256=rgeP3PFrBYhebvnWJ7dOEFmtpwvGmAacq8VfxZyPNzE,3842
|
|
27
|
+
tree_sitter_analyzer/cli/commands/partial_read_command.py,sha256=lbuy9X_q5pyf_cJXVvx_AYJg_tfxF1R0U93Is-MVW_A,4619
|
|
28
|
+
tree_sitter_analyzer/cli/commands/query_command.py,sha256=VFuCFJxffjSUrMa7NB_KJmMexUnJmnazpTDbw-i9Ulw,4003
|
|
29
|
+
tree_sitter_analyzer/cli/commands/search_content_cli.py,sha256=A30806cWaBfqfchhIZ0qK23cfoIQTTYk33Y119TGx34,5093
|
|
30
|
+
tree_sitter_analyzer/cli/commands/structure_command.py,sha256=UuCgqktBW4WwhaDjo-zowOfGMi4xGCJo96ZQAL8aDA4,8008
|
|
31
|
+
tree_sitter_analyzer/cli/commands/summary_command.py,sha256=REyXPS02O4-qu5giLoLu9w4Nh3Qy48qkP0mabhFNib4,6361
|
|
32
|
+
tree_sitter_analyzer/cli/commands/table_command.py,sha256=PE54jlEBE4jNFm1OvBH31-aGGq2Z2JrFWLHevYuML00,12282
|
|
33
|
+
tree_sitter_analyzer/core/__init__.py,sha256=VlYOy1epW16vjaVd__knESewnU0sfXF9a4hjrFxiSEE,440
|
|
34
|
+
tree_sitter_analyzer/core/analysis_engine.py,sha256=8J6p9HoSUjHA5u3lwJc9IHzLN_vFmdLoKej5u_jloUs,18827
|
|
35
|
+
tree_sitter_analyzer/core/cache_service.py,sha256=1qRApzdnwXn5TPY6D7VBMOPD14q3ppBcdnuR6Xk4SZw,10253
|
|
36
|
+
tree_sitter_analyzer/core/engine.py,sha256=5CheLzsxrApY6o2uM8sdYdzK4HkQypxlsYEFpUdai28,18357
|
|
37
|
+
tree_sitter_analyzer/core/parser.py,sha256=qT3yIlTRdod4tf_2o1hU_B-GYGukyM2BtaFxzSoxois,9293
|
|
38
|
+
tree_sitter_analyzer/core/query.py,sha256=44V1_4O6YMe5lBCnsghmSH3PGfph4Cv3494LHfvwOX0,17339
|
|
39
|
+
tree_sitter_analyzer/core/query_filter.py,sha256=PvGztAZFooFNZe6iHNmbg6RUNtMvq6f6hBZFzllig6Y,6591
|
|
40
|
+
tree_sitter_analyzer/core/query_service.py,sha256=DJRwKT_gvpK4t2fbe5wBRKoqa1r_ztxtzmLYq2-L5BU,12773
|
|
41
|
+
tree_sitter_analyzer/formatters/__init__.py,sha256=yVb4HF_4EEPRwTf3y3-vM2NllrhykG3zlvQhN-6dB4c,31
|
|
42
|
+
tree_sitter_analyzer/formatters/base_formatter.py,sha256=e3LQ9p3_XyaPSx1jevO7eo8r-fHimu4wuC_uUKgSijg,6698
|
|
43
|
+
tree_sitter_analyzer/formatters/formatter_factory.py,sha256=4fsSMxhBmGWFmPjcuwkTvgiIWWFireaOaChYi1UNnSM,2381
|
|
44
|
+
tree_sitter_analyzer/formatters/formatter_registry.py,sha256=_3z1nsiV3eqrAq8NZ53aUUBGBXqjibDvbTXElR2yHf0,11479
|
|
45
|
+
tree_sitter_analyzer/formatters/html_formatter.py,sha256=mleWyMEkzGl3wLexnsTDONnp2vxkenVjUMT6_7rxlxA,19008
|
|
46
|
+
tree_sitter_analyzer/formatters/java_formatter.py,sha256=0jxKfrWtsr_K2VG1zW0LH2E6w6nfpIhcXTfIyWw3Jmc,11163
|
|
47
|
+
tree_sitter_analyzer/formatters/javascript_formatter.py,sha256=31cbf4UldSdZXxZzcC5faEczkedVHcK9Mlq7lp74tKk,21320
|
|
48
|
+
tree_sitter_analyzer/formatters/language_formatter_factory.py,sha256=dIfeCb82huRBzhl0M111rkihhPp_sr0CKcXUwg76BU8,2288
|
|
49
|
+
tree_sitter_analyzer/formatters/markdown_formatter.py,sha256=ktmWscxJQykXDfjTJS1E0Yc26I_Rbq_pQZXVhPghyRA,27543
|
|
50
|
+
tree_sitter_analyzer/formatters/python_formatter.py,sha256=XWiMW6ycvrZOUQ-OAFCrnw4w6ES04016XE06ia8Ej4o,17282
|
|
51
|
+
tree_sitter_analyzer/formatters/typescript_formatter.py,sha256=oWEQV9Zk1Kklz68Zo_Hi0xwPVeDIsDPf_MzXhoOhOD0,20380
|
|
52
|
+
tree_sitter_analyzer/interfaces/__init__.py,sha256=OcT7eNIU0ZXvAeAXbhDqRG3puxn93HeSLqplwj6npTM,271
|
|
53
|
+
tree_sitter_analyzer/interfaces/cli.py,sha256=c6CGfF6cgOwgpBimHV1myZ5JfNqil5tCVBOfG5-zijU,17100
|
|
54
|
+
tree_sitter_analyzer/interfaces/cli_adapter.py,sha256=8j3xL3k6wWrGQCq0KCntqbvSxKy931sT5M96pYhkn9c,11402
|
|
55
|
+
tree_sitter_analyzer/interfaces/mcp_adapter.py,sha256=iSWcm-bn8_pL6YBu1Rrzherv72-5WUiavColu3uhSAY,7707
|
|
56
|
+
tree_sitter_analyzer/interfaces/mcp_server.py,sha256=eJH0s-T_n-jJK09MJ7UpxkXIvhax7dhW0Z3ms5B-RE4,16563
|
|
57
|
+
tree_sitter_analyzer/languages/__init__.py,sha256=VTXxJgVjHJAciLhX0zzXOS4EygZMtebeYUbi_0z6fGw,340
|
|
58
|
+
tree_sitter_analyzer/languages/css_plugin.py,sha256=5oF6PQ9toZTb8HGeAfbvT9SU5nITuI5mDCi_w9pF3S4,16296
|
|
59
|
+
tree_sitter_analyzer/languages/html_plugin.py,sha256=Xe__Gdwp4Yd-DdHVbdMlVyryQ6YW649yjjXsbNezqFo,17754
|
|
60
|
+
tree_sitter_analyzer/languages/java_plugin.py,sha256=u3mK7h6nz5w4xS6yek4aKiHVjpB5eBBKCp3Ecnu4tU0,57798
|
|
61
|
+
tree_sitter_analyzer/languages/javascript_plugin.py,sha256=JQ5wniSpYR9P6NluPv8vwjjk8qUZLSRwiOlOuD4fr6w,62398
|
|
62
|
+
tree_sitter_analyzer/languages/markdown_plugin.py,sha256=0bvE4mErqMYOfFRpFERJ6nUuGCaBiAjX5Gb14OwlJwI,79252
|
|
63
|
+
tree_sitter_analyzer/languages/python_plugin.py,sha256=kWL7__Je864jOrXPDTd-16mhP-s5l2QPp5sf66hLRg4,60998
|
|
64
|
+
tree_sitter_analyzer/languages/typescript_plugin.py,sha256=ug0RBlaW9aKT7SNF-TLafL6aVwao1Dm3jrBptxdgzmk,76372
|
|
65
|
+
tree_sitter_analyzer/mcp/__init__.py,sha256=8tC54ZYcZBcFEio-aDet7evzis50zV5gbHuvn_7K514,944
|
|
66
|
+
tree_sitter_analyzer/mcp/server.py,sha256=rESZ7p7i1z7MospY_Ze-bDLUg5dqpNzOQ3NudX7-wo4,32026
|
|
67
|
+
tree_sitter_analyzer/mcp/resources/__init__.py,sha256=D46ZDhPQaCrQze8dHmijMg1QZQ4ABRIjG532sFpuGPo,1367
|
|
68
|
+
tree_sitter_analyzer/mcp/resources/code_file_resource.py,sha256=ZX5ZYSJfylBedpL80kTDlco2YZqgRMb5f3OW0VvOVRM,6166
|
|
69
|
+
tree_sitter_analyzer/mcp/resources/project_stats_resource.py,sha256=YF_LyYwt1uoJx27FvWbVSbIaS5c5RDO-73QL_DfNwTE,20360
|
|
70
|
+
tree_sitter_analyzer/mcp/tools/__init__.py,sha256=9KfetZTaUhvWTeKuZPYzWb7ZomFQ8SsR1qmXVBT4E7c,739
|
|
71
|
+
tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py,sha256=5IobTL2LuzYalJhIBbk_8QV2ehGGPRbyNO71ECYLmLs,30966
|
|
72
|
+
tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py,sha256=mssed7bEfGeGxW4mOf7dg8BDS1oqHLolIBNX9DaZ3DM,8997
|
|
73
|
+
tree_sitter_analyzer/mcp/tools/base_tool.py,sha256=K02l34Yn6brgg45yIXuSsRPB4Cp870ba86ZBlSU4OW8,3689
|
|
74
|
+
tree_sitter_analyzer/mcp/tools/fd_rg_utils.py,sha256=MOuxAcunj4q0NUCSgrR-tBzE0zcHPk3WTHSy1XKvVmY,25069
|
|
75
|
+
tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py,sha256=if_P_rRqH72WGl845lCJ-aorb7nSOhnvh0cYPqdXje0,32126
|
|
76
|
+
tree_sitter_analyzer/mcp/tools/list_files_tool.py,sha256=o66KKI2IkObU8qD3bhWKGcuytjCjxuENlxKdLV4NGkg,18187
|
|
77
|
+
tree_sitter_analyzer/mcp/tools/query_tool.py,sha256=XOP21uVKe1J7ayiUnJJBUGls1QTJ5K0GoZ4HlbOr5YE,16887
|
|
78
|
+
tree_sitter_analyzer/mcp/tools/read_partial_tool.py,sha256=O7UyZSNW5_-5hGOkO9xiw4qDY5WKvHtTiGQ_WjhAIA8,18305
|
|
79
|
+
tree_sitter_analyzer/mcp/tools/search_content_tool.py,sha256=EY--l25VEKfbymP44ozWlfsfNTy94YEu1_3-vVrL6dY,35193
|
|
80
|
+
tree_sitter_analyzer/mcp/tools/table_format_tool.py,sha256=48zTj1AthSLfRT9KHzum332pKy3R2uxjGdw1omkzgfY,22853
|
|
81
|
+
tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py,sha256=-zZnqN9WcoyRTKM_16ADH859LSebzi34BGYwQL2zCOs,25084
|
|
82
|
+
tree_sitter_analyzer/mcp/utils/__init__.py,sha256=TgTTKsRJAqF95g1fAp5SR_zQVDkImpc_5R0Dw529UUw,3126
|
|
83
|
+
tree_sitter_analyzer/mcp/utils/error_handler.py,sha256=msrQHX67K3vhJsEc3OPRz5mmWU_yoHz55Lnxy0IZuy4,18404
|
|
84
|
+
tree_sitter_analyzer/mcp/utils/file_output_factory.py,sha256=6yRWBzJuUsYxp7iZhxiSNZ4go1t3wbg8WHuKzDs57Qc,7392
|
|
85
|
+
tree_sitter_analyzer/mcp/utils/file_output_manager.py,sha256=LDNdrv5xm99nIIuUfc6Qdx70_weXL24d-IjJFEme0rk,10790
|
|
86
|
+
tree_sitter_analyzer/mcp/utils/gitignore_detector.py,sha256=aGMulltlqoh1js6F8-rWvGkRZSqQSAgBKHqlDsQWvrM,11978
|
|
87
|
+
tree_sitter_analyzer/mcp/utils/path_resolver.py,sha256=77BmbyEuJCuDPNH9POcTOS4tYBorPu-IXFGpBC1DxOk,15006
|
|
88
|
+
tree_sitter_analyzer/mcp/utils/search_cache.py,sha256=ZNv84st6PeejDY1B50AKTbItpXs9HS6JrpR-Ozjyc1c,12991
|
|
89
|
+
tree_sitter_analyzer/plugins/__init__.py,sha256=ITE9bTz7NO4axnn8g5Z-1_ydhSLT0RnY6Y1J9OhUP3E,10326
|
|
90
|
+
tree_sitter_analyzer/plugins/base.py,sha256=wdsXUeQezaIW2Tk_3k7pz8fMnxE-M0Z6IVl-ejRNijI,18613
|
|
91
|
+
tree_sitter_analyzer/plugins/manager.py,sha256=ccypwnU88ClN8mCRSAzXWL_ihNr0UZ-m7XDFNy0kVwg,12719
|
|
92
|
+
tree_sitter_analyzer/queries/__init__.py,sha256=dwDDc7PCw_UWruxSeJ8uEBjY0O5uLDBI5YqyvBhbnN0,696
|
|
93
|
+
tree_sitter_analyzer/queries/css.py,sha256=az5BPZFG2YPI-YbJk1gQXNhpu2ydnyvMaMxA4azpFmQ,17778
|
|
94
|
+
tree_sitter_analyzer/queries/html.py,sha256=QIBs18hJfWNfmjPbcglnq2jsDhvfF1zkNG3KpVzfHIU,14552
|
|
95
|
+
tree_sitter_analyzer/queries/java.py,sha256=avaPFeHz3Ig-yTdCDKfUKaG-5sktOEkrXG2p9_mEZVs,12388
|
|
96
|
+
tree_sitter_analyzer/queries/javascript.py,sha256=XeIreI10rz__viix3zGCENCfC3yLT4ZQCp8DpYnbXKU,23104
|
|
97
|
+
tree_sitter_analyzer/queries/markdown.py,sha256=N8ttqfvvVK-zcEUR1TcG9zLpJKIwl4HzPIIZ8fVQZJo,6938
|
|
98
|
+
tree_sitter_analyzer/queries/python.py,sha256=VBLw-J5DLPi6JcQ4QIw0RzjiIrG20UVB-28WOTB5IAk,26171
|
|
99
|
+
tree_sitter_analyzer/queries/typescript.py,sha256=I0bWcCv-sRcZHVsdHdfb1UIRI_G3l0S9A1oR4LCjLwE,22527
|
|
100
|
+
tree_sitter_analyzer/security/__init__.py,sha256=ZTqTt24hsljCpTXAZpJC57L7MU5lJLTf_XnlvEzXwEE,623
|
|
101
|
+
tree_sitter_analyzer/security/boundary_manager.py,sha256=3eeENRKWtz2pyZHzd8DiVaq8fdeC6s1eVOuBylSmQPg,9347
|
|
102
|
+
tree_sitter_analyzer/security/regex_checker.py,sha256=jWK6H8PTPgzbwRPfK_RZ8bBTS6rtEbgjY5vr3YWjQ_U,9616
|
|
103
|
+
tree_sitter_analyzer/security/validator.py,sha256=OIrlMmIqrfpG7FxrI9_xR6g3sgPpJyWPFfYiWma7Rkk,21708
|
|
104
|
+
tree_sitter_analyzer/utils/__init__.py,sha256=ch_TjuMxxdGF9dDBOP_sYVGVZaMXzgGS1FOFn3sicHA,3863
|
|
105
|
+
tree_sitter_analyzer/utils/tree_sitter_compat.py,sha256=p565DG7r5sHK2GgZFyj7X4eLwpWujaN_M61Z3oDqAxE,10610
|
|
106
|
+
tree_sitter_analyzer-1.9.0.dist-info/METADATA,sha256=glMRTV71CBuIhCu3sJZAnvHzt5fcuBoEIO5u81BvgPI,49119
|
|
107
|
+
tree_sitter_analyzer-1.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
108
|
+
tree_sitter_analyzer-1.9.0.dist-info/entry_points.txt,sha256=TJmEXxAMz3og3VPphTHsuE8tNJxf7GuAPjNHwVhXRnc,972
|
|
109
|
+
tree_sitter_analyzer-1.9.0.dist-info/RECORD,,
|