tree-sitter-analyzer 0.7.0__py3-none-any.whl → 0.8.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.

Potentially problematic release.


This version of tree-sitter-analyzer might be problematic. Click here for more details.

Files changed (70) hide show
  1. tree_sitter_analyzer/__init__.py +132 -132
  2. tree_sitter_analyzer/__main__.py +11 -11
  3. tree_sitter_analyzer/api.py +533 -533
  4. tree_sitter_analyzer/cli/__init__.py +39 -39
  5. tree_sitter_analyzer/cli/__main__.py +12 -12
  6. tree_sitter_analyzer/cli/commands/__init__.py +26 -26
  7. tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
  8. tree_sitter_analyzer/cli/commands/base_command.py +178 -160
  9. tree_sitter_analyzer/cli/commands/default_command.py +18 -18
  10. tree_sitter_analyzer/cli/commands/partial_read_command.py +141 -141
  11. tree_sitter_analyzer/cli/commands/query_command.py +88 -81
  12. tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
  13. tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
  14. tree_sitter_analyzer/cli/commands/table_command.py +235 -235
  15. tree_sitter_analyzer/cli/info_commands.py +121 -121
  16. tree_sitter_analyzer/cli_main.py +303 -297
  17. tree_sitter_analyzer/core/__init__.py +15 -15
  18. tree_sitter_analyzer/core/analysis_engine.py +580 -555
  19. tree_sitter_analyzer/core/cache_service.py +320 -320
  20. tree_sitter_analyzer/core/engine.py +566 -566
  21. tree_sitter_analyzer/core/parser.py +293 -293
  22. tree_sitter_analyzer/encoding_utils.py +459 -459
  23. tree_sitter_analyzer/exceptions.py +406 -337
  24. tree_sitter_analyzer/file_handler.py +210 -210
  25. tree_sitter_analyzer/formatters/__init__.py +1 -1
  26. tree_sitter_analyzer/formatters/base_formatter.py +167 -167
  27. tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
  28. tree_sitter_analyzer/interfaces/__init__.py +9 -9
  29. tree_sitter_analyzer/interfaces/cli.py +528 -528
  30. tree_sitter_analyzer/interfaces/cli_adapter.py +343 -343
  31. tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
  32. tree_sitter_analyzer/interfaces/mcp_server.py +425 -405
  33. tree_sitter_analyzer/languages/__init__.py +10 -10
  34. tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
  35. tree_sitter_analyzer/languages/python_plugin.py +755 -755
  36. tree_sitter_analyzer/mcp/__init__.py +31 -31
  37. tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
  38. tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
  39. tree_sitter_analyzer/mcp/server.py +408 -333
  40. tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
  41. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +673 -654
  42. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -247
  43. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
  44. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +308 -300
  45. tree_sitter_analyzer/mcp/tools/table_format_tool.py +379 -362
  46. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +559 -543
  47. tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
  48. tree_sitter_analyzer/mcp/utils/error_handler.py +549 -549
  49. tree_sitter_analyzer/output_manager.py +253 -253
  50. tree_sitter_analyzer/plugins/__init__.py +280 -280
  51. tree_sitter_analyzer/plugins/base.py +529 -529
  52. tree_sitter_analyzer/plugins/manager.py +379 -379
  53. tree_sitter_analyzer/project_detector.py +317 -0
  54. tree_sitter_analyzer/queries/__init__.py +26 -26
  55. tree_sitter_analyzer/queries/java.py +391 -391
  56. tree_sitter_analyzer/queries/javascript.py +148 -148
  57. tree_sitter_analyzer/queries/python.py +285 -285
  58. tree_sitter_analyzer/queries/typescript.py +229 -229
  59. tree_sitter_analyzer/query_loader.py +257 -257
  60. tree_sitter_analyzer/security/__init__.py +22 -0
  61. tree_sitter_analyzer/security/boundary_manager.py +237 -0
  62. tree_sitter_analyzer/security/regex_checker.py +292 -0
  63. tree_sitter_analyzer/security/validator.py +241 -0
  64. tree_sitter_analyzer/table_formatter.py +652 -589
  65. tree_sitter_analyzer/utils.py +277 -277
  66. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.1.dist-info}/METADATA +27 -1
  67. tree_sitter_analyzer-0.8.1.dist-info/RECORD +77 -0
  68. tree_sitter_analyzer-0.7.0.dist-info/RECORD +0 -72
  69. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.1.dist-info}/WHEEL +0 -0
  70. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.1.dist-info}/entry_points.txt +0 -0
