codegraphcontext-rust 0.5.5__cp310-cp310-win_amd64.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.
Files changed (101) hide show
  1. codegraphcontext/__init__.py +2 -0
  2. codegraphcontext/__main__.py +5 -0
  3. codegraphcontext/_cgc_rust.cp310-win_amd64.pyd +0 -0
  4. codegraphcontext/cli/__init__.py +1 -0
  5. codegraphcontext/cli/cli_helpers.py +774 -0
  6. codegraphcontext/cli/config_manager.py +1051 -0
  7. codegraphcontext/cli/main.py +2386 -0
  8. codegraphcontext/cli/registry_commands.py +404 -0
  9. codegraphcontext/cli/setup_macos.py +93 -0
  10. codegraphcontext/cli/setup_wizard.py +991 -0
  11. codegraphcontext/cli/visualizer.py +50 -0
  12. codegraphcontext/core/__init__.py +165 -0
  13. codegraphcontext/core/bundle_registry.py +181 -0
  14. codegraphcontext/core/cgc_bundle.py +858 -0
  15. codegraphcontext/core/cgcignore.py +118 -0
  16. codegraphcontext/core/database.py +273 -0
  17. codegraphcontext/core/database_falkordb.py +480 -0
  18. codegraphcontext/core/database_falkordb_remote.py +199 -0
  19. codegraphcontext/core/database_kuzu.py +636 -0
  20. codegraphcontext/core/falkor_worker.py +132 -0
  21. codegraphcontext/core/jobs.py +132 -0
  22. codegraphcontext/core/watcher.py +260 -0
  23. codegraphcontext/prompts.py +125 -0
  24. codegraphcontext/server.py +471 -0
  25. codegraphcontext/tool_definitions.py +220 -0
  26. codegraphcontext/tools/__init__.py +0 -0
  27. codegraphcontext/tools/advanced_language_query_tool.py +103 -0
  28. codegraphcontext/tools/code_finder.py +1160 -0
  29. codegraphcontext/tools/graph_builder.py +337 -0
  30. codegraphcontext/tools/handlers/analysis_handlers.py +114 -0
  31. codegraphcontext/tools/handlers/indexing_handlers.py +116 -0
  32. codegraphcontext/tools/handlers/management_handlers.py +339 -0
  33. codegraphcontext/tools/handlers/query_handlers.py +83 -0
  34. codegraphcontext/tools/handlers/watcher_handlers.py +83 -0
  35. codegraphcontext/tools/indexing/__init__.py +1 -0
  36. codegraphcontext/tools/indexing/constants.py +25 -0
  37. codegraphcontext/tools/indexing/discovery.py +64 -0
  38. codegraphcontext/tools/indexing/engine.py +109 -0
  39. codegraphcontext/tools/indexing/persistence/__init__.py +3 -0
  40. codegraphcontext/tools/indexing/persistence/parquet_loader.py +643 -0
  41. codegraphcontext/tools/indexing/persistence/writer.py +1114 -0
  42. codegraphcontext/tools/indexing/pipeline.py +171 -0
  43. codegraphcontext/tools/indexing/pre_scan.py +105 -0
  44. codegraphcontext/tools/indexing/resolution/__init__.py +8 -0
  45. codegraphcontext/tools/indexing/resolution/calls.py +253 -0
  46. codegraphcontext/tools/indexing/resolution/inheritance.py +91 -0
  47. codegraphcontext/tools/indexing/sanitize.py +41 -0
  48. codegraphcontext/tools/indexing/schema.py +79 -0
  49. codegraphcontext/tools/indexing/schema_contract.py +44 -0
  50. codegraphcontext/tools/indexing/scip_pipeline.py +140 -0
  51. codegraphcontext/tools/languages/c.py +563 -0
  52. codegraphcontext/tools/languages/cpp.py +616 -0
  53. codegraphcontext/tools/languages/csharp.py +551 -0
  54. codegraphcontext/tools/languages/dart.py +378 -0
  55. codegraphcontext/tools/languages/elixir.py +460 -0
  56. codegraphcontext/tools/languages/go.py +499 -0
  57. codegraphcontext/tools/languages/haskell.py +426 -0
  58. codegraphcontext/tools/languages/java.py +500 -0
  59. codegraphcontext/tools/languages/javascript.py +589 -0
  60. codegraphcontext/tools/languages/kotlin.py +640 -0
  61. codegraphcontext/tools/languages/perl.py +260 -0
  62. codegraphcontext/tools/languages/php.py +519 -0
  63. codegraphcontext/tools/languages/python.py +576 -0
  64. codegraphcontext/tools/languages/ruby.py +537 -0
  65. codegraphcontext/tools/languages/rust.py +295 -0
  66. codegraphcontext/tools/languages/scala.py +519 -0
  67. codegraphcontext/tools/languages/swift.py +491 -0
  68. codegraphcontext/tools/languages/typescript.py +575 -0
  69. codegraphcontext/tools/languages/typescriptjsx.py +151 -0
  70. codegraphcontext/tools/package_resolver.py +472 -0
  71. codegraphcontext/tools/query_tool_languages/c_toolkit.py +5 -0
  72. codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +87 -0
  73. codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +5 -0
  74. codegraphcontext/tools/query_tool_languages/dart_toolkit.py +5 -0
  75. codegraphcontext/tools/query_tool_languages/go_toolkit.py +5 -0
  76. codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +5 -0
  77. codegraphcontext/tools/query_tool_languages/java_toolkit.py +5 -0
  78. codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +5 -0
  79. codegraphcontext/tools/query_tool_languages/perl_toolkit.py +5 -0
  80. codegraphcontext/tools/query_tool_languages/python_toolkit.py +5 -0
  81. codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +5 -0
  82. codegraphcontext/tools/query_tool_languages/rust_toolkit.py +5 -0
  83. codegraphcontext/tools/query_tool_languages/scala_toolkit.py +5 -0
  84. codegraphcontext/tools/query_tool_languages/swift_toolkit.py +5 -0
  85. codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +5 -0
  86. codegraphcontext/tools/scip_indexer.py +467 -0
  87. codegraphcontext/tools/scip_pb2.py +2455 -0
  88. codegraphcontext/tools/system.py +133 -0
  89. codegraphcontext/tools/tree_sitter_parser.py +103 -0
  90. codegraphcontext/utils/debug_log.py +90 -0
  91. codegraphcontext/utils/path_ignore.py +55 -0
  92. codegraphcontext/utils/repo_path.py +27 -0
  93. codegraphcontext/utils/tree_sitter_manager.py +285 -0
  94. codegraphcontext/utils/visualize_graph.py +0 -0
  95. codegraphcontext/viz/server.py +282 -0
  96. codegraphcontext_rust-0.5.5.dist-info/METADATA +537 -0
  97. codegraphcontext_rust-0.5.5.dist-info/RECORD +101 -0
  98. codegraphcontext_rust-0.5.5.dist-info/WHEEL +4 -0
  99. codegraphcontext_rust-0.5.5.dist-info/entry_points.txt +3 -0
  100. codegraphcontext_rust-0.5.5.dist-info/licenses/LICENSE +21 -0
  101. codegraphcontext_rust-0.5.5.dist-info/sboms/cgc-python.cyclonedx.json +2333 -0
