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,472 @@
1
+ #!/usr/bin/env python3
2
+ """CLI Main Module - Entry point for command-line interface."""
3
+
4
+ import argparse
5
+ import logging
6
+ import os
7
+ import sys
8
+ from typing import Any
9
+
10
+ from .cli.argument_validator import CLIArgumentValidator
11
+
12
+ # Import command classes
13
+ from .cli.commands import (
14
+ AdvancedCommand,
15
+ DefaultCommand,
16
+ PartialReadCommand,
17
+ QueryCommand,
18
+ StructureCommand,
19
+ SummaryCommand,
20
+ TableCommand,
21
+ )
22
+ from .cli.info_commands import (
23
+ DescribeQueryCommand,
24
+ ListQueriesCommand,
25
+ ShowExtensionsCommand,
26
+ ShowLanguagesCommand,
27
+ )
28
+ from .output_manager import output_error, output_info, output_list
29
+ from .query_loader import query_loader
30
+
31
+
32
+ class CLICommandFactory:
33
+ """Factory for creating CLI commands based on arguments."""
34
+
35
+ @staticmethod
36
+ def create_command(args: argparse.Namespace) -> Any:
37
+ """Create appropriate command based on arguments."""
38
+
39
+ # Validate argument combinations first
40
+ validator = CLIArgumentValidator()
41
+ validation_error = validator.validate_arguments(args)
42
+ if validation_error:
43
+ output_error(validation_error)
44
+ output_info(validator.get_usage_examples())
45
+ return None
46
+
47
+ # Information commands (no file analysis required)
48
+ if args.list_queries:
49
+ return ListQueriesCommand(args)
50
+
51
+ if args.describe_query:
52
+ return DescribeQueryCommand(args)
53
+
54
+ if args.show_supported_languages:
55
+ return ShowLanguagesCommand(args)
56
+
57
+ if args.show_supported_extensions:
58
+ return ShowExtensionsCommand(args)
59
+
60
+ if args.filter_help:
61
+ from tree_sitter_analyzer.core.query_filter import QueryFilter
62
+
63
+ filter_service = QueryFilter()
64
+ output_info(filter_service.get_filter_help())
65
+ return None # This will exit with code 0
66
+
67
+ # File analysis commands (require file path)
68
+ if not args.file_path:
69
+ return None
70
+
71
+ # Partial read command - highest priority for file operations
72
+ if hasattr(args, "partial_read") and args.partial_read:
73
+ return PartialReadCommand(args)
74
+
75
+ # Handle table command with or without query-key
76
+ if hasattr(args, "table") and args.table:
77
+ return TableCommand(args)
78
+
79
+ if hasattr(args, "structure") and args.structure:
80
+ return StructureCommand(args)
81
+
82
+ if hasattr(args, "summary") and args.summary is not None:
83
+ return SummaryCommand(args)
84
+
85
+ if hasattr(args, "advanced") and args.advanced:
86
+ return AdvancedCommand(args)
87
+
88
+ if hasattr(args, "query_key") and args.query_key:
89
+ return QueryCommand(args)
90
+
91
+ if hasattr(args, "query_string") and args.query_string:
92
+ return QueryCommand(args)
93
+
94
+ # Default command - if file_path is provided but no specific command, use default analysis
95
+ return DefaultCommand(args)
96
+
97
+
98
+ def create_argument_parser() -> argparse.ArgumentParser:
99
+ """Create and configure the argument parser."""
100
+ parser = argparse.ArgumentParser(
101
+ description="Analyze code using Tree-sitter and extract structured information.",
102
+ epilog="Example: tree-sitter-analyzer example.java --table=full",
103
+ )
104
+
105
+ # File path
106
+ parser.add_argument("file_path", nargs="?", help="Path to the file to analyze")
107
+
108
+ # Query options
109
+ query_group = parser.add_mutually_exclusive_group(required=False)
110
+ query_group.add_argument(
111
+ "--query-key", help="Available query key (e.g., class, method)"
112
+ )
113
+ query_group.add_argument(
114
+ "--query-string", help="Directly specify Tree-sitter query to execute"
115
+ )
116
+
117
+ # Query filter options
118
+ parser.add_argument(
119
+ "--filter",
120
+ help="Filter query results (e.g., 'name=main', 'name=~get*,public=true')",
121
+ )
122
+
123
+ # Information options
124
+ parser.add_argument(
125
+ "--list-queries",
126
+ action="store_true",
127
+ help="Display list of available query keys",
128
+ )
129
+ parser.add_argument(
130
+ "--filter-help",
131
+ action="store_true",
132
+ help="Display help for query filter syntax",
133
+ )
134
+ parser.add_argument(
135
+ "--describe-query", help="Display description of specified query key"
136
+ )
137
+ parser.add_argument(
138
+ "--show-supported-languages",
139
+ action="store_true",
140
+ help="Display list of supported languages",
141
+ )
142
+ parser.add_argument(
143
+ "--show-supported-extensions",
144
+ action="store_true",
145
+ help="Display list of supported file extensions",
146
+ )
147
+ parser.add_argument(
148
+ "--show-common-queries",
149
+ action="store_true",
150
+ help="Display list of common queries across multiple languages",
151
+ )
152
+ parser.add_argument(
153
+ "--show-query-languages",
154
+ action="store_true",
155
+ help="Display list of languages with query support",
156
+ )
157
+
158
+ # Output format options
159
+ parser.add_argument(
160
+ "--output-format",
161
+ choices=["json", "text"],
162
+ default="json",
163
+ help="Specify output format",
164
+ )
165
+ parser.add_argument(
166
+ "--table",
167
+ choices=["full", "compact", "csv", "json"],
168
+ help="Output in table format",
169
+ )
170
+ parser.add_argument(
171
+ "--include-javadoc",
172
+ action="store_true",
173
+ help="Include JavaDoc/documentation comments in output",
174
+ )
175
+
176
+ # Analysis options
177
+ parser.add_argument(
178
+ "--advanced", action="store_true", help="Use advanced analysis features"
179
+ )
180
+ parser.add_argument(
181
+ "--summary",
182
+ nargs="?",
183
+ const="classes,methods",
184
+ help="Display summary of specified element types",
185
+ )
186
+ parser.add_argument(
187
+ "--structure",
188
+ action="store_true",
189
+ help="Output detailed structure information in JSON format",
190
+ )
191
+ parser.add_argument(
192
+ "--statistics", action="store_true", help="Display only statistical information"
193
+ )
194
+
195
+ # Language options
196
+ parser.add_argument(
197
+ "--language",
198
+ help="Explicitly specify language (auto-detected from extension if omitted)",
199
+ )
200
+
201
+ # SQL Platform Compatibility options
202
+ parser.add_argument(
203
+ "--sql-platform-info",
204
+ action="store_true",
205
+ help="Show current SQL platform detection details",
206
+ )
207
+ parser.add_argument(
208
+ "--record-sql-profile",
209
+ action="store_true",
210
+ help="Record a new SQL behavior profile for the current platform",
211
+ )
212
+ parser.add_argument(
213
+ "--compare-sql-profiles",
214
+ nargs=2,
215
+ metavar=("PROFILE1", "PROFILE2"),
216
+ help="Compare two SQL behavior profiles",
217
+ )
218
+
219
+ # Project options
220
+ parser.add_argument(
221
+ "--project-root",
222
+ help="Project root directory for security validation (auto-detected if not specified)",
223
+ )
224
+
225
+ # Logging options
226
+ parser.add_argument(
227
+ "--quiet",
228
+ action="store_true",
229
+ help="Suppress INFO level logs (show errors only)",
230
+ )
231
+
232
+ # Partial reading options
233
+ parser.add_argument(
234
+ "--partial-read",
235
+ action="store_true",
236
+ help="Enable partial file reading mode",
237
+ )
238
+ parser.add_argument(
239
+ "--start-line", type=int, help="Starting line number for reading (1-based)"
240
+ )
241
+ parser.add_argument(
242
+ "--end-line", type=int, help="Ending line number for reading (1-based)"
243
+ )
244
+ parser.add_argument(
245
+ "--start-column", type=int, help="Starting column number for reading (0-based)"
246
+ )
247
+ parser.add_argument(
248
+ "--end-column", type=int, help="Ending column number for reading (0-based)"
249
+ )
250
+
251
+ return parser
252
+
253
+
254
+ def handle_special_commands(args: argparse.Namespace) -> int | None:
255
+ """Handle special commands that don't fit the normal pattern."""
256
+
257
+ # Validate partial read options
258
+ if hasattr(args, "partial_read") and args.partial_read:
259
+ if args.start_line is None:
260
+ output_error("--start-line is required")
261
+ return 1
262
+
263
+ if args.start_line < 1:
264
+ output_error("--start-line must be 1 or greater")
265
+ return 1
266
+
267
+ if args.end_line and args.end_line < args.start_line:
268
+ output_error("--end-line must be greater than or equal to --start-line")
269
+ return 1
270
+
271
+ if args.start_column is not None and args.start_column < 0:
272
+ output_error("--start-column must be 0 or greater")
273
+ return 1
274
+
275
+ if args.end_column is not None and args.end_column < 0:
276
+ output_error("--end-column must be 0 or greater")
277
+ return 1
278
+
279
+ # Query language commands
280
+ if args.show_query_languages:
281
+ output_list(["Languages with query support:"])
282
+ for lang in query_loader.list_supported_languages():
283
+ query_count = len(query_loader.list_queries_for_language(lang))
284
+ output_list([f" {lang:<15} ({query_count} queries)"])
285
+ return 0
286
+
287
+ if args.show_common_queries:
288
+ common_queries = query_loader.get_common_queries()
289
+ if common_queries:
290
+ output_list("Common queries across multiple languages:")
291
+ for query in common_queries:
292
+ output_list(f" {query}")
293
+ else:
294
+ output_info("No common queries found.")
295
+ return 0
296
+
297
+ # SQL Platform Compatibility Commands
298
+ if args.sql_platform_info:
299
+ from tree_sitter_analyzer.platform_compat.detector import PlatformDetector
300
+ from tree_sitter_analyzer.platform_compat.profiles import BehaviorProfile
301
+
302
+ info = PlatformDetector.detect()
303
+ output_list(
304
+ [
305
+ "SQL Platform Information:",
306
+ f" OS Name: {info.os_name}",
307
+ f" OS Version: {info.os_version}",
308
+ f" Python Version: {info.python_version}",
309
+ f" Platform Key: {info.platform_key}",
310
+ "",
311
+ ]
312
+ )
313
+
314
+ profile = BehaviorProfile.load(info.platform_key)
315
+ if profile:
316
+ output_list(
317
+ [
318
+ f"Loaded Profile: {info.platform_key}",
319
+ f" Schema Version: {profile.schema_version}",
320
+ f" Behaviors Recorded: {len(profile.behaviors)}",
321
+ f" Adaptation Rules: {', '.join(profile.adaptation_rules) if profile.adaptation_rules else 'None'}",
322
+ ]
323
+ )
324
+ else:
325
+ output_list(
326
+ [
327
+ f"No profile found for {info.platform_key}",
328
+ " Using default adaptation rules.",
329
+ ]
330
+ )
331
+ return 0
332
+
333
+ if args.record_sql_profile:
334
+ from pathlib import Path
335
+
336
+ from tree_sitter_analyzer.platform_compat.recorder import BehaviorRecorder
337
+
338
+ output_info("Starting SQL behavior recording...")
339
+ try:
340
+ recorder = BehaviorRecorder()
341
+ profile = recorder.record_all()
342
+
343
+ # Default output directory
344
+ output_dir = Path("tests/platform_profiles")
345
+ output_dir.mkdir(parents=True, exist_ok=True)
346
+
347
+ profile.save(output_dir)
348
+ output_info(f"Recorded profile for {profile.platform_key}")
349
+ output_info(f"Saved to {output_dir}")
350
+ except Exception as e:
351
+ output_error(f"Failed to record profile: {e}")
352
+ return 1
353
+ return 0
354
+
355
+ if args.compare_sql_profiles:
356
+ import json
357
+ from pathlib import Path
358
+
359
+ from tree_sitter_analyzer.platform_compat.compare import (
360
+ compare_profiles,
361
+ generate_diff_report,
362
+ )
363
+ from tree_sitter_analyzer.platform_compat.profiles import BehaviorProfile
364
+
365
+ p1_path = Path(args.compare_sql_profiles[0])
366
+ p2_path = Path(args.compare_sql_profiles[1])
367
+
368
+ if not p1_path.exists():
369
+ output_error(f"Profile not found: {p1_path}")
370
+ return 1
371
+ if not p2_path.exists():
372
+ output_error(f"Profile not found: {p2_path}")
373
+ return 1
374
+
375
+ try:
376
+ from tree_sitter_analyzer.platform_compat.profiles import ParsingBehavior
377
+
378
+ def load_profile(path):
379
+ with open(path, encoding="utf-8") as f:
380
+ data = json.load(f)
381
+ # Manual deserialization of nested objects
382
+ behaviors = {}
383
+ for key, b_data in data.get("behaviors", {}).items():
384
+ if isinstance(b_data, dict):
385
+ behaviors[key] = ParsingBehavior(**b_data)
386
+ else:
387
+ behaviors[key] = b_data
388
+
389
+ return BehaviorProfile(
390
+ schema_version=data.get("schema_version", "1.0.0"),
391
+ platform_key=data["platform_key"],
392
+ behaviors=behaviors,
393
+ adaptation_rules=data.get("adaptation_rules", []),
394
+ )
395
+
396
+ p1 = load_profile(p1_path)
397
+ p2 = load_profile(p2_path)
398
+
399
+ comparison = compare_profiles(p1, p2)
400
+ report = generate_diff_report(comparison)
401
+ print(report)
402
+ except Exception as e:
403
+ output_error(f"Error comparing profiles: {e}")
404
+ return 1
405
+ return 0
406
+
407
+ return None
408
+
409
+
410
+ def main() -> None:
411
+ """Main entry point for the CLI."""
412
+ # Early check for quiet mode to set environment variable before any imports
413
+ if "--quiet" in sys.argv:
414
+ os.environ["LOG_LEVEL"] = "ERROR"
415
+ else:
416
+ # Set default log level to ERROR to prevent log output in CLI
417
+ os.environ["LOG_LEVEL"] = "ERROR"
418
+
419
+ parser = create_argument_parser()
420
+ args = parser.parse_args()
421
+
422
+ # Configure all logging to ERROR level to prevent output contamination
423
+ logging.getLogger().setLevel(logging.ERROR)
424
+ logging.getLogger("tree_sitter_analyzer").setLevel(logging.ERROR)
425
+ logging.getLogger("tree_sitter_analyzer.performance").setLevel(logging.ERROR)
426
+ logging.getLogger("tree_sitter_analyzer.plugins").setLevel(logging.ERROR)
427
+ logging.getLogger("tree_sitter_analyzer.plugins.manager").setLevel(logging.ERROR)
428
+
429
+ # Configure logging for table output
430
+ if hasattr(args, "table") and args.table:
431
+ logging.getLogger().setLevel(logging.ERROR)
432
+ logging.getLogger("tree_sitter_analyzer").setLevel(logging.ERROR)
433
+ logging.getLogger("tree_sitter_analyzer.performance").setLevel(logging.ERROR)
434
+
435
+ # Configure logging for quiet mode
436
+ if hasattr(args, "quiet") and args.quiet:
437
+ logging.getLogger().setLevel(logging.ERROR)
438
+ logging.getLogger("tree_sitter_analyzer").setLevel(logging.ERROR)
439
+ logging.getLogger("tree_sitter_analyzer.performance").setLevel(logging.ERROR)
440
+
441
+ # Handle special commands first
442
+ special_result = handle_special_commands(args)
443
+ if special_result is not None:
444
+ sys.exit(special_result)
445
+
446
+ # Create and execute command
447
+ command = CLICommandFactory.create_command(args)
448
+
449
+ if command:
450
+ exit_code = command.execute()
451
+ sys.exit(exit_code)
452
+ elif command is None and hasattr(args, "filter_help") and args.filter_help:
453
+ # filter_help was processed successfully
454
+ sys.exit(0)
455
+ else:
456
+ if not args.file_path:
457
+ output_error("File path not specified.")
458
+ else:
459
+ output_error("No executable command specified.")
460
+ parser.print_help()
461
+ sys.exit(1)
462
+
463
+
464
+ if __name__ == "__main__":
465
+ try:
466
+ main()
467
+ except KeyboardInterrupt:
468
+ output_info("\nOperation cancelled by user.")
469
+ sys.exit(1)
470
+ except Exception as e:
471
+ output_error(f"Unexpected error: {e}")
472
+ sys.exit(1)
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Constants for tree-sitter-analyzer
4
+
5
+ This module defines constants used throughout the project to ensure consistency.
6
+ """
7
+
8
+ from typing import Any, cast
9
+
10
+ # Element types for unified element management system
11
+ ELEMENT_TYPE_CLASS = "class"
12
+ ELEMENT_TYPE_FUNCTION = "function"
13
+ ELEMENT_TYPE_VARIABLE = "variable"
14
+ ELEMENT_TYPE_IMPORT = "import"
15
+ ELEMENT_TYPE_PACKAGE = "package"
16
+ ELEMENT_TYPE_ANNOTATION = "annotation"
17
+
18
+ # SQL element types
19
+ ELEMENT_TYPE_SQL_TABLE = "table"
20
+ ELEMENT_TYPE_SQL_VIEW = "view"
21
+ ELEMENT_TYPE_SQL_PROCEDURE = "procedure"
22
+ ELEMENT_TYPE_SQL_FUNCTION = "sql_function"
23
+ ELEMENT_TYPE_SQL_TRIGGER = "trigger"
24
+ ELEMENT_TYPE_SQL_INDEX = "index"
25
+
26
+ # Element type mapping for backward compatibility
27
+ ELEMENT_TYPE_MAPPING = {
28
+ "Class": ELEMENT_TYPE_CLASS,
29
+ "Function": ELEMENT_TYPE_FUNCTION,
30
+ "Variable": ELEMENT_TYPE_VARIABLE,
31
+ "Import": ELEMENT_TYPE_IMPORT,
32
+ "Package": ELEMENT_TYPE_PACKAGE,
33
+ "Annotation": ELEMENT_TYPE_ANNOTATION,
34
+ }
35
+
36
+ # Legacy class name to element type mapping
37
+ LEGACY_CLASS_MAPPING = {
38
+ "Class": ELEMENT_TYPE_CLASS,
39
+ "Function": ELEMENT_TYPE_FUNCTION,
40
+ "Variable": ELEMENT_TYPE_VARIABLE,
41
+ "Import": ELEMENT_TYPE_IMPORT,
42
+ "Package": ELEMENT_TYPE_PACKAGE,
43
+ "Annotation": ELEMENT_TYPE_ANNOTATION,
44
+ # SQL element mappings
45
+ "SQLTable": ELEMENT_TYPE_SQL_TABLE,
46
+ "SQLView": ELEMENT_TYPE_SQL_VIEW,
47
+ "SQLProcedure": ELEMENT_TYPE_SQL_PROCEDURE,
48
+ "SQLFunction": ELEMENT_TYPE_SQL_FUNCTION,
49
+ "SQLTrigger": ELEMENT_TYPE_SQL_TRIGGER,
50
+ "SQLIndex": ELEMENT_TYPE_SQL_INDEX,
51
+ }
52
+
53
+
54
+ def get_element_type(element: Any) -> str:
55
+ """
56
+ Get the element type from an element object.
57
+
58
+ Args:
59
+ element: Element object with element_type attribute or __class__.__name__
60
+
61
+ Returns:
62
+ Standardized element type string
63
+ """
64
+ if hasattr(element, "element_type"):
65
+ return cast(str, element.element_type)
66
+
67
+ if hasattr(element, "__class__") and hasattr(element.__class__, "__name__"):
68
+ class_name = element.__class__.__name__
69
+ return LEGACY_CLASS_MAPPING.get(class_name, "unknown")
70
+
71
+ return "unknown"
72
+
73
+
74
+ def is_element_of_type(element: Any, element_type: str) -> bool:
75
+ """
76
+ Check if an element is of a specific type.
77
+
78
+ Args:
79
+ element: Element object to check
80
+ element_type: Expected element type
81
+
82
+ Returns:
83
+ True if element is of the specified type
84
+ """
85
+ return get_element_type(element) == element_type
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Core module for tree_sitter_analyzer.
4
+
5
+ This module contains the core components of the new architecture:
6
+ - AnalysisEngine: Main analysis orchestrator
7
+ - Parser: Tree-sitter parsing wrapper
8
+ - QueryExecutor: Query execution engine
9
+ """
10
+
11
+ from .engine import AnalysisEngine
12
+ from .parser import Parser, ParseResult
13
+ from .query import QueryExecutor
14
+
15
+ __all__ = ["AnalysisEngine", "Parser", "ParseResult", "QueryExecutor"]