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.
- tree_sitter_analyzer/__init__.py +132 -0
- tree_sitter_analyzer/__main__.py +11 -0
- tree_sitter_analyzer/api.py +853 -0
- tree_sitter_analyzer/cli/__init__.py +39 -0
- tree_sitter_analyzer/cli/__main__.py +12 -0
- tree_sitter_analyzer/cli/argument_validator.py +89 -0
- tree_sitter_analyzer/cli/commands/__init__.py +26 -0
- tree_sitter_analyzer/cli/commands/advanced_command.py +226 -0
- tree_sitter_analyzer/cli/commands/base_command.py +181 -0
- tree_sitter_analyzer/cli/commands/default_command.py +18 -0
- tree_sitter_analyzer/cli/commands/find_and_grep_cli.py +188 -0
- tree_sitter_analyzer/cli/commands/list_files_cli.py +133 -0
- tree_sitter_analyzer/cli/commands/partial_read_command.py +139 -0
- tree_sitter_analyzer/cli/commands/query_command.py +109 -0
- tree_sitter_analyzer/cli/commands/search_content_cli.py +161 -0
- tree_sitter_analyzer/cli/commands/structure_command.py +156 -0
- tree_sitter_analyzer/cli/commands/summary_command.py +116 -0
- tree_sitter_analyzer/cli/commands/table_command.py +414 -0
- tree_sitter_analyzer/cli/info_commands.py +124 -0
- tree_sitter_analyzer/cli_main.py +472 -0
- tree_sitter_analyzer/constants.py +85 -0
- tree_sitter_analyzer/core/__init__.py +15 -0
- tree_sitter_analyzer/core/analysis_engine.py +580 -0
- tree_sitter_analyzer/core/cache_service.py +333 -0
- tree_sitter_analyzer/core/engine.py +585 -0
- tree_sitter_analyzer/core/parser.py +293 -0
- tree_sitter_analyzer/core/query.py +605 -0
- tree_sitter_analyzer/core/query_filter.py +200 -0
- tree_sitter_analyzer/core/query_service.py +340 -0
- tree_sitter_analyzer/encoding_utils.py +530 -0
- tree_sitter_analyzer/exceptions.py +747 -0
- tree_sitter_analyzer/file_handler.py +246 -0
- tree_sitter_analyzer/formatters/__init__.py +1 -0
- tree_sitter_analyzer/formatters/base_formatter.py +201 -0
- tree_sitter_analyzer/formatters/csharp_formatter.py +367 -0
- tree_sitter_analyzer/formatters/formatter_config.py +197 -0
- tree_sitter_analyzer/formatters/formatter_factory.py +84 -0
- tree_sitter_analyzer/formatters/formatter_registry.py +377 -0
- tree_sitter_analyzer/formatters/formatter_selector.py +96 -0
- tree_sitter_analyzer/formatters/go_formatter.py +368 -0
- tree_sitter_analyzer/formatters/html_formatter.py +498 -0
- tree_sitter_analyzer/formatters/java_formatter.py +423 -0
- tree_sitter_analyzer/formatters/javascript_formatter.py +611 -0
- tree_sitter_analyzer/formatters/kotlin_formatter.py +268 -0
- tree_sitter_analyzer/formatters/language_formatter_factory.py +123 -0
- tree_sitter_analyzer/formatters/legacy_formatter_adapters.py +228 -0
- tree_sitter_analyzer/formatters/markdown_formatter.py +725 -0
- tree_sitter_analyzer/formatters/php_formatter.py +301 -0
- tree_sitter_analyzer/formatters/python_formatter.py +830 -0
- tree_sitter_analyzer/formatters/ruby_formatter.py +278 -0
- tree_sitter_analyzer/formatters/rust_formatter.py +233 -0
- tree_sitter_analyzer/formatters/sql_formatter_wrapper.py +689 -0
- tree_sitter_analyzer/formatters/sql_formatters.py +536 -0
- tree_sitter_analyzer/formatters/typescript_formatter.py +543 -0
- tree_sitter_analyzer/formatters/yaml_formatter.py +462 -0
- tree_sitter_analyzer/interfaces/__init__.py +9 -0
- tree_sitter_analyzer/interfaces/cli.py +535 -0
- tree_sitter_analyzer/interfaces/cli_adapter.py +359 -0
- tree_sitter_analyzer/interfaces/mcp_adapter.py +224 -0
- tree_sitter_analyzer/interfaces/mcp_server.py +428 -0
- tree_sitter_analyzer/language_detector.py +553 -0
- tree_sitter_analyzer/language_loader.py +271 -0
- tree_sitter_analyzer/languages/__init__.py +10 -0
- tree_sitter_analyzer/languages/csharp_plugin.py +1076 -0
- tree_sitter_analyzer/languages/css_plugin.py +449 -0
- tree_sitter_analyzer/languages/go_plugin.py +836 -0
- tree_sitter_analyzer/languages/html_plugin.py +496 -0
- tree_sitter_analyzer/languages/java_plugin.py +1299 -0
- tree_sitter_analyzer/languages/javascript_plugin.py +1622 -0
- tree_sitter_analyzer/languages/kotlin_plugin.py +656 -0
- tree_sitter_analyzer/languages/markdown_plugin.py +1928 -0
- tree_sitter_analyzer/languages/php_plugin.py +862 -0
- tree_sitter_analyzer/languages/python_plugin.py +1636 -0
- tree_sitter_analyzer/languages/ruby_plugin.py +757 -0
- tree_sitter_analyzer/languages/rust_plugin.py +673 -0
- tree_sitter_analyzer/languages/sql_plugin.py +2444 -0
- tree_sitter_analyzer/languages/typescript_plugin.py +1892 -0
- tree_sitter_analyzer/languages/yaml_plugin.py +695 -0
- tree_sitter_analyzer/legacy_table_formatter.py +860 -0
- tree_sitter_analyzer/mcp/__init__.py +34 -0
- tree_sitter_analyzer/mcp/resources/__init__.py +43 -0
- tree_sitter_analyzer/mcp/resources/code_file_resource.py +208 -0
- tree_sitter_analyzer/mcp/resources/project_stats_resource.py +586 -0
- tree_sitter_analyzer/mcp/server.py +869 -0
- tree_sitter_analyzer/mcp/tools/__init__.py +28 -0
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +779 -0
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +291 -0
- tree_sitter_analyzer/mcp/tools/base_tool.py +139 -0
- tree_sitter_analyzer/mcp/tools/fd_rg_utils.py +816 -0
- tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +686 -0
- tree_sitter_analyzer/mcp/tools/list_files_tool.py +413 -0
- tree_sitter_analyzer/mcp/tools/output_format_validator.py +148 -0
- tree_sitter_analyzer/mcp/tools/query_tool.py +443 -0
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +464 -0
- tree_sitter_analyzer/mcp/tools/search_content_tool.py +836 -0
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +572 -0
- tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +653 -0
- tree_sitter_analyzer/mcp/utils/__init__.py +113 -0
- tree_sitter_analyzer/mcp/utils/error_handler.py +569 -0
- tree_sitter_analyzer/mcp/utils/file_output_factory.py +217 -0
- tree_sitter_analyzer/mcp/utils/file_output_manager.py +322 -0
- tree_sitter_analyzer/mcp/utils/gitignore_detector.py +358 -0
- tree_sitter_analyzer/mcp/utils/path_resolver.py +414 -0
- tree_sitter_analyzer/mcp/utils/search_cache.py +343 -0
- tree_sitter_analyzer/models.py +840 -0
- tree_sitter_analyzer/mypy_current_errors.txt +2 -0
- tree_sitter_analyzer/output_manager.py +255 -0
- tree_sitter_analyzer/platform_compat/__init__.py +3 -0
- tree_sitter_analyzer/platform_compat/adapter.py +324 -0
- tree_sitter_analyzer/platform_compat/compare.py +224 -0
- tree_sitter_analyzer/platform_compat/detector.py +67 -0
- tree_sitter_analyzer/platform_compat/fixtures.py +228 -0
- tree_sitter_analyzer/platform_compat/profiles.py +217 -0
- tree_sitter_analyzer/platform_compat/record.py +55 -0
- tree_sitter_analyzer/platform_compat/recorder.py +155 -0
- tree_sitter_analyzer/platform_compat/report.py +92 -0
- tree_sitter_analyzer/plugins/__init__.py +280 -0
- tree_sitter_analyzer/plugins/base.py +647 -0
- tree_sitter_analyzer/plugins/manager.py +384 -0
- tree_sitter_analyzer/project_detector.py +328 -0
- tree_sitter_analyzer/queries/__init__.py +27 -0
- tree_sitter_analyzer/queries/csharp.py +216 -0
- tree_sitter_analyzer/queries/css.py +615 -0
- tree_sitter_analyzer/queries/go.py +275 -0
- tree_sitter_analyzer/queries/html.py +543 -0
- tree_sitter_analyzer/queries/java.py +402 -0
- tree_sitter_analyzer/queries/javascript.py +724 -0
- tree_sitter_analyzer/queries/kotlin.py +192 -0
- tree_sitter_analyzer/queries/markdown.py +258 -0
- tree_sitter_analyzer/queries/php.py +95 -0
- tree_sitter_analyzer/queries/python.py +859 -0
- tree_sitter_analyzer/queries/ruby.py +92 -0
- tree_sitter_analyzer/queries/rust.py +223 -0
- tree_sitter_analyzer/queries/sql.py +555 -0
- tree_sitter_analyzer/queries/typescript.py +871 -0
- tree_sitter_analyzer/queries/yaml.py +236 -0
- tree_sitter_analyzer/query_loader.py +272 -0
- tree_sitter_analyzer/security/__init__.py +22 -0
- tree_sitter_analyzer/security/boundary_manager.py +277 -0
- tree_sitter_analyzer/security/regex_checker.py +297 -0
- tree_sitter_analyzer/security/validator.py +599 -0
- tree_sitter_analyzer/table_formatter.py +782 -0
- tree_sitter_analyzer/utils/__init__.py +53 -0
- tree_sitter_analyzer/utils/logging.py +433 -0
- tree_sitter_analyzer/utils/tree_sitter_compat.py +289 -0
- tree_sitter_analyzer-1.9.17.1.dist-info/METADATA +485 -0
- tree_sitter_analyzer-1.9.17.1.dist-info/RECORD +149 -0
- tree_sitter_analyzer-1.9.17.1.dist-info/WHEEL +4 -0
- tree_sitter_analyzer-1.9.17.1.dist-info/entry_points.txt +25 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Command Line Interface
|
|
4
|
+
|
|
5
|
+
New CLI implementation that uses the API facade for all operations.
|
|
6
|
+
Provides a clean separation between CLI concerns and core analysis logic.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import importlib.metadata
|
|
11
|
+
import json
|
|
12
|
+
import logging
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from .. import api
|
|
18
|
+
|
|
19
|
+
# Configure logging for CLI
|
|
20
|
+
logging.basicConfig(
|
|
21
|
+
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
22
|
+
)
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def create_parser() -> argparse.ArgumentParser:
|
|
27
|
+
"""Create and configure the argument parser."""
|
|
28
|
+
parser = argparse.ArgumentParser(
|
|
29
|
+
prog="tree-sitter-analyzer",
|
|
30
|
+
description="Extensible multi-language code analyzer using Tree-sitter",
|
|
31
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
32
|
+
epilog="""
|
|
33
|
+
Examples:
|
|
34
|
+
# Analyze a Java file
|
|
35
|
+
tree-sitter-analyzer analyze example.java
|
|
36
|
+
|
|
37
|
+
# Analyze with specific language
|
|
38
|
+
tree-sitter-analyzer analyze --language python script.py
|
|
39
|
+
|
|
40
|
+
# Execute specific queries
|
|
41
|
+
tree-sitter-analyzer analyze --queries functions,classes example.java
|
|
42
|
+
|
|
43
|
+
# Extract only code elements
|
|
44
|
+
tree-sitter-analyzer extract example.py
|
|
45
|
+
|
|
46
|
+
# List supported languages
|
|
47
|
+
tree-sitter-analyzer languages
|
|
48
|
+
|
|
49
|
+
# Get framework information
|
|
50
|
+
tree-sitter-analyzer info
|
|
51
|
+
|
|
52
|
+
For more information, visit: https://github.com/aimasteracc/tree-sitter-analyzer
|
|
53
|
+
""",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Global options
|
|
57
|
+
# Get version dynamically from package metadata
|
|
58
|
+
try:
|
|
59
|
+
version = importlib.metadata.version("tree-sitter-analyzer")
|
|
60
|
+
except importlib.metadata.PackageNotFoundError:
|
|
61
|
+
version = "0.9.9" # Fallback version
|
|
62
|
+
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--version", action="version", version=f"tree-sitter-analyzer {version}"
|
|
65
|
+
)
|
|
66
|
+
parser.add_argument(
|
|
67
|
+
"--verbose", "-v", action="store_true", help="Enable verbose output"
|
|
68
|
+
)
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--quiet", "-q", action="store_true", help="Suppress non-essential output"
|
|
71
|
+
)
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"--output",
|
|
74
|
+
"-o",
|
|
75
|
+
choices=["json", "text", "table"],
|
|
76
|
+
default="text",
|
|
77
|
+
help="Output format (default: text)",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Subcommands
|
|
81
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
82
|
+
|
|
83
|
+
# Analyze command
|
|
84
|
+
analyze_parser = subparsers.add_parser(
|
|
85
|
+
"analyze",
|
|
86
|
+
help="Analyze source code files",
|
|
87
|
+
description="Perform comprehensive analysis of source code files",
|
|
88
|
+
)
|
|
89
|
+
analyze_parser.add_argument("file_path", help="Path to the source file to analyze")
|
|
90
|
+
analyze_parser.add_argument(
|
|
91
|
+
"--language", "-l", help="Programming language (auto-detected if not specified)"
|
|
92
|
+
)
|
|
93
|
+
analyze_parser.add_argument(
|
|
94
|
+
"--queries", help="Comma-separated list of queries to execute"
|
|
95
|
+
)
|
|
96
|
+
analyze_parser.add_argument(
|
|
97
|
+
"--no-elements", action="store_true", help="Skip code element extraction"
|
|
98
|
+
)
|
|
99
|
+
analyze_parser.add_argument(
|
|
100
|
+
"--no-queries", action="store_true", help="Skip query execution"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Extract command
|
|
104
|
+
extract_parser = subparsers.add_parser(
|
|
105
|
+
"extract",
|
|
106
|
+
help="Extract code elements from files",
|
|
107
|
+
description="Extract specific code elements like functions, classes, etc.",
|
|
108
|
+
)
|
|
109
|
+
extract_parser.add_argument("file_path", help="Path to the source file")
|
|
110
|
+
extract_parser.add_argument(
|
|
111
|
+
"--language", "-l", help="Programming language (auto-detected if not specified)"
|
|
112
|
+
)
|
|
113
|
+
extract_parser.add_argument(
|
|
114
|
+
"--types",
|
|
115
|
+
help="Comma-separated list of element types to extract (e.g., functions,classes)",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Query command
|
|
119
|
+
query_parser = subparsers.add_parser(
|
|
120
|
+
"query",
|
|
121
|
+
help="Execute specific queries on files",
|
|
122
|
+
description="Execute specific tree-sitter queries on source files",
|
|
123
|
+
)
|
|
124
|
+
query_parser.add_argument("file_path", help="Path to the source file")
|
|
125
|
+
query_parser.add_argument("query_name", help="Name of the query to execute")
|
|
126
|
+
query_parser.add_argument(
|
|
127
|
+
"--language", "-l", help="Programming language (auto-detected if not specified)"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Validate command
|
|
131
|
+
validate_parser = subparsers.add_parser(
|
|
132
|
+
"validate",
|
|
133
|
+
help="Validate source files",
|
|
134
|
+
description="Check if files can be parsed and analyzed",
|
|
135
|
+
)
|
|
136
|
+
validate_parser.add_argument(
|
|
137
|
+
"file_path", help="Path to the source file to validate"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Languages command
|
|
141
|
+
languages_parser = subparsers.add_parser(
|
|
142
|
+
"languages",
|
|
143
|
+
help="List supported languages",
|
|
144
|
+
description="Show all supported programming languages and their extensions",
|
|
145
|
+
)
|
|
146
|
+
languages_parser.add_argument(
|
|
147
|
+
"--extensions",
|
|
148
|
+
action="store_true",
|
|
149
|
+
help="Show file extensions for each language",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Info command
|
|
153
|
+
subparsers.add_parser(
|
|
154
|
+
"info",
|
|
155
|
+
help="Show framework information",
|
|
156
|
+
description="Display information about the analyzer framework",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Queries command
|
|
160
|
+
queries_parser = subparsers.add_parser(
|
|
161
|
+
"queries",
|
|
162
|
+
help="List available queries",
|
|
163
|
+
description="Show available queries for a specific language",
|
|
164
|
+
)
|
|
165
|
+
queries_parser.add_argument("language", help="Programming language name")
|
|
166
|
+
|
|
167
|
+
return parser
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def handle_analyze_command(args: argparse.Namespace) -> int:
|
|
171
|
+
"""Handle the analyze command."""
|
|
172
|
+
try:
|
|
173
|
+
file_path = Path(args.file_path)
|
|
174
|
+
|
|
175
|
+
if not file_path.exists():
|
|
176
|
+
print(f"Error: File '{file_path}' does not exist", file=sys.stderr)
|
|
177
|
+
return 1
|
|
178
|
+
|
|
179
|
+
# Parse queries if provided
|
|
180
|
+
queries = None
|
|
181
|
+
if args.queries:
|
|
182
|
+
queries = [q.strip() for q in args.queries.split(",")]
|
|
183
|
+
|
|
184
|
+
# Perform analysis
|
|
185
|
+
result = api.analyze_file(
|
|
186
|
+
file_path=file_path,
|
|
187
|
+
language=args.language,
|
|
188
|
+
queries=queries,
|
|
189
|
+
include_elements=not args.no_elements,
|
|
190
|
+
include_queries=not args.no_queries,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Output results
|
|
194
|
+
if args.output == "json":
|
|
195
|
+
print(json.dumps(result, indent=2))
|
|
196
|
+
else:
|
|
197
|
+
format_analysis_output(result, args.output)
|
|
198
|
+
|
|
199
|
+
return 0 if result.get("success", False) else 1
|
|
200
|
+
|
|
201
|
+
except Exception as e:
|
|
202
|
+
print(f"Error during analysis: {e}", file=sys.stderr)
|
|
203
|
+
return 1
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def handle_extract_command(args: argparse.Namespace) -> int:
|
|
207
|
+
"""Handle the extract command."""
|
|
208
|
+
try:
|
|
209
|
+
file_path = Path(args.file_path)
|
|
210
|
+
|
|
211
|
+
if not file_path.exists():
|
|
212
|
+
print(f"Error: File '{file_path}' does not exist", file=sys.stderr)
|
|
213
|
+
return 1
|
|
214
|
+
|
|
215
|
+
# Parse element types if provided
|
|
216
|
+
element_types = None
|
|
217
|
+
if args.types:
|
|
218
|
+
element_types = [t.strip() for t in args.types.split(",")]
|
|
219
|
+
|
|
220
|
+
# Extract elements
|
|
221
|
+
result = api.extract_elements(
|
|
222
|
+
file_path=file_path, language=args.language, element_types=element_types
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# Output results
|
|
226
|
+
if args.output == "json":
|
|
227
|
+
print(json.dumps(result, indent=2))
|
|
228
|
+
else:
|
|
229
|
+
format_extraction_output(result, args.output)
|
|
230
|
+
|
|
231
|
+
return 0 if result.get("success", False) else 1
|
|
232
|
+
|
|
233
|
+
except Exception as e:
|
|
234
|
+
print(f"Error during extraction: {e}", file=sys.stderr)
|
|
235
|
+
return 1
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def handle_query_command(args: argparse.Namespace) -> int:
|
|
239
|
+
"""Handle the query command."""
|
|
240
|
+
try:
|
|
241
|
+
file_path = Path(args.file_path)
|
|
242
|
+
|
|
243
|
+
if not file_path.exists():
|
|
244
|
+
print(f"Error: File '{file_path}' does not exist", file=sys.stderr)
|
|
245
|
+
return 1
|
|
246
|
+
|
|
247
|
+
# Execute query
|
|
248
|
+
result = api.execute_query(
|
|
249
|
+
file_path=file_path, query_name=args.query_name, language=args.language
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# Output results
|
|
253
|
+
if args.output == "json":
|
|
254
|
+
print(json.dumps(result, indent=2))
|
|
255
|
+
else:
|
|
256
|
+
format_query_output(result, args.output)
|
|
257
|
+
|
|
258
|
+
return 0 if result.get("success", False) else 1
|
|
259
|
+
|
|
260
|
+
except Exception as e:
|
|
261
|
+
print(f"Error during query execution: {e}", file=sys.stderr)
|
|
262
|
+
return 1
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def handle_validate_command(args: argparse.Namespace) -> int:
|
|
266
|
+
"""Handle the validate command."""
|
|
267
|
+
try:
|
|
268
|
+
file_path = Path(args.file_path)
|
|
269
|
+
|
|
270
|
+
# Validate file
|
|
271
|
+
result = api.validate_file(file_path)
|
|
272
|
+
|
|
273
|
+
# Output results
|
|
274
|
+
if args.output == "json":
|
|
275
|
+
print(json.dumps(result, indent=2))
|
|
276
|
+
else:
|
|
277
|
+
format_validation_output(result, args.output)
|
|
278
|
+
|
|
279
|
+
return 0 if result.get("valid", False) else 1
|
|
280
|
+
|
|
281
|
+
except Exception as e:
|
|
282
|
+
print(f"Error during validation: {e}", file=sys.stderr)
|
|
283
|
+
return 1
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def handle_languages_command(args: argparse.Namespace) -> int:
|
|
287
|
+
"""Handle the languages command."""
|
|
288
|
+
try:
|
|
289
|
+
languages = api.get_supported_languages()
|
|
290
|
+
|
|
291
|
+
if args.output == "json":
|
|
292
|
+
if args.extensions:
|
|
293
|
+
lang_info = {}
|
|
294
|
+
for lang in languages:
|
|
295
|
+
extensions = api.get_file_extensions(lang)
|
|
296
|
+
lang_info[lang] = extensions
|
|
297
|
+
print(json.dumps(lang_info, indent=2))
|
|
298
|
+
else:
|
|
299
|
+
print(json.dumps(languages, indent=2))
|
|
300
|
+
else:
|
|
301
|
+
print("Supported Languages:")
|
|
302
|
+
print("=" * 20)
|
|
303
|
+
for lang in sorted(languages):
|
|
304
|
+
if args.extensions:
|
|
305
|
+
extensions = api.get_file_extensions(lang)
|
|
306
|
+
ext_str = ", ".join(extensions) if extensions else "No extensions"
|
|
307
|
+
print(f" {lang:<12} - {ext_str}")
|
|
308
|
+
else:
|
|
309
|
+
print(f" {lang}")
|
|
310
|
+
|
|
311
|
+
if not args.extensions:
|
|
312
|
+
print(f"\nTotal: {len(languages)} languages")
|
|
313
|
+
print("Use --extensions to see file extensions for each language")
|
|
314
|
+
|
|
315
|
+
return 0
|
|
316
|
+
|
|
317
|
+
except Exception as e:
|
|
318
|
+
print(f"Error getting language information: {e}", file=sys.stderr)
|
|
319
|
+
return 1
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def handle_info_command(args: argparse.Namespace) -> int:
|
|
323
|
+
"""Handle the info command."""
|
|
324
|
+
try:
|
|
325
|
+
info = api.get_framework_info()
|
|
326
|
+
|
|
327
|
+
if args.output == "json":
|
|
328
|
+
print(json.dumps(info, indent=2))
|
|
329
|
+
else:
|
|
330
|
+
print("Tree-sitter Analyzer Framework Information")
|
|
331
|
+
print("=" * 45)
|
|
332
|
+
print(f"Name: {info.get('name', 'Unknown')}")
|
|
333
|
+
print(f"Version: {info.get('version', 'Unknown')}")
|
|
334
|
+
print(f"Supported Languages: {info.get('total_languages', 0)}")
|
|
335
|
+
|
|
336
|
+
languages = info.get("supported_languages", [])
|
|
337
|
+
if languages:
|
|
338
|
+
print(f"Languages: {', '.join(sorted(languages))}")
|
|
339
|
+
|
|
340
|
+
components = info.get("core_components", [])
|
|
341
|
+
if components:
|
|
342
|
+
print(f"Core Components: {', '.join(components)}")
|
|
343
|
+
|
|
344
|
+
return 0
|
|
345
|
+
|
|
346
|
+
except Exception as e:
|
|
347
|
+
print(f"Error getting framework information: {e}", file=sys.stderr)
|
|
348
|
+
return 1
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def handle_queries_command(args: argparse.Namespace) -> int:
|
|
352
|
+
"""Handle the queries command."""
|
|
353
|
+
try:
|
|
354
|
+
if not api.is_language_supported(args.language):
|
|
355
|
+
print(
|
|
356
|
+
f"Error: Language '{args.language}' is not supported", file=sys.stderr
|
|
357
|
+
)
|
|
358
|
+
return 1
|
|
359
|
+
|
|
360
|
+
queries = api.get_available_queries(args.language)
|
|
361
|
+
|
|
362
|
+
if args.output == "json":
|
|
363
|
+
print(json.dumps(queries, indent=2))
|
|
364
|
+
else:
|
|
365
|
+
print(f"Available Queries for {args.language}:")
|
|
366
|
+
print("=" * (25 + len(args.language)))
|
|
367
|
+
for query in sorted(queries):
|
|
368
|
+
print(f" {query}")
|
|
369
|
+
|
|
370
|
+
print(f"\nTotal: {len(queries)} queries")
|
|
371
|
+
|
|
372
|
+
return 0
|
|
373
|
+
|
|
374
|
+
except Exception as e:
|
|
375
|
+
print(f"Error getting query information: {e}", file=sys.stderr)
|
|
376
|
+
return 1
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def format_analysis_output(result: dict[str, Any], output_format: str) -> None:
|
|
380
|
+
"""Format and display analysis results."""
|
|
381
|
+
if not result.get("success", False):
|
|
382
|
+
print(
|
|
383
|
+
f"Analysis failed: {result.get('error', 'Unknown error')}", file=sys.stderr
|
|
384
|
+
)
|
|
385
|
+
return
|
|
386
|
+
|
|
387
|
+
print("Analysis Results")
|
|
388
|
+
print("=" * 16)
|
|
389
|
+
|
|
390
|
+
# File information
|
|
391
|
+
file_info = result.get("file_info", {})
|
|
392
|
+
print(f"File: {file_info.get('path', 'Unknown')}")
|
|
393
|
+
|
|
394
|
+
# Language information
|
|
395
|
+
lang_info = result.get("language_info", {})
|
|
396
|
+
language = lang_info.get("language", "Unknown")
|
|
397
|
+
auto_detected = lang_info.get("auto_detected", False)
|
|
398
|
+
detection_str = " (auto-detected)" if auto_detected else ""
|
|
399
|
+
print(f"Language: {language}{detection_str}")
|
|
400
|
+
|
|
401
|
+
# AST information
|
|
402
|
+
ast_info = result.get("ast_info", {})
|
|
403
|
+
print(f"Source Lines: {ast_info.get('source_lines', 0)}")
|
|
404
|
+
print(f"AST Nodes: {ast_info.get('node_count', 0)}")
|
|
405
|
+
|
|
406
|
+
# Query results
|
|
407
|
+
query_results = result.get("query_results", {})
|
|
408
|
+
if query_results:
|
|
409
|
+
print("\nQuery Results:")
|
|
410
|
+
for query_name, matches in query_results.items():
|
|
411
|
+
print(f" {query_name}: {len(matches)} matches")
|
|
412
|
+
|
|
413
|
+
# Elements
|
|
414
|
+
elements = result.get("elements", [])
|
|
415
|
+
if elements:
|
|
416
|
+
print(f"\nCode Elements: {len(elements)} found")
|
|
417
|
+
element_types: dict[str, int] = {}
|
|
418
|
+
for element in elements:
|
|
419
|
+
elem_type = element.get("type", "unknown")
|
|
420
|
+
element_types[elem_type] = element_types.get(elem_type, 0) + 1
|
|
421
|
+
|
|
422
|
+
for elem_type, count in sorted(element_types.items()):
|
|
423
|
+
print(f" {elem_type}: {count}")
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def format_extraction_output(result: dict[str, Any], output_format: str) -> None:
|
|
427
|
+
"""Format and display extraction results."""
|
|
428
|
+
if not result.get("success", False):
|
|
429
|
+
print(
|
|
430
|
+
f"Extraction failed: {result.get('error', 'Unknown error')}",
|
|
431
|
+
file=sys.stderr,
|
|
432
|
+
)
|
|
433
|
+
return
|
|
434
|
+
|
|
435
|
+
elements = result.get("elements", [])
|
|
436
|
+
language = result.get("language", "Unknown")
|
|
437
|
+
|
|
438
|
+
print("Code Element Extraction Results")
|
|
439
|
+
print("=" * 31)
|
|
440
|
+
print(f"File: {result.get('file_path', 'Unknown')}")
|
|
441
|
+
print(f"Language: {language}")
|
|
442
|
+
print(f"Elements Found: {len(elements)}")
|
|
443
|
+
|
|
444
|
+
if elements:
|
|
445
|
+
print("\nElements:")
|
|
446
|
+
for element in elements:
|
|
447
|
+
name = element.get("name", "Unknown")
|
|
448
|
+
elem_type = element.get("type", "unknown")
|
|
449
|
+
start_line = element.get("start_line", 0)
|
|
450
|
+
print(f" {elem_type}: {name} (line {start_line})")
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def format_query_output(result: dict[str, Any], output_format: str) -> None:
|
|
454
|
+
"""Format and display query results."""
|
|
455
|
+
if not result.get("success", False):
|
|
456
|
+
print(f"Query failed: {result.get('error', 'Unknown error')}", file=sys.stderr)
|
|
457
|
+
return
|
|
458
|
+
|
|
459
|
+
query_name = result.get("query_name", "Unknown")
|
|
460
|
+
matches = result.get("results", [])
|
|
461
|
+
language = result.get("language", "Unknown")
|
|
462
|
+
|
|
463
|
+
print("Query Execution Results")
|
|
464
|
+
print("=" * 23)
|
|
465
|
+
print(f"File: {result.get('file_path', 'Unknown')}")
|
|
466
|
+
print(f"Language: {language}")
|
|
467
|
+
print(f"Query: {query_name}")
|
|
468
|
+
print(f"Matches: {len(matches)}")
|
|
469
|
+
|
|
470
|
+
if matches:
|
|
471
|
+
print("\nMatches:")
|
|
472
|
+
for i, match in enumerate(matches, 1):
|
|
473
|
+
start_line = match.get("start_line", 0)
|
|
474
|
+
content = match.get("content", "").strip()
|
|
475
|
+
if len(content) > 50:
|
|
476
|
+
content = content[:47] + "..."
|
|
477
|
+
print(f" {i}. Line {start_line}: {content}")
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def format_validation_output(result: dict[str, Any], output_format: str) -> None:
|
|
481
|
+
"""Format and display validation results."""
|
|
482
|
+
valid = result.get("valid", False)
|
|
483
|
+
exists = result.get("exists", False)
|
|
484
|
+
readable = result.get("readable", False)
|
|
485
|
+
language = result.get("language")
|
|
486
|
+
supported = result.get("supported", False)
|
|
487
|
+
errors = result.get("errors", [])
|
|
488
|
+
|
|
489
|
+
print("File Validation Results")
|
|
490
|
+
print("=" * 23)
|
|
491
|
+
print(f"Valid: {'✓' if valid else '✗'}")
|
|
492
|
+
print(f"Exists: {'✓' if exists else '✗'}")
|
|
493
|
+
print(f"Readable: {'✓' if readable else '✗'}")
|
|
494
|
+
print(f"Language: {language or 'Unknown'}")
|
|
495
|
+
print(f"Supported: {'✓' if supported else '✗'}")
|
|
496
|
+
|
|
497
|
+
if errors:
|
|
498
|
+
print("\nErrors:")
|
|
499
|
+
for error in errors:
|
|
500
|
+
print(f" - {error}")
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def main() -> int:
|
|
504
|
+
"""Main CLI entry point."""
|
|
505
|
+
parser = create_parser()
|
|
506
|
+
args = parser.parse_args()
|
|
507
|
+
|
|
508
|
+
# Configure logging based on verbosity
|
|
509
|
+
if args.quiet:
|
|
510
|
+
logging.getLogger().setLevel(logging.ERROR)
|
|
511
|
+
elif args.verbose:
|
|
512
|
+
logging.getLogger().setLevel(logging.DEBUG)
|
|
513
|
+
|
|
514
|
+
# Handle commands
|
|
515
|
+
if args.command == "analyze":
|
|
516
|
+
return handle_analyze_command(args)
|
|
517
|
+
elif args.command == "extract":
|
|
518
|
+
return handle_extract_command(args)
|
|
519
|
+
elif args.command == "query":
|
|
520
|
+
return handle_query_command(args)
|
|
521
|
+
elif args.command == "validate":
|
|
522
|
+
return handle_validate_command(args)
|
|
523
|
+
elif args.command == "languages":
|
|
524
|
+
return handle_languages_command(args)
|
|
525
|
+
elif args.command == "info":
|
|
526
|
+
return handle_info_command(args)
|
|
527
|
+
elif args.command == "queries":
|
|
528
|
+
return handle_queries_command(args)
|
|
529
|
+
else:
|
|
530
|
+
parser.print_help()
|
|
531
|
+
return 1
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
if __name__ == "__main__":
|
|
535
|
+
sys.exit(main())
|