tree-sitter-analyzer 1.0.0__py3-none-any.whl → 1.1.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/api.py +542 -542
- tree_sitter_analyzer/cli/commands/base_command.py +181 -181
- tree_sitter_analyzer/cli/commands/partial_read_command.py +139 -139
- tree_sitter_analyzer/cli/info_commands.py +124 -124
- tree_sitter_analyzer/cli_main.py +327 -327
- tree_sitter_analyzer/core/analysis_engine.py +584 -584
- tree_sitter_analyzer/core/query_service.py +162 -162
- tree_sitter_analyzer/file_handler.py +212 -212
- tree_sitter_analyzer/formatters/base_formatter.py +169 -169
- tree_sitter_analyzer/interfaces/cli.py +535 -535
- tree_sitter_analyzer/mcp/__init__.py +1 -1
- tree_sitter_analyzer/mcp/resources/__init__.py +1 -1
- tree_sitter_analyzer/mcp/resources/project_stats_resource.py +16 -5
- tree_sitter_analyzer/mcp/server.py +655 -655
- tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
- tree_sitter_analyzer/mcp/utils/__init__.py +2 -2
- tree_sitter_analyzer/mcp/utils/error_handler.py +569 -569
- tree_sitter_analyzer/mcp/utils/path_resolver.py +414 -414
- tree_sitter_analyzer/output_manager.py +257 -257
- tree_sitter_analyzer/project_detector.py +330 -330
- tree_sitter_analyzer/security/boundary_manager.py +260 -260
- tree_sitter_analyzer/security/validator.py +257 -257
- tree_sitter_analyzer/table_formatter.py +710 -710
- tree_sitter_analyzer/utils.py +335 -335
- {tree_sitter_analyzer-1.0.0.dist-info → tree_sitter_analyzer-1.1.0.dist-info}/METADATA +11 -11
- {tree_sitter_analyzer-1.0.0.dist-info → tree_sitter_analyzer-1.1.0.dist-info}/RECORD +29 -29
- {tree_sitter_analyzer-1.0.0.dist-info → tree_sitter_analyzer-1.1.0.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-1.0.0.dist-info → tree_sitter_analyzer-1.1.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,162 +1,162 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Query Service
|
|
4
|
-
|
|
5
|
-
Unified query service for both CLI and MCP interfaces to avoid code duplication.
|
|
6
|
-
Provides core tree-sitter query functionality including predefined and custom queries.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import logging
|
|
10
|
-
from typing import Any
|
|
11
|
-
|
|
12
|
-
from ..encoding_utils import read_file_safe
|
|
13
|
-
from ..query_loader import query_loader
|
|
14
|
-
from .parser import Parser
|
|
15
|
-
from .query_filter import QueryFilter
|
|
16
|
-
|
|
17
|
-
logger = logging.getLogger(__name__)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class QueryService:
|
|
21
|
-
"""Unified query service providing tree-sitter query functionality"""
|
|
22
|
-
|
|
23
|
-
def __init__(self, project_root: str | None = None) -> None:
|
|
24
|
-
"""Initialize the query service"""
|
|
25
|
-
self.project_root = project_root
|
|
26
|
-
self.parser = Parser()
|
|
27
|
-
self.filter = QueryFilter()
|
|
28
|
-
|
|
29
|
-
async def execute_query(
|
|
30
|
-
self,
|
|
31
|
-
file_path: str,
|
|
32
|
-
language: str,
|
|
33
|
-
query_key: str | None = None,
|
|
34
|
-
query_string: str | None = None,
|
|
35
|
-
filter_expression: str | None = None,
|
|
36
|
-
) -> list[dict[str, Any]] | None:
|
|
37
|
-
"""
|
|
38
|
-
Execute a query
|
|
39
|
-
|
|
40
|
-
Args:
|
|
41
|
-
file_path: Path to the file to analyze
|
|
42
|
-
language: Programming language
|
|
43
|
-
query_key: Predefined query key (e.g., 'methods', 'class')
|
|
44
|
-
query_string: Custom query string (e.g., '(method_declaration) @method')
|
|
45
|
-
filter_expression: Filter expression (e.g., 'name=main', 'name=~get*,public=true')
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
List of query results, each containing capture_name, node_type, start_line, end_line, content
|
|
49
|
-
|
|
50
|
-
Raises:
|
|
51
|
-
ValueError: If neither query_key nor query_string is provided
|
|
52
|
-
FileNotFoundError: If file doesn't exist
|
|
53
|
-
Exception: If query execution fails
|
|
54
|
-
"""
|
|
55
|
-
if not query_key and not query_string:
|
|
56
|
-
raise ValueError("Must provide either query_key or query_string")
|
|
57
|
-
|
|
58
|
-
if query_key and query_string:
|
|
59
|
-
raise ValueError("Cannot provide both query_key and query_string")
|
|
60
|
-
|
|
61
|
-
try:
|
|
62
|
-
# Read file content
|
|
63
|
-
content, encoding = read_file_safe(file_path)
|
|
64
|
-
|
|
65
|
-
# Parse file
|
|
66
|
-
parse_result = self.parser.parse_code(content, language, file_path)
|
|
67
|
-
if not parse_result or not parse_result.tree:
|
|
68
|
-
raise Exception("Failed to parse file")
|
|
69
|
-
|
|
70
|
-
tree = parse_result.tree
|
|
71
|
-
language_obj = tree.language if hasattr(tree, "language") else None
|
|
72
|
-
if not language_obj:
|
|
73
|
-
raise Exception(f"Language object not available for {language}")
|
|
74
|
-
|
|
75
|
-
# Get query string
|
|
76
|
-
if query_key:
|
|
77
|
-
query_string = query_loader.get_query(language, query_key)
|
|
78
|
-
if not query_string:
|
|
79
|
-
raise ValueError(
|
|
80
|
-
f"Query '{query_key}' not found for language '{language}'"
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
# Execute tree-sitter query
|
|
84
|
-
ts_query = language_obj.query(query_string)
|
|
85
|
-
captures = ts_query.captures(tree.root_node)
|
|
86
|
-
|
|
87
|
-
# Process capture results
|
|
88
|
-
results = []
|
|
89
|
-
if isinstance(captures, dict):
|
|
90
|
-
# New tree-sitter API returns dictionary
|
|
91
|
-
for capture_name, nodes in captures.items():
|
|
92
|
-
for node in nodes:
|
|
93
|
-
results.append(self._create_result_dict(node, capture_name))
|
|
94
|
-
else:
|
|
95
|
-
# Old tree-sitter API returns list of tuples
|
|
96
|
-
for capture in captures:
|
|
97
|
-
if isinstance(capture, tuple) and len(capture) == 2:
|
|
98
|
-
node, name = capture
|
|
99
|
-
results.append(self._create_result_dict(node, name))
|
|
100
|
-
|
|
101
|
-
# Apply filters
|
|
102
|
-
if filter_expression and results:
|
|
103
|
-
results = self.filter.filter_results(results, filter_expression)
|
|
104
|
-
|
|
105
|
-
return results
|
|
106
|
-
|
|
107
|
-
except Exception as e:
|
|
108
|
-
logger.error(f"Query execution failed: {e}")
|
|
109
|
-
raise
|
|
110
|
-
|
|
111
|
-
def _create_result_dict(self, node: Any, capture_name: str) -> dict[str, Any]:
|
|
112
|
-
"""
|
|
113
|
-
Create result dictionary from tree-sitter node
|
|
114
|
-
|
|
115
|
-
Args:
|
|
116
|
-
node: tree-sitter node
|
|
117
|
-
capture_name: capture name
|
|
118
|
-
|
|
119
|
-
Returns:
|
|
120
|
-
Result dictionary
|
|
121
|
-
"""
|
|
122
|
-
return {
|
|
123
|
-
"capture_name": capture_name,
|
|
124
|
-
"node_type": node.type if hasattr(node, "type") else "unknown",
|
|
125
|
-
"start_line": (
|
|
126
|
-
node.start_point[0] + 1 if hasattr(node, "start_point") else 0
|
|
127
|
-
),
|
|
128
|
-
"end_line": node.end_point[0] + 1 if hasattr(node, "end_point") else 0,
|
|
129
|
-
"content": (
|
|
130
|
-
node.text.decode("utf-8", errors="replace")
|
|
131
|
-
if hasattr(node, "text") and node.text
|
|
132
|
-
else ""
|
|
133
|
-
),
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
def get_available_queries(self, language: str) -> list[str]:
|
|
137
|
-
"""
|
|
138
|
-
Get available query keys for specified language
|
|
139
|
-
|
|
140
|
-
Args:
|
|
141
|
-
language: Programming language
|
|
142
|
-
|
|
143
|
-
Returns:
|
|
144
|
-
List of available query keys
|
|
145
|
-
"""
|
|
146
|
-
return query_loader.list_queries(language)
|
|
147
|
-
|
|
148
|
-
def get_query_description(self, language: str, query_key: str) -> str | None:
|
|
149
|
-
"""
|
|
150
|
-
Get description for query key
|
|
151
|
-
|
|
152
|
-
Args:
|
|
153
|
-
language: Programming language
|
|
154
|
-
query_key: Query key
|
|
155
|
-
|
|
156
|
-
Returns:
|
|
157
|
-
Query description, or None if not found
|
|
158
|
-
"""
|
|
159
|
-
try:
|
|
160
|
-
return query_loader.get_query_description(language, query_key)
|
|
161
|
-
except Exception:
|
|
162
|
-
return None
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Query Service
|
|
4
|
+
|
|
5
|
+
Unified query service for both CLI and MCP interfaces to avoid code duplication.
|
|
6
|
+
Provides core tree-sitter query functionality including predefined and custom queries.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from ..encoding_utils import read_file_safe
|
|
13
|
+
from ..query_loader import query_loader
|
|
14
|
+
from .parser import Parser
|
|
15
|
+
from .query_filter import QueryFilter
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class QueryService:
|
|
21
|
+
"""Unified query service providing tree-sitter query functionality"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, project_root: str | None = None) -> None:
|
|
24
|
+
"""Initialize the query service"""
|
|
25
|
+
self.project_root = project_root
|
|
26
|
+
self.parser = Parser()
|
|
27
|
+
self.filter = QueryFilter()
|
|
28
|
+
|
|
29
|
+
async def execute_query(
|
|
30
|
+
self,
|
|
31
|
+
file_path: str,
|
|
32
|
+
language: str,
|
|
33
|
+
query_key: str | None = None,
|
|
34
|
+
query_string: str | None = None,
|
|
35
|
+
filter_expression: str | None = None,
|
|
36
|
+
) -> list[dict[str, Any]] | None:
|
|
37
|
+
"""
|
|
38
|
+
Execute a query
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
file_path: Path to the file to analyze
|
|
42
|
+
language: Programming language
|
|
43
|
+
query_key: Predefined query key (e.g., 'methods', 'class')
|
|
44
|
+
query_string: Custom query string (e.g., '(method_declaration) @method')
|
|
45
|
+
filter_expression: Filter expression (e.g., 'name=main', 'name=~get*,public=true')
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
List of query results, each containing capture_name, node_type, start_line, end_line, content
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
ValueError: If neither query_key nor query_string is provided
|
|
52
|
+
FileNotFoundError: If file doesn't exist
|
|
53
|
+
Exception: If query execution fails
|
|
54
|
+
"""
|
|
55
|
+
if not query_key and not query_string:
|
|
56
|
+
raise ValueError("Must provide either query_key or query_string")
|
|
57
|
+
|
|
58
|
+
if query_key and query_string:
|
|
59
|
+
raise ValueError("Cannot provide both query_key and query_string")
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
# Read file content
|
|
63
|
+
content, encoding = read_file_safe(file_path)
|
|
64
|
+
|
|
65
|
+
# Parse file
|
|
66
|
+
parse_result = self.parser.parse_code(content, language, file_path)
|
|
67
|
+
if not parse_result or not parse_result.tree:
|
|
68
|
+
raise Exception("Failed to parse file")
|
|
69
|
+
|
|
70
|
+
tree = parse_result.tree
|
|
71
|
+
language_obj = tree.language if hasattr(tree, "language") else None
|
|
72
|
+
if not language_obj:
|
|
73
|
+
raise Exception(f"Language object not available for {language}")
|
|
74
|
+
|
|
75
|
+
# Get query string
|
|
76
|
+
if query_key:
|
|
77
|
+
query_string = query_loader.get_query(language, query_key)
|
|
78
|
+
if not query_string:
|
|
79
|
+
raise ValueError(
|
|
80
|
+
f"Query '{query_key}' not found for language '{language}'"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Execute tree-sitter query
|
|
84
|
+
ts_query = language_obj.query(query_string)
|
|
85
|
+
captures = ts_query.captures(tree.root_node)
|
|
86
|
+
|
|
87
|
+
# Process capture results
|
|
88
|
+
results = []
|
|
89
|
+
if isinstance(captures, dict):
|
|
90
|
+
# New tree-sitter API returns dictionary
|
|
91
|
+
for capture_name, nodes in captures.items():
|
|
92
|
+
for node in nodes:
|
|
93
|
+
results.append(self._create_result_dict(node, capture_name))
|
|
94
|
+
else:
|
|
95
|
+
# Old tree-sitter API returns list of tuples
|
|
96
|
+
for capture in captures:
|
|
97
|
+
if isinstance(capture, tuple) and len(capture) == 2:
|
|
98
|
+
node, name = capture
|
|
99
|
+
results.append(self._create_result_dict(node, name))
|
|
100
|
+
|
|
101
|
+
# Apply filters
|
|
102
|
+
if filter_expression and results:
|
|
103
|
+
results = self.filter.filter_results(results, filter_expression)
|
|
104
|
+
|
|
105
|
+
return results
|
|
106
|
+
|
|
107
|
+
except Exception as e:
|
|
108
|
+
logger.error(f"Query execution failed: {e}")
|
|
109
|
+
raise
|
|
110
|
+
|
|
111
|
+
def _create_result_dict(self, node: Any, capture_name: str) -> dict[str, Any]:
|
|
112
|
+
"""
|
|
113
|
+
Create result dictionary from tree-sitter node
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
node: tree-sitter node
|
|
117
|
+
capture_name: capture name
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Result dictionary
|
|
121
|
+
"""
|
|
122
|
+
return {
|
|
123
|
+
"capture_name": capture_name,
|
|
124
|
+
"node_type": node.type if hasattr(node, "type") else "unknown",
|
|
125
|
+
"start_line": (
|
|
126
|
+
node.start_point[0] + 1 if hasattr(node, "start_point") else 0
|
|
127
|
+
),
|
|
128
|
+
"end_line": node.end_point[0] + 1 if hasattr(node, "end_point") else 0,
|
|
129
|
+
"content": (
|
|
130
|
+
node.text.decode("utf-8", errors="replace")
|
|
131
|
+
if hasattr(node, "text") and node.text
|
|
132
|
+
else ""
|
|
133
|
+
),
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
def get_available_queries(self, language: str) -> list[str]:
|
|
137
|
+
"""
|
|
138
|
+
Get available query keys for specified language
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
language: Programming language
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
List of available query keys
|
|
145
|
+
"""
|
|
146
|
+
return query_loader.list_queries(language)
|
|
147
|
+
|
|
148
|
+
def get_query_description(self, language: str, query_key: str) -> str | None:
|
|
149
|
+
"""
|
|
150
|
+
Get description for query key
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
language: Programming language
|
|
154
|
+
query_key: Query key
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Query description, or None if not found
|
|
158
|
+
"""
|
|
159
|
+
try:
|
|
160
|
+
return query_loader.get_query_description(language, query_key)
|
|
161
|
+
except Exception:
|
|
162
|
+
return None
|