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,460 @@
1
+ from pathlib import Path
2
+ from typing import Any, Dict, Optional, Tuple
3
+ from codegraphcontext.utils.debug_log import warning_logger
4
+
5
+ # In Elixir's tree-sitter grammar, most constructs are `call` nodes
6
+ # with identifiers like `defmodule`, `def`, `defp`, etc.
7
+
8
+ ELIXIR_QUERIES = {
9
+ "modules": """
10
+ (call
11
+ target: (identifier) @keyword
12
+ (arguments (alias) @name)
13
+ (do_block)
14
+ ) @module_node
15
+ """,
16
+ "functions": """
17
+ (call
18
+ target: (identifier) @keyword
19
+ (arguments
20
+ (call
21
+ target: (identifier) @name
22
+ )
23
+ )
24
+ ) @function_node
25
+ """,
26
+ "imports": """
27
+ (call
28
+ target: (identifier) @keyword
29
+ (arguments (alias) @path)
30
+ ) @import_node
31
+ """,
32
+ "calls": """
33
+ (call
34
+ target: (dot
35
+ left: (_) @receiver
36
+ right: (identifier) @name
37
+ )
38
+ (arguments) @args
39
+ ) @call_node
40
+ """,
41
+ "simple_calls": """
42
+ (call
43
+ target: (identifier) @name
44
+ (arguments) @args
45
+ ) @call_node
46
+ """,
47
+ "module_attributes": """
48
+ (unary_operator
49
+ operator: "@"
50
+ operand: (call
51
+ target: (identifier) @attr_name
52
+ (arguments (_) @attr_value)
53
+ )
54
+ ) @attribute
55
+ """,
56
+ "comments": """
57
+ (comment) @comment
58
+ """,
59
+ }
60
+
61
+ # Keywords that define modules/namespaces
62
+ MODULE_KEYWORDS = {"defmodule", "defprotocol", "defimpl"}
63
+
64
+ # Keywords that define functions
65
+ FUNCTION_KEYWORDS = {"def", "defp", "defmacro", "defmacrop", "defguard", "defguardp", "defdelegate"}
66
+
67
+ # Keywords that represent imports/dependencies
68
+ IMPORT_KEYWORDS = {"use", "import", "alias", "require"}
69
+
70
+ # Keywords to exclude from general call detection
71
+ ELIXIR_KEYWORDS = MODULE_KEYWORDS | FUNCTION_KEYWORDS | IMPORT_KEYWORDS | {
72
+ "quote", "unquote", "case", "cond", "if", "unless", "for", "with",
73
+ "try", "receive", "raise", "reraise", "throw", "super",
74
+ }
75
+
76
+
77
+ class ElixirTreeSitterParser:
78
+ """An Elixir-specific parser using tree-sitter."""
79
+
80
+ def __init__(self, generic_parser_wrapper: Any):
81
+ self.generic_parser_wrapper = generic_parser_wrapper
82
+ self.language_name = "elixir"
83
+ self.language = generic_parser_wrapper.language
84
+ self.parser = generic_parser_wrapper.parser
85
+ self.index_source = False
86
+
87
+ def _get_node_text(self, node: Any) -> str:
88
+ return node.text.decode("utf-8")
89
+
90
+ def _get_parent_context(self, node: Any):
91
+ """Find parent module or function context."""
92
+ curr = node.parent
93
+ while curr:
94
+ if curr.type == 'call':
95
+ # Check if it's a defmodule/def/defp etc
96
+ for child in curr.children:
97
+ if child.type == 'identifier':
98
+ keyword = self._get_node_text(child)
99
+ if keyword in MODULE_KEYWORDS:
100
+ # Get module name from arguments
101
+ for arg_child in curr.children:
102
+ if arg_child.type == 'arguments':
103
+ for ac in arg_child.children:
104
+ if ac.type == 'alias':
105
+ return self._get_node_text(ac), 'module', curr.start_point[0] + 1
106
+ elif keyword in FUNCTION_KEYWORDS:
107
+ for arg_child in curr.children:
108
+ if arg_child.type == 'arguments':
109
+ for ac in arg_child.children:
110
+ if ac.type == 'call':
111
+ name_node = ac.child_by_field_name('target')
112
+ if name_node:
113
+ return self._get_node_text(name_node), 'function', curr.start_point[0] + 1
114
+ break
115
+ curr = curr.parent
116
+ return None, None, None
117
+
118
+ def _enclosing_module_name(self, node: Any) -> Optional[str]:
119
+ """Find the enclosing module name."""
120
+ curr = node.parent
121
+ while curr:
122
+ if curr.type == 'call':
123
+ for child in curr.children:
124
+ if child.type == 'identifier':
125
+ keyword = self._get_node_text(child)
126
+ if keyword in MODULE_KEYWORDS:
127
+ for arg_child in curr.children:
128
+ if arg_child.type == 'arguments':
129
+ for ac in arg_child.children:
130
+ if ac.type == 'alias':
131
+ return self._get_node_text(ac)
132
+ break
133
+ curr = curr.parent
134
+ return None
135
+
136
+ def _calculate_complexity(self, node: Any) -> int:
137
+ """Calculate cyclomatic complexity for Elixir constructs."""
138
+ complexity_keywords = {
139
+ "if", "unless", "case", "cond", "with", "for", "try",
140
+ "receive", "and", "or", "&&", "||", "when",
141
+ }
142
+ count = 1
143
+
144
+ def traverse(n):
145
+ nonlocal count
146
+ if n.type == 'identifier' and self._get_node_text(n) in complexity_keywords:
147
+ count += 1
148
+ elif n.type in ('binary_operator',):
149
+ op_text = self._get_node_text(n)
150
+ if '&&' in op_text or '||' in op_text or ' and ' in op_text or ' or ' in op_text:
151
+ count += 1
152
+ for child in n.children:
153
+ traverse(child)
154
+
155
+ traverse(node)
156
+ return count
157
+
158
+ def _get_docstring(self, node: Any) -> Optional[str]:
159
+ """Extract @doc or @moduledoc attribute as docstring."""
160
+ prev = node.prev_sibling
161
+ while prev:
162
+ if prev.type == 'unary_operator':
163
+ text = self._get_node_text(prev)
164
+ if text.startswith('@doc') or text.startswith('@moduledoc'):
165
+ return text.strip()
166
+ elif prev.type == 'comment':
167
+ return self._get_node_text(prev).strip()
168
+ else:
169
+ break
170
+ prev = prev.prev_sibling
171
+ return None
172
+
173
+ def parse(self, path: Path, is_dependency: bool = False, index_source: bool = False) -> Dict[str, Any]:
174
+ """Parses an Elixir file and returns its structure."""
175
+ self.index_source = index_source
176
+ with open(path, "r", encoding="utf-8", errors="ignore") as f:
177
+ source_code = f.read()
178
+
179
+ tree = self.parser.parse(bytes(source_code, "utf8"))
180
+ root_node = tree.root_node
181
+
182
+ functions = self._find_functions(root_node)
183
+ modules = self._find_modules(root_node)
184
+ imports = self._find_imports(root_node)
185
+ function_calls = self._find_calls(root_node)
186
+ variables = [] # Elixir uses pattern matching, not traditional assignments
187
+
188
+ return {
189
+ "path": str(path),
190
+ "functions": functions,
191
+ "classes": [], # Elixir doesn't have classes
192
+ "variables": variables,
193
+ "imports": imports,
194
+ "function_calls": function_calls,
195
+ "is_dependency": is_dependency,
196
+ "lang": self.language_name,
197
+ "modules": modules,
198
+ }
199
+
200
+ def _find_modules(self, root_node: Any) -> list[Dict[str, Any]]:
201
+ """Find all defmodule, defprotocol, defimpl definitions."""
202
+ modules = []
203
+ self._find_modules_recursive(root_node, modules)
204
+ return modules
205
+
206
+ def _find_modules_recursive(self, node: Any, modules: list):
207
+ """Recursively find module definitions."""
208
+ if node.type == 'call':
209
+ keyword = None
210
+ name = None
211
+ has_do_block = False
212
+
213
+ for child in node.children:
214
+ if child.type == 'identifier':
215
+ kw = self._get_node_text(child)
216
+ if kw in MODULE_KEYWORDS:
217
+ keyword = kw
218
+ elif child.type == 'arguments' and keyword:
219
+ for ac in child.children:
220
+ if ac.type == 'alias':
221
+ name = self._get_node_text(ac)
222
+ break
223
+ elif child.type == 'do_block':
224
+ has_do_block = True
225
+
226
+ if keyword and name and has_do_block:
227
+ module_data = {
228
+ "name": name,
229
+ "line_number": node.start_point[0] + 1,
230
+ "end_line": node.end_point[0] + 1,
231
+ "lang": self.language_name,
232
+ "is_dependency": False,
233
+ "type": keyword, # defmodule, defprotocol, defimpl
234
+ }
235
+ if self.index_source:
236
+ module_data["source"] = self._get_node_text(node)
237
+ modules.append(module_data)
238
+
239
+ for child in node.children:
240
+ self._find_modules_recursive(child, modules)
241
+
242
+ def _find_functions(self, root_node: Any) -> list[Dict[str, Any]]:
243
+ """Find all def, defp, defmacro, etc. definitions."""
244
+ functions = []
245
+ self._find_functions_recursive(root_node, functions)
246
+ return functions
247
+
248
+ def _find_functions_recursive(self, node: Any, functions: list):
249
+ """Recursively find function definitions."""
250
+ if node.type == 'call':
251
+ keyword = None
252
+ func_name = None
253
+ args = []
254
+
255
+ for child in node.children:
256
+ if child.type == 'identifier':
257
+ kw = self._get_node_text(child)
258
+ if kw in FUNCTION_KEYWORDS:
259
+ keyword = kw
260
+ elif child.type == 'arguments' and keyword:
261
+ for ac in child.children:
262
+ if ac.type == 'call':
263
+ # The function head: name(arg1, arg2)
264
+ target = ac.child_by_field_name('target')
265
+ if target:
266
+ func_name = self._get_node_text(target)
267
+ # Extract arguments
268
+ for acc in ac.children:
269
+ if acc.type == 'arguments':
270
+ for arg in acc.children:
271
+ if arg.type not in (',', '(', ')'):
272
+ args.append(self._get_node_text(arg))
273
+ elif ac.type == 'identifier' and not func_name:
274
+ # Zero-arity function: def my_func, do: ...
275
+ func_name = self._get_node_text(ac)
276
+
277
+ if keyword and func_name:
278
+ module_name = self._enclosing_module_name(node)
279
+ docstring = self._get_docstring(node)
280
+
281
+ func_data = {
282
+ "name": func_name,
283
+ "line_number": node.start_point[0] + 1,
284
+ "end_line": node.end_point[0] + 1,
285
+ "args": args,
286
+ "lang": self.language_name,
287
+ "is_dependency": False,
288
+ "visibility": "private" if keyword.endswith("p") else "public",
289
+ "type": keyword, # def, defp, defmacro, etc.
290
+ }
291
+ if self.index_source:
292
+ func_data["source"] = self._get_node_text(node)
293
+ func_data["docstring"] = docstring
294
+ if module_name:
295
+ func_data["context"] = module_name
296
+ func_data["context_type"] = "module"
297
+ func_data["class_context"] = module_name
298
+
299
+ functions.append(func_data)
300
+
301
+ for child in node.children:
302
+ self._find_functions_recursive(child, functions)
303
+
304
+ def _find_imports(self, root_node: Any) -> list[Dict[str, Any]]:
305
+ """Find all use, import, alias, require statements."""
306
+ imports = []
307
+ self._find_imports_recursive(root_node, imports)
308
+ return imports
309
+
310
+ def _find_imports_recursive(self, node: Any, imports: list):
311
+ """Recursively find import-like statements."""
312
+ if node.type == 'call':
313
+ keyword = None
314
+ path = None
315
+
316
+ for child in node.children:
317
+ if child.type == 'identifier':
318
+ kw = self._get_node_text(child)
319
+ if kw in IMPORT_KEYWORDS:
320
+ keyword = kw
321
+ elif child.type == 'arguments' and keyword:
322
+ for ac in child.children:
323
+ if ac.type == 'alias':
324
+ path = self._get_node_text(ac)
325
+ break
326
+
327
+ if keyword and path:
328
+ imports.append({
329
+ "name": path,
330
+ "full_import_name": f"{keyword} {path}",
331
+ "line_number": node.start_point[0] + 1,
332
+ "alias": path.split('.')[-1] if keyword == 'alias' else None,
333
+ "lang": self.language_name,
334
+ "is_dependency": False,
335
+ "import_type": keyword, # use, import, alias, require
336
+ })
337
+
338
+ for child in node.children:
339
+ self._find_imports_recursive(child, imports)
340
+
341
+ def _find_calls(self, root_node: Any) -> list[Dict[str, Any]]:
342
+ """Find all function calls (excluding def/defmodule/etc keywords)."""
343
+ calls = []
344
+ self._find_calls_recursive(root_node, calls)
345
+ return calls
346
+
347
+ def _find_calls_recursive(self, node: Any, calls: list):
348
+ """Recursively find function calls."""
349
+ if node.type == 'call':
350
+ target = None
351
+ receiver = None
352
+ name = None
353
+ args = []
354
+
355
+ for child in node.children:
356
+ if child.type == 'dot':
357
+ # Module.function() style call
358
+ left = child.child_by_field_name('left')
359
+ right = child.child_by_field_name('right')
360
+ if left:
361
+ receiver = self._get_node_text(left)
362
+ if right:
363
+ name = self._get_node_text(right)
364
+ elif child.type == 'identifier' and target is None:
365
+ target = self._get_node_text(child)
366
+ elif child.type == 'arguments':
367
+ for arg in child.children:
368
+ if arg.type not in (',', '(', ')'):
369
+ args.append(self._get_node_text(arg))
370
+
371
+ # Dot-call: Module.func(args)
372
+ if name and receiver:
373
+ full_name = f"{receiver}.{name}"
374
+ context_name, context_type, context_line = self._get_parent_context(node)
375
+ class_context = context_name if context_type == 'module' else None
376
+ if context_type == 'function':
377
+ class_context = self._enclosing_module_name(node)
378
+
379
+ calls.append({
380
+ "name": name,
381
+ "full_name": full_name,
382
+ "line_number": node.start_point[0] + 1,
383
+ "args": args,
384
+ "inferred_obj_type": receiver,
385
+ "context": (context_name, context_type, context_line),
386
+ "class_context": class_context,
387
+ "lang": self.language_name,
388
+ "is_dependency": False,
389
+ })
390
+ # Simple call: func(args), but skip Elixir keywords
391
+ elif target and target not in ELIXIR_KEYWORDS:
392
+ context_name, context_type, context_line = self._get_parent_context(node)
393
+ class_context = context_name if context_type == 'module' else None
394
+ if context_type == 'function':
395
+ class_context = self._enclosing_module_name(node)
396
+
397
+ calls.append({
398
+ "name": target,
399
+ "full_name": target,
400
+ "line_number": node.start_point[0] + 1,
401
+ "args": args,
402
+ "inferred_obj_type": None,
403
+ "context": (context_name, context_type, context_line),
404
+ "class_context": class_context,
405
+ "lang": self.language_name,
406
+ "is_dependency": False,
407
+ })
408
+
409
+ for child in node.children:
410
+ self._find_calls_recursive(child, calls)
411
+
412
+
413
+ def pre_scan_elixir(files: list[Path], parser_wrapper) -> dict:
414
+ """Scans Elixir files to create a map of module/function names to their file paths."""
415
+ imports_map = {}
416
+
417
+ for path in files:
418
+ try:
419
+ with open(path, "r", encoding="utf-8") as f:
420
+ source = f.read()
421
+ tree = parser_wrapper.parser.parse(bytes(source, "utf8"))
422
+ _pre_scan_recursive(tree.root_node, path, imports_map)
423
+ except Exception as e:
424
+ warning_logger(f"Tree-sitter pre-scan failed for {path}: {e}")
425
+
426
+ return imports_map
427
+
428
+
429
+ def _pre_scan_recursive(node, path: Path, imports_map: dict):
430
+ """Recursively scan for module and function names."""
431
+ if node.type == 'call':
432
+ for child in node.children:
433
+ if child.type == 'identifier':
434
+ keyword = child.text.decode('utf-8')
435
+ if keyword in MODULE_KEYWORDS:
436
+ # Get module name
437
+ for sib in node.children:
438
+ if sib.type == 'arguments':
439
+ for ac in sib.children:
440
+ if ac.type == 'alias':
441
+ name = ac.text.decode('utf-8')
442
+ if name not in imports_map:
443
+ imports_map[name] = []
444
+ imports_map[name].append(str(path.resolve()))
445
+ elif keyword in FUNCTION_KEYWORDS:
446
+ # Get function name
447
+ for sib in node.children:
448
+ if sib.type == 'arguments':
449
+ for ac in sib.children:
450
+ if ac.type == 'call':
451
+ target = ac.child_by_field_name('target')
452
+ if target:
453
+ name = target.text.decode('utf-8')
454
+ if name not in imports_map:
455
+ imports_map[name] = []
456
+ imports_map[name].append(str(path.resolve()))
457
+ break
458
+
459
+ for child in node.children:
460
+ _pre_scan_recursive(child, path, imports_map)