tree-sitter-analyzer 0.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.

Files changed (78) hide show
  1. tree_sitter_analyzer/__init__.py +121 -0
  2. tree_sitter_analyzer/__main__.py +12 -0
  3. tree_sitter_analyzer/api.py +539 -0
  4. tree_sitter_analyzer/cli/__init__.py +39 -0
  5. tree_sitter_analyzer/cli/__main__.py +13 -0
  6. tree_sitter_analyzer/cli/commands/__init__.py +27 -0
  7. tree_sitter_analyzer/cli/commands/advanced_command.py +88 -0
  8. tree_sitter_analyzer/cli/commands/base_command.py +155 -0
  9. tree_sitter_analyzer/cli/commands/default_command.py +19 -0
  10. tree_sitter_analyzer/cli/commands/partial_read_command.py +133 -0
  11. tree_sitter_analyzer/cli/commands/query_command.py +82 -0
  12. tree_sitter_analyzer/cli/commands/structure_command.py +121 -0
  13. tree_sitter_analyzer/cli/commands/summary_command.py +93 -0
  14. tree_sitter_analyzer/cli/commands/table_command.py +233 -0
  15. tree_sitter_analyzer/cli/info_commands.py +121 -0
  16. tree_sitter_analyzer/cli_main.py +276 -0
  17. tree_sitter_analyzer/core/__init__.py +20 -0
  18. tree_sitter_analyzer/core/analysis_engine.py +574 -0
  19. tree_sitter_analyzer/core/cache_service.py +330 -0
  20. tree_sitter_analyzer/core/engine.py +560 -0
  21. tree_sitter_analyzer/core/parser.py +288 -0
  22. tree_sitter_analyzer/core/query.py +502 -0
  23. tree_sitter_analyzer/encoding_utils.py +460 -0
  24. tree_sitter_analyzer/exceptions.py +340 -0
  25. tree_sitter_analyzer/file_handler.py +222 -0
  26. tree_sitter_analyzer/formatters/__init__.py +1 -0
  27. tree_sitter_analyzer/formatters/base_formatter.py +168 -0
  28. tree_sitter_analyzer/formatters/formatter_factory.py +74 -0
  29. tree_sitter_analyzer/formatters/java_formatter.py +270 -0
  30. tree_sitter_analyzer/formatters/python_formatter.py +235 -0
  31. tree_sitter_analyzer/interfaces/__init__.py +10 -0
  32. tree_sitter_analyzer/interfaces/cli.py +557 -0
  33. tree_sitter_analyzer/interfaces/cli_adapter.py +319 -0
  34. tree_sitter_analyzer/interfaces/mcp_adapter.py +170 -0
  35. tree_sitter_analyzer/interfaces/mcp_server.py +416 -0
  36. tree_sitter_analyzer/java_analyzer.py +219 -0
  37. tree_sitter_analyzer/language_detector.py +400 -0
  38. tree_sitter_analyzer/language_loader.py +228 -0
  39. tree_sitter_analyzer/languages/__init__.py +11 -0
  40. tree_sitter_analyzer/languages/java_plugin.py +1113 -0
  41. tree_sitter_analyzer/languages/python_plugin.py +712 -0
  42. tree_sitter_analyzer/mcp/__init__.py +32 -0
  43. tree_sitter_analyzer/mcp/resources/__init__.py +47 -0
  44. tree_sitter_analyzer/mcp/resources/code_file_resource.py +213 -0
  45. tree_sitter_analyzer/mcp/resources/project_stats_resource.py +550 -0
  46. tree_sitter_analyzer/mcp/server.py +319 -0
  47. tree_sitter_analyzer/mcp/tools/__init__.py +36 -0
  48. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +558 -0
  49. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +245 -0
  50. tree_sitter_analyzer/mcp/tools/base_tool.py +55 -0
  51. tree_sitter_analyzer/mcp/tools/get_positions_tool.py +448 -0
  52. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +302 -0
  53. tree_sitter_analyzer/mcp/tools/table_format_tool.py +359 -0
  54. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +476 -0
  55. tree_sitter_analyzer/mcp/utils/__init__.py +106 -0
  56. tree_sitter_analyzer/mcp/utils/error_handler.py +549 -0
  57. tree_sitter_analyzer/models.py +481 -0
  58. tree_sitter_analyzer/output_manager.py +264 -0
  59. tree_sitter_analyzer/plugins/__init__.py +334 -0
  60. tree_sitter_analyzer/plugins/base.py +446 -0
  61. tree_sitter_analyzer/plugins/java_plugin.py +625 -0
  62. tree_sitter_analyzer/plugins/javascript_plugin.py +439 -0
  63. tree_sitter_analyzer/plugins/manager.py +355 -0
  64. tree_sitter_analyzer/plugins/plugin_loader.py +83 -0
  65. tree_sitter_analyzer/plugins/python_plugin.py +598 -0
  66. tree_sitter_analyzer/plugins/registry.py +366 -0
  67. tree_sitter_analyzer/queries/__init__.py +27 -0
  68. tree_sitter_analyzer/queries/java.py +394 -0
  69. tree_sitter_analyzer/queries/javascript.py +149 -0
  70. tree_sitter_analyzer/queries/python.py +286 -0
  71. tree_sitter_analyzer/queries/typescript.py +230 -0
  72. tree_sitter_analyzer/query_loader.py +260 -0
  73. tree_sitter_analyzer/table_formatter.py +448 -0
  74. tree_sitter_analyzer/utils.py +201 -0
  75. tree_sitter_analyzer-0.1.0.dist-info/METADATA +581 -0
  76. tree_sitter_analyzer-0.1.0.dist-info/RECORD +78 -0
  77. tree_sitter_analyzer-0.1.0.dist-info/WHEEL +4 -0
  78. tree_sitter_analyzer-0.1.0.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,355 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Plugin Manager
