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,439 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ JavaScript Language Plugin
5
+
6
+ Provides JavaScript-specific parsing and element extraction functionality.
7
+ """
8
+
9
+ import re
10
+ from typing import TYPE_CHECKING, List, Optional
11
+
12
+ if TYPE_CHECKING:
13
+ import tree_sitter
14
+
15
+ try:
16
+ import tree_sitter
17
+
18
+ TREE_SITTER_AVAILABLE = True
19
+ except ImportError:
20
+ TREE_SITTER_AVAILABLE = False
21
+
22
+ from ..language_loader import loader
23
+ from ..models import AnalysisResult, Class, Function, Import, Variable
24
+ from ..utils import log_debug, log_error, log_warning
25
+ from . import ElementExtractor, LanguagePlugin
26
+ from ..core.analysis_engine import AnalysisRequest
27
+
28
+
29
+ class JavaScriptElementExtractor(ElementExtractor):
30
+ """JavaScript-specific element extractor"""
31
+
32
+ def extract_functions(
33
+ self, tree: "tree_sitter.Tree", source_code: str
34
+ ) -> List[Function]:
35
+ """Extract JavaScript function definitions"""
36
+ functions = []
37
+
38
+ # Multiple function patterns in JavaScript
39
+ queries = [
40
+ # Regular function declarations
41
+ """
42
+ (function_declaration
43
+ name: (identifier) @func.name
44
+ parameters: (formal_parameters) @func.params
45
+ body: (statement_block) @func.body) @func.declaration
46
+ """,
47
+ # Method definitions (class methods)
48
+ """
49
+ (method_definition
50
+ name: (property_identifier) @func.name
51
+ parameters: (formal_parameters) @func.params
52
+ body: (statement_block) @func.body) @func.method
53
+ """,
54
+ # Arrow functions
55
+ """
56
+ (variable_declarator
57
+ name: (identifier) @func.name
58
+ value: (arrow_function
59
+ parameters: (formal_parameters) @func.params
60
+ body: (_) @func.body)) @func.arrow
61
+ """,
62
+ # Function expressions
63
+ """
64
+ (variable_declarator
65
+ name: (identifier) @func.name
66
+ value: (function_expression
67
+ parameters: (formal_parameters) @func.params
68
+ body: (statement_block) @func.body)) @func.expression
69
+ """,
70
+ ]
71
+
72
+ try:
73
+ language = tree.language if hasattr(tree, "language") else None
74
+ if language:
75
+ for query_string in queries:
76
+ query = language.query(query_string)
77
+ captures = query.captures(tree.root_node)
78
+
79
+ if isinstance(captures, dict):
80
+ # Handle different function types
81
+ for capture_key in ["func.declaration", "func.method", "func.arrow", "func.expression"]:
82
+ func_nodes = captures.get(capture_key, [])
83
+ for node in func_nodes:
84
+ function = self._extract_function_info(node, source_code)
85
+ if function:
86
+ functions.append(function)
87
+
88
+ except Exception as e:
89
+ log_warning(f"Could not extract JavaScript functions: {e}")
90
+
91
+ return functions
92
+
93
+ def extract_classes(
94
+ self, tree: "tree_sitter.Tree", source_code: str
95
+ ) -> List[Class]:
96
+ """Extract JavaScript class definitions"""
97
+ classes = []
98
+
99
+ query_string = """
100
+ (class_declaration
101
+ name: (identifier) @class.name
102
+ body: (class_body) @class.body) @class.declaration
103
+ """
104
+
105
+ try:
106
+ language = tree.language if hasattr(tree, "language") else None
107
+ if language:
108
+ query = language.query(query_string)
109
+ captures = query.captures(tree.root_node)
110
+
111
+ if isinstance(captures, dict):
112
+ class_nodes = captures.get("class.declaration", [])
113
+ for node in class_nodes:
114
+ cls = self._extract_class_info(node, source_code)
115
+ if cls:
116
+ classes.append(cls)
117
+
118
+ except Exception as e:
119
+ log_warning(f"Could not extract JavaScript classes: {e}")
120
+
121
+ return classes
122
+
123
+ def extract_variables(
124
+ self, tree: "tree_sitter.Tree", source_code: str
125
+ ) -> List[Variable]:
126
+ """Extract JavaScript variable definitions"""
127
+ variables = []
128
+
129
+ # Variable declarations (let, const, var)
130
+ queries = [
131
+ # var declarations
132
+ """
133
+ (variable_declaration
134
+ (variable_declarator
135
+ name: (identifier) @var.name
136
+ value: (_)? @var.value)) @var.declaration
137
+ """,
138
+ # let/const declarations
139
+ """
140
+ (lexical_declaration
141
+ (variable_declarator
142
+ name: (identifier) @var.name
143
+ value: (_)? @var.value)) @var.lexical
144
+ """
145
+ ]
146
+
147
+ try:
148
+ language = tree.language if hasattr(tree, "language") else None
149
+ if language:
150
+ for query_string in queries:
151
+ query = language.query(query_string)
152
+ captures = query.captures(tree.root_node)
153
+
154
+ if isinstance(captures, dict):
155
+ # Handle both var and lexical declarations
156
+ for capture_key in ["var.declaration", "var.lexical"]:
157
+ var_nodes = captures.get(capture_key, [])
158
+ for node in var_nodes:
159
+ variable = self._extract_variable_info(node, source_code)
160
+ if variable:
161
+ variables.append(variable)
162
+
163
+ except Exception as e:
164
+ log_warning(f"Could not extract JavaScript variables: {e}")
165
+
166
+ return variables
167
+
168
+ def extract_imports(
169
+ self, tree: "tree_sitter.Tree", source_code: str
170
+ ) -> List[Import]:
171
+ """Extract JavaScript import statements"""
172
+ imports = []
173
+
174
+ # ES6 import statements
175
+ query_string = """
176
+ (import_statement
177
+ source: (string) @import.source) @import.declaration
178
+ """
179
+
180
+ try:
181
+ language = tree.language if hasattr(tree, "language") else None
182
+ if language:
183
+ query = language.query(query_string)
184
+ captures = query.captures(tree.root_node)
185
+
186
+ if isinstance(captures, dict):
187
+ import_nodes = captures.get("import.declaration", [])
188
+ for node in import_nodes:
189
+ imp = self._extract_import_info(node, source_code)
190
+ if imp:
191
+ imports.append(imp)
192
+
193
+ except Exception as e:
194
+ log_warning(f"Could not extract JavaScript imports: {e}")
195
+
196
+ return imports
197
+
198
+ def _extract_function_info(
199
+ self, node: "tree_sitter.Node", source_code: str
200
+ ) -> Optional[Function]:
201
+ """Extract function information from AST node"""
202
+ try:
203
+ name_node = None
204
+ params_node = None
205
+
206
+ # Navigate the node structure to find name and parameters
207
+ for child in node.children:
208
+ if child.type == "identifier":
209
+ name_node = child
210
+ elif child.type == "property_identifier": # For method definitions
211
+ name_node = child
212
+ elif child.type == "formal_parameters":
213
+ params_node = child
214
+ elif child.type == "variable_declarator":
215
+ # For arrow functions and function expressions
216
+ for subchild in child.children:
217
+ if subchild.type == "identifier":
218
+ name_node = subchild
219
+ elif subchild.type in ["arrow_function", "function_expression"]:
220
+ for funcchild in subchild.children:
221
+ if funcchild.type == "formal_parameters":
222
+ params_node = funcchild
223
+
224
+ if not name_node:
225
+ return None
226
+
227
+ name = source_code[name_node.start_byte : name_node.end_byte]
228
+
229
+ # Extract parameters
230
+ parameters = []
231
+ if params_node:
232
+ for child in params_node.children:
233
+ if child.type == "identifier":
234
+ param_name = source_code[child.start_byte : child.end_byte]
235
+ parameters.append(param_name)
236
+
237
+ return Function(
238
+ name=name,
239
+ parameters=parameters,
240
+ start_line=node.start_point[0] + 1,
241
+ end_line=node.end_point[0] + 1,
242
+ raw_text=source_code[node.start_byte : node.end_byte],
243
+ language="javascript",
244
+ )
245
+
246
+ except Exception as e:
247
+ log_warning(f"Could not extract function info: {e}")
248
+ return None
249
+
250
+ def _extract_class_info(
251
+ self, node: "tree_sitter.Node", source_code: str
252
+ ) -> Optional[Class]:
253
+ """Extract class information from AST node"""
254
+ try:
255
+ name_node = None
256
+
257
+ for child in node.children:
258
+ if child.type == "identifier":
259
+ name_node = child
260
+ break
261
+
262
+ if not name_node:
263
+ return None
264
+
265
+ name = source_code[name_node.start_byte : name_node.end_byte]
266
+
267
+ return Class(
268
+ name=name,
269
+ class_type="class",
270
+ start_line=node.start_point[0] + 1,
271
+ end_line=node.end_point[0] + 1,
272
+ raw_text=source_code[node.start_byte : node.end_byte],
273
+ language="javascript",
274
+ )
275
+
276
+ except Exception as e:
277
+ log_warning(f"Could not extract class info: {e}")
278
+ return None
279
+
280
+ def _extract_variable_info(
281
+ self, node: "tree_sitter.Node", source_code: str
282
+ ) -> Optional[Variable]:
283
+ """Extract variable information from AST node"""
284
+ try:
285
+ name_node = None
286
+
287
+ # Find the identifier in variable declarator
288
+ for child in node.children:
289
+ if child.type == "variable_declarator":
290
+ for subchild in child.children:
291
+ if subchild.type == "identifier":
292
+ name_node = subchild
293
+ break
294
+ break
295
+
296
+ if not name_node:
297
+ return None
298
+
299
+ name = source_code[name_node.start_byte : name_node.end_byte]
300
+
301
+ return Variable(
302
+ name=name,
303
+ start_line=node.start_point[0] + 1,
304
+ end_line=node.end_point[0] + 1,
305
+ raw_text=source_code[node.start_byte : node.end_byte],
306
+ language="javascript",
307
+ )
308
+
309
+ except Exception as e:
310
+ log_warning(f"Could not extract variable info: {e}")
311
+ return None
312
+
313
+ def _extract_import_info(
314
+ self, node: "tree_sitter.Node", source_code: str
315
+ ) -> Optional[Import]:
316
+ """Extract import information from AST node"""
317
+ try:
318
+ source_node = None
319
+
320
+ for child in node.children:
321
+ if child.type == "string":
322
+ source_node = child
323
+ break
324
+
325
+ if not source_node:
326
+ return None
327
+
328
+ module_path = source_code[source_node.start_byte : source_node.end_byte]
329
+ # Remove quotes from string
330
+ module_path = module_path.strip("\"'")
331
+
332
+ return Import(
333
+ name="import",
334
+ module_path=module_path,
335
+ start_line=node.start_point[0] + 1,
336
+ end_line=node.end_point[0] + 1,
337
+ raw_text=source_code[node.start_byte : node.end_byte],
338
+ language="javascript",
339
+ )
340
+
341
+ except Exception as e:
342
+ log_warning(f"Could not extract import info: {e}")
343
+ return None
344
+
345
+
346
+ class JavaScriptPlugin(LanguagePlugin):
347
+ """JavaScript language plugin"""
348
+
349
+ def __init__(self) -> None:
350
+ self._extractor = JavaScriptElementExtractor()
351
+ self._language: Optional["tree_sitter.Language"] = None
352
+
353
+ @property
354
+ def language_name(self) -> str:
355
+ return "javascript"
356
+
357
+ @property
358
+ def file_extensions(self) -> List[str]:
359
+ return [".js", ".mjs", ".jsx"]
360
+
361
+ def get_language_name(self) -> str:
362
+ """Return the name of the programming language this plugin supports"""
363
+ return "javascript"
364
+
365
+ def get_file_extensions(self) -> List[str]:
366
+ """Return list of file extensions this plugin supports"""
367
+ return [".js", ".mjs", ".jsx"]
368
+
369
+ def create_extractor(self) -> ElementExtractor:
370
+ """Create and return an element extractor for this language"""
371
+ return JavaScriptElementExtractor()
372
+
373
+ def get_extractor(self) -> ElementExtractor:
374
+ return self._extractor
375
+
376
+ def get_tree_sitter_language(self) -> Optional["tree_sitter.Language"]:
377
+ """Load and return JavaScript tree-sitter language"""
378
+ if self._language is None:
379
+ self._language = loader.load_language("javascript")
380
+ return self._language
381
+
382
+ async def analyze_file(
383
+ self, file_path: str, request: AnalysisRequest
384
+ ) -> AnalysisResult:
385
+ """Analyze a JavaScript file and return the analysis results."""
386
+ if not TREE_SITTER_AVAILABLE:
387
+ return AnalysisResult(
388
+ file_path=file_path,
389
+ language=self.language_name,
390
+ success=False,
391
+ error_message="Tree-sitter library not available.",
392
+ )
393
+
394
+ language = self.get_tree_sitter_language()
395
+ if not language:
396
+ return AnalysisResult(
397
+ file_path=file_path,
398
+ language=self.language_name,
399
+ success=False,
400
+ error_message="Could not load JavaScript language for parsing.",
401
+ )
402
+
403
+ try:
404
+ with open(file_path, "r", encoding="utf-8") as f:
405
+ source_code = f.read()
406
+
407
+ parser = tree_sitter.Parser()
408
+ parser.language = language
409
+ tree = parser.parse(bytes(source_code, "utf8"))
410
+
411
+ extractor = self.create_extractor()
412
+ elements = []
413
+ elements.extend(extractor.extract_functions(tree, source_code))
414
+ elements.extend(extractor.extract_classes(tree, source_code))
415
+ elements.extend(extractor.extract_variables(tree, source_code))
416
+ elements.extend(extractor.extract_imports(tree, source_code))
417
+
418
+ def count_nodes(node: "tree_sitter.Node") -> int:
419
+ count = 1
420
+ for child in node.children:
421
+ count += count_nodes(child)
422
+ return count
423
+
424
+ return AnalysisResult(
425
+ file_path=file_path,
426
+ language=self.language_name,
427
+ success=True,
428
+ elements=elements,
429
+ line_count=len(source_code.splitlines()),
430
+ node_count=count_nodes(tree.root_node),
431
+ )
432
+ except Exception as e:
433
+ log_error(f"Error analyzing JavaScript file {file_path}: {e}")
434
+ return AnalysisResult(
435
+ file_path=file_path,
436
+ language=self.language_name,
437
+ success=False,
438
+ error_message=str(e),
439
+ )