tree-sitter-analyzer 0.8.3__py3-none-any.whl → 0.9.2__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 +182 -180
- tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
- tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
- tree_sitter_analyzer/core/__init__.py +15 -15
- tree_sitter_analyzer/core/analysis_engine.py +74 -78
- 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/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/formatters/java_formatter.py +18 -18
- tree_sitter_analyzer/formatters/python_formatter.py +19 -19
- tree_sitter_analyzer/interfaces/__init__.py +9 -9
- tree_sitter_analyzer/interfaces/cli.py +528 -528
- tree_sitter_analyzer/interfaces/cli_adapter.py +344 -343
- tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
- tree_sitter_analyzer/language_detector.py +53 -53
- tree_sitter_analyzer/languages/__init__.py +10 -10
- tree_sitter_analyzer/languages/java_plugin.py +1 -1
- tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
- tree_sitter_analyzer/languages/python_plugin.py +755 -755
- tree_sitter_analyzer/mcp/__init__.py +34 -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 +623 -436
- tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +10 -6
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -242
- tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +310 -308
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +386 -379
- tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +563 -559
- tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
- tree_sitter_analyzer/models.py +10 -10
- 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/boundary_manager.py +237 -279
- tree_sitter_analyzer/security/validator.py +60 -58
- tree_sitter_analyzer/utils.py +294 -277
- {tree_sitter_analyzer-0.8.3.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/METADATA +28 -19
- tree_sitter_analyzer-0.9.2.dist-info/RECORD +77 -0
- {tree_sitter_analyzer-0.8.3.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/entry_points.txt +1 -0
- tree_sitter_analyzer-0.8.3.dist-info/RECORD +0 -77
- {tree_sitter_analyzer-0.8.3.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/WHEEL +0 -0
tree_sitter_analyzer/utils.py
CHANGED
|
@@ -1,277 +1,294 @@
|
|
|
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
|
|
37
|
-
handler = SafeStreamHandler(
|
|
38
|
-
formatter = logging.Formatter(
|
|
39
|
-
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
40
|
-
)
|
|
41
|
-
handler.setFormatter(formatter)
|
|
42
|
-
logger.addHandler(handler)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
"""
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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 writes to stderr to avoid breaking MCP stdio
|
|
37
|
+
handler = SafeStreamHandler()
|
|
38
|
+
formatter = logging.Formatter(
|
|
39
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
40
|
+
)
|
|
41
|
+
handler.setFormatter(formatter)
|
|
42
|
+
logger.addHandler(handler)
|
|
43
|
+
|
|
44
|
+
# Also log to a local file for debugging when launched by clients (e.g., Cursor)
|
|
45
|
+
# This helps diagnose cases where stdio is captured by the client and logs are hidden.
|
|
46
|
+
try:
|
|
47
|
+
file_handler = logging.FileHandler(
|
|
48
|
+
"cursor_mcp_server.log", encoding="utf-8"
|
|
49
|
+
)
|
|
50
|
+
file_handler.setFormatter(formatter)
|
|
51
|
+
logger.addHandler(file_handler)
|
|
52
|
+
except Exception:
|
|
53
|
+
# Never let logging configuration break runtime behavior
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
logger.setLevel(level)
|
|
57
|
+
|
|
58
|
+
return logger
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class SafeStreamHandler(logging.StreamHandler):
|
|
62
|
+
"""
|
|
63
|
+
A StreamHandler that safely handles closed streams
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, stream=None):
|
|
67
|
+
# Default to sys.stderr to keep stdout clean for MCP stdio
|
|
68
|
+
super().__init__(stream if stream is not None else sys.stderr)
|
|
69
|
+
|
|
70
|
+
def emit(self, record: Any) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Emit a record, safely handling closed streams
|
|
73
|
+
"""
|
|
74
|
+
try:
|
|
75
|
+
# Check if stream is closed before writing
|
|
76
|
+
if hasattr(self.stream, "closed") and self.stream.closed:
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
# Check if we can write to the stream
|
|
80
|
+
if not hasattr(self.stream, "write"):
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
super().emit(record)
|
|
84
|
+
except (ValueError, OSError, AttributeError):
|
|
85
|
+
# Silently ignore I/O errors during shutdown
|
|
86
|
+
pass
|
|
87
|
+
except Exception:
|
|
88
|
+
# For any other unexpected errors, use handleError
|
|
89
|
+
self.handleError(record)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def setup_safe_logging_shutdown() -> None:
|
|
93
|
+
"""
|
|
94
|
+
Setup safe logging shutdown to prevent I/O errors
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
def cleanup_logging() -> None:
|
|
98
|
+
"""Clean up logging handlers safely"""
|
|
99
|
+
try:
|
|
100
|
+
# Get all loggers
|
|
101
|
+
loggers = [logging.getLogger()] + [
|
|
102
|
+
logging.getLogger(name) for name in logging.Logger.manager.loggerDict
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
for logger in loggers:
|
|
106
|
+
for handler in logger.handlers[:]:
|
|
107
|
+
try:
|
|
108
|
+
handler.close()
|
|
109
|
+
logger.removeHandler(handler)
|
|
110
|
+
except Exception:
|
|
111
|
+
pass
|
|
112
|
+
except Exception:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
# Register cleanup function
|
|
116
|
+
atexit.register(cleanup_logging)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# Setup safe shutdown on import
|
|
120
|
+
setup_safe_logging_shutdown()
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# Global logger instance
|
|
124
|
+
logger = setup_logger()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def log_info(message: str, *args: Any, **kwargs: Any) -> None:
|
|
128
|
+
"""Log info message"""
|
|
129
|
+
try:
|
|
130
|
+
logger.info(message, *args, **kwargs)
|
|
131
|
+
except (ValueError, OSError):
|
|
132
|
+
pass # Silently ignore I/O errors
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def log_warning(message: str, *args: Any, **kwargs: Any) -> None:
|
|
136
|
+
"""Log warning message"""
|
|
137
|
+
try:
|
|
138
|
+
logger.warning(message, *args, **kwargs)
|
|
139
|
+
except (ValueError, OSError):
|
|
140
|
+
pass # Silently ignore I/O errors
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def log_error(message: str, *args: Any, **kwargs: Any) -> None:
|
|
144
|
+
"""Log error message"""
|
|
145
|
+
try:
|
|
146
|
+
logger.error(message, *args, **kwargs)
|
|
147
|
+
except (ValueError, OSError):
|
|
148
|
+
pass # Silently ignore I/O errors
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def log_debug(message: str, *args: Any, **kwargs: Any) -> None:
|
|
152
|
+
"""Log debug message"""
|
|
153
|
+
try:
|
|
154
|
+
logger.debug(message, *args, **kwargs)
|
|
155
|
+
except (ValueError, OSError):
|
|
156
|
+
pass # Silently ignore I/O errors
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def suppress_output(func: Any) -> Any:
|
|
160
|
+
"""Decorator to suppress print statements in production"""
|
|
161
|
+
|
|
162
|
+
@wraps(func)
|
|
163
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
164
|
+
# Check if we're in test/debug mode
|
|
165
|
+
if getattr(sys, "_testing", False):
|
|
166
|
+
return func(*args, **kwargs)
|
|
167
|
+
|
|
168
|
+
# Redirect stdout to suppress prints
|
|
169
|
+
old_stdout = sys.stdout
|
|
170
|
+
try:
|
|
171
|
+
sys.stdout = (
|
|
172
|
+
open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
|
|
173
|
+
)
|
|
174
|
+
result = func(*args, **kwargs)
|
|
175
|
+
finally:
|
|
176
|
+
try:
|
|
177
|
+
sys.stdout.close()
|
|
178
|
+
except Exception:
|
|
179
|
+
pass
|
|
180
|
+
sys.stdout = old_stdout
|
|
181
|
+
|
|
182
|
+
return result
|
|
183
|
+
|
|
184
|
+
return wrapper
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class QuietMode:
|
|
188
|
+
"""Context manager for quiet execution"""
|
|
189
|
+
|
|
190
|
+
def __init__(self, enabled: bool = True):
|
|
191
|
+
self.enabled = enabled
|
|
192
|
+
self.old_level: int | None = None
|
|
193
|
+
|
|
194
|
+
def __enter__(self) -> "QuietMode":
|
|
195
|
+
if self.enabled:
|
|
196
|
+
self.old_level = logger.level
|
|
197
|
+
logger.setLevel(logging.ERROR)
|
|
198
|
+
return self
|
|
199
|
+
|
|
200
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
201
|
+
if self.enabled and self.old_level is not None:
|
|
202
|
+
logger.setLevel(self.old_level)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def safe_print(message: str, level: str = "info", quiet: bool = False) -> None:
|
|
206
|
+
"""Safe print function that can be controlled"""
|
|
207
|
+
if quiet:
|
|
208
|
+
return
|
|
209
|
+
|
|
210
|
+
level_map = {
|
|
211
|
+
"info": log_info,
|
|
212
|
+
"warning": log_warning,
|
|
213
|
+
"error": log_error,
|
|
214
|
+
"debug": log_debug,
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
log_func = level_map.get(level.lower(), log_info)
|
|
218
|
+
log_func(message)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def create_performance_logger(name: str) -> logging.Logger:
|
|
222
|
+
"""Create performance-focused logger"""
|
|
223
|
+
perf_logger = logging.getLogger(f"{name}.performance")
|
|
224
|
+
|
|
225
|
+
if not perf_logger.handlers:
|
|
226
|
+
handler = SafeStreamHandler()
|
|
227
|
+
formatter = logging.Formatter("%(asctime)s - PERF - %(message)s")
|
|
228
|
+
handler.setFormatter(formatter)
|
|
229
|
+
perf_logger.addHandler(handler)
|
|
230
|
+
perf_logger.setLevel(logging.INFO)
|
|
231
|
+
|
|
232
|
+
return perf_logger
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# Performance logger instance
|
|
236
|
+
perf_logger = create_performance_logger("tree_sitter_analyzer")
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def log_performance(
|
|
240
|
+
operation: str,
|
|
241
|
+
execution_time: float | None = None,
|
|
242
|
+
details: dict[Any, Any] | str | None = None,
|
|
243
|
+
) -> None:
|
|
244
|
+
"""Log performance metrics"""
|
|
245
|
+
try:
|
|
246
|
+
message = f"{operation}"
|
|
247
|
+
if execution_time is not None:
|
|
248
|
+
message += f": {execution_time:.4f}s"
|
|
249
|
+
if details:
|
|
250
|
+
if isinstance(details, dict):
|
|
251
|
+
detail_str = ", ".join([f"{k}: {v}" for k, v in details.items()])
|
|
252
|
+
else:
|
|
253
|
+
detail_str = str(details)
|
|
254
|
+
message += f" - {detail_str}"
|
|
255
|
+
perf_logger.info(message)
|
|
256
|
+
except (ValueError, OSError):
|
|
257
|
+
pass # Silently ignore I/O errors
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def setup_performance_logger() -> logging.Logger:
|
|
261
|
+
"""Set up performance logging"""
|
|
262
|
+
perf_logger = logging.getLogger("performance")
|
|
263
|
+
|
|
264
|
+
# Add handler if not already configured
|
|
265
|
+
if not perf_logger.handlers:
|
|
266
|
+
handler = SafeStreamHandler()
|
|
267
|
+
formatter = logging.Formatter("%(asctime)s - Performance - %(message)s")
|
|
268
|
+
handler.setFormatter(formatter)
|
|
269
|
+
perf_logger.addHandler(handler)
|
|
270
|
+
perf_logger.setLevel(logging.INFO)
|
|
271
|
+
|
|
272
|
+
return perf_logger
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class LoggingContext:
|
|
276
|
+
"""Context manager for controlling logging behavior"""
|
|
277
|
+
|
|
278
|
+
def __init__(self, enabled: bool = True, level: int | None = None):
|
|
279
|
+
self.enabled = enabled
|
|
280
|
+
self.level = level
|
|
281
|
+
self.old_level: int | None = None
|
|
282
|
+
self.target_logger = (
|
|
283
|
+
logging.getLogger()
|
|
284
|
+
) # Use root logger for compatibility with tests
|
|
285
|
+
|
|
286
|
+
def __enter__(self) -> "LoggingContext":
|
|
287
|
+
if self.enabled and self.level is not None:
|
|
288
|
+
self.old_level = self.target_logger.level
|
|
289
|
+
self.target_logger.setLevel(self.level)
|
|
290
|
+
return self
|
|
291
|
+
|
|
292
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
293
|
+
if self.enabled and self.old_level is not None:
|
|
294
|
+
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.9.2
|
|
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
|
|
@@ -137,7 +137,7 @@ Description-Content-Type: text/markdown
|
|
|
137
137
|
|
|
138
138
|
[](https://python.org)
|
|
139
139
|
[](LICENSE)
|
|
140
|
-
[](#testing)
|
|
141
141
|
[](#testing)
|
|
142
142
|
[](#quality)
|
|
143
143
|
|
|
@@ -228,11 +228,10 @@ Extract specific code sections efficiently:
|
|
|
228
228
|
- Content length information
|
|
229
229
|
|
|
230
230
|
### 3. AI Assistant Integration
|
|
231
|
-
|
|
232
|
-
- `
|
|
233
|
-
- `analyze_code_structure` - Generate detailed structure tables
|
|
234
|
-
- `
|
|
235
|
-
- `analyze_code_universal` - Universal analysis with auto-detection
|
|
231
|
+
Three-step workflow MCP tools for AI assistants:
|
|
232
|
+
- `check_code_scale` - **Step 1:** Get code metrics and complexity
|
|
233
|
+
- `analyze_code_structure` - **Step 2:** Generate detailed structure tables with line positions
|
|
234
|
+
- `extract_code_section` - **Step 3:** Extract specific code sections by line range
|
|
236
235
|
|
|
237
236
|
### 4. Multi-Language Support
|
|
238
237
|
- **Java** - Full support with advanced analysis
|
|
@@ -244,14 +243,25 @@ Four powerful MCP tools for AI assistants:
|
|
|
244
243
|
|
|
245
244
|
### AI Assistant Usage (via Claude Desktop)
|
|
246
245
|
|
|
247
|
-
**Step 1:
|
|
248
|
-
|
|
246
|
+
**Step 1: Check code scale**
|
|
247
|
+
```
|
|
248
|
+
Use tool: check_code_scale
|
|
249
|
+
Parameters: {"file_path": "examples/Sample.java"}
|
|
250
|
+
```
|
|
249
251
|
|
|
250
|
-
**Step 2: Analyze
|
|
251
|
-
|
|
252
|
+
**Step 2: Analyze structure (for large files >100 lines)**
|
|
253
|
+
```
|
|
254
|
+
Use tool: analyze_code_structure
|
|
255
|
+
Parameters: {"file_path": "examples/Sample.java", "format_type": "full"}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Step 3: Extract specific code (using line positions from step 2)**
|
|
259
|
+
```
|
|
260
|
+
Use tool: extract_code_section
|
|
261
|
+
Parameters: {"file_path": "examples/Sample.java", "start_line": 84, "end_line": 86}
|
|
262
|
+
```
|
|
252
263
|
|
|
253
|
-
**
|
|
254
|
-
> "Show me lines 84-86 from examples/Sample.java"
|
|
264
|
+
> **Note:** Always use snake_case parameter names: `file_path`, `start_line`, `end_line`, `format_type`
|
|
255
265
|
|
|
256
266
|
### CLI Usage
|
|
257
267
|
|
|
@@ -344,12 +354,11 @@ This project maintains **enterprise-grade quality** with comprehensive testing:
|
|
|
344
354
|
- **Zero test failures** - Complete CI/CD readiness
|
|
345
355
|
- **Cross-platform compatibility** - Windows, macOS, Linux
|
|
346
356
|
|
|
347
|
-
### 🏆 Recent Quality Achievements (v0.8.2
|
|
348
|
-
- ✅ **Complete test suite stabilization** -
|
|
349
|
-
- ✅ **
|
|
350
|
-
- ✅ **
|
|
351
|
-
- ✅ **
|
|
352
|
-
- ✅ **Security framework enhancements** - Better project boundary management
|
|
357
|
+
### 🏆 Recent Quality Achievements (v0.8.2)
|
|
358
|
+
- ✅ **Complete test suite stabilization** - Fixed all 31 failing tests
|
|
359
|
+
- ✅ **Formatters module breakthrough** - 0% → 42.30% coverage
|
|
360
|
+
- ✅ **Error handling improvements** - 61.64% → 82.76% coverage
|
|
361
|
+
- ✅ **104 new comprehensive tests** across critical modules
|
|
353
362
|
|
|
354
363
|
### 🔧 Running Tests
|
|
355
364
|
```bash
|