tree-sitter-analyzer 1.9.17.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. tree_sitter_analyzer/__init__.py +132 -0
  2. tree_sitter_analyzer/__main__.py +11 -0
  3. tree_sitter_analyzer/api.py +853 -0
  4. tree_sitter_analyzer/cli/__init__.py +39 -0
  5. tree_sitter_analyzer/cli/__main__.py +12 -0
  6. tree_sitter_analyzer/cli/argument_validator.py +89 -0
  7. tree_sitter_analyzer/cli/commands/__init__.py +26 -0
  8. tree_sitter_analyzer/cli/commands/advanced_command.py +226 -0
  9. tree_sitter_analyzer/cli/commands/base_command.py +181 -0
  10. tree_sitter_analyzer/cli/commands/default_command.py +18 -0
  11. tree_sitter_analyzer/cli/commands/find_and_grep_cli.py +188 -0
  12. tree_sitter_analyzer/cli/commands/list_files_cli.py +133 -0
  13. tree_sitter_analyzer/cli/commands/partial_read_command.py +139 -0
  14. tree_sitter_analyzer/cli/commands/query_command.py +109 -0
  15. tree_sitter_analyzer/cli/commands/search_content_cli.py +161 -0
  16. tree_sitter_analyzer/cli/commands/structure_command.py +156 -0
  17. tree_sitter_analyzer/cli/commands/summary_command.py +116 -0
  18. tree_sitter_analyzer/cli/commands/table_command.py +414 -0
  19. tree_sitter_analyzer/cli/info_commands.py +124 -0
  20. tree_sitter_analyzer/cli_main.py +472 -0
  21. tree_sitter_analyzer/constants.py +85 -0
  22. tree_sitter_analyzer/core/__init__.py +15 -0
  23. tree_sitter_analyzer/core/analysis_engine.py +580 -0
  24. tree_sitter_analyzer/core/cache_service.py +333 -0
  25. tree_sitter_analyzer/core/engine.py +585 -0
  26. tree_sitter_analyzer/core/parser.py +293 -0
  27. tree_sitter_analyzer/core/query.py +605 -0
  28. tree_sitter_analyzer/core/query_filter.py +200 -0
  29. tree_sitter_analyzer/core/query_service.py +340 -0
  30. tree_sitter_analyzer/encoding_utils.py +530 -0
  31. tree_sitter_analyzer/exceptions.py +747 -0
  32. tree_sitter_analyzer/file_handler.py +246 -0
  33. tree_sitter_analyzer/formatters/__init__.py +1 -0
  34. tree_sitter_analyzer/formatters/base_formatter.py +201 -0
  35. tree_sitter_analyzer/formatters/csharp_formatter.py +367 -0
  36. tree_sitter_analyzer/formatters/formatter_config.py +197 -0
  37. tree_sitter_analyzer/formatters/formatter_factory.py +84 -0
  38. tree_sitter_analyzer/formatters/formatter_registry.py +377 -0
  39. tree_sitter_analyzer/formatters/formatter_selector.py +96 -0
  40. tree_sitter_analyzer/formatters/go_formatter.py +368 -0
  41. tree_sitter_analyzer/formatters/html_formatter.py +498 -0
  42. tree_sitter_analyzer/formatters/java_formatter.py +423 -0
  43. tree_sitter_analyzer/formatters/javascript_formatter.py +611 -0
  44. tree_sitter_analyzer/formatters/kotlin_formatter.py +268 -0
  45. tree_sitter_analyzer/formatters/language_formatter_factory.py +123 -0
  46. tree_sitter_analyzer/formatters/legacy_formatter_adapters.py +228 -0
  47. tree_sitter_analyzer/formatters/markdown_formatter.py +725 -0
  48. tree_sitter_analyzer/formatters/php_formatter.py +301 -0
  49. tree_sitter_analyzer/formatters/python_formatter.py +830 -0
  50. tree_sitter_analyzer/formatters/ruby_formatter.py +278 -0
  51. tree_sitter_analyzer/formatters/rust_formatter.py +233 -0
  52. tree_sitter_analyzer/formatters/sql_formatter_wrapper.py +689 -0
  53. tree_sitter_analyzer/formatters/sql_formatters.py +536 -0
  54. tree_sitter_analyzer/formatters/typescript_formatter.py +543 -0
  55. tree_sitter_analyzer/formatters/yaml_formatter.py +462 -0
  56. tree_sitter_analyzer/interfaces/__init__.py +9 -0
  57. tree_sitter_analyzer/interfaces/cli.py +535 -0
  58. tree_sitter_analyzer/interfaces/cli_adapter.py +359 -0
  59. tree_sitter_analyzer/interfaces/mcp_adapter.py +224 -0
  60. tree_sitter_analyzer/interfaces/mcp_server.py +428 -0
  61. tree_sitter_analyzer/language_detector.py +553 -0
  62. tree_sitter_analyzer/language_loader.py +271 -0
  63. tree_sitter_analyzer/languages/__init__.py +10 -0
  64. tree_sitter_analyzer/languages/csharp_plugin.py +1076 -0
  65. tree_sitter_analyzer/languages/css_plugin.py +449 -0
  66. tree_sitter_analyzer/languages/go_plugin.py +836 -0
  67. tree_sitter_analyzer/languages/html_plugin.py +496 -0
  68. tree_sitter_analyzer/languages/java_plugin.py +1299 -0
  69. tree_sitter_analyzer/languages/javascript_plugin.py +1622 -0
  70. tree_sitter_analyzer/languages/kotlin_plugin.py +656 -0
  71. tree_sitter_analyzer/languages/markdown_plugin.py +1928 -0
  72. tree_sitter_analyzer/languages/php_plugin.py +862 -0
  73. tree_sitter_analyzer/languages/python_plugin.py +1636 -0
  74. tree_sitter_analyzer/languages/ruby_plugin.py +757 -0
  75. tree_sitter_analyzer/languages/rust_plugin.py +673 -0
  76. tree_sitter_analyzer/languages/sql_plugin.py +2444 -0
  77. tree_sitter_analyzer/languages/typescript_plugin.py +1892 -0
  78. tree_sitter_analyzer/languages/yaml_plugin.py +695 -0
  79. tree_sitter_analyzer/legacy_table_formatter.py +860 -0
  80. tree_sitter_analyzer/mcp/__init__.py +34 -0
  81. tree_sitter_analyzer/mcp/resources/__init__.py +43 -0
  82. tree_sitter_analyzer/mcp/resources/code_file_resource.py +208 -0
  83. tree_sitter_analyzer/mcp/resources/project_stats_resource.py +586 -0
  84. tree_sitter_analyzer/mcp/server.py +869 -0
  85. tree_sitter_analyzer/mcp/tools/__init__.py +28 -0
  86. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +779 -0
  87. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +291 -0
  88. tree_sitter_analyzer/mcp/tools/base_tool.py +139 -0
  89. tree_sitter_analyzer/mcp/tools/fd_rg_utils.py +816 -0
  90. tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +686 -0
  91. tree_sitter_analyzer/mcp/tools/list_files_tool.py +413 -0
  92. tree_sitter_analyzer/mcp/tools/output_format_validator.py +148 -0
  93. tree_sitter_analyzer/mcp/tools/query_tool.py +443 -0
  94. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +464 -0
  95. tree_sitter_analyzer/mcp/tools/search_content_tool.py +836 -0
  96. tree_sitter_analyzer/mcp/tools/table_format_tool.py +572 -0
  97. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +653 -0
  98. tree_sitter_analyzer/mcp/utils/__init__.py +113 -0
  99. tree_sitter_analyzer/mcp/utils/error_handler.py +569 -0
  100. tree_sitter_analyzer/mcp/utils/file_output_factory.py +217 -0
  101. tree_sitter_analyzer/mcp/utils/file_output_manager.py +322 -0
  102. tree_sitter_analyzer/mcp/utils/gitignore_detector.py +358 -0
  103. tree_sitter_analyzer/mcp/utils/path_resolver.py +414 -0
  104. tree_sitter_analyzer/mcp/utils/search_cache.py +343 -0
  105. tree_sitter_analyzer/models.py +840 -0
  106. tree_sitter_analyzer/mypy_current_errors.txt +2 -0
  107. tree_sitter_analyzer/output_manager.py +255 -0
  108. tree_sitter_analyzer/platform_compat/__init__.py +3 -0
  109. tree_sitter_analyzer/platform_compat/adapter.py +324 -0
  110. tree_sitter_analyzer/platform_compat/compare.py +224 -0
  111. tree_sitter_analyzer/platform_compat/detector.py +67 -0
  112. tree_sitter_analyzer/platform_compat/fixtures.py +228 -0
  113. tree_sitter_analyzer/platform_compat/profiles.py +217 -0
  114. tree_sitter_analyzer/platform_compat/record.py +55 -0
  115. tree_sitter_analyzer/platform_compat/recorder.py +155 -0
  116. tree_sitter_analyzer/platform_compat/report.py +92 -0
  117. tree_sitter_analyzer/plugins/__init__.py +280 -0
  118. tree_sitter_analyzer/plugins/base.py +647 -0
  119. tree_sitter_analyzer/plugins/manager.py +384 -0
  120. tree_sitter_analyzer/project_detector.py +328 -0
  121. tree_sitter_analyzer/queries/__init__.py +27 -0
  122. tree_sitter_analyzer/queries/csharp.py +216 -0
  123. tree_sitter_analyzer/queries/css.py +615 -0
  124. tree_sitter_analyzer/queries/go.py +275 -0
  125. tree_sitter_analyzer/queries/html.py +543 -0
  126. tree_sitter_analyzer/queries/java.py +402 -0
  127. tree_sitter_analyzer/queries/javascript.py +724 -0
  128. tree_sitter_analyzer/queries/kotlin.py +192 -0
  129. tree_sitter_analyzer/queries/markdown.py +258 -0
  130. tree_sitter_analyzer/queries/php.py +95 -0
  131. tree_sitter_analyzer/queries/python.py +859 -0
  132. tree_sitter_analyzer/queries/ruby.py +92 -0
  133. tree_sitter_analyzer/queries/rust.py +223 -0
  134. tree_sitter_analyzer/queries/sql.py +555 -0
  135. tree_sitter_analyzer/queries/typescript.py +871 -0
  136. tree_sitter_analyzer/queries/yaml.py +236 -0
  137. tree_sitter_analyzer/query_loader.py +272 -0
  138. tree_sitter_analyzer/security/__init__.py +22 -0
  139. tree_sitter_analyzer/security/boundary_manager.py +277 -0
  140. tree_sitter_analyzer/security/regex_checker.py +297 -0
  141. tree_sitter_analyzer/security/validator.py +599 -0
  142. tree_sitter_analyzer/table_formatter.py +782 -0
  143. tree_sitter_analyzer/utils/__init__.py +53 -0
  144. tree_sitter_analyzer/utils/logging.py +433 -0
  145. tree_sitter_analyzer/utils/tree_sitter_compat.py +289 -0
  146. tree_sitter_analyzer-1.9.17.1.dist-info/METADATA +485 -0
  147. tree_sitter_analyzer-1.9.17.1.dist-info/RECORD +149 -0
  148. tree_sitter_analyzer-1.9.17.1.dist-info/WHEEL +4 -0
  149. tree_sitter_analyzer-1.9.17.1.dist-info/entry_points.txt +25 -0
