tree-sitter-analyzer 0.6.2__py3-none-any.whl → 0.8.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 +132 -132
- tree_sitter_analyzer/__main__.py +11 -11
- tree_sitter_analyzer/api.py +533 -533
- tree_sitter_analyzer/cli/__init__.py +39 -39
- tree_sitter_analyzer/cli/__main__.py +12 -12
- tree_sitter_analyzer/cli/commands/__init__.py +26 -26
- tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
- tree_sitter_analyzer/cli/commands/base_command.py +160 -160
- tree_sitter_analyzer/cli/commands/default_command.py +18 -18
- tree_sitter_analyzer/cli/commands/partial_read_command.py +141 -141
- tree_sitter_analyzer/cli/commands/query_command.py +81 -81
- tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
- tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
- tree_sitter_analyzer/cli/commands/table_command.py +235 -235
- tree_sitter_analyzer/cli/info_commands.py +121 -121
- tree_sitter_analyzer/cli_main.py +297 -297
- tree_sitter_analyzer/core/__init__.py +15 -15
- tree_sitter_analyzer/core/analysis_engine.py +555 -555
- tree_sitter_analyzer/core/cache_service.py +320 -320
- tree_sitter_analyzer/core/engine.py +566 -566
- tree_sitter_analyzer/core/parser.py +293 -293
- tree_sitter_analyzer/encoding_utils.py +459 -459
- tree_sitter_analyzer/exceptions.py +406 -337
- tree_sitter_analyzer/file_handler.py +210 -210
- tree_sitter_analyzer/formatters/__init__.py +1 -1
- tree_sitter_analyzer/formatters/base_formatter.py +167 -167
- tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
- tree_sitter_analyzer/interfaces/__init__.py +9 -9
- tree_sitter_analyzer/interfaces/cli.py +528 -528
- tree_sitter_analyzer/interfaces/cli_adapter.py +343 -343
- tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
- tree_sitter_analyzer/interfaces/mcp_server.py +425 -405
- tree_sitter_analyzer/languages/__init__.py +10 -10
- tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
- tree_sitter_analyzer/languages/python_plugin.py +755 -755
- tree_sitter_analyzer/mcp/__init__.py +31 -31
- tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
- tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
- tree_sitter_analyzer/mcp/server.py +346 -333
- tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +654 -654
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -247
- tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +300 -300
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +362 -362
- tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +543 -543
- tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
- tree_sitter_analyzer/mcp/utils/error_handler.py +549 -549
- tree_sitter_analyzer/output_manager.py +253 -253
- tree_sitter_analyzer/plugins/__init__.py +280 -280
- tree_sitter_analyzer/plugins/base.py +529 -529
- tree_sitter_analyzer/plugins/manager.py +379 -379
- tree_sitter_analyzer/queries/__init__.py +26 -26
- tree_sitter_analyzer/queries/java.py +391 -391
- tree_sitter_analyzer/queries/javascript.py +148 -148
- tree_sitter_analyzer/queries/python.py +285 -285
- tree_sitter_analyzer/queries/typescript.py +229 -229
- tree_sitter_analyzer/query_loader.py +257 -257
- tree_sitter_analyzer/security/__init__.py +22 -0
- tree_sitter_analyzer/security/boundary_manager.py +237 -0
- tree_sitter_analyzer/security/regex_checker.py +292 -0
- tree_sitter_analyzer/security/validator.py +224 -0
- tree_sitter_analyzer/table_formatter.py +652 -473
- tree_sitter_analyzer/utils.py +277 -277
- {tree_sitter_analyzer-0.6.2.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/METADATA +4 -1
- tree_sitter_analyzer-0.8.0.dist-info/RECORD +76 -0
- tree_sitter_analyzer-0.6.2.dist-info/RECORD +0 -72
- {tree_sitter_analyzer-0.6.2.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-0.6.2.dist-info → tree_sitter_analyzer-0.8.0.dist-info}/entry_points.txt +0 -0
tree_sitter_analyzer/utils.py
CHANGED
|
@@ -1,277 +1,277 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Utilities for Tree-sitter Analyzer
|
|
4
|
-
|
|
5
|
-
Provides logging, debugging, and common utility functions.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import atexit
|
|
9
|
-
import logging
|
|
10
|
-
import sys
|
|
11
|
-
from functools import wraps
|
|
12
|
-
from typing import Any
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# Configure global logger
|
|
16
|
-
def setup_logger(
|
|
17
|
-
name: str = "tree_sitter_analyzer", level: int = logging.INFO
|
|
18
|
-
) -> logging.Logger:
|
|
19
|
-
"""Setup unified logger for the project"""
|
|
20
|
-
import os
|
|
21
|
-
|
|
22
|
-
# Get log level from environment variable
|
|
23
|
-
env_level = os.environ.get("LOG_LEVEL", "").upper()
|
|
24
|
-
if env_level == "DEBUG":
|
|
25
|
-
level = logging.DEBUG
|
|
26
|
-
elif env_level == "INFO":
|
|
27
|
-
level = logging.INFO
|
|
28
|
-
elif env_level == "WARNING":
|
|
29
|
-
level = logging.WARNING
|
|
30
|
-
elif env_level == "ERROR":
|
|
31
|
-
level = logging.ERROR
|
|
32
|
-
|
|
33
|
-
logger = logging.getLogger(name)
|
|
34
|
-
|
|
35
|
-
if not logger.handlers: # Avoid duplicate handlers
|
|
36
|
-
# Create a safe handler that won't fail on closed streams
|
|
37
|
-
handler = SafeStreamHandler(sys.stdout)
|
|
38
|
-
formatter = logging.Formatter(
|
|
39
|
-
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
40
|
-
)
|
|
41
|
-
handler.setFormatter(formatter)
|
|
42
|
-
logger.addHandler(handler)
|
|
43
|
-
logger.setLevel(level)
|
|
44
|
-
|
|
45
|
-
return logger
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class SafeStreamHandler(logging.StreamHandler):
|
|
49
|
-
"""
|
|
50
|
-
A StreamHandler that safely handles closed streams
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
def emit(self, record: Any) -> None:
|
|
54
|
-
"""
|
|
55
|
-
Emit a record, safely handling closed streams
|
|
56
|
-
"""
|
|
57
|
-
try:
|
|
58
|
-
# Check if stream is closed before writing
|
|
59
|
-
if hasattr(self.stream, "closed") and self.stream.closed:
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
# Check if we can write to the stream
|
|
63
|
-
if not hasattr(self.stream, "write"):
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
super().emit(record)
|
|
67
|
-
except (ValueError, OSError, AttributeError):
|
|
68
|
-
# Silently ignore I/O errors during shutdown
|
|
69
|
-
pass
|
|
70
|
-
except Exception:
|
|
71
|
-
# For any other unexpected errors, use handleError
|
|
72
|
-
self.handleError(record)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def setup_safe_logging_shutdown() -> None:
|
|
76
|
-
"""
|
|
77
|
-
Setup safe logging shutdown to prevent I/O errors
|
|
78
|
-
"""
|
|
79
|
-
|
|
80
|
-
def cleanup_logging() -> None:
|
|
81
|
-
"""Clean up logging handlers safely"""
|
|
82
|
-
try:
|
|
83
|
-
# Get all loggers
|
|
84
|
-
loggers = [logging.getLogger()] + [
|
|
85
|
-
logging.getLogger(name) for name in logging.Logger.manager.loggerDict
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
for logger in loggers:
|
|
89
|
-
for handler in logger.handlers[:]:
|
|
90
|
-
try:
|
|
91
|
-
handler.close()
|
|
92
|
-
logger.removeHandler(handler)
|
|
93
|
-
except Exception:
|
|
94
|
-
pass
|
|
95
|
-
except Exception:
|
|
96
|
-
pass
|
|
97
|
-
|
|
98
|
-
# Register cleanup function
|
|
99
|
-
atexit.register(cleanup_logging)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# Setup safe shutdown on import
|
|
103
|
-
setup_safe_logging_shutdown()
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
# Global logger instance
|
|
107
|
-
logger = setup_logger()
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def log_info(message: str, *args: Any, **kwargs: Any) -> None:
|
|
111
|
-
"""Log info message"""
|
|
112
|
-
try:
|
|
113
|
-
logger.info(message, *args, **kwargs)
|
|
114
|
-
except (ValueError, OSError):
|
|
115
|
-
pass # Silently ignore I/O errors
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def log_warning(message: str, *args: Any, **kwargs: Any) -> None:
|
|
119
|
-
"""Log warning message"""
|
|
120
|
-
try:
|
|
121
|
-
logger.warning(message, *args, **kwargs)
|
|
122
|
-
except (ValueError, OSError):
|
|
123
|
-
pass # Silently ignore I/O errors
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def log_error(message: str, *args: Any, **kwargs: Any) -> None:
|
|
127
|
-
"""Log error message"""
|
|
128
|
-
try:
|
|
129
|
-
logger.error(message, *args, **kwargs)
|
|
130
|
-
except (ValueError, OSError):
|
|
131
|
-
pass # Silently ignore I/O errors
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def log_debug(message: str, *args: Any, **kwargs: Any) -> None:
|
|
135
|
-
"""Log debug message"""
|
|
136
|
-
try:
|
|
137
|
-
logger.debug(message, *args, **kwargs)
|
|
138
|
-
except (ValueError, OSError):
|
|
139
|
-
pass # Silently ignore I/O errors
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def suppress_output(func: Any) -> Any:
|
|
143
|
-
"""Decorator to suppress print statements in production"""
|
|
144
|
-
|
|
145
|
-
@wraps(func)
|
|
146
|
-
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
147
|
-
# Check if we're in test/debug mode
|
|
148
|
-
if getattr(sys, "_testing", False):
|
|
149
|
-
return func(*args, **kwargs)
|
|
150
|
-
|
|
151
|
-
# Redirect stdout to suppress prints
|
|
152
|
-
old_stdout = sys.stdout
|
|
153
|
-
try:
|
|
154
|
-
sys.stdout = (
|
|
155
|
-
open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
|
|
156
|
-
)
|
|
157
|
-
result = func(*args, **kwargs)
|
|
158
|
-
finally:
|
|
159
|
-
try:
|
|
160
|
-
sys.stdout.close()
|
|
161
|
-
except Exception:
|
|
162
|
-
pass
|
|
163
|
-
sys.stdout = old_stdout
|
|
164
|
-
|
|
165
|
-
return result
|
|
166
|
-
|
|
167
|
-
return wrapper
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class QuietMode:
|
|
171
|
-
"""Context manager for quiet execution"""
|
|
172
|
-
|
|
173
|
-
def __init__(self, enabled: bool = True):
|
|
174
|
-
self.enabled = enabled
|
|
175
|
-
self.old_level: int | None = None
|
|
176
|
-
|
|
177
|
-
def __enter__(self) -> "QuietMode":
|
|
178
|
-
if self.enabled:
|
|
179
|
-
self.old_level = logger.level
|
|
180
|
-
logger.setLevel(logging.ERROR)
|
|
181
|
-
return self
|
|
182
|
-
|
|
183
|
-
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
184
|
-
if self.enabled and self.old_level is not None:
|
|
185
|
-
logger.setLevel(self.old_level)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def safe_print(message: str, level: str = "info", quiet: bool = False) -> None:
|
|
189
|
-
"""Safe print function that can be controlled"""
|
|
190
|
-
if quiet:
|
|
191
|
-
return
|
|
192
|
-
|
|
193
|
-
level_map = {
|
|
194
|
-
"info": log_info,
|
|
195
|
-
"warning": log_warning,
|
|
196
|
-
"error": log_error,
|
|
197
|
-
"debug": log_debug,
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
log_func = level_map.get(level.lower(), log_info)
|
|
201
|
-
log_func(message)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
def create_performance_logger(name: str) -> logging.Logger:
|
|
205
|
-
"""Create performance-focused logger"""
|
|
206
|
-
perf_logger = logging.getLogger(f"{name}.performance")
|
|
207
|
-
|
|
208
|
-
if not perf_logger.handlers:
|
|
209
|
-
handler = SafeStreamHandler()
|
|
210
|
-
formatter = logging.Formatter("%(asctime)s - PERF - %(message)s")
|
|
211
|
-
handler.setFormatter(formatter)
|
|
212
|
-
perf_logger.addHandler(handler)
|
|
213
|
-
perf_logger.setLevel(logging.INFO)
|
|
214
|
-
|
|
215
|
-
return perf_logger
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
# Performance logger instance
|
|
219
|
-
perf_logger = create_performance_logger("tree_sitter_analyzer")
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
def log_performance(
|
|
223
|
-
operation: str,
|
|
224
|
-
execution_time: float | None = None,
|
|
225
|
-
details: dict[Any, Any] | str | None = None,
|
|
226
|
-
) -> None:
|
|
227
|
-
"""Log performance metrics"""
|
|
228
|
-
try:
|
|
229
|
-
message = f"{operation}"
|
|
230
|
-
if execution_time is not None:
|
|
231
|
-
message += f": {execution_time:.4f}s"
|
|
232
|
-
if details:
|
|
233
|
-
if isinstance(details, dict):
|
|
234
|
-
detail_str = ", ".join([f"{k}: {v}" for k, v in details.items()])
|
|
235
|
-
else:
|
|
236
|
-
detail_str = str(details)
|
|
237
|
-
message += f" - {detail_str}"
|
|
238
|
-
perf_logger.info(message)
|
|
239
|
-
except (ValueError, OSError):
|
|
240
|
-
pass # Silently ignore I/O errors
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
def setup_performance_logger() -> logging.Logger:
|
|
244
|
-
"""Set up performance logging"""
|
|
245
|
-
perf_logger = logging.getLogger("performance")
|
|
246
|
-
|
|
247
|
-
# Add handler if not already configured
|
|
248
|
-
if not perf_logger.handlers:
|
|
249
|
-
handler = SafeStreamHandler()
|
|
250
|
-
formatter = logging.Formatter("%(asctime)s - Performance - %(message)s")
|
|
251
|
-
handler.setFormatter(formatter)
|
|
252
|
-
perf_logger.addHandler(handler)
|
|
253
|
-
perf_logger.setLevel(logging.INFO)
|
|
254
|
-
|
|
255
|
-
return perf_logger
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
class LoggingContext:
|
|
259
|
-
"""Context manager for controlling logging behavior"""
|
|
260
|
-
|
|
261
|
-
def __init__(self, enabled: bool = True, level: int | None = None):
|
|
262
|
-
self.enabled = enabled
|
|
263
|
-
self.level = level
|
|
264
|
-
self.old_level: int | None = None
|
|
265
|
-
self.target_logger = (
|
|
266
|
-
logging.getLogger()
|
|
267
|
-
) # Use root logger for compatibility with tests
|
|
268
|
-
|
|
269
|
-
def __enter__(self) -> "LoggingContext":
|
|
270
|
-
if self.enabled and self.level is not None:
|
|
271
|
-
self.old_level = self.target_logger.level
|
|
272
|
-
self.target_logger.setLevel(self.level)
|
|
273
|
-
return self
|
|
274
|
-
|
|
275
|
-
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
276
|
-
if self.enabled and self.old_level is not None:
|
|
277
|
-
self.target_logger.setLevel(self.old_level)
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Utilities for Tree-sitter Analyzer
|
|
4
|
+
|
|
5
|
+
Provides logging, debugging, and common utility functions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import atexit
|
|
9
|
+
import logging
|
|
10
|
+
import sys
|
|
11
|
+
from functools import wraps
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Configure global logger
|
|
16
|
+
def setup_logger(
|
|
17
|
+
name: str = "tree_sitter_analyzer", level: int = logging.INFO
|
|
18
|
+
) -> logging.Logger:
|
|
19
|
+
"""Setup unified logger for the project"""
|
|
20
|
+
import os
|
|
21
|
+
|
|
22
|
+
# Get log level from environment variable
|
|
23
|
+
env_level = os.environ.get("LOG_LEVEL", "").upper()
|
|
24
|
+
if env_level == "DEBUG":
|
|
25
|
+
level = logging.DEBUG
|
|
26
|
+
elif env_level == "INFO":
|
|
27
|
+
level = logging.INFO
|
|
28
|
+
elif env_level == "WARNING":
|
|
29
|
+
level = logging.WARNING
|
|
30
|
+
elif env_level == "ERROR":
|
|
31
|
+
level = logging.ERROR
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(name)
|
|
34
|
+
|
|
35
|
+
if not logger.handlers: # Avoid duplicate handlers
|
|
36
|
+
# Create a safe handler that won't fail on closed streams
|
|
37
|
+
handler = SafeStreamHandler(sys.stdout)
|
|
38
|
+
formatter = logging.Formatter(
|
|
39
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
40
|
+
)
|
|
41
|
+
handler.setFormatter(formatter)
|
|
42
|
+
logger.addHandler(handler)
|
|
43
|
+
logger.setLevel(level)
|
|
44
|
+
|
|
45
|
+
return logger
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SafeStreamHandler(logging.StreamHandler):
|
|
49
|
+
"""
|
|
50
|
+
A StreamHandler that safely handles closed streams
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def emit(self, record: Any) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Emit a record, safely handling closed streams
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
# Check if stream is closed before writing
|
|
59
|
+
if hasattr(self.stream, "closed") and self.stream.closed:
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
# Check if we can write to the stream
|
|
63
|
+
if not hasattr(self.stream, "write"):
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
super().emit(record)
|
|
67
|
+
except (ValueError, OSError, AttributeError):
|
|
68
|
+
# Silently ignore I/O errors during shutdown
|
|
69
|
+
pass
|
|
70
|
+
except Exception:
|
|
71
|
+
# For any other unexpected errors, use handleError
|
|
72
|
+
self.handleError(record)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def setup_safe_logging_shutdown() -> None:
|
|
76
|
+
"""
|
|
77
|
+
Setup safe logging shutdown to prevent I/O errors
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def cleanup_logging() -> None:
|
|
81
|
+
"""Clean up logging handlers safely"""
|
|
82
|
+
try:
|
|
83
|
+
# Get all loggers
|
|
84
|
+
loggers = [logging.getLogger()] + [
|
|
85
|
+
logging.getLogger(name) for name in logging.Logger.manager.loggerDict
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
for logger in loggers:
|
|
89
|
+
for handler in logger.handlers[:]:
|
|
90
|
+
try:
|
|
91
|
+
handler.close()
|
|
92
|
+
logger.removeHandler(handler)
|
|
93
|
+
except Exception:
|
|
94
|
+
pass
|
|
95
|
+
except Exception:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
# Register cleanup function
|
|
99
|
+
atexit.register(cleanup_logging)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Setup safe shutdown on import
|
|
103
|
+
setup_safe_logging_shutdown()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# Global logger instance
|
|
107
|
+
logger = setup_logger()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def log_info(message: str, *args: Any, **kwargs: Any) -> None:
|
|
111
|
+
"""Log info message"""
|
|
112
|
+
try:
|
|
113
|
+
logger.info(message, *args, **kwargs)
|
|
114
|
+
except (ValueError, OSError):
|
|
115
|
+
pass # Silently ignore I/O errors
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def log_warning(message: str, *args: Any, **kwargs: Any) -> None:
|
|
119
|
+
"""Log warning message"""
|
|
120
|
+
try:
|
|
121
|
+
logger.warning(message, *args, **kwargs)
|
|
122
|
+
except (ValueError, OSError):
|
|
123
|
+
pass # Silently ignore I/O errors
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def log_error(message: str, *args: Any, **kwargs: Any) -> None:
|
|
127
|
+
"""Log error message"""
|
|
128
|
+
try:
|
|
129
|
+
logger.error(message, *args, **kwargs)
|
|
130
|
+
except (ValueError, OSError):
|
|
131
|
+
pass # Silently ignore I/O errors
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def log_debug(message: str, *args: Any, **kwargs: Any) -> None:
|
|
135
|
+
"""Log debug message"""
|
|
136
|
+
try:
|
|
137
|
+
logger.debug(message, *args, **kwargs)
|
|
138
|
+
except (ValueError, OSError):
|
|
139
|
+
pass # Silently ignore I/O errors
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def suppress_output(func: Any) -> Any:
|
|
143
|
+
"""Decorator to suppress print statements in production"""
|
|
144
|
+
|
|
145
|
+
@wraps(func)
|
|
146
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
147
|
+
# Check if we're in test/debug mode
|
|
148
|
+
if getattr(sys, "_testing", False):
|
|
149
|
+
return func(*args, **kwargs)
|
|
150
|
+
|
|
151
|
+
# Redirect stdout to suppress prints
|
|
152
|
+
old_stdout = sys.stdout
|
|
153
|
+
try:
|
|
154
|
+
sys.stdout = (
|
|
155
|
+
open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
|
|
156
|
+
)
|
|
157
|
+
result = func(*args, **kwargs)
|
|
158
|
+
finally:
|
|
159
|
+
try:
|
|
160
|
+
sys.stdout.close()
|
|
161
|
+
except Exception:
|
|
162
|
+
pass
|
|
163
|
+
sys.stdout = old_stdout
|
|
164
|
+
|
|
165
|
+
return result
|
|
166
|
+
|
|
167
|
+
return wrapper
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class QuietMode:
|
|
171
|
+
"""Context manager for quiet execution"""
|
|
172
|
+
|
|
173
|
+
def __init__(self, enabled: bool = True):
|
|
174
|
+
self.enabled = enabled
|
|
175
|
+
self.old_level: int | None = None
|
|
176
|
+
|
|
177
|
+
def __enter__(self) -> "QuietMode":
|
|
178
|
+
if self.enabled:
|
|
179
|
+
self.old_level = logger.level
|
|
180
|
+
logger.setLevel(logging.ERROR)
|
|
181
|
+
return self
|
|
182
|
+
|
|
183
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
184
|
+
if self.enabled and self.old_level is not None:
|
|
185
|
+
logger.setLevel(self.old_level)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def safe_print(message: str, level: str = "info", quiet: bool = False) -> None:
|
|
189
|
+
"""Safe print function that can be controlled"""
|
|
190
|
+
if quiet:
|
|
191
|
+
return
|
|
192
|
+
|
|
193
|
+
level_map = {
|
|
194
|
+
"info": log_info,
|
|
195
|
+
"warning": log_warning,
|
|
196
|
+
"error": log_error,
|
|
197
|
+
"debug": log_debug,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
log_func = level_map.get(level.lower(), log_info)
|
|
201
|
+
log_func(message)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def create_performance_logger(name: str) -> logging.Logger:
|
|
205
|
+
"""Create performance-focused logger"""
|
|
206
|
+
perf_logger = logging.getLogger(f"{name}.performance")
|
|
207
|
+
|
|
208
|
+
if not perf_logger.handlers:
|
|
209
|
+
handler = SafeStreamHandler()
|
|
210
|
+
formatter = logging.Formatter("%(asctime)s - PERF - %(message)s")
|
|
211
|
+
handler.setFormatter(formatter)
|
|
212
|
+
perf_logger.addHandler(handler)
|
|
213
|
+
perf_logger.setLevel(logging.INFO)
|
|
214
|
+
|
|
215
|
+
return perf_logger
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# Performance logger instance
|
|
219
|
+
perf_logger = create_performance_logger("tree_sitter_analyzer")
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def log_performance(
|
|
223
|
+
operation: str,
|
|
224
|
+
execution_time: float | None = None,
|
|
225
|
+
details: dict[Any, Any] | str | None = None,
|
|
226
|
+
) -> None:
|
|
227
|
+
"""Log performance metrics"""
|
|
228
|
+
try:
|
|
229
|
+
message = f"{operation}"
|
|
230
|
+
if execution_time is not None:
|
|
231
|
+
message += f": {execution_time:.4f}s"
|
|
232
|
+
if details:
|
|
233
|
+
if isinstance(details, dict):
|
|
234
|
+
detail_str = ", ".join([f"{k}: {v}" for k, v in details.items()])
|
|
235
|
+
else:
|
|
236
|
+
detail_str = str(details)
|
|
237
|
+
message += f" - {detail_str}"
|
|
238
|
+
perf_logger.info(message)
|
|
239
|
+
except (ValueError, OSError):
|
|
240
|
+
pass # Silently ignore I/O errors
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def setup_performance_logger() -> logging.Logger:
|
|
244
|
+
"""Set up performance logging"""
|
|
245
|
+
perf_logger = logging.getLogger("performance")
|
|
246
|
+
|
|
247
|
+
# Add handler if not already configured
|
|
248
|
+
if not perf_logger.handlers:
|
|
249
|
+
handler = SafeStreamHandler()
|
|
250
|
+
formatter = logging.Formatter("%(asctime)s - Performance - %(message)s")
|
|
251
|
+
handler.setFormatter(formatter)
|
|
252
|
+
perf_logger.addHandler(handler)
|
|
253
|
+
perf_logger.setLevel(logging.INFO)
|
|
254
|
+
|
|
255
|
+
return perf_logger
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class LoggingContext:
|
|
259
|
+
"""Context manager for controlling logging behavior"""
|
|
260
|
+
|
|
261
|
+
def __init__(self, enabled: bool = True, level: int | None = None):
|
|
262
|
+
self.enabled = enabled
|
|
263
|
+
self.level = level
|
|
264
|
+
self.old_level: int | None = None
|
|
265
|
+
self.target_logger = (
|
|
266
|
+
logging.getLogger()
|
|
267
|
+
) # Use root logger for compatibility with tests
|
|
268
|
+
|
|
269
|
+
def __enter__(self) -> "LoggingContext":
|
|
270
|
+
if self.enabled and self.level is not None:
|
|
271
|
+
self.old_level = self.target_logger.level
|
|
272
|
+
self.target_logger.setLevel(self.level)
|
|
273
|
+
return self
|
|
274
|
+
|
|
275
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
276
|
+
if self.enabled and self.old_level is not None:
|
|
277
|
+
self.target_logger.setLevel(self.old_level)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tree-sitter-analyzer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Extensible multi-language code analyzer framework using Tree-sitter with dynamic plugin architecture
|
|
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
|
|
@@ -33,8 +33,11 @@ Classifier: Typing :: Typed
|
|
|
33
33
|
Requires-Python: >=3.10
|
|
34
34
|
Requires-Dist: cachetools>=5.0.0
|
|
35
35
|
Requires-Dist: chardet>=5.0.0
|
|
36
|
+
Requires-Dist: mcp>=1.12.3
|
|
36
37
|
Requires-Dist: tree-sitter-cpp>=0.23.4
|
|
37
38
|
Requires-Dist: tree-sitter-java>=0.23.5
|
|
39
|
+
Requires-Dist: tree-sitter-javascript>=0.23.1
|
|
40
|
+
Requires-Dist: tree-sitter-python>=0.23.6
|
|
38
41
|
Requires-Dist: tree-sitter==0.24.0
|
|
39
42
|
Provides-Extra: all-languages
|
|
40
43
|
Requires-Dist: tree-sitter-c>=0.20.0; extra == 'all-languages'
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
tree_sitter_analyzer/__init__.py,sha256=T8urKvmHQaqEoh_-jKgNJOb2Snz2ySjMqYWE53vLKKA,3199
|
|
2
|
+
tree_sitter_analyzer/__main__.py,sha256=ilhMPpn_ar28oelzxLfQcX6WH_UbQ2euxiSoV3z_yCg,239
|
|
3
|
+
tree_sitter_analyzer/api.py,sha256=_94HoE1LKGELSE6FpZ6pEqm2R7qfoPokyfpGSjawliQ,17487
|
|
4
|
+
tree_sitter_analyzer/cli_main.py,sha256=bJP7CUHMSSgbPrze7PmOYsVXJ1z1jfhaP0nIVkU7dRw,9581
|
|
5
|
+
tree_sitter_analyzer/encoding_utils.py,sha256=C5DpH2-qkAKfsJeSGNHbhOCy4bmn46X6rUw5xPpki34,14938
|
|
6
|
+
tree_sitter_analyzer/exceptions.py,sha256=xO_U6JuJ4QPkmZoXL_3nmV9QUbTa7-hrI05VAuo5r-Y,12093
|
|
7
|
+
tree_sitter_analyzer/file_handler.py,sha256=vl4bGx-OgC6Lq63FEZNu2XCXNM0iDTmpNCRTK2msP3U,7104
|
|
8
|
+
tree_sitter_analyzer/language_detector.py,sha256=IjkYF1E7_TtWlwYjz780ZUJAyPltL2aZVzo-doTbAug,12540
|
|
9
|
+
tree_sitter_analyzer/language_loader.py,sha256=gdLxkSoajm-q7c1vcvFONtBf5XJRgasUVI4L0wMzra0,8124
|
|
10
|
+
tree_sitter_analyzer/models.py,sha256=z0aqdZOVA8rYWF0143TSAUoCvncVRLZ1O70eAjV87gU,16564
|
|
11
|
+
tree_sitter_analyzer/output_manager.py,sha256=eiBOSL2vUUQi1ghYBr4gwT7aOYC2WTgIoISBZlXkzPo,8399
|
|
12
|
+
tree_sitter_analyzer/query_loader.py,sha256=NilC2XmmhYrBL6ONlzRGlehGa23C_4V6nDVap6YG8v0,10120
|
|
13
|
+
tree_sitter_analyzer/table_formatter.py,sha256=BfrAouAr3r6MD9xY9yhHw_PwD0aJ4BQo5p1UFhorT5k,27284
|
|
14
|
+
tree_sitter_analyzer/utils.py,sha256=Pq_2vlDPul8jean0PwlQ_XC-RDjkuaUbwoXp2ls7dV8,8268
|
|
15
|
+
tree_sitter_analyzer/cli/__init__.py,sha256=swCjWlrPEVIKGznqM_BPxbNvd_0Qz5r1_RmZ-j6EWIU,910
|
|
16
|
+
tree_sitter_analyzer/cli/__main__.py,sha256=xgCuvLv5NNeEsxKM40pF_7b1apgj3DZ4ECa-xcbLKWc,230
|
|
17
|
+
tree_sitter_analyzer/cli/info_commands.py,sha256=z6JhXO1Sm983dHj0uxNVzycWBYz1JIGVCOi0ukSAyTM,4419
|
|
18
|
+
tree_sitter_analyzer/cli/commands/__init__.py,sha256=qLtJ7rRge-Reu4aZbczn_jmUHQNQ4lEAsve9BZYHYd0,697
|
|
19
|
+
tree_sitter_analyzer/cli/commands/advanced_command.py,sha256=YJGrFBEqFPpS0VB-o28Un89Cjwr-eTirNdcFLP4rlN8,3512
|
|
20
|
+
tree_sitter_analyzer/cli/commands/base_command.py,sha256=LNRTNYMpAuSAwyxM7rtA1oZcvWPMaAHXsBdv--FOGgw,5947
|
|
21
|
+
tree_sitter_analyzer/cli/commands/default_command.py,sha256=-bJJC3Klie7EU3B3n_YXUYKAUSBzC2XUHP3XOnwENvQ,549
|
|
22
|
+
tree_sitter_analyzer/cli/commands/partial_read_command.py,sha256=D8dY3CUaNn5EEPgrJNR4e7IClfJal7zenlbWxZcHwPQ,4825
|
|
23
|
+
tree_sitter_analyzer/cli/commands/query_command.py,sha256=5SsxwJQInS0YQz9W6ZD_P88-wekfl7VKN_Utlm47YTk,3200
|
|
24
|
+
tree_sitter_analyzer/cli/commands/structure_command.py,sha256=u-NKm06CLgx4srdK5bVo7WtcV4dArA7WYWQWmeXcWMs,5358
|
|
25
|
+
tree_sitter_analyzer/cli/commands/summary_command.py,sha256=X3pLK7t2ma4SDlG7yYsaFX6bQ4OVUrHv8OWDfgTMNMw,3703
|
|
26
|
+
tree_sitter_analyzer/cli/commands/table_command.py,sha256=LuQWeWqCxOArrINcDY9fnXnFyWtESKpffwg_oMQByGw,9683
|
|
27
|
+
tree_sitter_analyzer/core/__init__.py,sha256=Um_BRFICWihZybxoAR6Ck32gJ42ZatkBoZR18XGl9FQ,455
|
|
28
|
+
tree_sitter_analyzer/core/analysis_engine.py,sha256=pWyvdYOlTHyLTBcV90yg-yaWQRRi7MWbXTGhoylpzQ0,19122
|
|
29
|
+
tree_sitter_analyzer/core/cache_service.py,sha256=lTFhGsmuGWgEauxtk2pz_1h5Z945456CaQILfreS5Rw,9944
|
|
30
|
+
tree_sitter_analyzer/core/engine.py,sha256=6NRPBlN1GvFDtSh8hDJ8udKLC7IOjvoCPetuM7MPrnw,19287
|
|
31
|
+
tree_sitter_analyzer/core/parser.py,sha256=07vL-mESeMsaIrQqAg-3sr9MLWYVdzT5RyBDO1AkBh0,9586
|
|
32
|
+
tree_sitter_analyzer/core/query.py,sha256=fmuPMLsU4XUnMViaQADPRPoiZ-MzeE2k_e9N35VBNSA,16899
|
|
33
|
+
tree_sitter_analyzer/formatters/__init__.py,sha256=0YJGj4VxZRB5b29zlOKWN4UG74C5EWlljYBx0HWI9sg,32
|
|
34
|
+
tree_sitter_analyzer/formatters/base_formatter.py,sha256=bFthHalpKOSIP76MpKc9ga-GEkgowR7aI5aWNv9UYpw,5930
|
|
35
|
+
tree_sitter_analyzer/formatters/formatter_factory.py,sha256=fRlgm6Z3Wf9mTLegBrRCvbA-TmX23nF93vjsT5bf8KY,2147
|
|
36
|
+
tree_sitter_analyzer/formatters/java_formatter.py,sha256=MKssGZwvOXxARq-P9DT0ksclAYC3YpVQuY3c-oiKQhI,11622
|
|
37
|
+
tree_sitter_analyzer/formatters/python_formatter.py,sha256=HkkUu5O7pGvw2e5SSsQTSUJWkS84pg6uuIkiG0lDxkQ,10275
|
|
38
|
+
tree_sitter_analyzer/interfaces/__init__.py,sha256=qS0b_9AzhwX-5olNChVh-NUINpohCuVWHxegiqEnXYA,280
|
|
39
|
+
tree_sitter_analyzer/interfaces/cli.py,sha256=KW-OJxYoiRsushiGNN0uF_gDDzlyfRTP7OHnie_Mt_k,17368
|
|
40
|
+
tree_sitter_analyzer/interfaces/cli_adapter.py,sha256=H50tbqfs_3UueQPhq5_9s6I1ZwoCKr2vZXXGAMl3L3c,11535
|
|
41
|
+
tree_sitter_analyzer/interfaces/mcp_adapter.py,sha256=q94pFJgO1434Dngdbob6c4UQn-Z6BmxVwLND4pp32P8,7317
|
|
42
|
+
tree_sitter_analyzer/interfaces/mcp_server.py,sha256=-vOxiDEJqPaMbRiPr5n0fGtIXOkTM-GxkxKovE2tsB4,16934
|
|
43
|
+
tree_sitter_analyzer/languages/__init__.py,sha256=D-b1wReVcu3XRBvbeWgO80i29naGJ6u1uP5bOfFKbiY,350
|
|
44
|
+
tree_sitter_analyzer/languages/java_plugin.py,sha256=o_9F_anKCemnUDV6hq28RatRmBm3e0nchcQZ-v0nDv4,48454
|
|
45
|
+
tree_sitter_analyzer/languages/javascript_plugin.py,sha256=9al0ScXmM5Y8Xl82oNp7cUaU9P59eNCJCPXSlfea4u8,16290
|
|
46
|
+
tree_sitter_analyzer/languages/python_plugin.py,sha256=nlVxDx6thOB5o6QfQzGbD7gph3_YuM32YYzqYZoHlMw,29899
|
|
47
|
+
tree_sitter_analyzer/mcp/__init__.py,sha256=mL_XjEks3tJOGAl9ULs_09KQOH1BWi92yvXpBidwmlI,752
|
|
48
|
+
tree_sitter_analyzer/mcp/server.py,sha256=uXV4hUroFRnHTP8_axkKWh2OkN3o6OwNxS-BjlrKMfA,12937
|
|
49
|
+
tree_sitter_analyzer/mcp/resources/__init__.py,sha256=PHDvZyHZawoToDQVqrepsmcTk00ZlaTsu6uxwVjoa4A,1433
|
|
50
|
+
tree_sitter_analyzer/mcp/resources/code_file_resource.py,sha256=MDHvJl6akElHtcxlN6eCcY5WYSjQEQFCyhAVGiPGk9s,6462
|
|
51
|
+
tree_sitter_analyzer/mcp/resources/project_stats_resource.py,sha256=lZF9TGxjKvTwPyuWE_o3I3V4LK0zEj3lab4L0Iq-hho,19758
|
|
52
|
+
tree_sitter_analyzer/mcp/tools/__init__.py,sha256=RMvJOzfZMVe24WUNWJJ-pdygc1RbEVrhW5NZwpykDoQ,792
|
|
53
|
+
tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py,sha256=ZVNEghqKFOcLNZKsv9cJI19t8ZqcgcPp_bXiNkfoWps,26997
|
|
54
|
+
tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py,sha256=Ie1yeGTFNxuEeTLgXVnKEdKktoMEV27ychIMVkStRY8,9244
|
|
55
|
+
tree_sitter_analyzer/mcp/tools/base_tool.py,sha256=szW84sSYejzRyBlFbskOARQbsfc2JLwHmjZ6rJZ8SQA,1264
|
|
56
|
+
tree_sitter_analyzer/mcp/tools/read_partial_tool.py,sha256=aWBfJXDbjUpiu9xx_-89Js_GebB468mUyupAwT8oA5E,11035
|
|
57
|
+
tree_sitter_analyzer/mcp/tools/table_format_tool.py,sha256=O9bxfwGNNjTNpBN5HJ5iTgKALoMTZ2HSYRryBZxaQu0,14623
|
|
58
|
+
tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py,sha256=1UslG_OpB9r1upX1xPYUSquRLYSVzglV8XgO3V2RJjs,21328
|
|
59
|
+
tree_sitter_analyzer/mcp/utils/__init__.py,sha256=F_qFFC2gvGNdgRWGLxIh4Amd0dPhZv0Ni1ZbCbaYLlI,3063
|
|
60
|
+
tree_sitter_analyzer/mcp/utils/error_handler.py,sha256=n9ME2U5L1o65Vewnv8kD2O8dVI1CiEGm1pLWdnpnyqM,17972
|
|
61
|
+
tree_sitter_analyzer/plugins/__init__.py,sha256=MfSW8P9GLaL_9XgLISdlpIUY4quqapk0avPLIpBdMTg,10606
|
|
62
|
+
tree_sitter_analyzer/plugins/base.py,sha256=or-p0ZkXxVPuXEsysRbOcBGo2r-Di-BgnN3e0fnN44Q,17696
|
|
63
|
+
tree_sitter_analyzer/plugins/manager.py,sha256=DTe1kGNzElOKXjlcKuHkA-SOOpInBeFCeT6rSdxR3AI,12914
|
|
64
|
+
tree_sitter_analyzer/queries/__init__.py,sha256=3jKMxFXiGUhI8V_tGRNGjlZfXYW7iguVTZut6OS9N6Y,722
|
|
65
|
+
tree_sitter_analyzer/queries/java.py,sha256=guHrEQD2PvzUvY7dVxIXpul2KmIJMLefq7G7qSyxQN4,12640
|
|
66
|
+
tree_sitter_analyzer/queries/javascript.py,sha256=wIv5k-l48e1_sW_vqNUBkdNKO97CBs-L8IZcQIQeZh0,4110
|
|
67
|
+
tree_sitter_analyzer/queries/python.py,sha256=tl72D3JTOSNIG-1lXww0YKQ41AgMKB5iBUkNBaqfkiI,7855
|
|
68
|
+
tree_sitter_analyzer/queries/typescript.py,sha256=I1ndwPjAMGOIa1frSK3ewLqEkeDAJuAE9qzD9seEGf4,6937
|
|
69
|
+
tree_sitter_analyzer/security/__init__.py,sha256=zVpzS5jtECwgYnhKL4YoMfnIdkJABnVeziTBB4IOTyU,624
|
|
70
|
+
tree_sitter_analyzer/security/boundary_manager.py,sha256=e4iOJTygHLqlImkOntjLhfTpCvqCfb2LTpYwGpYmVQg,8051
|
|
71
|
+
tree_sitter_analyzer/security/regex_checker.py,sha256=Qvldh-TiVYqtcYQbD80wk0eHUvhALYtWTWBy_bGmJUk,10025
|
|
72
|
+
tree_sitter_analyzer/security/validator.py,sha256=RRGyacxCjJ2CbfvGzpZCvza8YxqSrOiO2JWY49oFMh8,8187
|
|
73
|
+
tree_sitter_analyzer-0.8.0.dist-info/METADATA,sha256=JtFjrCj-g9vPbMvYKurXQXB8I8Ogxo_DGB_lATblvIk,13525
|
|
74
|
+
tree_sitter_analyzer-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
75
|
+
tree_sitter_analyzer-0.8.0.dist-info/entry_points.txt,sha256=EA0Ow27x2SqNt2300sv70RTWxKRIxJzOhNPIVlez4NM,417
|
|
76
|
+
tree_sitter_analyzer-0.8.0.dist-info/RECORD,,
|