tree-sitter-analyzer 0.9.1__py3-none-any.whl → 0.9.3__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 (64) 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 +181 -178
  9. tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
  10. tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
  11. tree_sitter_analyzer/cli_main.py +7 -3
  12. tree_sitter_analyzer/core/__init__.py +15 -15
  13. tree_sitter_analyzer/core/analysis_engine.py +91 -87
  14. tree_sitter_analyzer/core/cache_service.py +320 -320
  15. tree_sitter_analyzer/core/engine.py +566 -566
  16. tree_sitter_analyzer/core/parser.py +293 -293
  17. tree_sitter_analyzer/encoding_utils.py +459 -459
  18. tree_sitter_analyzer/file_handler.py +210 -210
  19. tree_sitter_analyzer/formatters/__init__.py +1 -1
  20. tree_sitter_analyzer/formatters/base_formatter.py +167 -167
  21. tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
  22. tree_sitter_analyzer/formatters/java_formatter.py +18 -18
  23. tree_sitter_analyzer/formatters/python_formatter.py +19 -19
  24. tree_sitter_analyzer/interfaces/__init__.py +9 -9
  25. tree_sitter_analyzer/interfaces/cli.py +528 -528
  26. tree_sitter_analyzer/interfaces/cli_adapter.py +344 -343
  27. tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
  28. tree_sitter_analyzer/language_detector.py +53 -53
  29. tree_sitter_analyzer/languages/__init__.py +10 -10
  30. tree_sitter_analyzer/languages/java_plugin.py +1 -1
  31. tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
  32. tree_sitter_analyzer/languages/python_plugin.py +755 -755
  33. tree_sitter_analyzer/mcp/__init__.py +34 -45
  34. tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
  35. tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
  36. tree_sitter_analyzer/mcp/server.py +623 -568
  37. tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
  38. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +681 -673
  39. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -247
  40. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
  41. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +310 -308
  42. tree_sitter_analyzer/mcp/tools/table_format_tool.py +386 -379
  43. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +563 -559
  44. tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
  45. tree_sitter_analyzer/models.py +10 -10
  46. tree_sitter_analyzer/output_manager.py +253 -253
  47. tree_sitter_analyzer/plugins/__init__.py +280 -280
  48. tree_sitter_analyzer/plugins/base.py +529 -529
  49. tree_sitter_analyzer/plugins/manager.py +379 -379
  50. tree_sitter_analyzer/project_detector.py +330 -317
  51. tree_sitter_analyzer/queries/__init__.py +26 -26
  52. tree_sitter_analyzer/queries/java.py +391 -391
  53. tree_sitter_analyzer/queries/javascript.py +148 -148
  54. tree_sitter_analyzer/queries/python.py +285 -285
  55. tree_sitter_analyzer/queries/typescript.py +229 -229
  56. tree_sitter_analyzer/query_loader.py +257 -257
  57. tree_sitter_analyzer/security/boundary_manager.py +57 -51
  58. tree_sitter_analyzer/security/validator.py +246 -241
  59. tree_sitter_analyzer/utils.py +294 -277
  60. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.3.dist-info}/METADATA +13 -13
  61. tree_sitter_analyzer-0.9.3.dist-info/RECORD +77 -0
  62. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.3.dist-info}/entry_points.txt +1 -0
  63. tree_sitter_analyzer-0.9.1.dist-info/RECORD +0 -77
  64. {tree_sitter_analyzer-0.9.1.dist-info → tree_sitter_analyzer-0.9.3.dist-info}/WHEEL +0 -0
@@ -8,7 +8,6 @@ outside the designated project directory.
8
8
 
9
9
  import os
10
10
  from pathlib import Path
11
- from typing import Optional, Set
12
11
 
13
12
  from ..exceptions import SecurityError
14
13
  from ..utils import log_debug, log_info, log_warning
@@ -17,10 +16,10 @@ from ..utils import log_debug, log_info, log_warning
17
16
  class ProjectBoundaryManager:
18
17
  """
19
18
  Project boundary manager for access control.
20
-
19
+
21
20
  This class enforces strict boundaries around project directories
22
21
  to prevent unauthorized file access outside the project scope.
23
-
22
+
24
23
  Features:
25
24
  - Real path resolution for symlink protection
26
25
  - Configurable allowed directories
@@ -31,59 +30,59 @@ class ProjectBoundaryManager:
31
30
  def __init__(self, project_root: str) -> None:
32
31
  """
33
32
  Initialize project boundary manager.
34
-
33
+
35
34
  Args:
36
35
  project_root: Root directory of the project
37
-
36
+
38
37
  Raises:
39
38
  SecurityError: If project root is invalid
40
39
  """
41
40
  if not project_root:
42
41
  raise SecurityError("Project root cannot be empty")
43
-
42
+
44
43
  if not os.path.exists(project_root):
45
44
  raise SecurityError(f"Project root does not exist: {project_root}")
46
-
45
+
47
46
  if not os.path.isdir(project_root):
48
47
  raise SecurityError(f"Project root is not a directory: {project_root}")
49
-
48
+
50
49
  # Store real path to prevent symlink attacks
51
50
  self.project_root = os.path.realpath(project_root)
52
- self.allowed_directories: Set[str] = {self.project_root}
53
-
54
- log_info(f"ProjectBoundaryManager initialized with root: {self.project_root}")
51
+ self.allowed_directories: set[str] = {self.project_root}
52
+
53
+ log_debug(f"ProjectBoundaryManager initialized with root: {self.project_root}")
55
54
 
56
55
  def add_allowed_directory(self, directory: str) -> None:
57
56
  """
58
57
  Add an additional allowed directory.
59
-
58
+
60
59
  Args:
61
60
  directory: Directory path to allow access to
62
-
61
+
63
62
  Raises:
64
63
  SecurityError: If directory is invalid
65
64
  """
66
65
  if not directory:
67
66
  raise SecurityError("Directory cannot be empty")
68
-
67
+
69
68
  if not os.path.exists(directory):
70
69
  raise SecurityError(f"Directory does not exist: {directory}")
71
-
70
+
72
71
  if not os.path.isdir(directory):
73
72
  raise SecurityError(f"Path is not a directory: {directory}")
74
-
73
+
75
74
  real_dir = os.path.realpath(directory)
76
75
  self.allowed_directories.add(real_dir)
77
-
76
+
78
77
  log_info(f"Added allowed directory: {real_dir}")
79
78
 
80
79
  def is_within_project(self, file_path: str) -> bool:
81
80
  """
82
81
  Check if file path is within project boundaries.
83
-
82
+
84
83
  Args:
85
84
  file_path: File path to check
86
-
85
+
87
86
  Returns:
88
87
  True if path is within allowed boundaries
89
88
  """
@@ -91,58 +90,61 @@ class ProjectBoundaryManager:
91
90
  if not file_path:
92
91
  log_warning("Empty file path provided to boundary check")
93
92
  return False
94
-
93
+
95
94
  # Resolve real path to handle symlinks
96
95
  real_path = os.path.realpath(file_path)
97
-
96
+
98
97
  # Check against all allowed directories
99
98
  for allowed_dir in self.allowed_directories:
100
- if real_path.startswith(allowed_dir + os.sep) or real_path == allowed_dir:
99
+ if (
100
+ real_path.startswith(allowed_dir + os.sep)
101
+ or real_path == allowed_dir
102
+ ):
101
103
  log_debug(f"File path within boundaries: {file_path}")
102
104
  return True
103
-
105
+
104
106
  log_warning(f"File path outside boundaries: {file_path} -> {real_path}")
105
107
  return False
106
-
108
+
107
109
  except Exception as e:
108
110
  log_warning(f"Boundary check error for {file_path}: {e}")
109
111
  return False
110
112
 
111
- def get_relative_path(self, file_path: str) -> Optional[str]:
113
+ def get_relative_path(self, file_path: str) -> str | None:
112
114
  """
113
115
  Get relative path from project root if within boundaries.
114
-
116
+
115
117
  Args:
116
118
  file_path: File path to convert
117
-
119
+
118
120
  Returns:
119
121
  Relative path from project root, or None if outside boundaries
