tree-sitter-analyzer 1.9.1__py3-none-any.whl → 1.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.
- tree_sitter_analyzer/__init__.py +1 -1
- tree_sitter_analyzer/api.py +10 -6
- tree_sitter_analyzer/cli/argument_validator.py +1 -1
- tree_sitter_analyzer/cli/commands/advanced_command.py +3 -6
- tree_sitter_analyzer/cli/commands/query_command.py +3 -1
- tree_sitter_analyzer/cli/commands/table_command.py +3 -3
- tree_sitter_analyzer/constants.py +5 -3
- tree_sitter_analyzer/core/analysis_engine.py +1 -1
- tree_sitter_analyzer/core/cache_service.py +1 -1
- tree_sitter_analyzer/core/engine.py +1 -1
- tree_sitter_analyzer/core/query.py +0 -2
- tree_sitter_analyzer/exceptions.py +1 -1
- tree_sitter_analyzer/file_handler.py +6 -6
- tree_sitter_analyzer/formatters/base_formatter.py +1 -1
- tree_sitter_analyzer/formatters/html_formatter.py +24 -14
- tree_sitter_analyzer/formatters/javascript_formatter.py +28 -21
- tree_sitter_analyzer/formatters/language_formatter_factory.py +7 -4
- tree_sitter_analyzer/formatters/markdown_formatter.py +4 -4
- tree_sitter_analyzer/formatters/python_formatter.py +4 -4
- tree_sitter_analyzer/formatters/typescript_formatter.py +1 -1
- tree_sitter_analyzer/interfaces/mcp_adapter.py +4 -2
- tree_sitter_analyzer/interfaces/mcp_server.py +10 -10
- tree_sitter_analyzer/language_detector.py +30 -5
- tree_sitter_analyzer/language_loader.py +46 -26
- tree_sitter_analyzer/languages/css_plugin.py +6 -6
- tree_sitter_analyzer/languages/html_plugin.py +12 -8
- tree_sitter_analyzer/languages/java_plugin.py +307 -520
- tree_sitter_analyzer/languages/javascript_plugin.py +22 -78
- tree_sitter_analyzer/languages/markdown_plugin.py +277 -297
- tree_sitter_analyzer/languages/python_plugin.py +47 -85
- tree_sitter_analyzer/languages/typescript_plugin.py +48 -123
- tree_sitter_analyzer/mcp/resources/project_stats_resource.py +14 -8
- tree_sitter_analyzer/mcp/server.py +38 -23
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +10 -7
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +51 -7
- tree_sitter_analyzer/mcp/tools/fd_rg_utils.py +15 -2
- tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +8 -6
- tree_sitter_analyzer/mcp/tools/list_files_tool.py +6 -6
- tree_sitter_analyzer/mcp/tools/search_content_tool.py +48 -19
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +13 -8
- tree_sitter_analyzer/mcp/utils/file_output_manager.py +8 -3
- tree_sitter_analyzer/mcp/utils/gitignore_detector.py +24 -12
- tree_sitter_analyzer/mcp/utils/path_resolver.py +2 -2
- tree_sitter_analyzer/models.py +16 -0
- tree_sitter_analyzer/mypy_current_errors.txt +2 -0
- tree_sitter_analyzer/plugins/base.py +66 -0
- tree_sitter_analyzer/queries/java.py +1 -1
- tree_sitter_analyzer/queries/javascript.py +3 -8
- tree_sitter_analyzer/queries/markdown.py +1 -1
- tree_sitter_analyzer/queries/python.py +2 -2
- tree_sitter_analyzer/security/boundary_manager.py +2 -5
- tree_sitter_analyzer/security/regex_checker.py +2 -2
- tree_sitter_analyzer/security/validator.py +5 -1
- tree_sitter_analyzer/table_formatter.py +4 -4
- tree_sitter_analyzer/utils/__init__.py +27 -116
- tree_sitter_analyzer/{utils.py → utils/logging.py} +2 -2
- tree_sitter_analyzer/utils/tree_sitter_compat.py +2 -2
- {tree_sitter_analyzer-1.9.1.dist-info → tree_sitter_analyzer-1.9.3.dist-info}/METADATA +70 -30
- tree_sitter_analyzer-1.9.3.dist-info/RECORD +110 -0
- tree_sitter_analyzer-1.9.1.dist-info/RECORD +0 -109
- {tree_sitter_analyzer-1.9.1.dist-info → tree_sitter_analyzer-1.9.3.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-1.9.1.dist-info → tree_sitter_analyzer-1.9.3.dist-info}/entry_points.txt +0 -0
|
@@ -69,20 +69,16 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
69
69
|
"function_definition": self._extract_function_optimized,
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
if tree is None
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
log_debug(f"Error during function extraction: {e}")
|
|
82
|
-
# Return empty list on error to handle gracefully
|
|
83
|
-
return []
|
|
72
|
+
if tree is not None and tree.root_node is not None:
|
|
73
|
+
try:
|
|
74
|
+
self._traverse_and_extract_iterative(
|
|
75
|
+
tree.root_node, extractors, functions, "function"
|
|
76
|
+
)
|
|
77
|
+
log_debug(f"Extracted {len(functions)} Python functions")
|
|
78
|
+
except Exception as e:
|
|
79
|
+
log_debug(f"Error during function extraction: {e}")
|
|
80
|
+
return []
|
|
84
81
|
|
|
85
|
-
log_debug(f"Extracted {len(functions)} Python functions")
|
|
86
82
|
return functions
|
|
87
83
|
|
|
88
84
|
def extract_classes(
|
|
@@ -100,15 +96,16 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
100
96
|
"class_definition": self._extract_class_optimized,
|
|
101
97
|
}
|
|
102
98
|
|
|
103
|
-
if tree is None
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
99
|
+
if tree is not None and tree.root_node is not None:
|
|
100
|
+
try:
|
|
101
|
+
self._traverse_and_extract_iterative(
|
|
102
|
+
tree.root_node, extractors, classes, "class"
|
|
103
|
+
)
|
|
104
|
+
log_debug(f"Extracted {len(classes)} Python classes")
|
|
105
|
+
except Exception as e:
|
|
106
|
+
log_debug(f"Error during class extraction: {e}")
|
|
107
|
+
return []
|
|
110
108
|
|
|
111
|
-
log_debug(f"Extracted {len(classes)} Python classes")
|
|
112
109
|
return classes
|
|
113
110
|
|
|
114
111
|
def extract_variables(
|
|
@@ -178,7 +175,7 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
178
175
|
|
|
179
176
|
def _traverse_and_extract_iterative(
|
|
180
177
|
self,
|
|
181
|
-
root_node: "tree_sitter.Node",
|
|
178
|
+
root_node: Optional["tree_sitter.Node"],
|
|
182
179
|
extractors: dict[str, Any],
|
|
183
180
|
results: list[Any],
|
|
184
181
|
element_type: str,
|
|
@@ -255,22 +252,23 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
255
252
|
except Exception:
|
|
256
253
|
# Skip nodes that cause extraction errors
|
|
257
254
|
self._processed_nodes.add(node_id)
|
|
258
|
-
continue
|
|
259
255
|
|
|
260
256
|
# Add children to stack
|
|
261
257
|
if current_node.children:
|
|
262
258
|
try:
|
|
263
259
|
# Try to reverse children for proper traversal order
|
|
264
|
-
|
|
260
|
+
children_list = list(current_node.children)
|
|
261
|
+
children_iter = reversed(children_list)
|
|
265
262
|
except TypeError:
|
|
266
263
|
# Fallback for Mock objects or other non-reversible types
|
|
267
264
|
try:
|
|
268
|
-
|
|
265
|
+
children_list = list(current_node.children)
|
|
266
|
+
children_iter = iter(children_list) # type: ignore
|
|
269
267
|
except TypeError:
|
|
270
268
|
# If children is not iterable, skip
|
|
271
|
-
|
|
269
|
+
children_iter = iter([]) # type: ignore
|
|
272
270
|
|
|
273
|
-
for child in
|
|
271
|
+
for child in children_iter:
|
|
274
272
|
node_stack.append((child, depth + 1))
|
|
275
273
|
|
|
276
274
|
log_debug(f"Iterative traversal processed {processed_nodes} nodes")
|
|
@@ -314,7 +312,7 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
314
312
|
# Ensure column indices are within line bounds
|
|
315
313
|
start_col = max(0, min(start_point[1], len(line)))
|
|
316
314
|
end_col = max(start_col, min(end_point[1], len(line)))
|
|
317
|
-
result = line[start_col:end_col]
|
|
315
|
+
result: str = line[start_col:end_col]
|
|
318
316
|
self._node_text_cache[node_id] = result
|
|
319
317
|
return result
|
|
320
318
|
else:
|
|
@@ -498,9 +496,8 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
498
496
|
break
|
|
499
497
|
docstring_lines.append(next_line)
|
|
500
498
|
|
|
501
|
-
# If no closing quote found, return None (malformed docstring)
|
|
502
499
|
if not found_closing_quote:
|
|
503
|
-
self._docstring_cache[target_line] =
|
|
500
|
+
self._docstring_cache[target_line] = ""
|
|
504
501
|
return None
|
|
505
502
|
|
|
506
503
|
# Join preserving formatting and add leading newline for multi-line
|
|
@@ -511,7 +508,7 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
511
508
|
self._docstring_cache[target_line] = docstring
|
|
512
509
|
return docstring
|
|
513
510
|
|
|
514
|
-
self._docstring_cache[target_line] =
|
|
511
|
+
self._docstring_cache[target_line] = ""
|
|
515
512
|
return None
|
|
516
513
|
|
|
517
514
|
except Exception as e:
|
|
@@ -748,7 +745,7 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
748
745
|
)
|
|
749
746
|
|
|
750
747
|
# Group captures by name
|
|
751
|
-
captures_dict = {}
|
|
748
|
+
captures_dict: dict[str, list[Any]] = {}
|
|
752
749
|
for node, capture_name in captures:
|
|
753
750
|
if capture_name not in captures_dict:
|
|
754
751
|
captures_dict[capture_name] = []
|
|
@@ -787,7 +784,7 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
787
784
|
"""Manual import extraction for tree-sitter 0.25.x compatibility"""
|
|
788
785
|
imports = []
|
|
789
786
|
|
|
790
|
-
def walk_tree(node):
|
|
787
|
+
def walk_tree(node: "tree_sitter.Node") -> None:
|
|
791
788
|
if node.type in ["import_statement", "import_from_statement"]:
|
|
792
789
|
try:
|
|
793
790
|
start_line = node.start_point[0] + 1
|
|
@@ -824,9 +821,11 @@ class PythonElementExtractor(ElementExtractor):
|
|
|
824
821
|
|
|
825
822
|
if module_name or imported_names:
|
|
826
823
|
import_obj = Import(
|
|
827
|
-
name=
|
|
828
|
-
|
|
829
|
-
|
|
824
|
+
name=(
|
|
825
|
+
module_name or imported_names[0]
|
|
826
|
+
if imported_names
|
|
827
|
+
else "unknown"
|
|
828
|
+
),
|
|
830
829
|
start_line=start_line,
|
|
831
830
|
end_line=end_line,
|
|
832
831
|
raw_text=raw_text,
|
|
@@ -1294,51 +1293,13 @@ class PythonPlugin(LanguagePlugin):
|
|
|
1294
1293
|
}
|
|
1295
1294
|
|
|
1296
1295
|
def execute_query_strategy(
|
|
1297
|
-
self,
|
|
1298
|
-
) ->
|
|
1299
|
-
"""
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
Args:
|
|
1303
|
-
tree: Tree-sitter tree object
|
|
1304
|
-
source_code: Source code string
|
|
1305
|
-
query_key: Query key to execute
|
|
1306
|
-
|
|
1307
|
-
Returns:
|
|
1308
|
-
List of query results
|
|
1309
|
-
"""
|
|
1310
|
-
# Use the extractor to get elements based on query_key
|
|
1311
|
-
extractor = self.get_extractor()
|
|
1296
|
+
self, query_key: str | None, language: str
|
|
1297
|
+
) -> str | None:
|
|
1298
|
+
"""Execute query strategy for Python language"""
|
|
1299
|
+
queries = self.get_queries()
|
|
1300
|
+
return queries.get(query_key) if query_key else None
|
|
1312
1301
|
|
|
1313
|
-
|
|
1314
|
-
if query_key in ["function", "functions", "method", "methods"]:
|
|
1315
|
-
elements = extractor.extract_functions(tree, source_code)
|
|
1316
|
-
elif query_key in ["class", "classes"]:
|
|
1317
|
-
elements = extractor.extract_classes(tree, source_code)
|
|
1318
|
-
elif query_key in ["variable", "variables"]:
|
|
1319
|
-
elements = extractor.extract_variables(tree, source_code)
|
|
1320
|
-
elif query_key in ["import", "imports", "from_import", "from_imports"]:
|
|
1321
|
-
elements = extractor.extract_imports(tree, source_code)
|
|
1322
|
-
else:
|
|
1323
|
-
# For unknown query keys, return empty list
|
|
1324
|
-
return []
|
|
1325
|
-
|
|
1326
|
-
# Convert elements to query result format
|
|
1327
|
-
results = []
|
|
1328
|
-
for element in elements:
|
|
1329
|
-
result = {
|
|
1330
|
-
"capture_name": query_key,
|
|
1331
|
-
"node_type": self._get_node_type_for_element(element),
|
|
1332
|
-
"start_line": element.start_line,
|
|
1333
|
-
"end_line": element.end_line,
|
|
1334
|
-
"text": element.raw_text,
|
|
1335
|
-
"name": element.name,
|
|
1336
|
-
}
|
|
1337
|
-
results.append(result)
|
|
1338
|
-
|
|
1339
|
-
return results
|
|
1340
|
-
|
|
1341
|
-
def _get_node_type_for_element(self, element) -> str:
|
|
1302
|
+
def _get_node_type_for_element(self, element: Any) -> str:
|
|
1342
1303
|
"""Get appropriate node type for element"""
|
|
1343
1304
|
from ..models import Class, Function, Import, Variable
|
|
1344
1305
|
|
|
@@ -1459,8 +1420,9 @@ class PythonPlugin(LanguagePlugin):
|
|
|
1459
1420
|
)
|
|
1460
1421
|
|
|
1461
1422
|
try:
|
|
1462
|
-
|
|
1463
|
-
|
|
1423
|
+
from ..encoding_utils import read_file_safe
|
|
1424
|
+
|
|
1425
|
+
source_code, _ = read_file_safe(file_path)
|
|
1464
1426
|
|
|
1465
1427
|
parser = tree_sitter.Parser()
|
|
1466
1428
|
parser.language = language
|
|
@@ -1536,9 +1498,9 @@ class PythonPlugin(LanguagePlugin):
|
|
|
1536
1498
|
|
|
1537
1499
|
try:
|
|
1538
1500
|
elements.extend(extractor.extract_functions(tree, source_code))
|
|
1539
|
-
elements.extend(extractor.extract_classes(tree, source_code))
|
|
1540
|
-
elements.extend(extractor.extract_variables(tree, source_code))
|
|
1541
|
-
elements.extend(extractor.extract_imports(tree, source_code))
|
|
1501
|
+
elements.extend(extractor.extract_classes(tree, source_code)) # type: ignore
|
|
1502
|
+
elements.extend(extractor.extract_variables(tree, source_code)) # type: ignore
|
|
1503
|
+
elements.extend(extractor.extract_imports(tree, source_code)) # type: ignore
|
|
1542
1504
|
except Exception as e:
|
|
1543
1505
|
log_error(f"Failed to extract elements: {e}")
|
|
1544
1506
|
|
|
@@ -189,7 +189,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
189
189
|
|
|
190
190
|
def _traverse_and_extract_iterative(
|
|
191
191
|
self,
|
|
192
|
-
root_node: "tree_sitter.Node",
|
|
192
|
+
root_node: Optional["tree_sitter.Node"],
|
|
193
193
|
extractors: dict[str, Any],
|
|
194
194
|
results: list[Any],
|
|
195
195
|
element_type: str,
|
|
@@ -303,7 +303,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
303
303
|
|
|
304
304
|
if start_point[0] == end_point[0]:
|
|
305
305
|
line = self.content_lines[start_point[0]]
|
|
306
|
-
return line[start_point[1] : end_point[1]]
|
|
306
|
+
return str(line[start_point[1] : end_point[1]])
|
|
307
307
|
else:
|
|
308
308
|
lines = []
|
|
309
309
|
for i in range(start_point[0], end_point[0] + 1):
|
|
@@ -335,6 +335,10 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
335
335
|
function_info
|
|
336
336
|
)
|
|
337
337
|
|
|
338
|
+
# Skip if no name found
|
|
339
|
+
if name is None:
|
|
340
|
+
return None
|
|
341
|
+
|
|
338
342
|
# Extract TSDoc
|
|
339
343
|
tsdoc = self._extract_tsdoc_for_line(start_line)
|
|
340
344
|
|
|
@@ -461,6 +465,10 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
461
465
|
generics,
|
|
462
466
|
) = method_info
|
|
463
467
|
|
|
468
|
+
# Skip if no name found
|
|
469
|
+
if name is None:
|
|
470
|
+
return None
|
|
471
|
+
|
|
464
472
|
# Extract TSDoc
|
|
465
473
|
tsdoc = self._extract_tsdoc_for_line(start_line)
|
|
466
474
|
|
|
@@ -519,6 +527,10 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
519
527
|
generics,
|
|
520
528
|
) = method_info
|
|
521
529
|
|
|
530
|
+
# Skip if no name found
|
|
531
|
+
if name is None:
|
|
532
|
+
return None
|
|
533
|
+
|
|
522
534
|
# Extract TSDoc
|
|
523
535
|
tsdoc = self._extract_tsdoc_for_line(start_line)
|
|
524
536
|
|
|
@@ -540,12 +552,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
540
552
|
# TypeScript-specific properties
|
|
541
553
|
is_arrow=False,
|
|
542
554
|
is_method=True,
|
|
543
|
-
is_signature=True,
|
|
544
555
|
framework_type=self.framework_type,
|
|
545
|
-
visibility=visibility,
|
|
546
|
-
is_getter=is_getter,
|
|
547
|
-
is_setter=is_setter,
|
|
548
|
-
# TypeScript-specific properties handled above
|
|
549
556
|
)
|
|
550
557
|
except Exception as e:
|
|
551
558
|
log_debug(f"Failed to extract method signature info: {e}")
|
|
@@ -566,6 +573,10 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
566
573
|
|
|
567
574
|
name, parameters, is_async, _, return_type, generics = function_info
|
|
568
575
|
|
|
576
|
+
# Skip if no name found
|
|
577
|
+
if name is None:
|
|
578
|
+
return None
|
|
579
|
+
|
|
569
580
|
# Extract TSDoc
|
|
570
581
|
tsdoc = self._extract_tsdoc_for_line(start_line)
|
|
571
582
|
|
|
@@ -995,7 +1006,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
995
1006
|
|
|
996
1007
|
def _parse_function_signature_optimized(
|
|
997
1008
|
self, node: "tree_sitter.Node"
|
|
998
|
-
) -> tuple[str, list[str], bool, bool, str | None, list[str]] | None:
|
|
1009
|
+
) -> tuple[str | None, list[str], bool, bool, str | None, list[str]] | None:
|
|
999
1010
|
"""Parse function signature for TypeScript functions"""
|
|
1000
1011
|
try:
|
|
1001
1012
|
name = None
|
|
@@ -1027,7 +1038,18 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1027
1038
|
def _parse_method_signature_optimized(
|
|
1028
1039
|
self, node: "tree_sitter.Node"
|
|
1029
1040
|
) -> (
|
|
1030
|
-
tuple[
|
|
1041
|
+
tuple[
|
|
1042
|
+
str | None,
|
|
1043
|
+
list[str],
|
|
1044
|
+
bool,
|
|
1045
|
+
bool,
|
|
1046
|
+
bool,
|
|
1047
|
+
bool,
|
|
1048
|
+
bool,
|
|
1049
|
+
str | None,
|
|
1050
|
+
str,
|
|
1051
|
+
list[str],
|
|
1052
|
+
]
|
|
1031
1053
|
| None
|
|
1032
1054
|
):
|
|
1033
1055
|
"""Parse method signature for TypeScript class methods"""
|
|
@@ -1261,7 +1283,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1261
1283
|
self, import_clause_node: "tree_sitter.Node", import_text: str = ""
|
|
1262
1284
|
) -> list[str]:
|
|
1263
1285
|
"""Extract import names from import clause"""
|
|
1264
|
-
names = []
|
|
1286
|
+
names: list[str] = []
|
|
1265
1287
|
|
|
1266
1288
|
try:
|
|
1267
1289
|
# Handle Mock objects in tests
|
|
@@ -1416,11 +1438,14 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1416
1438
|
|
|
1417
1439
|
try:
|
|
1418
1440
|
# Test if _get_node_text_optimized is working (for error handling tests)
|
|
1419
|
-
if
|
|
1441
|
+
if (
|
|
1442
|
+
hasattr(self, "_get_node_text_optimized")
|
|
1443
|
+
and tree
|
|
1444
|
+
and hasattr(tree, "root_node")
|
|
1445
|
+
and tree.root_node
|
|
1446
|
+
):
|
|
1420
1447
|
# This will trigger the mocked exception in tests
|
|
1421
|
-
self._get_node_text_optimized(
|
|
1422
|
-
tree.root_node if tree and hasattr(tree, "root_node") else None
|
|
1423
|
-
)
|
|
1448
|
+
self._get_node_text_optimized(tree.root_node)
|
|
1424
1449
|
|
|
1425
1450
|
# Use regex to find require statements
|
|
1426
1451
|
require_pattern = r"(?:const|let|var)\s+(\w+)\s*=\s*require\s*\(\s*[\"']([^\"']+)[\"']\s*\)"
|
|
@@ -1551,7 +1576,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1551
1576
|
return cleaned
|
|
1552
1577
|
current_line -= 1
|
|
1553
1578
|
|
|
1554
|
-
self._tsdoc_cache[target_line] =
|
|
1579
|
+
self._tsdoc_cache[target_line] = ""
|
|
1555
1580
|
return None
|
|
1556
1581
|
|
|
1557
1582
|
except Exception as e:
|
|
@@ -1749,8 +1774,9 @@ class TypeScriptPlugin(LanguagePlugin):
|
|
|
1749
1774
|
)
|
|
1750
1775
|
|
|
1751
1776
|
try:
|
|
1752
|
-
|
|
1753
|
-
|
|
1777
|
+
from ..encoding_utils import read_file_safe
|
|
1778
|
+
|
|
1779
|
+
source_code, _ = read_file_safe(file_path)
|
|
1754
1780
|
|
|
1755
1781
|
parser = tree_sitter.Parser()
|
|
1756
1782
|
parser.language = language
|
|
@@ -1811,112 +1837,11 @@ class TypeScriptPlugin(LanguagePlugin):
|
|
|
1811
1837
|
return all_elements
|
|
1812
1838
|
|
|
1813
1839
|
def execute_query_strategy(
|
|
1814
|
-
self,
|
|
1815
|
-
) ->
|
|
1816
|
-
"""Execute
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
# Initialize extractor with source code
|
|
1821
|
-
self._extractor.source_code = source_code
|
|
1822
|
-
self._extractor.content_lines = source_code.split("\n")
|
|
1823
|
-
self._extractor._reset_caches()
|
|
1824
|
-
self._extractor._detect_file_characteristics()
|
|
1825
|
-
|
|
1826
|
-
# Map query_key to appropriate extraction method
|
|
1827
|
-
query_mapping = {
|
|
1828
|
-
# Function-related queries
|
|
1829
|
-
"function": lambda: self._extractor.extract_functions(tree, source_code),
|
|
1830
|
-
"async_function": lambda: [
|
|
1831
|
-
f
|
|
1832
|
-
for f in self._extractor.extract_functions(tree, source_code)
|
|
1833
|
-
if getattr(f, "is_async", False)
|
|
1834
|
-
],
|
|
1835
|
-
"arrow_function": lambda: [
|
|
1836
|
-
f
|
|
1837
|
-
for f in self._extractor.extract_functions(tree, source_code)
|
|
1838
|
-
if getattr(f, "is_arrow", False)
|
|
1839
|
-
],
|
|
1840
|
-
"method": lambda: [
|
|
1841
|
-
f
|
|
1842
|
-
for f in self._extractor.extract_functions(tree, source_code)
|
|
1843
|
-
if getattr(f, "is_method", False)
|
|
1844
|
-
],
|
|
1845
|
-
"constructor": lambda: [
|
|
1846
|
-
f
|
|
1847
|
-
for f in self._extractor.extract_functions(tree, source_code)
|
|
1848
|
-
if getattr(f, "is_constructor", False)
|
|
1849
|
-
],
|
|
1850
|
-
"signature": lambda: [
|
|
1851
|
-
f
|
|
1852
|
-
for f in self._extractor.extract_functions(tree, source_code)
|
|
1853
|
-
if getattr(f, "is_signature", False)
|
|
1854
|
-
],
|
|
1855
|
-
# Class-related queries
|
|
1856
|
-
"class": lambda: self._extractor.extract_classes(tree, source_code),
|
|
1857
|
-
"interface": lambda: [
|
|
1858
|
-
c
|
|
1859
|
-
for c in self._extractor.extract_classes(tree, source_code)
|
|
1860
|
-
if getattr(c, "class_type", "") == "interface"
|
|
1861
|
-
],
|
|
1862
|
-
"type_alias": lambda: [
|
|
1863
|
-
c
|
|
1864
|
-
for c in self._extractor.extract_classes(tree, source_code)
|
|
1865
|
-
if getattr(c, "class_type", "") == "type"
|
|
1866
|
-
],
|
|
1867
|
-
"enum": lambda: [
|
|
1868
|
-
c
|
|
1869
|
-
for c in self._extractor.extract_classes(tree, source_code)
|
|
1870
|
-
if getattr(c, "class_type", "") == "enum"
|
|
1871
|
-
],
|
|
1872
|
-
# Variable-related queries
|
|
1873
|
-
"variable": lambda: self._extractor.extract_variables(tree, source_code),
|
|
1874
|
-
# Import/Export queries
|
|
1875
|
-
"import": lambda: self._extractor.extract_imports(tree, source_code),
|
|
1876
|
-
"export": lambda: [
|
|
1877
|
-
i
|
|
1878
|
-
for i in self._extractor.extract_imports(tree, source_code)
|
|
1879
|
-
if "export" in getattr(i, "raw_text", "")
|
|
1880
|
-
],
|
|
1881
|
-
# TypeScript-specific queries
|
|
1882
|
-
"generic": lambda: [
|
|
1883
|
-
c
|
|
1884
|
-
for c in self._extractor.extract_classes(tree, source_code)
|
|
1885
|
-
if "generics" in getattr(c, "raw_text", "")
|
|
1886
|
-
],
|
|
1887
|
-
"decorator": lambda: [
|
|
1888
|
-
f
|
|
1889
|
-
for f in self._extractor.extract_functions(tree, source_code)
|
|
1890
|
-
if "@" in getattr(f, "raw_text", "")
|
|
1891
|
-
],
|
|
1892
|
-
# Framework-specific queries
|
|
1893
|
-
"react_component": lambda: [
|
|
1894
|
-
c
|
|
1895
|
-
for c in self._extractor.extract_classes(tree, source_code)
|
|
1896
|
-
if getattr(c, "is_react_component", False)
|
|
1897
|
-
],
|
|
1898
|
-
"angular_component": lambda: [
|
|
1899
|
-
c
|
|
1900
|
-
for c in self._extractor.extract_classes(tree, source_code)
|
|
1901
|
-
if getattr(c, "framework_type", "") == "angular"
|
|
1902
|
-
],
|
|
1903
|
-
"vue_component": lambda: [
|
|
1904
|
-
c
|
|
1905
|
-
for c in self._extractor.extract_classes(tree, source_code)
|
|
1906
|
-
if getattr(c, "framework_type", "") == "vue"
|
|
1907
|
-
],
|
|
1908
|
-
}
|
|
1909
|
-
|
|
1910
|
-
# Execute the appropriate extraction method
|
|
1911
|
-
if query_key in query_mapping:
|
|
1912
|
-
try:
|
|
1913
|
-
return query_mapping[query_key]()
|
|
1914
|
-
except Exception as e:
|
|
1915
|
-
log_error(f"Error executing TypeScript query '{query_key}': {e}")
|
|
1916
|
-
return []
|
|
1917
|
-
else:
|
|
1918
|
-
log_warning(f"Unsupported TypeScript query key: {query_key}")
|
|
1919
|
-
return []
|
|
1840
|
+
self, query_key: str | None, language: str
|
|
1841
|
+
) -> str | None:
|
|
1842
|
+
"""Execute query strategy for TypeScript language"""
|
|
1843
|
+
queries = self.get_queries()
|
|
1844
|
+
return queries.get(query_key) if query_key else None
|
|
1920
1845
|
|
|
1921
1846
|
def get_element_categories(self) -> dict[str, list[str]]:
|
|
1922
1847
|
"""Get TypeScript element categories mapping query_key to node_types"""
|
|
@@ -214,9 +214,11 @@ class ProjectStatsResource:
|
|
|
214
214
|
if file_path.is_file() and self._is_supported_code_file(file_path):
|
|
215
215
|
total_files += 1
|
|
216
216
|
try:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
from ...encoding_utils import read_file_safe
|
|
218
|
+
|
|
219
|
+
content, _ = read_file_safe(file_path)
|
|
220
|
+
file_lines = len(content.splitlines())
|
|
221
|
+
total_lines += file_lines
|
|
220
222
|
except Exception as e:
|
|
221
223
|
logger.debug(
|
|
222
224
|
f"Skipping unreadable file during overview scan: {file_path} ({e})"
|
|
@@ -280,9 +282,11 @@ class ProjectStatsResource:
|
|
|
280
282
|
if file_path.is_file() and self._is_supported_code_file(file_path):
|
|
281
283
|
total_files += 1
|
|
282
284
|
try:
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
285
|
+
from ...encoding_utils import read_file_safe
|
|
286
|
+
|
|
287
|
+
content, _ = read_file_safe(file_path)
|
|
288
|
+
file_lines = len(content.splitlines())
|
|
289
|
+
total_lines += file_lines
|
|
286
290
|
except Exception as e:
|
|
287
291
|
logger.debug(f"Failed to count lines for {file_path}: {e}")
|
|
288
292
|
file_lines = 0
|
|
@@ -452,8 +456,10 @@ class ProjectStatsResource:
|
|
|
452
456
|
|
|
453
457
|
# Count lines
|
|
454
458
|
try:
|
|
455
|
-
|
|
456
|
-
|
|
459
|
+
from ...encoding_utils import read_file_safe
|
|
460
|
+
|
|
461
|
+
content, _ = read_file_safe(file_path)
|
|
462
|
+
line_count = len(content.splitlines())
|
|
457
463
|
except Exception:
|
|
458
464
|
line_count = 0
|
|
459
465
|
|