@@ -0,0 +1,605 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Query module for tree_sitter_analyzer.core.
4
+
5
+ This module provides the QueryExecutor class which handles Tree-sitter
6
+ query execution in the new architecture.
7
+ """
8
+
9
+ import logging
10
+ import time
11
+ from typing import Any
12
+
13
+ from tree_sitter import Language, Node, Tree
14
+
15
+ from ..query_loader import get_query_loader
16
+ from ..utils.tree_sitter_compat import TreeSitterQueryCompat, get_node_text_safe
17
+
18
+ # Configure logging
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class QueryExecutor:
23
+ """
24
+ Tree-sitter query executor for the new architecture.
25
+
26
+ This class provides a unified interface for executing Tree-sitter queries
27
+ with proper error handling and result processing.
28
+ """
29
+
30
+ def __init__(self) -> None:
31
+ """Initialize the QueryExecutor."""
32
+ self._query_loader = get_query_loader()
33
+ self._execution_stats: dict[str, Any] = {
34
+ "total_queries": 0,
35
+ "successful_queries": 0,
36
+ "failed_queries": 0,
37
+ "total_execution_time": 0.0,
38
+ }
39
+ logger.info("QueryExecutor initialized successfully")
40
+
41
+ def execute_query(
42
+ self,
43
+ tree: Tree | None,
44
+ language: Language,
45
+ query_name: str,
46
+ source_code: str,
47
+ ) -> dict[str, Any]:
48
+ """
49
+ Execute a predefined query by name.
50
+
51
+ Args:
52
+ tree: Tree-sitter tree to query
53
+ language: Tree-sitter language object
54
+ query_name: Name of the predefined query
55
+ source_code: Source code for context
56
+
57
+ Returns:
58
+ Dictionary containing query results and metadata
59
+ """
60
+ start_time = time.time()
61
+ self._execution_stats["total_queries"] += 1
62
+
63
+ try:
64
+ # Validate inputs
65
+ if tree is None:
66
+ return self._create_error_result("Tree is None", query_name=query_name)
67
+ if language is None:
68
+ return self._create_error_result(
69
+ "Language is None", query_name=query_name
70
+ )
71
+
72
+ # Get the query string with robust language name handling
73
+ language_name = None
74
+ if language:
75
+ # Try multiple ways to get language name
76
+ language_name = getattr(language, "name", None)
77
+ if not language_name:
78
+ language_name = getattr(language, "_name", None)
79
+ if not language_name:
80
+ language_name = (
81
+ str(language).split(".")[-1]
82
+ if hasattr(language, "__class__")
83
+ else None
84
+ )
85
+
86
+ # Ensure we have a valid language name
87
+ if (
88
+ not language_name
89
+ or language_name.strip() == ""
90
+ or language_name == "None"
91
+ ):
92
+ language_name = "unknown"
93
+ else:
94
+ language_name = language_name.strip().lower()
95
+
96
+ query_string = self._query_loader.get_query(language_name, query_name)
97
+ if query_string is None:
98
+ return self._create_error_result(
99
+ f"Query '{query_name}' not found", query_name=query_name
100
+ )
101
+
102
+ # Create and execute the query using modern API
103
+ try:
104
+ captures = TreeSitterQueryCompat.safe_execute_query(
105
+ language, query_string, tree.root_node, fallback_result=[]
106
+ )
107
+
108
+ # Process captures
109
+ try:
110
+ processed_captures = self._process_captures(captures, source_code)
111
+ except Exception as e:
112
+ logger.error(f"Error processing captures for {query_name}: {e}")
113
+ return self._create_error_result(
114
+ f"Capture processing failed: {str(e)}", query_name=query_name
115
+ )
116
+
117
+ self._execution_stats["successful_queries"] += 1
118
+ execution_time = time.time() - start_time
119
+ self._execution_stats["total_execution_time"] += execution_time
120
+
121
+ return {
122
+ "captures": processed_captures,
123
+ "query_name": query_name,
124
+ "query_string": query_string,
125
+ "execution_time": execution_time,
126
+ "success": True,
127
+ }
128
+
129
+ except Exception as e:
130
+ logger.error(f"Error executing query '{query_name}': {e}")
131
+ return self._create_error_result(
132
+ f"Query execution failed: {str(e)}", query_name=query_name
133
+ )
134
+
135
+ except Exception as e:
136
+ logger.error(f"Unexpected error in execute_query: {e}")
137
+ self._execution_stats["failed_queries"] += 1
138
+ return self._create_error_result(
139
+ f"Unexpected error: {str(e)}", query_name=query_name
140
+ )
141
+
142
+ def execute_query_with_language_name(
143
+ self,
144
+ tree: Tree | None,
145
+ language: Language,
146
+ query_name: str,
147
+ source_code: str,
148
+ language_name: str,
149
+ ) -> dict[str, Any]:
150
+ """
151
+ Execute a predefined query by name with explicit language name.
152
+
153
+ Args:
154
+ tree: Tree-sitter tree to query
155
+ language: Tree-sitter language object
156
+ query_name: Name of the predefined query
157
+ source_code: Source code for context
158
+ language_name: Name of the programming language
159
+
160
+ Returns:
161
+ Dictionary containing query results and metadata
162
+ """
163
+ start_time = time.time()
164
+ self._execution_stats["total_queries"] += 1
165
+
166
+ try:
167
+ # Validate inputs
168
+ if tree is None:
169
+ return self._create_error_result("Tree is None", query_name=query_name)
170
+ if language is None:
171
+ return self._create_error_result(
172
+ "Language is None", query_name=query_name
173
+ )
174
+
175
+ # Use the provided language name
176
+ language_name = (
177
+ language_name.strip().lower() if language_name else "unknown"
178
+ )
179
+
180
+ query_string = self._query_loader.get_query(language_name, query_name)
181
+ if query_string is None:
182
+ return self._create_error_result(
183
+ f"Query '{query_name}' not found", query_name=query_name
184
+ )
185
+
186
+ # Create and execute the query using modern API
187
+ try:
188
+ captures = TreeSitterQueryCompat.safe_execute_query(
189
+ language, query_string, tree.root_node, fallback_result=[]
190
+ )
191
+
192
+ # Process captures
193
+ try:
194
+ processed_captures = self._process_captures(captures, source_code)
195
+ except Exception as e:
196
+ logger.error(f"Error processing captures for {query_name}: {e}")
197
+ return self._create_error_result(
198
+ f"Capture processing failed: {str(e)}", query_name=query_name
199
+ )
200
+
201
+ self._execution_stats["successful_queries"] += 1
202
+ execution_time = time.time() - start_time
203
+ self._execution_stats["total_execution_time"] += execution_time
204
+
205
+ return {
206
+ "captures": processed_captures,
207
+ "query_name": query_name,
208
+ "query_string": query_string,
209
+ "execution_time": execution_time,
210
+ "success": True,
211
+ }
212
+
213
+ except Exception as e:
214
+ logger.error(f"Error executing query '{query_name}': {e}")
215
+ return self._create_error_result(
216
+ f"Query execution failed: {str(e)}", query_name=query_name
217
+ )
218
+
219
+ except Exception as e:
220
+ logger.error(f"Unexpected error in execute_query: {e}")
221
+ self._execution_stats["failed_queries"] += 1
222
+ return self._create_error_result(
223
+ f"Unexpected error: {str(e)}", query_name=query_name
224
+ )
225
+
226
+ def execute_query_string(
227
+ self,
228
+ tree: Tree | None,
229
+ language: Language,
230
+ query_string: str,
231
+ source_code: str,
232
+ ) -> dict[str, Any]:
233
+ """
234
+ Execute a query string directly.
235
+
236
+ Args:
237
+ tree: Tree-sitter tree to query
238
+ language: Tree-sitter language object
239
+ query_string: Query string to execute
240
+ source_code: Source code for context
241
+
242
+ Returns:
243
+ Dictionary containing query results and metadata
244
+ """
245
+ start_time = time.time()
246
+ self._execution_stats["total_queries"] += 1
247
+
248
+ try:
249
+ # Validate inputs
250
+ if tree is None:
251
+ return self._create_error_result("Tree is None")
252
+ if language is None:
253
+ return self._create_error_result("Language is None")
254
+
255
+ # Create and execute the query using modern API
256
+ try:
257
+ captures = TreeSitterQueryCompat.safe_execute_query(
258
+ language, query_string, tree.root_node, fallback_result=[]
259
+ )
260
+
261
+ # Process captures
262
+ try:
263
+ processed_captures = self._process_captures(captures, source_code)
264
+ except Exception as e:
265
+ logger.error(f"Error processing captures: {e}")
266
+ return self._create_error_result(
267
+ f"Capture processing failed: {str(e)}"
268
+ )
269
+
270
+ self._execution_stats["successful_queries"] += 1
271
+ execution_time = time.time() - start_time
272
+ self._execution_stats["total_execution_time"] += execution_time
273
+
274
+ return {
275
+ "captures": processed_captures,
276
+ "query_string": query_string,
277
+ "execution_time": execution_time,
278
+ "success": True,
279
+ }
280
+
281
+ except Exception as e:
282
+ logger.error(f"Error executing query string: {e}")
283
+ return self._create_error_result(
284
+ f"Query execution failed: {str(e)}", query_string=query_string
285
+ )
286
+
287
+ except Exception as e:
288
+ logger.error(f"Unexpected error in execute_query_string: {e}")
289
+ self._execution_stats["failed_queries"] += 1
290
+ return self._create_error_result(f"Unexpected error: {str(e)}")
291
+
292
+ def execute_multiple_queries(
293
+ self, tree: Tree, language: Language, query_names: list[str], source_code: str
294
+ ) -> dict[str, dict[str, Any]]:
295
+ """
296
+ Execute multiple queries and return combined results.
297
+
298
+ Args:
299
+ tree: Tree-sitter tree to query
300
+ language: Tree-sitter language object
301
+ query_names: List of query names to execute
302
+ source_code: Source code for context
303
+
304
+ Returns:
305
+ Dictionary mapping query names to their results
306
+ """
307
+ results = {}
308
+
309
+ for query_name in query_names:
310
+ result = self.execute_query(tree, language, query_name, source_code)
311
+ results[query_name] = result
312
+
313
+ return results
314
+
315
+ def _process_captures(
316
+ self, captures: Any, source_code: str
317
+ ) -> list[dict[str, Any]]:
318
+ """
319
+ Process query captures into standardized format.
320
+
321
+ Args:
322
+ captures: Raw captures from Tree-sitter query
323
+ source_code: Source code for context
324
+
325
+ Returns:
326
+ List of processed capture dictionaries
327
+ """
328
+ processed = []
329
+
330
+ try:
331
+ for capture in captures:
332
+ try:
333
+ # Handle tuple format from modern API
334
+ if isinstance(capture, tuple) and len(capture) == 2:
335
+ node, name = capture
336
+ # Handle dictionary format (legacy API compatibility)
337
+ elif (
338
+ isinstance(capture, dict)
339
+ and "node" in capture
340
+ and "name" in capture
341
+ ):
342
+ node = capture["node"]
343
+ name = capture["name"]
344
+ else:
345
+ logger.warning(f"Unexpected capture format: {type(capture)}")
346
+ continue
347
+
348
+ if node is None:
349
+ continue
350
+
351
+ result_dict = self._create_result_dict(node, name, source_code)
352
+ processed.append(result_dict)
353
+
354
+ except Exception as e:
355
+ logger.error(f"Error processing capture: {e}")
356
+ continue
357
+
358
+ except Exception as e:
359
+ logger.error(f"Error in _process_captures: {e}")
360
+
361
+ return processed
362
+
363
+ def _create_result_dict(
364
+ self, node: Node, capture_name: str, source_code: str
365
+ ) -> dict[str, Any]:
366
+ """
367
+ Create a result dictionary from a Tree-sitter node.
368
+
369
+ Args:
370
+ node: Tree-sitter node
371
+ capture_name: Name of the capture
372
+ source_code: Source code for context
373
+
374
+ Returns:
375
+ Dictionary containing node information
376
+ """
377
+ try:
378
+ # Extract node text using safe utility
379
+ node_text = get_node_text_safe(node, source_code)
380
+
381
+ return {
382
+ "capture_name": capture_name,
383
+ "node_type": getattr(node, "type", "unknown"),
384
+ "start_point": getattr(node, "start_point", (0, 0)),
385
+ "end_point": getattr(node, "end_point", (0, 0)),
386
+ "start_byte": getattr(node, "start_byte", 0),
387
+ "end_byte": getattr(node, "end_byte", 0),
388
+ "text": node_text,
389
+ "line_number": getattr(node, "start_point", (0, 0))[0] + 1,
390
+ "column_number": getattr(node, "start_point", (0, 0))[1],
391
+ }
392
+
393
+ except Exception as e:
394
+ logger.error(f"Error creating result dict: {e}")
395
+ return {"capture_name": capture_name, "node_type": "error", "error": str(e)}
396
+
397
+ def _create_error_result(
398
+ self, error_message: str, query_name: str | None = None, **kwargs: Any
399
+ ) -> dict[str, Any]:
400
+ """
401
+ Create an error result dictionary.
402
+
403
+ Args:
404
+ error_message: Error message
405
+ query_name: Optional query name
406
+ **kwargs: Additional fields to include in the error result
407
+
408
+ Returns:
409
+ Error result dictionary
410
+ """
411
+ result = {"captures": [], "error": error_message, "success": False}
412
+
413
+ if query_name:
414
+ result["query_name"] = query_name
415
+
416
+ result.update(kwargs)
417
+ return result
418
+
419
+ def get_available_queries(self, language: str) -> list[str]:
420
+ """
421
+ Get available queries for a language.
422
+
423
+ Args:
424
+ language: Programming language name
425
+
426
+ Returns:
427
+ List of available query names
428
+ """
429
+ try:
430
+ queries = self._query_loader.get_all_queries_for_language(language)
431
+ if isinstance(queries, dict):
432
+ return list(queries.keys())
433
+ # Handle other iterable types
434
+ try: # type: ignore[unreachable]
435
+ return list(queries) if queries else []
436
+ except (TypeError, ValueError):
437
+ return []
438
+ except Exception as e:
439
+ logger.error(f"Error getting available queries for {language}: {e}")
440
+ return []
441
+
442
+ def get_query_description(self, language: str, query_name: str) -> str | None:
443
+ """
444
+ Get description for a specific query.
445
+
446
+ Args:
447
+ language: Programming language name
448
+ query_name: Name of the query
449
+
450
+ Returns:
451
+ Query description or None if not found
452
+ """
453
+ try:
454
+ return self._query_loader.get_query_description(language, query_name)
455
+ except Exception as e:
456
+ logger.error(f"Error getting query description: {e}")
457
+ return None
458
+
459
+ def validate_query(self, language: str, query_string: str) -> bool:
460
+ """
461
+ Validate a query string for a specific language.
462
+
463
+ Args:
464
+ language: Programming language name
465
+ query_string: Query string to validate
466
+
467
+ Returns:
468
+ True if query is valid, False otherwise
469
+ """
470
+ try:
471
+ # This would require loading the language and attempting to create the query
472
+ # For now, we'll do basic validation
473
+ from ..language_loader import get_loader
474
+
475
+ loader = get_loader()
476
+
477
+ lang_obj = loader.load_language(language)
478
+ if lang_obj is None:
479
+ return False
480
+
481
+ # Try to create the query
482
+ lang_obj.query(query_string)
483
+ return True
484
+
485
+ except Exception as e:
486
+ logger.error(f"Query validation failed: {e}")
487
+ return False
488
+
489
+ def get_query_statistics(self) -> dict[str, Any]:
490
+ """
491
+ Get query execution statistics.
492
+
493
+ Returns:
494
+ Dictionary containing execution statistics
495
+ """
496
+ stats = self._execution_stats.copy()
497
+
498
+ if stats["total_queries"] > 0:
499
+ stats["success_rate"] = stats["successful_queries"] / stats["total_queries"]
500
+ stats["average_execution_time"] = (
501
+ stats["total_execution_time"] / stats["total_queries"]
502
+ )
503
+ else:
504
+ stats["success_rate"] = 0.0
505
+ stats["average_execution_time"] = 0.0
506
+
507
+ return stats
508
+
509
+ def reset_statistics(self) -> None:
510
+ """Reset query execution statistics."""
511
+ self._execution_stats = {
512
+ "total_queries": 0,
513
+ "successful_queries": 0,
514
+ "failed_queries": 0,
515
+ "total_execution_time": 0.0,
516
+ }
517
+
518
+
519
+ # Module-level convenience functions for backward compatibility
520
+ def get_available_queries(language: str | None = None) -> list[str]:
521
+ """
522
+ Get available queries for a language (module-level function).
523
+
524
+ Args:
525
+ language: Programming language name (optional)
526
+
527
+ Returns:
528
+ List of available query names
529
+ """
530
+ try:
531
+ loader = get_query_loader()
532
+ if language:
533
+ return loader.list_queries_for_language(language)
534
+
535
+ # If no language, return a list of all query names across supported languages
536
+ all_queries = set()
537
+ for lang in loader.list_supported_languages():
538
+ all_queries.update(loader.list_queries_for_language(lang))
539
+ return sorted(all_queries)
540
+
541
+ except Exception as e:
542
+ logger.error(f"Error getting available queries: {e}")
543
+ return []
544
+
545
+
546
+ def get_query_description(language: str, query_name: str) -> str | None:
547
+ """
548
+ Get description for a specific query (module-level function).
549
+
550
+ Args:
551
+ language: Programming language name
552
+ query_name: Name of the query
553
+
554
+ Returns:
555
+ Query description or None if not found
556
+ """
557
+ try:
558
+ from ..query_loader import get_query_loader
559
+
560
+ loader = get_query_loader()
561
+ return loader.get_query_description(language, query_name)
562
+ except Exception as e:
563
+ logger.error(f"Error getting query description: {e}")
564
+ return None
565
+
566
+
567
+ # Module-level attributes for backward compatibility
568
+ try:
569
+ query_loader = get_query_loader()
570
+ except Exception:
571
+ query_loader = None # type: ignore
572
+
573
+
574
+ def get_all_queries_for_language(language: str) -> list[str]:
575
+ """
576
+ Get all available queries for a specific language.
577
+
578
+ Args:
579
+ language: Programming language name
580
+
581
+ Returns:
582
+ List of available query names for the language
583
+
584
+ .. deprecated:: 0.2.1
585
+ This function is deprecated and will be removed in a future version.
586
+ Use the unified analysis engine instead.
587
+ """
588
+ import warnings
589
+
590
+ warnings.warn(
591
+ "get_all_queries_for_language is deprecated and will be removed "
592
+ "in a future version. Use the unified analysis engine instead.",
593
+ DeprecationWarning,
594
+ stacklevel=2,
595
+ )
596
+ return []
597
+
598
+
599
+ # Update module-level attributes for backward compatibility
600
+ try:
601
+ from ..language_loader import get_loader
602
+
603
+ loader = get_loader()
604
+ except Exception:
605
+ loader = None # type: ignore