@@ -1,160 +1,178 @@
1
- #!/usr/bin/env python3
2
- """
3
- Base Command Class
4
-
5
- Abstract base class for all CLI commands implementing the Command Pattern.
6
- """
7
-
8
- import asyncio
9
- from abc import ABC, abstractmethod
10
- from argparse import Namespace
11
- from typing import Optional
12
-
13
- from ...core.analysis_engine import AnalysisRequest, get_analysis_engine
14
- from ...file_handler import read_file_partial
15
- from ...language_detector import detect_language_from_file, is_language_supported
16
- from ...models import AnalysisResult
17
- from ...output_manager import output_error, output_info
18
-
19
-
20
- class BaseCommand(ABC):
21
- """
22
- Base class for all CLI commands.
23
-
24
- Implements common functionality like file validation, language detection,
25
- and analysis engine interaction.
26
- """
27
-
28
- def __init__(self, args: Namespace):
29
- """Initialize command with parsed arguments."""
30
- self.args = args
31
- self.analysis_engine = get_analysis_engine()
32
-
33
- def validate_file(self) -> bool:
34
- """Validate input file exists and is accessible."""
35
- if not hasattr(self.args, "file_path") or not self.args.file_path:
36
- output_error("ERROR: File path not specified.")
37
- return False
38
-
39
- import os
40
-
41
- if not os.path.exists(self.args.file_path):
42
- output_error(f"ERROR: File not found: {self.args.file_path}")
43
- return False
44
-
45
- return True
46
-
47
- def detect_language(self) -> str | None:
48
- """Detect or validate the target language."""
49
- if hasattr(self.args, "language") and self.args.language:
50
- target_language = self.args.language.lower()
51
- if (not hasattr(self.args, "table") or not self.args.table) and (
52
- not hasattr(self.args, "quiet") or not self.args.quiet
53
- ):
54
- output_info(f"INFO: Language explicitly specified: {target_language}")
55
- else:
56
- target_language = detect_language_from_file(self.args.file_path)
57
- if target_language == "unknown":
58
- output_error(
59
- f"ERROR: Could not determine language for file '{self.args.file_path}'."
60
- )
61
- return None
62
- else:
63
- if (not hasattr(self.args, "table") or not self.args.table) and (
64
- not hasattr(self.args, "quiet") or not self.args.quiet
65
- ):
66
- output_info(
67
- f"INFO: Language auto-detected from extension: {target_language}"
68
- )
69
-
70
- # Language support validation
71
- if not is_language_supported(target_language):
72
- if target_language != "java":
73
- if (not hasattr(self.args, "table") or not self.args.table) and (
74
- not hasattr(self.args, "quiet") or not self.args.quiet
75
- ):
76
- output_info(
77
- "INFO: Trying with Java analysis engine. May not work correctly."
78
- )
79
- target_language = "java" # Fallback
80
-
81
- return str(target_language) if target_language else None
82
-
83
- async def analyze_file(self, language: str) -> Optional["AnalysisResult"]:
84
- """Perform file analysis using the unified analysis engine."""
85
- try:
86
- # Handle partial read if enabled
87
- if hasattr(self.args, "partial_read") and self.args.partial_read:
88
- try:
89
- partial_content = read_file_partial(
90
- self.args.file_path,
91
- start_line=self.args.start_line,
92
- end_line=getattr(self.args, "end_line", None),
93
- start_column=getattr(self.args, "start_column", None),
94
- end_column=getattr(self.args, "end_column", None),
95
- )
96
- if partial_content is None:
97
- output_error("ERROR: Failed to read file partially")
98
- return None
99
- except Exception as e:
100
- output_error(f"ERROR: Failed to read file partially: {e}")
101
- return None
102
-
103
- request = AnalysisRequest(
104
- file_path=self.args.file_path,
105
- language=language,
106
- include_complexity=True,
107
- include_details=True,
108
- )
109
- analysis_result = await self.analysis_engine.analyze(request)
110
-
111
- if not analysis_result or not analysis_result.success:
112
- error_msg = (
113
- analysis_result.error_message
114
- if analysis_result
115
- else "Unknown error"
116
- )
117
- output_error(f"ERROR: Analysis failed: {error_msg}")
118
- return None
119
-
120
- return analysis_result
121
-
122
- except Exception as e:
123
- output_error(f"ERROR: An error occurred during analysis: {e}")
124
- return None
125
-
126
- def execute(self) -> int:
127
- """
128
- Execute the command.
129
-
130
- Returns:
131
- int: Exit code (0 for success, 1 for failure)
132
- """
133
- # Validate inputs
134
- if not self.validate_file():
135
- return 1
136
-
137
- # Detect language
138
- language = self.detect_language()
139
- if not language:
140
- return 1
141
-
142
- # Execute the specific command
143
- try:
144
- return asyncio.run(self.execute_async(language))
145
- except Exception as e:
146
- output_error(f"ERROR: An error occurred during command execution: {e}")
147
- return 1
148
-
149
- @abstractmethod
150
- async def execute_async(self, language: str) -> int:
151
- """
152
- Execute the command asynchronously.
153
-
154
- Args:
155
- language: Detected/specified target language
156
-
157
- Returns:
158
- int: Exit code (0 for success, 1 for failure)
159
- """
160
- pass
1
+ #!/usr/bin/env python3
2
+ """
3
+ Base Command Class
4
+
5
+ Abstract base class for all CLI commands implementing the Command Pattern.
6
+ """
7
+
8
+ import asyncio
9
+ from abc import ABC, abstractmethod
10
+ from argparse import Namespace
11
+ from typing import Optional
12
+
13
+ from ...core.analysis_engine import AnalysisRequest, get_analysis_engine
14
+ from ...file_handler import read_file_partial
15
+ from ...language_detector import detect_language_from_file, is_language_supported
16
+ from ...models import AnalysisResult
17
+ from ...output_manager import output_error, output_info
18
+ from ...project_detector import detect_project_root
19
+ from ...security import SecurityValidator
20
+
21
+
22
+ class BaseCommand(ABC):
23
+ """
24
+ Base class for all CLI commands.
25
+
26
+ Implements common functionality like file validation, language detection,
27
+ and analysis engine interaction.
28
+ """
29
+
30
+ def __init__(self, args: Namespace):
31
+ """Initialize command with parsed arguments."""
32
+ self.args = args
33
+
34
+ # Detect project root with priority handling
35
+ file_path = getattr(args, 'file_path', None)
36
+ explicit_root = getattr(args, 'project_root', None)
37
+ self.project_root = detect_project_root(file_path, explicit_root)
38
+
39
+ # Initialize components with project root
40
+ self.analysis_engine = get_analysis_engine(self.project_root)
41
+ self.security_validator = SecurityValidator(self.project_root)
42
+
43
+ def validate_file(self) -> bool:
44
+ """Validate input file exists and is accessible."""
45
+ if not hasattr(self.args, "file_path") or not self.args.file_path:
46
+ output_error("File path not specified.")
47
+ return False
48
+
49
+ # Security validation
50
+ is_valid, error_msg = self.security_validator.validate_file_path(self.args.file_path)
51
+ if not is_valid:
52
+ output_error(f"Invalid file path: {error_msg}")
53
+ return False
54
+
55
+ import os
56
+
57
+ if not os.path.exists(self.args.file_path):
58
+ output_error(f"File not found: {self.args.file_path}")
59
+ return False
60
+
61
+ return True
62
+
63
+ def detect_language(self) -> str | None:
64
+ """Detect or validate the target language."""
65
+ if hasattr(self.args, "language") and self.args.language:
66
+ # Sanitize language input
67
+ sanitized_language = self.security_validator.sanitize_input(self.args.language, max_length=50)
68
+ target_language = sanitized_language.lower()
69
+ if (not hasattr(self.args, "table") or not self.args.table) and (
70
+ not hasattr(self.args, "quiet") or not self.args.quiet
71
+ ):
72
+ output_info(f"INFO: Language explicitly specified: {target_language}")
73
+ else:
74
+ target_language = detect_language_from_file(self.args.file_path)
75
+ if target_language == "unknown":
76
+ output_error(
77
+ f"ERROR: Could not determine language for file '{self.args.file_path}'."
78
+ )
79
+ return None
80
+ else:
81
+ if (not hasattr(self.args, "table") or not self.args.table) and (
82
+ not hasattr(self.args, "quiet") or not self.args.quiet
83
+ ):
84
+ output_info(
85
+ f"INFO: Language auto-detected from extension: {target_language}"
86
+ )
87
+
88
+ # Language support validation
89
+ if not is_language_supported(target_language):
90
+ if target_language != "java":
91
+ if (not hasattr(self.args, "table") or not self.args.table) and (
92
+ not hasattr(self.args, "quiet") or not self.args.quiet
93
+ ):
94
+ output_info(
95
+ "INFO: Trying with Java analysis engine. May not work correctly."
96
+ )
97
+ target_language = "java" # Fallback
98
+
99
+ return str(target_language) if target_language else None
100
+
101
+ async def analyze_file(self, language: str) -> Optional["AnalysisResult"]:
102
+ """Perform file analysis using the unified analysis engine."""
103
+ try:
104
+ # Handle partial read if enabled
105
+ if hasattr(self.args, "partial_read") and self.args.partial_read:
106
+ try:
107
+ partial_content = read_file_partial(
108
+ self.args.file_path,
109
+ start_line=self.args.start_line,
110
+ end_line=getattr(self.args, "end_line", None),
111
+ start_column=getattr(self.args, "start_column", None),
112
+ end_column=getattr(self.args, "end_column", None),
113
+ )
114
+ if partial_content is None:
115
+ output_error("Failed to read file partially")
116
+ return None
117
+ except Exception as e:
118
+ output_error(f"Failed to read file partially: {e}")
119
+ return None
120
+
121
+ request = AnalysisRequest(
122
+ file_path=self.args.file_path,
123
+ language=language,
124
+ include_complexity=True,
125
+ include_details=True,
126
+ )
127
+ analysis_result = await self.analysis_engine.analyze(request)
128
+
129
+ if not analysis_result or not analysis_result.success:
130
+ error_msg = (
131
+ analysis_result.error_message
132
+ if analysis_result
133
+ else "Unknown error"
134
+ )
135
+ output_error(f"Analysis failed: {error_msg}")
136
+ return None
137
+
138
+ return analysis_result
139
+
140
+ except Exception as e:
141
+ output_error(f"An error occurred during analysis: {e}")
142
+ return None
143
+
144
+ def execute(self) -> int:
145
+ """
146
+ Execute the command.
147
+
148
+ Returns:
149
+ int: Exit code (0 for success, 1 for failure)
150
+ """
151
+ # Validate inputs
152
+ if not self.validate_file():
153
+ return 1
154
+
155
+ # Detect language
156
+ language = self.detect_language()
157
+ if not language:
158
+ return 1
159
+
160
+ # Execute the specific command
161
+ try:
162
+ return asyncio.run(self.execute_async(language))
163
+ except Exception as e:
164
+ output_error(f"An error occurred during command execution: {e}")
165
+ return 1
166
+
167
+ @abstractmethod
168
+ async def execute_async(self, language: str) -> int:
169
+ """
170
+ Execute the command asynchronously.
171
+
172
+ Args:
173
+ language: Detected/specified target language
174
+
175
+ Returns:
176
+ int: Exit code (0 for success, 1 for failure)
177
+ """
178
+ pass
@@ -1,18 +1,18 @@
1
- #!/usr/bin/env python3
2
- """
3
- Default Command
4
-
5
- Handles default analysis when no specific command is specified.
6
- """
7
-
8
- from ...output_manager import output_error
9
- from .base_command import BaseCommand
10
-
11
-
12
- class DefaultCommand(BaseCommand):
13
- """Default command that shows error when no specific command is given."""
14
-
15
- async def execute_async(self, language: str) -> int:
16
- """Execute default command - show error for missing options."""
17
- output_error("ERROR: Please specify a query or --advanced option")
18
- return 1
1
+ #!/usr/bin/env python3
2
+ """
3
+ Default Command
4
+
5
+ Handles default analysis when no specific command is specified.
6
+ """
7
+
8
+ from ...output_manager import output_error
9
+ from .base_command import BaseCommand
10
+
11
+
12
+ class DefaultCommand(BaseCommand):
13
+ """Default command that shows error when no specific command is given."""
14
+
15
+ async def execute_async(self, language: str) -> int:
16
+ """Execute default command - show error for missing options."""
17
+ output_error("Please specify a query or --advanced option")
18
+ return 1