@@ -0,0 +1,575 @@
1
+ from pathlib import Path
2
+ from typing import Dict
3
+ from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger, debug_logger
4
+ from codegraphcontext.utils.tree_sitter_manager import execute_query
5
+
6
+ TS_QUERIES = {
7
+ "functions": """
8
+ (function_declaration
9
+ name: (identifier) @name
10
+ parameters: (formal_parameters) @params
11
+ ) @function_node
12
+
13
+ (variable_declarator
14
+ name: (identifier) @name
15
+ value: (function_expression
16
+ parameters: (formal_parameters) @params
17
+ ) @function_node
18
+ )
19
+
20
+ (variable_declarator
21
+ name: (identifier) @name
22
+ value: (arrow_function
23
+ parameters: (formal_parameters) @params
24
+ ) @function_node
25
+ )
26
+
27
+ (variable_declarator
28
+ name: (identifier) @name
29
+ value: (arrow_function
30
+ parameter: (identifier) @single_param
31
+ ) @function_node
32
+ )
33
+
34
+ (method_definition
35
+ name: (property_identifier) @name
36
+ parameters: (formal_parameters) @params
37
+ ) @function_node
38
+
39
+ (assignment_expression
40
+ left: (member_expression
41
+ property: (property_identifier) @name
42
+ )
43
+ right: (function_expression
44
+ parameters: (formal_parameters) @params
45
+ ) @function_node
46
+ )
47
+
48
+ (assignment_expression
49
+ left: (member_expression
50
+ property: (property_identifier) @name
51
+ )
52
+ right: (arrow_function
53
+ parameters: (formal_parameters) @params
54
+ ) @function_node
55
+ )
56
+ """,
57
+ "classes": """
58
+ (class_declaration) @class
59
+ (abstract_class_declaration) @class
60
+ (class) @class
61
+ """,
62
+ "interfaces": """
63
+ (interface_declaration
64
+ name: (type_identifier) @name
65
+ ) @interface_node
66
+ """,
67
+ "type_aliases": """
68
+ (type_alias_declaration
69
+ name: (type_identifier) @name
70
+ ) @type_alias_node
71
+ """,
72
+ "imports": """
73
+ (import_statement) @import
74
+ (call_expression
75
+ function: (identifier) @require_call (#eq? @require_call "require")
76
+ ) @import
77
+ """,
78
+ "calls": """
79
+ (call_expression function: (identifier) @name)
80
+ (call_expression function: (member_expression property: (property_identifier) @name))
81
+ (new_expression constructor: (identifier) @name)
82
+ (new_expression constructor: (member_expression property: (property_identifier) @name))
83
+ """,
84
+ "variables": """
85
+ (variable_declarator name: (identifier) @name)
86
+ """,
87
+ "docstrings": """
88
+ (comment) @docstring_comment
89
+ """,
90
+ }
91
+
92
+ def is_typescript_file(path: Path) -> bool:
93
+ return path.suffix in {".ts", ".tsx"}
94
+
95
+ class TypescriptTreeSitterParser:
96
+ """A TypeScript-specific parser using tree-sitter, encapsulating language-specific logic."""
97
+
98
+ def __init__(self, generic_parser_wrapper):
99
+ self.generic_parser_wrapper = generic_parser_wrapper
100
+ self.language_name = generic_parser_wrapper.language_name
101
+ self.language = generic_parser_wrapper.language
102
+ self.parser = generic_parser_wrapper.parser
103
+
104
+ def _get_node_text(self, node) -> str:
105
+ return node.text.decode('utf-8')
106
+
107
+ def _get_parent_context(self, node, types=('function_declaration', 'class_declaration', 'method_definition', 'function_expression', 'arrow_function')):
108
+ curr = node.parent
109
+ while curr:
110
+ if curr.type in types:
111
+ name_node = curr.child_by_field_name('name')
112
+ if not name_node and curr.type in ('function_expression', 'arrow_function'):
113
+ # Try to find name from variable declaration
114
+ if curr.parent and curr.parent.type == 'variable_declarator':
115
+ name_node = curr.parent.child_by_field_name('name')
116
+ elif curr.parent and curr.parent.type == 'assignment_expression':
117
+ name_node = curr.parent.child_by_field_name('left')
118
+ elif curr.parent and curr.parent.type == 'pair': # property: function
119
+ name_node = curr.parent.child_by_field_name('key')
120
+
121
+ return self._get_node_text(name_node) if name_node else None, curr.type, curr.start_point[0] + 1
122
+ curr = curr.parent
123
+ return None, None, None
124
+
125
+ def _calculate_complexity(self, node):
126
+ complexity_nodes = {
127
+ "if_statement", "for_statement", "while_statement", "do_statement",
128
+ "switch_statement", "case_statement", "conditional_expression",
129
+ "logical_expression", "binary_expression", "catch_clause"
130
+ }
131
+ count = 1
132
+ def traverse(n):
133
+ nonlocal count
134
+ if n.type in complexity_nodes:
135
+ count += 1
136
+ for child in n.children:
137
+ traverse(child)
138
+ traverse(node)
139
+ return count
140
+
141
+ def _get_docstring(self, body_node):
142
+ return None
143
+
144
+ def parse(self, path: Path, is_dependency: bool = False, index_source: bool = False) -> Dict:
145
+ self.index_source = index_source
146
+ with open(path, "r", encoding="utf-8") as f:
147
+ source_code = f.read()
148
+ tree = self.parser.parse(bytes(source_code, "utf8"))
149
+ root_node = tree.root_node
150
+
151
+ functions = self._find_functions(root_node)
152
+ classes = self._find_classes(root_node)
153
+ interfaces = self._find_interfaces(root_node)
154
+ type_aliases = self._find_type_aliases(root_node)
155
+ imports = self._find_imports(root_node)
156
+ function_calls = self._find_calls(root_node)
157
+ variables = self._find_variables(root_node)
158
+
159
+ return {
160
+ "path": str(path),
161
+ "functions": functions,
162
+ "classes": classes,
163
+ "interfaces": interfaces,
164
+ "type_aliases": type_aliases,
165
+ "variables": variables,
166
+ "imports": imports,
167
+ "function_calls": function_calls,
168
+ "is_dependency": is_dependency,
169
+ "lang": self.language_name,
170
+ }
171
+
172
+
173
+ def _find_functions(self, root_node):
174
+ functions = []
175
+ query_str = TS_QUERIES['functions']
176
+ def _fn_for_name(name_node):
177
+ current = name_node.parent
178
+ while current:
179
+ if current.type in ('function_declaration', 'function', 'arrow_function', 'method_definition'):
180
+ return current
181
+ elif current.type in ('variable_declarator', 'assignment_expression'):
182
+ for child in current.children:
183
+ if child.type in ('function', 'arrow_function'):
184
+ return child
185
+ current = current.parent
186
+ return None
187
+ def _fn_for_params(params_node):
188
+ current = params_node.parent
189
+ while current:
190
+ if current.type in ('function_declaration', 'function', 'arrow_function', 'method_definition'):
191
+ return current
192
+ current = current.parent
193
+ return None
194
+ def _key(n):
195
+ return (n.start_byte, n.end_byte, n.type)
196
+ captures_by_function = {}
197
+ def _bucket_for(node):
198
+ fid = _key(node)
199
+ return captures_by_function.setdefault(fid, {
200
+ 'node': node, 'name': None, 'params': None, 'single_param': None
201
+ })
202
+ for node, capture_name in execute_query(self.language, query_str, root_node):
203
+ if capture_name == 'function_node':
204
+ _bucket_for(node)
205
+ elif capture_name == 'name':
206
+ fn = _fn_for_name(node)
207
+ if fn:
208
+ b = _bucket_for(fn)
209
+ b['name'] = self._get_node_text(node)
210
+ elif capture_name == 'params':
211
+ fn = _fn_for_params(node)
212
+ if fn:
213
+ b = _bucket_for(fn)
214
+ b['params'] = node
215
+ elif capture_name == 'single_param':
216
+ fn = _fn_for_params(node)
217
+ if fn:
218
+ b = _bucket_for(fn)
219
+ b['single_param'] = node
220
+ for _, data in captures_by_function.items():
221
+ func_node = data['node']
222
+ name = data.get('name')
223
+ if not name and func_node.type == 'method_definition':
224
+ nm = func_node.child_by_field_name('name')
225
+ if nm:
226
+ name = self._get_node_text(nm)
227
+ if not name:
228
+ continue
229
+ args = []
230
+ if data.get('params'):
231
+ args = self._extract_parameters(data['params'])
232
+ elif data.get('single_param'):
233
+ args = [self._get_node_text(data['single_param'])]
234
+ context, context_type, _ = self._get_parent_context(func_node)
235
+ class_context = context if context_type == 'class_declaration' else None
236
+ docstring = None
237
+ func_data = {
238
+ "name": name,
239
+ "line_number": func_node.start_point[0] + 1,
240
+ "end_line": func_node.end_point[0] + 1,
241
+ "args": args,
242
+ "cyclomatic_complexity": self._calculate_complexity(func_node),
243
+ "context": context,
244
+ "context_type": context_type,
245
+ "class_context": class_context,
246
+ "decorators": [],
247
+ "lang": self.language_name,
248
+ "is_dependency": False,
249
+ }
250
+
251
+ if self.index_source:
252
+ func_data["source"] = self._get_node_text(func_node)
253
+ func_data["docstring"] = docstring
254
+ functions.append(func_data)
255
+ return functions
256
+
257
+ def _extract_parameters(self, params_node):
258
+ params = []
259
+ if params_node.type == 'formal_parameters':
260
+ for child in params_node.children:
261
+ if child.type == 'identifier':
262
+ params.append(self._get_node_text(child))
263
+ elif child.type == 'required_parameter':
264
+ # required_parameter -> pattern (identifier) + type_annotation
265
+ pattern = child.child_by_field_name('pattern')
266
+ if pattern:
267
+ params.append(self._get_node_text(pattern))
268
+ else:
269
+ # Fallback: first child that is an identifier or pattern
270
+ for sub in child.children:
271
+ if sub.type in ('identifier', 'object_pattern', 'array_pattern'):
272
+ params.append(self._get_node_text(sub))
273
+ break
274
+ elif child.type == 'optional_parameter':
275
+ pattern = child.child_by_field_name('pattern')
276
+ if pattern:
277
+ params.append(self._get_node_text(pattern))
278
+ elif child.type == 'assignment_pattern':
279
+ left_child = child.child_by_field_name('left')
280
+ if left_child and left_child.type == 'identifier':
281
+ params.append(self._get_node_text(left_child))
282
+ elif child.type == 'rest_pattern':
283
+ argument = child.child_by_field_name('argument')
284
+ if argument and argument.type == 'identifier':
285
+ params.append(f"...{self._get_node_text(argument)}")
286
+ return params
287
+
288
+ def _find_classes(self, root_node):
289
+ classes = []
290
+ query_str = TS_QUERIES['classes']
291
+ for class_node, capture_name in execute_query(self.language, query_str, root_node):
292
+ if capture_name == 'class':
293
+ name_node = class_node.child_by_field_name('name')
294
+ if not name_node: continue
295
+ name = self._get_node_text(name_node)
296
+ bases = []
297
+ heritage_node = next((child for child in class_node.children if child.type == 'class_heritage'), None)
298
+ if heritage_node:
299
+ for child in heritage_node.children:
300
+ if child.type == 'extends_clause':
301
+ # extends_clause -> extends identifier
302
+ for sub in child.children:
303
+ if sub.type in ('identifier', 'type_identifier', 'member_expression'):
304
+ bases.append(self._get_node_text(sub))
305
+ elif child.type == 'implements_clause':
306
+ # implements_clause -> implements identifier, identifier...
307
+ for sub in child.children:
308
+ if sub.type in ('identifier', 'type_identifier', 'member_expression'):
309
+ bases.append(self._get_node_text(sub))
310
+ class_data = {
311
+ "name": name,
312
+ "line_number": class_node.start_point[0] + 1,
313
+ "end_line": class_node.end_point[0] + 1,
314
+ "bases": bases,
315
+ "context": None,
316
+ "decorators": [],
317
+ "lang": self.language_name,
318
+ "is_dependency": False,
319
+ }
320
+ if self.index_source:
321
+ class_data["source"] = self._get_node_text(class_node)
322
+ class_data["docstring"] = self._get_docstring(class_node)
323
+ classes.append(class_data)
324
+ return classes
325
+
326
+ def _find_interfaces(self, root_node):
327
+ interfaces = []
328
+ query_str = TS_QUERIES['interfaces']
329
+ for node, capture_name in execute_query(self.language, query_str, root_node):
330
+ if capture_name == 'interface_node':
331
+ name_node = node.child_by_field_name('name')
332
+ if not name_node: continue
333
+
334
+ name = self._get_node_text(name_node)
335
+ interface_data = {
336
+ "name": name,
337
+ "line_number": node.start_point[0] + 1,
338
+ "end_line": node.end_point[0] + 1,
339
+ "end_line": node.end_point[0] + 1,
340
+ }
341
+ if self.index_source:
342
+ interface_data["source"] = self._get_node_text(node)
343
+ interfaces.append(interface_data)
344
+ return interfaces
345
+
346
+ def _find_type_aliases(self, root_node):
347
+ type_aliases = []
348
+ query_str = TS_QUERIES['type_aliases']
349
+ for node, capture_name in execute_query(self.language, query_str, root_node):
350
+ if capture_name == 'type_alias_node':
351
+ name_node = node.child_by_field_name('name')
352
+ if not name_node: continue
353
+
354
+ name = self._get_node_text(name_node)
355
+ type_alias_data = {
356
+ "name": name,
357
+ "line_number": node.start_point[0] + 1,
358
+ "end_line": node.end_point[0] + 1,
359
+ "end_line": node.end_point[0] + 1,
360
+ }
361
+ if self.index_source:
362
+ type_alias_data["source"] = self._get_node_text(node)
363
+ type_aliases.append(type_alias_data)
364
+ return type_aliases
365
+
366
+ def _find_imports(self, root_node):
367
+ imports = []
368
+ query_str = TS_QUERIES['imports']
369
+ for node, capture_name in execute_query(self.language, query_str, root_node):
370
+ if capture_name != 'import':
371
+ continue
372
+ line_number = node.start_point[0] + 1
373
+ if node.type == 'import_statement':
374
+ source = self._get_node_text(node.child_by_field_name('source')).strip('\'"')
375
+ import_clause = node.child_by_field_name('import')
376
+ if not import_clause:
377
+ imports.append({'name': source, 'source': source, 'alias': None, 'line_number': line_number,
378
+ 'lang': self.language_name})
379
+ continue
380
+ if import_clause.type == 'identifier':
381
+ alias = self._get_node_text(import_clause)
382
+ imports.append({'name': 'default', 'source': source, 'alias': alias, 'line_number': line_number,
383
+ 'lang': self.language_name})
384
+ elif import_clause.type == 'namespace_import':
385
+ alias_node = import_clause.child_by_field_name('alias')
386
+ if alias_node:
387
+ alias = self._get_node_text(alias_node)
388
+ imports.append({'name': '*', 'source': source, 'alias': alias, 'line_number': line_number,
389
+ 'lang': self.language_name})
390
+ elif import_clause.type == 'named_imports':
391
+ for specifier in import_clause.children:
392
+ if specifier.type == 'import_specifier':
393
+ name_node = specifier.child_by_field_name('name')
394
+ alias_node = specifier.child_by_field_name('alias')
395
+ original_name = self._get_node_text(name_node)
396
+ alias = self._get_node_text(alias_node) if alias_node else None
397
+ imports.append(
398
+ {'name': original_name, 'source': source, 'alias': alias, 'line_number': line_number,
399
+ 'lang': self.language_name})
400
+ elif node.type == 'call_expression':
401
+ args = node.child_by_field_name('arguments')
402
+ if not args or args.named_child_count == 0: continue
403
+ source_node = args.named_child(0)
404
+ if not source_node or source_node.type != 'string': continue
405
+ source = self._get_node_text(source_node).strip('\'"')
406
+ alias = None
407
+ if node.parent.type == 'variable_declarator':
408
+ alias_node = node.parent.child_by_field_name('name')
409
+ if alias_node:
410
+ alias = self._get_node_text(alias_node)
411
+ imports.append({'name': source, 'source': source, 'alias': alias, 'line_number': line_number,
412
+ 'lang': self.language_name})
413
+ return imports
414
+
415
+ def _find_calls(self, root_node):
416
+ calls = []
417
+ query_str = TS_QUERIES['calls']
418
+ for node, capture_name in execute_query(self.language, query_str, root_node):
419
+ if capture_name == 'name':
420
+ # Traverse up to find the call/new expression
421
+ call_node = node.parent
422
+ while call_node and call_node.type not in ('call_expression', 'new_expression') and call_node.type != 'program':
423
+ call_node = call_node.parent
424
+
425
+ name = self._get_node_text(node)
426
+
427
+ # Improved args extraction
428
+ args = []
429
+ arguments_node = None
430
+ if call_node and call_node.type in ('call_expression', 'new_expression'):
431
+ arguments_node = call_node.child_by_field_name('arguments')
432
+
433
+ if arguments_node:
434
+ for arg in arguments_node.children:
435
+ if arg.type not in ('(', ')', ','):
436
+ args.append(self._get_node_text(arg))
437
+
438
+ call_data = {
439
+ "name": name,
440
+ "full_name": self._get_node_text(call_node) if call_node else name,
441
+ "line_number": node.start_point[0] + 1,
442
+ "args": args,
443
+ "inferred_obj_type": None,
444
+ "context": self._get_parent_context(node),
445
+ "class_context": self._get_parent_context(node, types=('class_declaration', 'abstract_class_declaration')),
446
+ "lang": self.language_name,
447
+ "is_dependency": False,
448
+ }
449
+ calls.append(call_data)
450
+ return calls
451
+
452
+ def _find_variables(self, root_node):
453
+ variables = []
454
+ query_str = TS_QUERIES['variables']
455
+ for match in execute_query(self.language, query_str, root_node):
456
+ capture_name = match[1]
457
+ node = match[0]
458
+ if capture_name == 'name':
459
+ var_node = node.parent
460
+ name = self._get_node_text(node)
461
+ value = None
462
+ type_text = None
463
+
464
+ # Detect if variable assigned to a function
465
+ value_node = var_node.child_by_field_name("value") if var_node else None
466
+
467
+ if value_node:
468
+ value_type = value_node.type
469
+
470
+ # --- Skip variables that are assigned a function ---
471
+ if value_type in ("function_expression", "arrow_function"):
472
+ continue
473
+
474
+ if "function" in value_type or "arrow" in value_type:
475
+ continue
476
+
477
+ # --- Handle various assignment types ---
478
+ if value_type == "call_expression":
479
+ func_node = value_node.child_by_field_name("function")
480
+ value = self._get_node_text(func_node) if func_node else name
481
+ else:
482
+ value = self._get_node_text(value_node)
483
+
484
+ context, context_type, context_line = self._get_parent_context(node)
485
+ class_context = context if context_type == 'class_declaration' else None
486
+
487
+ variable_data = {
488
+ "name": name,
489
+ "line_number": node.start_point[0] + 1,
490
+ "value": value,
491
+ "type": type_text,
492
+ "context": context,
493
+ "class_context": class_context,
494
+ "lang": self.language_name,
495
+ "is_dependency": False,
496
+ }
497
+ variables.append(variable_data)
498
+ return variables
499
+
500
+ def pre_scan_typescript(files: list[Path], parser_wrapper) -> dict:
501
+ """Scans TypeScript files to create a map of class/function names to their file paths."""
502
+ imports_map = {}
503
+
504
+ # Simplified queries that capture the parent nodes, then extract names manually
505
+ query_strings = [
506
+ "(class_declaration) @class",
507
+ "(function_declaration) @function",
508
+ "(variable_declarator) @var_decl",
509
+ "(method_definition) @method",
510
+ "(interface_declaration) @interface",
511
+ "(type_alias_declaration) @type_alias",
512
+ ]
513
+
514
+ for path in files:
515
+ try:
516
+ with open(path, "r", encoding="utf-8") as f:
517
+ source_code = f.read()
518
+ tree = parser_wrapper.parser.parse(bytes(source_code, "utf8"))
519
+
520
+ # Run each query separately
521
+ for query_str in query_strings:
522
+ try:
523
+
524
+ for node, capture_name in execute_query(parser_wrapper.language, query_str, tree.root_node):
525
+ name = None
526
+
527
+ # Extract name based on node type
528
+ if capture_name == 'class':
529
+ name_node = node.child_by_field_name('name')
530
+ if name_node:
531
+ name = name_node.text.decode('utf-8')
532
+
533
+ elif capture_name == 'function':
534
+ name_node = node.child_by_field_name('name')
535
+ if name_node:
536
+ name = name_node.text.decode('utf-8')
537
+
538
+ elif capture_name == 'var_decl':
539
+ # Check if it's a function or arrow function
540
+ name_node = node.child_by_field_name('name')
541
+ value_node = node.child_by_field_name('value')
542
+ if name_node and value_node:
543
+ if value_node.type in ('function', 'arrow_function'):
544
+ name = name_node.text.decode('utf-8')
545
+
546
+ elif capture_name == 'method':
547
+ name_node = node.child_by_field_name('name')
548
+ if name_node:
549
+ name = name_node.text.decode('utf-8')
550
+
551
+ elif capture_name == 'interface':
552
+ name_node = node.child_by_field_name('name')
553
+ if name_node:
554
+ name = name_node.text.decode('utf-8')
555
+
556
+ elif capture_name == 'type_alias':
557
+ name_node = node.child_by_field_name('name')
558
+ if name_node:
559
+ name = name_node.text.decode('utf-8')
560
+
561
+ # Add to imports map if we found a name
562
+ if name:
563
+ if name not in imports_map:
564
+ imports_map[name] = []
565
+ file_path_str = str(path.resolve())
566
+ if file_path_str not in imports_map[name]:
567
+ imports_map[name].append(file_path_str)
568
+
569
+ except Exception as query_error:
570
+ warning_logger(f"Query failed for pattern '{query_str}': {query_error}")
571
+
572
+ except Exception as e:
573
+ warning_logger(f"Tree-sitter pre-scan failed for {path}: {e}")
574
+
575
+ return imports_map