5
+
6
+ Dynamic plugin discovery and management system.
7
+ Handles loading plugins from entry points and local directories.
8
+ """
9
+
10
+ import importlib
11
+ import importlib.metadata
12
+ import pkgutil
13
+ from pathlib import Path
14
+ from typing import List, Dict, Optional, Type
15
+ import logging
16
+
17
+ from .base import LanguagePlugin
18
+ from ..utils import log_error, log_info, log_warning, log_debug
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class PluginManager:
24
+ """
25
+ Manages dynamic discovery and loading of language plugins.
26
+
27
+ This class handles:
28
+ - Discovery of plugins via entry points
29
+ - Loading plugins from local directories
30
+ - Plugin lifecycle management
31
+ - Error handling and fallback mechanisms
32
+ """
33
+
34
+ def __init__(self):
35
+ """Initialize the plugin manager."""
36
+ self._loaded_plugins: Dict[str, LanguagePlugin] = {}
37
+ self._plugin_classes: Dict[str, Type[LanguagePlugin]] = {}
38
+ self._entry_point_group = "tree_sitter_analyzer.plugins"
39
+
40
+ def load_plugins(self) -> List[LanguagePlugin]:
41
+ """
42
+ Load all available plugins from various sources.
43
+
44
+ Returns:
45
+ List of successfully loaded plugin instances
46
+ """
47
+ loaded_plugins = []
48
+
49
+ # Load plugins from entry points (installed packages)
50
+ entry_point_plugins = self._load_from_entry_points()
51
+ loaded_plugins.extend(entry_point_plugins)
52
+
53
+ # Load plugins from local languages directory
54
+ local_plugins = self._load_from_local_directory()
55
+ loaded_plugins.extend(local_plugins)
56
+
57
+ # Store loaded plugins
58
+ for plugin in loaded_plugins:
59
+ language = plugin.get_language_name()
60
+ self._loaded_plugins[language] = plugin
61
+
62
+ log_info(f"Successfully loaded {len(loaded_plugins)} plugins")
63
+ return loaded_plugins
64
+
65
+ def _load_from_entry_points(self) -> List[LanguagePlugin]:
66
+ """
67
+ Load plugins from setuptools entry points.
68
+
69
+ Returns:
70
+ List of plugin instances loaded from entry points
71
+ """
72
+ plugins = []
73
+
74
+ try:
75
+ # Get entry points for our plugin group
76
+ entry_points = importlib.metadata.entry_points()
77
+
78
+ # Handle both old and new entry_points API
79
+ if hasattr(entry_points, 'select'):
80
+ # New API (Python 3.10+)
81
+ plugin_entries = entry_points.select(group=self._entry_point_group)
82
+ else:
83
+ # Old API
84
+ plugin_entries = entry_points.get(self._entry_point_group, [])
85
+
86
+ for entry_point in plugin_entries:
87
+ try:
88
+ # Load the plugin class
89
+ plugin_class = entry_point.load()
90
+
91
+ # Validate it's a LanguagePlugin
92
+ if not issubclass(plugin_class, LanguagePlugin):
93
+ log_warning(f"Entry point {entry_point.name} is not a LanguagePlugin")
94
+ continue
95
+
96
+ # Create instance
97
+ plugin_instance = plugin_class()
98
+ plugins.append(plugin_instance)
99
+
100
+ log_debug(f"Loaded plugin from entry point: {entry_point.name}")
101
+
102
+ except Exception as e:
103
+ log_error(f"Failed to load plugin from entry point {entry_point.name}: {e}")
104
+
105
+ except Exception as e:
106
+ log_warning(f"Failed to load plugins from entry points: {e}")
107
+
108
+ return plugins
109
+
110
+ def _load_from_local_directory(self) -> List[LanguagePlugin]:
111
+ """
112
+ Load plugins from the local languages directory.
113
+
114
+ Returns:
115
+ List of plugin instances loaded from local directory
116
+ """
117
+ plugins = []
118
+
119
+ try:
120
+ # Get the languages directory path
121
+ current_dir = Path(__file__).parent.parent
122
+ languages_dir = current_dir / "languages"
123
+
124
+ if not languages_dir.exists():
125
+ log_debug("Languages directory does not exist, creating it")
126
+ languages_dir.mkdir(exist_ok=True)
127
+ # Create __init__.py
128
+ (languages_dir / "__init__.py").touch()
129
+ return plugins
130
+
131
+ # Import the languages package
132
+ languages_package = "tree_sitter_analyzer.languages"
133
+
134
+ try:
135
+ languages_module = importlib.import_module(languages_package)
136
+ except ImportError as e:
137
+ log_warning(f"Could not import languages package: {e}")
138
+ return plugins
139
+
140
+ # Discover plugin modules in the languages directory
141
+ for finder, name, ispkg in pkgutil.iter_modules(
142
+ languages_module.__path__,
143
+ languages_module.__name__ + "."
144
+ ):
145
+ if ispkg:
146
+ continue
147
+
148
+ try:
149
+ # Import the module
150
+ module = importlib.import_module(name)
151
+
152
+ # Look for LanguagePlugin classes
153
+ plugin_classes = self._find_plugin_classes(module)
154
+
155
+ for plugin_class in plugin_classes:
156
+ try:
157
+ plugin_instance = plugin_class()
158
+ plugins.append(plugin_instance)
159
+ log_debug(f"Loaded local plugin: {plugin_class.__name__}")
160
+ except Exception as e:
161
+ log_error(f"Failed to instantiate plugin {plugin_class.__name__}: {e}")
162
+
163
+ except Exception as e:
164
+ log_error(f"Failed to load plugin module {name}: {e}")
165
+
166
+ except Exception as e:
167
+ log_warning(f"Failed to load plugins from local directory: {e}")
168
+
169
+ return plugins
170
+
171
+ def _find_plugin_classes(self, module) -> List[Type[LanguagePlugin]]:
172
+ """
173
+ Find LanguagePlugin classes in a module.
174
+
175
+ Args:
176
+ module: Python module to search
177
+
178
+ Returns:
179
+ List of LanguagePlugin classes found in the module
180
+ """
181
+ plugin_classes = []
182
+
183
+ for attr_name in dir(module):
184
+ attr = getattr(module, attr_name)
185
+
186
+ # Check if it's a class and subclass of LanguagePlugin
187
+ if (isinstance(attr, type) and
188
+ issubclass(attr, LanguagePlugin) and
189
+ attr is not LanguagePlugin):
190
+ plugin_classes.append(attr)
191
+
192
+ return plugin_classes
193
+
194
+ def get_plugin(self, language: str) -> Optional[LanguagePlugin]:
195
+ """
196
+ Get a plugin for a specific language.
197
+
198
+ Args:
199
+ language: Programming language name
200
+
201
+ Returns:
202
+ Plugin instance or None if not found
203
+ """
204
+ return self._loaded_plugins.get(language)
205
+
206
+ def get_all_plugins(self) -> Dict[str, LanguagePlugin]:
207
+ """
208
+ Get all loaded plugins.
209
+
210
+ Returns:
211
+ Dictionary mapping language names to plugin instances
212
+ """
213
+ return self._loaded_plugins.copy()
214
+
215
+ def get_supported_languages(self) -> List[str]:
216
+ """
217
+ Get list of all supported languages.
218
+
219
+ Returns:
220
+ List of supported language names
221
+ """
222
+ return list(self._loaded_plugins.keys())
223
+
224
+ def reload_plugins(self) -> List[LanguagePlugin]:
225
+ """
226
+ Reload all plugins (useful for development).
227
+
228
+ Returns:
229
+ List of reloaded plugin instances
230
+ """
231
+ log_info("Reloading all plugins")
232
+
233
+ # Clear existing plugins
234
+ self._loaded_plugins.clear()
235
+ self._plugin_classes.clear()
236
+
237
+ # Reload
238
+ return self.load_plugins()
239
+
240
+ def register_plugin(self, plugin: LanguagePlugin) -> bool:
241
+ """
242
+ Manually register a plugin instance.
243
+
244
+ Args:
245
+ plugin: Plugin instance to register
246
+
247
+ Returns:
248
+ True if registration was successful
249
+ """
250
+ try:
251
+ language = plugin.get_language_name()
252
+
253
+ if language in self._loaded_plugins:
254
+ log_warning(f"Plugin for language '{language}' already exists, replacing")
255
+
256
+ self._loaded_plugins[language] = plugin
257
+ log_debug(f"Manually registered plugin for language: {language}")
258
+ return True
259
+
260
+ except Exception as e:
261
+ log_error(f"Failed to register plugin: {e}")
262
+ return False
263
+
264
+ def unregister_plugin(self, language: str) -> bool:
265
+ """
266
+ Unregister a plugin for a specific language.
267
+
268
+ Args:
269
+ language: Programming language name
270
+
271
+ Returns:
272
+ True if unregistration was successful
273
+ """
274
+ if language in self._loaded_plugins:
275
+ del self._loaded_plugins[language]
276
+ log_debug(f"Unregistered plugin for language: {language}")
277
+ return True
278
+
279
+ return False
280
+
281
+ def get_plugin_info(self, language: str) -> Optional[Dict[str, any]]:
282
+ """
283
+ Get information about a specific plugin.
284
+
285
+ Args:
286
+ language: Programming language name
287
+
288
+ Returns:
289
+ Plugin information dictionary or None
290
+ """
291
+ plugin = self.get_plugin(language)
292
+ if not plugin:
293
+ return None
294
+
295
+ try:
296
+ return {
297
+ "language": plugin.get_language_name(),
298
+ "extensions": plugin.get_file_extensions(),
299
+ "class_name": plugin.__class__.__name__,
300
+ "module": plugin.__class__.__module__,
301
+ "has_extractor": hasattr(plugin, 'create_extractor')
302
+ }
303
+ except Exception as e:
304
+ log_error(f"Failed to get plugin info for {language}: {e}")
305
+ return None
306
+
307
+ def validate_plugin(self, plugin: LanguagePlugin) -> bool:
308
+ """
309
+ Validate that a plugin implements the required interface correctly.
310
+
311
+ Args:
312
+ plugin: Plugin instance to validate
313
+
314
+ Returns:
315
+ True if the plugin is valid
316
+ """
317
+ try:
318
+ # Check required methods
319
+ required_methods = [
320
+ 'get_language_name',
321
+ 'get_file_extensions',
322
+ 'create_extractor'
323
+ ]
324
+
325
+ for method_name in required_methods:
326
+ if not hasattr(plugin, method_name):
327
+ log_error(f"Plugin missing required method: {method_name}")
328
+ return False
329
+
330
+ method = getattr(plugin, method_name)
331
+ if not callable(method):
332
+ log_error(f"Plugin method {method_name} is not callable")
333
+ return False
334
+
335
+ # Test basic functionality
336
+ language = plugin.get_language_name()
337
+ if not language or not isinstance(language, str):
338
+ log_error("Plugin get_language_name() must return a non-empty string")
339
+ return False
340
+
341
+ extensions = plugin.get_file_extensions()
342
+ if not isinstance(extensions, list):
343
+ log_error("Plugin get_file_extensions() must return a list")
344
+ return False
345
+
346
+ extractor = plugin.create_extractor()
347
+ if not extractor:
348
+ log_error("Plugin create_extractor() must return an extractor instance")
349
+ return False
350
+
351
+ return True
352
+
353
+ except Exception as e:
354
+ log_error(f"Plugin validation failed: {e}")
355
+ return False
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Plugin Loader for Tree-sitter Analyzer
5
+
6
+ Automatically loads and registers all available language plugins.
7
+ """
8
+
9
+ from typing import List
10
+
11
+ from ..utils import log_debug, log_error, log_info
12
+ from . import plugin_registry
13
+
14
+
15
+ def load_all_plugins() -> List[str]:
16
+ """Load and register all available language plugins"""
17
+ loaded_plugins = []
18
+
19
+ try:
20
+ # Import and register Java plugin
21
+ from .java_plugin import JavaPlugin
22
+
23
+ java_plugin = JavaPlugin()
24
+ plugin_registry.register_plugin(java_plugin)
25
+ loaded_plugins.append("java")
26
+ log_debug("Loaded Java plugin")
27
+ except Exception as e:
28
+ log_error(f"Failed to load Java plugin: {e}")
29
+
30
+ try:
31
+ # Import and register JavaScript plugin
32
+ from .javascript_plugin import JavaScriptPlugin
33
+
34
+ js_plugin = JavaScriptPlugin()
35
+ plugin_registry.register_plugin(js_plugin)
36
+ loaded_plugins.append("javascript")
37
+ log_debug("Loaded JavaScript plugin")
38
+ except Exception as e:
39
+ log_error(f"Failed to load JavaScript plugin: {e}")
40
+
41
+ try:
42
+ # Import and register Python plugin
43
+ from .python_plugin import PythonPlugin
44
+
45
+ python_plugin = PythonPlugin()
46
+ plugin_registry.register_plugin(python_plugin)
47
+ loaded_plugins.append("python")
48
+ log_debug("Loaded Python plugin")
49
+ except Exception as e:
50
+ log_error(f"Failed to load Python plugin: {e}")
51
+
52
+ if loaded_plugins:
53
+ log_info(
54
+ f"Successfully loaded {len(loaded_plugins)} language plugins: {', '.join(loaded_plugins)}"
55
+ )
56
+ else:
57
+ log_error("No language plugins were loaded successfully")
58
+
59
+ return loaded_plugins
60
+
61
+
62
+ def get_supported_languages() -> List[str]:
63
+ """Get list of all supported languages"""
64
+ return plugin_registry.list_supported_languages()
65
+
66
+
67
+ def get_supported_extensions() -> List[str]:
68
+ """Get list of all supported file extensions"""
69
+ return plugin_registry.list_supported_extensions()
70
+
71
+
72
+ def get_plugin_for_file(file_path: str):
73
+ """Get appropriate plugin for a file"""
74
+ return plugin_registry.get_plugin_for_file(file_path)
75
+
76
+
77
+ def get_plugin_by_language(language: str):
78
+ """Get plugin by language name"""
79
+ return plugin_registry.get_plugin(language)
80
+
81
+
82
+ # Auto-load plugins when module is imported
83
+ _loaded_plugins = load_all_plugins()