tree-sitter-analyzer 1.8.4__py3-none-any.whl → 1.9.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.
- tree_sitter_analyzer/__init__.py +1 -1
- tree_sitter_analyzer/api.py +4 -4
- tree_sitter_analyzer/cli/argument_validator.py +29 -17
- tree_sitter_analyzer/cli/commands/advanced_command.py +7 -5
- tree_sitter_analyzer/cli/commands/structure_command.py +7 -5
- tree_sitter_analyzer/cli/commands/summary_command.py +10 -6
- tree_sitter_analyzer/cli/commands/table_command.py +8 -7
- tree_sitter_analyzer/cli/info_commands.py +1 -1
- tree_sitter_analyzer/cli_main.py +3 -2
- tree_sitter_analyzer/core/analysis_engine.py +5 -5
- tree_sitter_analyzer/core/cache_service.py +3 -1
- tree_sitter_analyzer/core/query.py +17 -5
- tree_sitter_analyzer/core/query_service.py +1 -1
- tree_sitter_analyzer/encoding_utils.py +3 -3
- tree_sitter_analyzer/exceptions.py +61 -50
- tree_sitter_analyzer/file_handler.py +3 -0
- tree_sitter_analyzer/formatters/base_formatter.py +10 -5
- tree_sitter_analyzer/formatters/formatter_registry.py +83 -68
- tree_sitter_analyzer/formatters/html_formatter.py +90 -54
- tree_sitter_analyzer/formatters/javascript_formatter.py +21 -16
- tree_sitter_analyzer/formatters/language_formatter_factory.py +7 -6
- tree_sitter_analyzer/formatters/markdown_formatter.py +247 -124
- tree_sitter_analyzer/formatters/python_formatter.py +61 -38
- tree_sitter_analyzer/formatters/typescript_formatter.py +113 -45
- tree_sitter_analyzer/interfaces/mcp_server.py +2 -2
- tree_sitter_analyzer/language_detector.py +6 -6
- tree_sitter_analyzer/language_loader.py +3 -1
- tree_sitter_analyzer/languages/css_plugin.py +120 -61
- tree_sitter_analyzer/languages/html_plugin.py +159 -62
- tree_sitter_analyzer/languages/java_plugin.py +42 -34
- tree_sitter_analyzer/languages/javascript_plugin.py +59 -30
- tree_sitter_analyzer/languages/markdown_plugin.py +402 -368
- tree_sitter_analyzer/languages/python_plugin.py +111 -64
- tree_sitter_analyzer/languages/typescript_plugin.py +241 -132
- tree_sitter_analyzer/mcp/server.py +22 -18
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +13 -8
- tree_sitter_analyzer/mcp/tools/base_tool.py +2 -2
- tree_sitter_analyzer/mcp/tools/fd_rg_utils.py +232 -26
- tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +31 -23
- tree_sitter_analyzer/mcp/tools/list_files_tool.py +21 -19
- tree_sitter_analyzer/mcp/tools/query_tool.py +17 -18
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +30 -31
- tree_sitter_analyzer/mcp/tools/search_content_tool.py +131 -77
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +29 -16
- tree_sitter_analyzer/mcp/utils/file_output_factory.py +64 -51
- tree_sitter_analyzer/mcp/utils/file_output_manager.py +34 -24
- tree_sitter_analyzer/mcp/utils/gitignore_detector.py +8 -4
- tree_sitter_analyzer/models.py +7 -5
- tree_sitter_analyzer/plugins/base.py +9 -7
- tree_sitter_analyzer/plugins/manager.py +1 -0
- tree_sitter_analyzer/queries/css.py +2 -21
- tree_sitter_analyzer/queries/html.py +2 -15
- tree_sitter_analyzer/queries/markdown.py +30 -41
- tree_sitter_analyzer/queries/python.py +20 -5
- tree_sitter_analyzer/query_loader.py +5 -5
- tree_sitter_analyzer/security/validator.py +114 -86
- tree_sitter_analyzer/utils/__init__.py +58 -28
- tree_sitter_analyzer/utils/tree_sitter_compat.py +72 -65
- tree_sitter_analyzer/utils.py +26 -15
- {tree_sitter_analyzer-1.8.4.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/METADATA +1 -1
- tree_sitter_analyzer-1.9.0.dist-info/RECORD +109 -0
- tree_sitter_analyzer-1.8.4.dist-info/RECORD +0 -109
- {tree_sitter_analyzer-1.8.4.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-1.8.4.dist-info → tree_sitter_analyzer-1.9.0.dist-info}/entry_points.txt +0 -0
|
@@ -175,7 +175,9 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
175
175
|
self.is_module = "import " in self.source_code or "export " in self.source_code
|
|
176
176
|
|
|
177
177
|
# Check if it contains TSX/JSX
|
|
178
|
-
self.is_tsx = "</" in self.source_code and self.current_file.lower().endswith(
|
|
178
|
+
self.is_tsx = "</" in self.source_code and self.current_file.lower().endswith(
|
|
179
|
+
(".tsx", ".jsx")
|
|
180
|
+
)
|
|
179
181
|
|
|
180
182
|
# Detect framework
|
|
181
183
|
if "react" in self.source_code.lower() or "jsx" in self.source_code:
|
|
@@ -329,7 +331,9 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
329
331
|
if not function_info:
|
|
330
332
|
return None
|
|
331
333
|
|
|
332
|
-
name, parameters, is_async, is_generator, return_type, generics =
|
|
334
|
+
name, parameters, is_async, is_generator, return_type, generics = (
|
|
335
|
+
function_info
|
|
336
|
+
)
|
|
333
337
|
|
|
334
338
|
# Extract TSDoc
|
|
335
339
|
tsdoc = self._extract_tsdoc_for_line(start_line)
|
|
@@ -603,7 +607,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
603
607
|
class_name = None
|
|
604
608
|
superclass = None
|
|
605
609
|
interfaces = []
|
|
606
|
-
generics = []
|
|
610
|
+
# generics = [] # Commented out as not used yet
|
|
607
611
|
is_abstract = node.type == "abstract_class_declaration"
|
|
608
612
|
|
|
609
613
|
for child in node.children:
|
|
@@ -615,12 +619,16 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
615
619
|
extends_match = re.search(r"extends\s+(\w+)", heritage_text)
|
|
616
620
|
if extends_match:
|
|
617
621
|
superclass = extends_match.group(1)
|
|
618
|
-
|
|
619
|
-
implements_matches = re.findall(
|
|
622
|
+
|
|
623
|
+
implements_matches = re.findall(
|
|
624
|
+
r"implements\s+([\w,\s]+)", heritage_text
|
|
625
|
+
)
|
|
620
626
|
if implements_matches:
|
|
621
|
-
interfaces = [
|
|
627
|
+
interfaces = [
|
|
628
|
+
iface.strip() for iface in implements_matches[0].split(",")
|
|
629
|
+
]
|
|
622
630
|
elif child.type == "type_parameters":
|
|
623
|
-
|
|
631
|
+
self._extract_generics(child)
|
|
624
632
|
|
|
625
633
|
if not class_name:
|
|
626
634
|
return None
|
|
@@ -664,7 +672,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
664
672
|
# Extract interface name
|
|
665
673
|
interface_name = None
|
|
666
674
|
extends_interfaces = []
|
|
667
|
-
generics = []
|
|
675
|
+
# generics = [] # Commented out as not used yet
|
|
668
676
|
|
|
669
677
|
for child in node.children:
|
|
670
678
|
if child.type == "type_identifier":
|
|
@@ -674,9 +682,11 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
674
682
|
extends_text = self._get_node_text_optimized(child)
|
|
675
683
|
extends_matches = re.findall(r"extends\s+([\w,\s]+)", extends_text)
|
|
676
684
|
if extends_matches:
|
|
677
|
-
extends_interfaces = [
|
|
685
|
+
extends_interfaces = [
|
|
686
|
+
iface.strip() for iface in extends_matches[0].split(",")
|
|
687
|
+
]
|
|
678
688
|
elif child.type == "type_parameters":
|
|
679
|
-
|
|
689
|
+
self._extract_generics(child)
|
|
680
690
|
|
|
681
691
|
if not interface_name:
|
|
682
692
|
return None
|
|
@@ -713,13 +723,13 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
713
723
|
|
|
714
724
|
# Extract type alias name
|
|
715
725
|
type_name = None
|
|
716
|
-
generics = []
|
|
726
|
+
# generics = [] # Commented out as not used yet
|
|
717
727
|
|
|
718
728
|
for child in node.children:
|
|
719
729
|
if child.type == "type_identifier":
|
|
720
730
|
type_name = child.text.decode("utf8") if child.text else None
|
|
721
731
|
elif child.type == "type_parameters":
|
|
722
|
-
|
|
732
|
+
self._extract_generics(child)
|
|
723
733
|
|
|
724
734
|
if not type_name:
|
|
725
735
|
return None
|
|
@@ -813,14 +823,22 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
813
823
|
visibility = "public"
|
|
814
824
|
|
|
815
825
|
# Handle children if they exist
|
|
816
|
-
if hasattr(node,
|
|
826
|
+
if hasattr(node, "children") and node.children:
|
|
817
827
|
for child in node.children:
|
|
818
|
-
if hasattr(child,
|
|
828
|
+
if hasattr(child, "type"):
|
|
819
829
|
if child.type == "property_identifier":
|
|
820
830
|
prop_name = self._get_node_text_optimized(child)
|
|
821
831
|
elif child.type == "type_annotation":
|
|
822
|
-
prop_type = self._get_node_text_optimized(child).lstrip(
|
|
823
|
-
|
|
832
|
+
prop_type = self._get_node_text_optimized(child).lstrip(
|
|
833
|
+
": "
|
|
834
|
+
)
|
|
835
|
+
elif child.type in [
|
|
836
|
+
"string",
|
|
837
|
+
"number",
|
|
838
|
+
"true",
|
|
839
|
+
"false",
|
|
840
|
+
"null",
|
|
841
|
+
]:
|
|
824
842
|
prop_value = self._get_node_text_optimized(child)
|
|
825
843
|
|
|
826
844
|
# Check modifiers from parent or node text
|
|
@@ -865,7 +883,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
865
883
|
# Extract property signature name and type
|
|
866
884
|
prop_name = None
|
|
867
885
|
prop_type = None
|
|
868
|
-
is_optional = False
|
|
886
|
+
# is_optional = False # Commented out as not used yet
|
|
869
887
|
|
|
870
888
|
for child in node.children:
|
|
871
889
|
if child.type == "property_identifier":
|
|
@@ -874,8 +892,9 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
874
892
|
prop_type = self._get_node_text_optimized(child).lstrip(": ")
|
|
875
893
|
|
|
876
894
|
# Check for optional property
|
|
877
|
-
node_text = self._get_node_text_optimized(node)
|
|
878
|
-
|
|
895
|
+
# node_text = self._get_node_text_optimized(node) # Commented out as not used yet
|
|
896
|
+
# Check for optional property (not used but kept for future reference)
|
|
897
|
+
# is_optional = "?" in node_text
|
|
879
898
|
|
|
880
899
|
if not prop_name:
|
|
881
900
|
return None
|
|
@@ -1007,7 +1026,10 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1007
1026
|
|
|
1008
1027
|
def _parse_method_signature_optimized(
|
|
1009
1028
|
self, node: "tree_sitter.Node"
|
|
1010
|
-
) ->
|
|
1029
|
+
) -> (
|
|
1030
|
+
tuple[str, list[str], bool, bool, bool, bool, bool, str | None, str, list[str]]
|
|
1031
|
+
| None
|
|
1032
|
+
):
|
|
1011
1033
|
"""Parse method signature for TypeScript class methods"""
|
|
1012
1034
|
try:
|
|
1013
1035
|
name = None
|
|
@@ -1036,8 +1058,12 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1036
1058
|
if child.type in ["property_identifier", "identifier"]:
|
|
1037
1059
|
name = self._get_node_text_optimized(child)
|
|
1038
1060
|
# Fallback to direct text attribute if _get_node_text_optimized returns empty
|
|
1039
|
-
if not name and hasattr(child,
|
|
1040
|
-
name =
|
|
1061
|
+
if not name and hasattr(child, "text") and child.text:
|
|
1062
|
+
name = (
|
|
1063
|
+
child.text.decode("utf-8")
|
|
1064
|
+
if isinstance(child.text, bytes)
|
|
1065
|
+
else str(child.text)
|
|
1066
|
+
)
|
|
1041
1067
|
is_constructor = name == "constructor"
|
|
1042
1068
|
elif child.type == "formal_parameters":
|
|
1043
1069
|
parameters = self._extract_parameters_with_types(child)
|
|
@@ -1051,10 +1077,14 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1051
1077
|
node_text = self._get_node_text_optimized(node)
|
|
1052
1078
|
# Try to extract method name from the text
|
|
1053
1079
|
import re
|
|
1054
|
-
|
|
1080
|
+
|
|
1081
|
+
match = re.search(
|
|
1082
|
+
r"(?:async\s+)?(?:static\s+)?(?:public\s+|private\s+|protected\s+)?(\w+)\s*\(",
|
|
1083
|
+
node_text,
|
|
1084
|
+
)
|
|
1055
1085
|
if match:
|
|
1056
1086
|
name = match.group(1)
|
|
1057
|
-
|
|
1087
|
+
|
|
1058
1088
|
# Set constructor flag after name is determined
|
|
1059
1089
|
if name:
|
|
1060
1090
|
is_constructor = name == "constructor"
|
|
@@ -1080,7 +1110,9 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1080
1110
|
except Exception:
|
|
1081
1111
|
return None
|
|
1082
1112
|
|
|
1083
|
-
def _extract_parameters_with_types(
|
|
1113
|
+
def _extract_parameters_with_types(
|
|
1114
|
+
self, params_node: "tree_sitter.Node"
|
|
1115
|
+
) -> list[str]:
|
|
1084
1116
|
"""Extract function parameters with TypeScript type annotations"""
|
|
1085
1117
|
parameters = []
|
|
1086
1118
|
|
|
@@ -1122,7 +1154,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1122
1154
|
"""Extract import information from import_statement node"""
|
|
1123
1155
|
try:
|
|
1124
1156
|
# Handle Mock objects in tests
|
|
1125
|
-
if hasattr(node,
|
|
1157
|
+
if hasattr(node, "start_point") and hasattr(node, "end_point"):
|
|
1126
1158
|
start_line = node.start_point[0] + 1
|
|
1127
1159
|
end_line = node.end_point[0] + 1
|
|
1128
1160
|
else:
|
|
@@ -1131,55 +1163,72 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1131
1163
|
|
|
1132
1164
|
# Get raw text
|
|
1133
1165
|
raw_text = ""
|
|
1134
|
-
if
|
|
1166
|
+
if (
|
|
1167
|
+
hasattr(node, "start_byte")
|
|
1168
|
+
and hasattr(node, "end_byte")
|
|
1169
|
+
and self.source_code
|
|
1170
|
+
):
|
|
1135
1171
|
# Real tree-sitter node
|
|
1136
1172
|
start_byte = node.start_byte
|
|
1137
1173
|
end_byte = node.end_byte
|
|
1138
1174
|
source_bytes = self.source_code.encode("utf-8")
|
|
1139
1175
|
raw_text = source_bytes[start_byte:end_byte].decode("utf-8")
|
|
1140
|
-
elif hasattr(node,
|
|
1176
|
+
elif hasattr(node, "text"):
|
|
1141
1177
|
# Mock object
|
|
1142
1178
|
text = node.text
|
|
1143
1179
|
if isinstance(text, bytes):
|
|
1144
|
-
raw_text = text.decode(
|
|
1180
|
+
raw_text = text.decode("utf-8")
|
|
1145
1181
|
else:
|
|
1146
1182
|
raw_text = str(text)
|
|
1147
1183
|
else:
|
|
1148
1184
|
# Fallback
|
|
1149
|
-
raw_text =
|
|
1185
|
+
raw_text = (
|
|
1186
|
+
self._get_node_text_optimized(node)
|
|
1187
|
+
if hasattr(self, "_get_node_text_optimized")
|
|
1188
|
+
else ""
|
|
1189
|
+
)
|
|
1150
1190
|
|
|
1151
1191
|
# Extract import details from AST structure
|
|
1152
1192
|
import_names = []
|
|
1153
1193
|
module_path = ""
|
|
1154
|
-
|
|
1194
|
+
# Check for type import (not used but kept for future reference)
|
|
1195
|
+
# is_type_import = "type" in raw_text
|
|
1155
1196
|
|
|
1156
1197
|
# Handle children
|
|
1157
|
-
if hasattr(node,
|
|
1198
|
+
if hasattr(node, "children") and node.children:
|
|
1158
1199
|
for child in node.children:
|
|
1159
1200
|
if child.type == "import_clause":
|
|
1160
1201
|
import_names.extend(self._extract_import_names(child))
|
|
1161
1202
|
elif child.type == "string":
|
|
1162
1203
|
# Module path
|
|
1163
|
-
if
|
|
1204
|
+
if (
|
|
1205
|
+
hasattr(child, "start_byte")
|
|
1206
|
+
and hasattr(child, "end_byte")
|
|
1207
|
+
and self.source_code
|
|
1208
|
+
):
|
|
1164
1209
|
source_bytes = self.source_code.encode("utf-8")
|
|
1165
1210
|
module_text = source_bytes[
|
|
1166
1211
|
child.start_byte : child.end_byte
|
|
1167
1212
|
].decode("utf-8")
|
|
1168
1213
|
module_path = module_text.strip("\"'")
|
|
1169
|
-
elif hasattr(child,
|
|
1214
|
+
elif hasattr(child, "text"):
|
|
1170
1215
|
# Mock object
|
|
1171
1216
|
text = child.text
|
|
1172
1217
|
if isinstance(text, bytes):
|
|
1173
|
-
module_path = text.decode(
|
|
1218
|
+
module_path = text.decode("utf-8").strip("\"'")
|
|
1174
1219
|
else:
|
|
1175
1220
|
module_path = str(text).strip("\"'")
|
|
1176
1221
|
|
|
1177
1222
|
# If no import names found but we have a mocked _extract_import_names, try calling it
|
|
1178
|
-
if not import_names and hasattr(self,
|
|
1223
|
+
if not import_names and hasattr(self, "_extract_import_names"):
|
|
1179
1224
|
# For test scenarios where _extract_import_names is mocked
|
|
1180
1225
|
try:
|
|
1181
1226
|
# Try to find import_clause in children
|
|
1182
|
-
for child in (
|
|
1227
|
+
for child in (
|
|
1228
|
+
node.children
|
|
1229
|
+
if hasattr(node, "children") and node.children
|
|
1230
|
+
else []
|
|
1231
|
+
):
|
|
1183
1232
|
if child.type == "import_clause":
|
|
1184
1233
|
import_names.extend(self._extract_import_names(child))
|
|
1185
1234
|
break
|
|
@@ -1189,7 +1238,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1189
1238
|
# If no module path found, return None for edge case tests
|
|
1190
1239
|
if not module_path and not import_names:
|
|
1191
1240
|
return None
|
|
1192
|
-
|
|
1241
|
+
|
|
1193
1242
|
# Use first import name or "unknown"
|
|
1194
1243
|
primary_name = import_names[0] if import_names else "unknown"
|
|
1195
1244
|
|
|
@@ -1213,84 +1262,108 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1213
1262
|
) -> list[str]:
|
|
1214
1263
|
"""Extract import names from import clause"""
|
|
1215
1264
|
names = []
|
|
1216
|
-
|
|
1265
|
+
|
|
1217
1266
|
try:
|
|
1218
1267
|
# Handle Mock objects in tests
|
|
1219
|
-
if
|
|
1268
|
+
if (
|
|
1269
|
+
hasattr(import_clause_node, "children")
|
|
1270
|
+
and import_clause_node.children is not None
|
|
1271
|
+
):
|
|
1220
1272
|
children = import_clause_node.children
|
|
1221
1273
|
else:
|
|
1222
1274
|
return names
|
|
1223
|
-
|
|
1275
|
+
|
|
1224
1276
|
source_bytes = self.source_code.encode("utf-8") if self.source_code else b""
|
|
1225
1277
|
|
|
1226
1278
|
for child in children:
|
|
1227
1279
|
if child.type == "import_default_specifier":
|
|
1228
1280
|
# Default import
|
|
1229
|
-
if hasattr(child,
|
|
1281
|
+
if hasattr(child, "children") and child.children:
|
|
1230
1282
|
for grandchild in child.children:
|
|
1231
1283
|
if grandchild.type == "identifier":
|
|
1232
|
-
if
|
|
1284
|
+
if (
|
|
1285
|
+
hasattr(grandchild, "start_byte")
|
|
1286
|
+
and hasattr(grandchild, "end_byte")
|
|
1287
|
+
and source_bytes
|
|
1288
|
+
):
|
|
1233
1289
|
name_text = source_bytes[
|
|
1234
1290
|
grandchild.start_byte : grandchild.end_byte
|
|
1235
1291
|
].decode("utf-8")
|
|
1236
1292
|
names.append(name_text)
|
|
1237
|
-
elif hasattr(grandchild,
|
|
1293
|
+
elif hasattr(grandchild, "text"):
|
|
1238
1294
|
# Handle Mock objects
|
|
1239
1295
|
text = grandchild.text
|
|
1240
1296
|
if isinstance(text, bytes):
|
|
1241
|
-
names.append(text.decode(
|
|
1297
|
+
names.append(text.decode("utf-8"))
|
|
1242
1298
|
else:
|
|
1243
1299
|
names.append(str(text))
|
|
1244
1300
|
elif child.type == "named_imports":
|
|
1245
1301
|
# Named imports
|
|
1246
|
-
if hasattr(child,
|
|
1302
|
+
if hasattr(child, "children") and child.children:
|
|
1247
1303
|
for grandchild in child.children:
|
|
1248
1304
|
if grandchild.type == "import_specifier":
|
|
1249
1305
|
# For Mock objects, use _get_node_text_optimized
|
|
1250
|
-
if hasattr(self,
|
|
1251
|
-
name_text = self._get_node_text_optimized(
|
|
1306
|
+
if hasattr(self, "_get_node_text_optimized"):
|
|
1307
|
+
name_text = self._get_node_text_optimized(
|
|
1308
|
+
grandchild
|
|
1309
|
+
)
|
|
1252
1310
|
if name_text:
|
|
1253
1311
|
names.append(name_text)
|
|
1254
|
-
elif
|
|
1312
|
+
elif (
|
|
1313
|
+
hasattr(grandchild, "children")
|
|
1314
|
+
and grandchild.children
|
|
1315
|
+
):
|
|
1255
1316
|
for ggchild in grandchild.children:
|
|
1256
1317
|
if ggchild.type == "identifier":
|
|
1257
|
-
if
|
|
1318
|
+
if (
|
|
1319
|
+
hasattr(ggchild, "start_byte")
|
|
1320
|
+
and hasattr(ggchild, "end_byte")
|
|
1321
|
+
and source_bytes
|
|
1322
|
+
):
|
|
1258
1323
|
name_text = source_bytes[
|
|
1259
1324
|
ggchild.start_byte : ggchild.end_byte
|
|
1260
1325
|
].decode("utf-8")
|
|
1261
1326
|
names.append(name_text)
|
|
1262
|
-
elif hasattr(ggchild,
|
|
1327
|
+
elif hasattr(ggchild, "text"):
|
|
1263
1328
|
# Handle Mock objects
|
|
1264
1329
|
text = ggchild.text
|
|
1265
1330
|
if isinstance(text, bytes):
|
|
1266
|
-
names.append(text.decode(
|
|
1331
|
+
names.append(text.decode("utf-8"))
|
|
1267
1332
|
else:
|
|
1268
1333
|
names.append(str(text))
|
|
1269
1334
|
elif child.type == "identifier":
|
|
1270
1335
|
# Direct identifier (default import case)
|
|
1271
|
-
if
|
|
1336
|
+
if (
|
|
1337
|
+
hasattr(child, "start_byte")
|
|
1338
|
+
and hasattr(child, "end_byte")
|
|
1339
|
+
and source_bytes
|
|
1340
|
+
):
|
|
1272
1341
|
name_text = source_bytes[
|
|
1273
1342
|
child.start_byte : child.end_byte
|
|
1274
1343
|
].decode("utf-8")
|
|
1275
1344
|
names.append(name_text)
|
|
1276
|
-
elif hasattr(child,
|
|
1345
|
+
elif hasattr(child, "text"):
|
|
1277
1346
|
# Handle Mock objects
|
|
1278
1347
|
text = child.text
|
|
1279
1348
|
if isinstance(text, bytes):
|
|
1280
|
-
names.append(text.decode(
|
|
1349
|
+
names.append(text.decode("utf-8"))
|
|
1281
1350
|
else:
|
|
1282
1351
|
names.append(str(text))
|
|
1283
1352
|
elif child.type == "namespace_import":
|
|
1284
1353
|
# Namespace import (import * as name)
|
|
1285
|
-
if hasattr(child,
|
|
1354
|
+
if hasattr(child, "children") and child.children:
|
|
1286
1355
|
for grandchild in child.children:
|
|
1287
1356
|
if grandchild.type == "identifier":
|
|
1288
|
-
if
|
|
1357
|
+
if (
|
|
1358
|
+
hasattr(grandchild, "start_byte")
|
|
1359
|
+
and hasattr(grandchild, "end_byte")
|
|
1360
|
+
and source_bytes
|
|
1361
|
+
):
|
|
1289
1362
|
name_text = source_bytes[
|
|
1290
1363
|
grandchild.start_byte : grandchild.end_byte
|
|
1291
1364
|
].decode("utf-8")
|
|
1292
1365
|
names.append(f"* as {name_text}")
|
|
1293
|
-
elif hasattr(grandchild,
|
|
1366
|
+
elif hasattr(grandchild, "text"):
|
|
1294
1367
|
# Handle Mock objects
|
|
1295
1368
|
text = grandchild.text
|
|
1296
1369
|
if isinstance(text, bytes):
|
|
@@ -1299,7 +1372,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1299
1372
|
names.append(f"* as {str(text)}")
|
|
1300
1373
|
except Exception as e:
|
|
1301
1374
|
log_debug(f"Failed to extract import names: {e}")
|
|
1302
|
-
|
|
1375
|
+
|
|
1303
1376
|
return names
|
|
1304
1377
|
|
|
1305
1378
|
def _extract_dynamic_import(self, node: "tree_sitter.Node") -> Import | None:
|
|
@@ -1313,9 +1386,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1313
1386
|
)
|
|
1314
1387
|
if not import_match:
|
|
1315
1388
|
# Try alternative pattern without quotes
|
|
1316
|
-
import_match = re.search(
|
|
1317
|
-
r"import\s*\(\s*([^)]+)\s*\)", node_text
|
|
1318
|
-
)
|
|
1389
|
+
import_match = re.search(r"import\s*\(\s*([^)]+)\s*\)", node_text)
|
|
1319
1390
|
if import_match:
|
|
1320
1391
|
source = import_match.group(1).strip("\"'")
|
|
1321
1392
|
else:
|
|
@@ -1345,10 +1416,12 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1345
1416
|
|
|
1346
1417
|
try:
|
|
1347
1418
|
# Test if _get_node_text_optimized is working (for error handling tests)
|
|
1348
|
-
if hasattr(self,
|
|
1419
|
+
if hasattr(self, "_get_node_text_optimized"):
|
|
1349
1420
|
# This will trigger the mocked exception in tests
|
|
1350
|
-
self._get_node_text_optimized(
|
|
1351
|
-
|
|
1421
|
+
self._get_node_text_optimized(
|
|
1422
|
+
tree.root_node if tree and hasattr(tree, "root_node") else None
|
|
1423
|
+
)
|
|
1424
|
+
|
|
1352
1425
|
# Use regex to find require statements
|
|
1353
1426
|
require_pattern = r"(?:const|let|var)\s+(\w+)\s*=\s*require\s*\(\s*[\"']([^\"']+)[\"']\s*\)"
|
|
1354
1427
|
|
|
@@ -1377,7 +1450,9 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1377
1450
|
|
|
1378
1451
|
return imports
|
|
1379
1452
|
|
|
1380
|
-
def _is_framework_component(
|
|
1453
|
+
def _is_framework_component(
|
|
1454
|
+
self, node: "tree_sitter.Node", class_name: str
|
|
1455
|
+
) -> bool:
|
|
1381
1456
|
"""Check if class is a framework component"""
|
|
1382
1457
|
if self.framework_type == "react":
|
|
1383
1458
|
# Check if extends React.Component or Component
|
|
@@ -1396,7 +1471,10 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1396
1471
|
def _is_exported_class(self, class_name: str) -> bool:
|
|
1397
1472
|
"""Check if class is exported"""
|
|
1398
1473
|
# Simple check for export statements
|
|
1399
|
-
return
|
|
1474
|
+
return (
|
|
1475
|
+
f"export class {class_name}" in self.source_code
|
|
1476
|
+
or f"export default {class_name}" in self.source_code
|
|
1477
|
+
)
|
|
1400
1478
|
|
|
1401
1479
|
def _infer_type_from_value(self, value: str | None) -> str:
|
|
1402
1480
|
"""Infer TypeScript type from value"""
|
|
@@ -1447,7 +1525,7 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1447
1525
|
# Check for TSDoc end or single-line TSDoc
|
|
1448
1526
|
if current_line > 0:
|
|
1449
1527
|
line = self.content_lines[current_line - 1].strip()
|
|
1450
|
-
|
|
1528
|
+
|
|
1451
1529
|
# Check for single-line TSDoc comment
|
|
1452
1530
|
if line.startswith("/**") and line.endswith("*/"):
|
|
1453
1531
|
# Single line TSDoc
|
|
@@ -1532,16 +1610,18 @@ class TypeScriptElementExtractor(ElementExtractor):
|
|
|
1532
1610
|
self._complexity_cache[node_id] = complexity
|
|
1533
1611
|
return complexity
|
|
1534
1612
|
|
|
1535
|
-
def extract_elements(
|
|
1613
|
+
def extract_elements(
|
|
1614
|
+
self, tree: "tree_sitter.Tree", source_code: str
|
|
1615
|
+
) -> list[CodeElement]:
|
|
1536
1616
|
"""Legacy method for backward compatibility with tests"""
|
|
1537
1617
|
all_elements: list[CodeElement] = []
|
|
1538
|
-
|
|
1618
|
+
|
|
1539
1619
|
# Extract all types of elements
|
|
1540
1620
|
all_elements.extend(self.extract_functions(tree, source_code))
|
|
1541
1621
|
all_elements.extend(self.extract_classes(tree, source_code))
|
|
1542
1622
|
all_elements.extend(self.extract_variables(tree, source_code))
|
|
1543
1623
|
all_elements.extend(self.extract_imports(tree, source_code))
|
|
1544
|
-
|
|
1624
|
+
|
|
1545
1625
|
return all_elements
|
|
1546
1626
|
|
|
1547
1627
|
|
|
@@ -1715,20 +1795,24 @@ class TypeScriptPlugin(LanguagePlugin):
|
|
|
1715
1795
|
error_message=str(e),
|
|
1716
1796
|
)
|
|
1717
1797
|
|
|
1718
|
-
def extract_elements(
|
|
1798
|
+
def extract_elements(
|
|
1799
|
+
self, tree: "tree_sitter.Tree", source_code: str
|
|
1800
|
+
) -> list[CodeElement]:
|
|
1719
1801
|
"""Legacy method for backward compatibility with tests"""
|
|
1720
1802
|
extractor = self.create_extractor()
|
|
1721
1803
|
all_elements: list[CodeElement] = []
|
|
1722
|
-
|
|
1804
|
+
|
|
1723
1805
|
# Extract all types of elements
|
|
1724
1806
|
all_elements.extend(extractor.extract_functions(tree, source_code))
|
|
1725
1807
|
all_elements.extend(extractor.extract_classes(tree, source_code))
|
|
1726
1808
|
all_elements.extend(extractor.extract_variables(tree, source_code))
|
|
1727
1809
|
all_elements.extend(extractor.extract_imports(tree, source_code))
|
|
1728
|
-
|
|
1810
|
+
|
|
1729
1811
|
return all_elements
|
|
1730
1812
|
|
|
1731
|
-
def execute_query_strategy(
|
|
1813
|
+
def execute_query_strategy(
|
|
1814
|
+
self, tree: "tree_sitter.Tree", source_code: str, query_key: str
|
|
1815
|
+
) -> list[CodeElement]:
|
|
1732
1816
|
"""Execute TypeScript-specific query strategy based on query_key"""
|
|
1733
1817
|
if not tree or not source_code:
|
|
1734
1818
|
return []
|
|
@@ -1743,33 +1827,84 @@ class TypeScriptPlugin(LanguagePlugin):
|
|
|
1743
1827
|
query_mapping = {
|
|
1744
1828
|
# Function-related queries
|
|
1745
1829
|
"function": lambda: self._extractor.extract_functions(tree, source_code),
|
|
1746
|
-
"async_function": lambda: [
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
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
|
+
],
|
|
1752
1855
|
# Class-related queries
|
|
1753
1856
|
"class": lambda: self._extractor.extract_classes(tree, source_code),
|
|
1754
|
-
"interface": lambda: [
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
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
|
+
],
|
|
1758
1872
|
# Variable-related queries
|
|
1759
1873
|
"variable": lambda: self._extractor.extract_variables(tree, source_code),
|
|
1760
|
-
|
|
1761
1874
|
# Import/Export queries
|
|
1762
1875
|
"import": lambda: self._extractor.extract_imports(tree, source_code),
|
|
1763
|
-
"export": lambda: [
|
|
1764
|
-
|
|
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
|
+
],
|
|
1765
1881
|
# TypeScript-specific queries
|
|
1766
|
-
"generic": lambda: [
|
|
1767
|
-
|
|
1768
|
-
|
|
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
|
+
],
|
|
1769
1892
|
# Framework-specific queries
|
|
1770
|
-
"react_component": lambda: [
|
|
1771
|
-
|
|
1772
|
-
|
|
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
|
+
],
|
|
1773
1908
|
}
|
|
1774
1909
|
|
|
1775
1910
|
# Execute the appropriate extraction method
|
|
@@ -1791,68 +1926,42 @@ class TypeScriptPlugin(LanguagePlugin):
|
|
|
1791
1926
|
"function_declaration",
|
|
1792
1927
|
"function_expression",
|
|
1793
1928
|
"arrow_function",
|
|
1794
|
-
"generator_function_declaration"
|
|
1929
|
+
"generator_function_declaration",
|
|
1795
1930
|
],
|
|
1796
1931
|
"async_function": [
|
|
1797
1932
|
"function_declaration",
|
|
1798
1933
|
"function_expression",
|
|
1799
1934
|
"arrow_function",
|
|
1800
|
-
"method_definition"
|
|
1801
|
-
],
|
|
1802
|
-
"arrow_function": ["arrow_function"],
|
|
1803
|
-
"method": [
|
|
1804
1935
|
"method_definition",
|
|
1805
|
-
"method_signature"
|
|
1806
1936
|
],
|
|
1937
|
+
"arrow_function": ["arrow_function"],
|
|
1938
|
+
"method": ["method_definition", "method_signature"],
|
|
1807
1939
|
"constructor": ["method_definition"],
|
|
1808
1940
|
"signature": ["method_signature"],
|
|
1809
|
-
|
|
1810
1941
|
# Class-related categories
|
|
1811
|
-
"class": [
|
|
1812
|
-
"class_declaration",
|
|
1813
|
-
"abstract_class_declaration"
|
|
1814
|
-
],
|
|
1942
|
+
"class": ["class_declaration", "abstract_class_declaration"],
|
|
1815
1943
|
"interface": ["interface_declaration"],
|
|
1816
1944
|
"type_alias": ["type_alias_declaration"],
|
|
1817
1945
|
"enum": ["enum_declaration"],
|
|
1818
|
-
|
|
1819
1946
|
# Variable-related categories
|
|
1820
1947
|
"variable": [
|
|
1821
1948
|
"variable_declaration",
|
|
1822
1949
|
"lexical_declaration",
|
|
1823
1950
|
"property_definition",
|
|
1824
|
-
"property_signature"
|
|
1951
|
+
"property_signature",
|
|
1825
1952
|
],
|
|
1826
|
-
|
|
1827
1953
|
# Import/Export categories
|
|
1828
1954
|
"import": ["import_statement"],
|
|
1829
|
-
"export": [
|
|
1830
|
-
"export_statement",
|
|
1831
|
-
"export_declaration"
|
|
1832
|
-
],
|
|
1833
|
-
|
|
1955
|
+
"export": ["export_statement", "export_declaration"],
|
|
1834
1956
|
# TypeScript-specific categories
|
|
1835
|
-
"generic": [
|
|
1836
|
-
|
|
1837
|
-
"type_parameter"
|
|
1838
|
-
],
|
|
1839
|
-
"decorator": [
|
|
1840
|
-
"decorator",
|
|
1841
|
-
"decorator_call_expression"
|
|
1842
|
-
],
|
|
1843
|
-
|
|
1957
|
+
"generic": ["type_parameters", "type_parameter"],
|
|
1958
|
+
"decorator": ["decorator", "decorator_call_expression"],
|
|
1844
1959
|
# Framework-specific categories
|
|
1845
1960
|
"react_component": [
|
|
1846
1961
|
"class_declaration",
|
|
1847
1962
|
"function_declaration",
|
|
1848
|
-
"arrow_function"
|
|
1849
|
-
],
|
|
1850
|
-
"angular_component": [
|
|
1851
|
-
"class_declaration",
|
|
1852
|
-
"decorator"
|
|
1963
|
+
"arrow_function",
|
|
1853
1964
|
],
|
|
1854
|
-
"
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
]
|
|
1858
|
-
}
|
|
1965
|
+
"angular_component": ["class_declaration", "decorator"],
|
|
1966
|
+
"vue_component": ["class_declaration", "function_declaration"],
|
|
1967
|
+
}
|