120
122
  """
121
123
  if not self.is_within_project(file_path):
122
124
  return None
123
-
125
+
124
126
  try:
125
127
  real_path = os.path.realpath(file_path)
126
128
  rel_path = os.path.relpath(real_path, self.project_root)
127
-
129
+
128
130
  # Ensure relative path doesn't start with ..
129
131
  if rel_path.startswith(".."):
130
132
  log_warning(f"Relative path calculation failed: {rel_path}")
131
133
  return None
132
-
134
+
133
135
  return rel_path
134
-
136
+
135
137
  except Exception as e:
136
138
  log_warning(f"Relative path calculation error: {e}")
137
139
  return None
138
140
 
139
- def validate_and_resolve_path(self, file_path: str) -> Optional[str]:
141
+ def validate_and_resolve_path(self, file_path: str) -> str | None:
140
142
  """
141
143
  Validate path and return resolved absolute path if within boundaries.
142
-
144
+
143
145
  Args:
144
146
  file_path: File path to validate and resolve
145
-
147
+
146
148
  Returns:
147
149
  Resolved absolute path if valid, None otherwise
148
150
  """
@@ -152,22 +154,22 @@ class ProjectBoundaryManager:
152
154
  full_path = os.path.join(self.project_root, file_path)
153
155
  else:
154
156
  full_path = file_path
155
-
157
+
156
158
  # Check boundaries
157
159
  if not self.is_within_project(full_path):
158
160
  return None
159
-
161
+
160
162
  # Return real path
161
163
  return os.path.realpath(full_path)
162
-
164
+
163
165
  except Exception as e:
164
166
  log_warning(f"Path validation error: {e}")
165
167
  return None
166
168
 
167
- def list_allowed_directories(self) -> Set[str]:
169
+ def list_allowed_directories(self) -> set[str]:
168
170
  """
169
171
  Get list of all allowed directories.
170
-
172
+
171
173
  Returns:
172
174
  Set of allowed directory paths
173
175
  """
@@ -176,33 +178,37 @@ class ProjectBoundaryManager:
176
178
  def is_symlink_safe(self, file_path: str) -> bool:
177
179
  """
178
180
  Check if file path is safe from symlink attacks.
179
-
181
+
180
182
  Args:
181
183
  file_path: File path to check
182
-
184
+
183
185
  Returns:
184
186
  True if path is safe from symlink attacks
185
187
  """
186
188
  try:
187
189
  if not os.path.exists(file_path):
188
190
  return True # Non-existent files are safe
189
-
191
+
190
192
  # Check if any component in the path is a symlink
191
193
  path_parts = Path(file_path).parts
192
194
  current_path = ""
193
-
195
+
194
196
  for part in path_parts:
195
- current_path = os.path.join(current_path, part) if current_path else part
196
-
197
+ current_path = (
198
+ os.path.join(current_path, part) if current_path else part
199
+ )
200
+
197
201
  if os.path.islink(current_path):
198
202
  # Check if symlink target is within boundaries
199
203
  target = os.path.realpath(current_path)
200
204
  if not self.is_within_project(target):
201
- log_warning(f"Unsafe symlink detected: {current_path} -> {target}")
205
+ log_warning(
206
+ f"Unsafe symlink detected: {current_path} -> {target}"
207
+ )
202
208
  return False
203
-
209
+
204
210
  return True
205
-
211
+
206
212
  except Exception as e:
207
213
  log_warning(f"Symlink safety check error: {e}")
208
214
  return False
@@ -210,16 +216,16 @@ class ProjectBoundaryManager:
210
216
  def audit_access(self, file_path: str, operation: str) -> None:
211
217
  """
212
218
  Log file access for security auditing.
213
-
219
+
214
220
  Args:
215
221
  file_path: File path being accessed
216
222
  operation: Type of operation (read, write, analyze, etc.)
217
223
  """
218
224
  is_within = self.is_within_project(file_path)
219
225
  status = "ALLOWED" if is_within else "DENIED"
220
-
226
+
221
227
  log_info(f"AUDIT: {status} {operation} access to {file_path}")
222
-
228
+
223
229
  if not is_within:
224
230
  log_warning(f"SECURITY: Unauthorized access attempt to {file_path}")
225
231