codegraph-py 1.0.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.
Files changed (44) hide show
  1. codegraph/__init__.py +12 -0
  2. codegraph/__main__.py +6 -0
  3. codegraph/cli.py +911 -0
  4. codegraph/codegraph.py +618 -0
  5. codegraph/context/__init__.py +216 -0
  6. codegraph/db/__init__.py +11 -0
  7. codegraph/db/connection.py +163 -0
  8. codegraph/db/queries.py +752 -0
  9. codegraph/db/schema.sql +151 -0
  10. codegraph/directory.py +160 -0
  11. codegraph/errors.py +101 -0
  12. codegraph/extraction/__init__.py +956 -0
  13. codegraph/extraction/languages/__init__.py +64 -0
  14. codegraph/extraction/languages/base.py +132 -0
  15. codegraph/extraction/languages/c_cfg.py +53 -0
  16. codegraph/extraction/languages/cpp_cfg.py +60 -0
  17. codegraph/extraction/languages/dart_cfg.py +53 -0
  18. codegraph/extraction/languages/go_cfg.py +70 -0
  19. codegraph/extraction/languages/java_cfg.py +62 -0
  20. codegraph/extraction/languages/javascript_cfg.py +84 -0
  21. codegraph/extraction/languages/kotlin_cfg.py +52 -0
  22. codegraph/extraction/languages/lua_cfg.py +65 -0
  23. codegraph/extraction/languages/python_cfg.py +75 -0
  24. codegraph/extraction/languages/ruby_cfg.py +48 -0
  25. codegraph/extraction/languages/rust_cfg.py +68 -0
  26. codegraph/extraction/languages/scala_cfg.py +59 -0
  27. codegraph/extraction/languages/swift_cfg.py +64 -0
  28. codegraph/extraction/languages/typescript_cfg.py +89 -0
  29. codegraph/extraction/tree_sitter_extractor.py +689 -0
  30. codegraph/graph/__init__.py +685 -0
  31. codegraph/installer/__init__.py +6 -0
  32. codegraph/mcp/__init__.py +668 -0
  33. codegraph/project_config.py +191 -0
  34. codegraph/resolution/__init__.py +337 -0
  35. codegraph/search/__init__.py +653 -0
  36. codegraph/sync/__init__.py +204 -0
  37. codegraph/types.py +334 -0
  38. codegraph/ui/__init__.py +11 -0
  39. codegraph/utils.py +218 -0
  40. codegraph_py-1.0.0.dist-info/METADATA +238 -0
  41. codegraph_py-1.0.0.dist-info/RECORD +44 -0
  42. codegraph_py-1.0.0.dist-info/WHEEL +5 -0
  43. codegraph_py-1.0.0.dist-info/entry_points.txt +2 -0
  44. codegraph_py-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,65 @@
1
+ """
2
+ Lua language extraction configuration.
3
+ """
4
+ from tree_sitter import Node as TSNode
5
+ from .base import LanguageConfig, ImportInfo
6
+
7
+
8
+ class LuaConfig(LanguageConfig):
9
+ """Lua extraction configuration."""
10
+
11
+ language_id = 'lua'
12
+
13
+ function_types = ['function_declaration']
14
+ class_types = []
15
+ method_types = ['function_declaration'] # Methods using self syntax
16
+ interface_types = []
17
+ struct_types = []
18
+ enum_types = []
19
+ type_alias_types = []
20
+ import_types = ['require_statement']
21
+ call_types = ['function_call']
22
+ variable_types = ['variable_declaration', 'assignment_statement']
23
+ field_types = ['field']
24
+ property_types = []
25
+
26
+ name_field = 'name'
27
+ body_field = 'body'
28
+ params_field = 'parameters'
29
+ return_field = None
30
+
31
+ def get_signature(self, node: TSNode, source: bytes) -> str | None:
32
+ params = node.child_by_field_name('parameters')
33
+ if not params:
34
+ return None
35
+ return source[params.start_byte:params.end_byte].decode('utf-8', errors='replace')
36
+
37
+ def extract_import(self, node: TSNode, source: bytes) -> ImportInfo | None:
38
+ if node.type == 'require_statement':
39
+ text = source[node.start_byte:node.end_byte].decode('utf-8', errors='replace').strip()
40
+ # require('module') or require "module"
41
+ arg = node.child_by_field_name('module') or node.child(1)
42
+ if arg:
43
+ module_name = source[arg.start_byte:arg.end_byte].decode('utf-8', errors='replace')
44
+ module_name = module_name.strip('\'"')
45
+ return ImportInfo(module_name=module_name, signature=text)
46
+ return None
47
+
48
+ def is_exported(self, node: TSNode, source: bytes) -> bool:
49
+ # Lua: functions in module scope, not starting with _
50
+ name_node = node.child_by_field_name('name')
51
+ if name_node:
52
+ try:
53
+ t = name_node.text
54
+ if isinstance(t, bytes):
55
+ name = t.decode('utf-8', errors='replace')
56
+ else:
57
+ name = str(t)
58
+ return not name.startswith('_')
59
+ except Exception:
60
+ pass
61
+ return True
62
+
63
+ def classify_class_node(self, node: TSNode) -> str:
64
+ # Lua uses metatables, treat function_declaration returning a table as class
65
+ return 'class'
@@ -0,0 +1,75 @@
1
+ """
2
+ Python language extraction configuration.
3
+ """
4
+ from tree_sitter import Node as TSNode
5
+ from .base import LanguageConfig, ImportInfo
6
+
7
+
8
+ class PythonConfig(LanguageConfig):
9
+ """Python-specific extraction configuration."""
10
+
11
+ language_id = 'python'
12
+
13
+ function_types = ['function_definition']
14
+ class_types = ['class_definition']
15
+ method_types = ['function_definition'] # Methods are functions inside classes
16
+ interface_types = []
17
+ struct_types = []
18
+ enum_types = []
19
+ type_alias_types = []
20
+ import_types = ['import_statement', 'import_from_statement']
21
+ call_types = ['call']
22
+ variable_types = ['assignment']
23
+ field_types = []
24
+ property_types = []
25
+
26
+ name_field = 'name'
27
+ body_field = 'body'
28
+ params_field = 'parameters'
29
+ return_field = 'return_type'
30
+
31
+ def get_signature(self, node: TSNode, source: bytes) -> str | None:
32
+ params = node.child_by_field_name('parameters')
33
+ return_type = node.child_by_field_name('return_type')
34
+ if not params:
35
+ return None
36
+ sig = source[params.start_byte:params.end_byte].decode('utf-8', errors='replace')
37
+ if return_type:
38
+ sig += ' -> ' + source[return_type.start_byte:return_type.end_byte].decode('utf-8', errors='replace')
39
+ return sig
40
+
41
+ def is_async(self, node: TSNode) -> bool:
42
+ prev = node.prev_sibling
43
+ return prev is not None and prev.type == 'async'
44
+
45
+ def is_static(self, node: TSNode) -> bool:
46
+ prev = node.prev_named_sibling
47
+ if prev is not None and prev.type == 'decorator':
48
+ text = _node_text(prev)
49
+ return 'staticmethod' in text
50
+ return False
51
+
52
+ def extract_import(self, node: TSNode, source: bytes) -> ImportInfo | None:
53
+ text = source[node.start_byte:node.end_byte].decode('utf-8', errors='replace').strip()
54
+ if node.type == 'import_from_statement':
55
+ module_node = node.child_by_field_name('module_name')
56
+ if module_node:
57
+ module_name = source[module_node.start_byte:module_node.end_byte].decode('utf-8', errors='replace')
58
+ return ImportInfo(module_name=module_name, signature=text)
59
+ elif node.type == 'import_statement':
60
+ name_node = node.child_by_field_name('name')
61
+ if name_node:
62
+ module_name = source[name_node.start_byte:name_node.end_byte].decode('utf-8', errors='replace')
63
+ return ImportInfo(module_name=module_name, signature=text)
64
+ return None
65
+
66
+
67
+ def _node_text(node: TSNode) -> str:
68
+ """Get text from a tree-sitter node safely."""
69
+ try:
70
+ t = node.text
71
+ if isinstance(t, bytes):
72
+ return t.decode('utf-8', errors='replace')
73
+ return str(t)
74
+ except Exception:
75
+ return ''
@@ -0,0 +1,48 @@
1
+ """
2
+ Ruby language extraction configuration.
3
+ """
4
+ from tree_sitter import Node as TSNode
5
+ from .base import LanguageConfig, ImportInfo
6
+
7
+
8
+ class RubyConfig(LanguageConfig):
9
+ """Ruby extraction configuration."""
10
+
11
+ language_id = 'ruby'
12
+
13
+ function_types = ['method']
14
+ class_types = ['class']
15
+ method_types = ['method'] # Methods inside class bodies
16
+ interface_types = []
17
+ struct_types = []
18
+ enum_types = []
19
+ type_alias_types = []
20
+ import_types = ['require', 'require_relative']
21
+ call_types = ['call', 'method_call']
22
+ variable_types = ['assignment']
23
+ field_types = []
24
+ property_types = []
25
+
26
+ name_field = 'name'
27
+ body_field = 'body'
28
+ params_field = 'parameters'
29
+ return_field = None
30
+
31
+ def get_signature(self, node: TSNode, source: bytes) -> str | None:
32
+ params = node.child_by_field_name('parameters')
33
+ if not params:
34
+ return None
35
+ return source[params.start_byte:params.end_byte].decode('utf-8', errors='replace')
36
+
37
+ def extract_import(self, node: TSNode, source: bytes) -> ImportInfo | None:
38
+ text = source[node.start_byte:node.end_byte].decode('utf-8', errors='replace').strip()
39
+ if node.type in ('require', 'require_relative'):
40
+ arg = node.child_by_field_name('path') or node.child(1)
41
+ if arg:
42
+ module_name = source[arg.start_byte:arg.end_byte].decode('utf-8', errors='replace')
43
+ module_name = module_name.strip('\'"')
44
+ return ImportInfo(module_name=module_name, signature=text)
45
+ return None
46
+
47
+ def is_exported(self, node: TSNode, source: bytes) -> bool:
48
+ return not node.type.startswith('_')
@@ -0,0 +1,68 @@
1
+ """
2
+ Rust language extraction configuration.
3
+ """
4
+ from tree_sitter import Node as TSNode
5
+ from .base import LanguageConfig, ImportInfo
6
+
7
+
8
+ class RustConfig(LanguageConfig):
9
+ """Rust extraction configuration."""
10
+
11
+ language_id = 'rust'
12
+
13
+ function_types = ['function_item']
14
+ class_types = []
15
+ method_types = ['function_item'] # Methods in impl blocks
16
+ interface_types = []
17
+ struct_types = ['struct_item']
18
+ enum_types = ['enum_item']
19
+ type_alias_types = ['type_item']
20
+ import_types = ['use_declaration']
21
+ call_types = ['call_expression']
22
+ variable_types = ['let_declaration']
23
+ field_types = []
24
+ property_types = []
25
+
26
+ name_field = 'name'
27
+ body_field = 'body'
28
+ params_field = 'parameters'
29
+ return_field = 'return_type'
30
+
31
+ def get_signature(self, node: TSNode, source: bytes) -> str | None:
32
+ params = node.child_by_field_name('parameters')
33
+ if not params:
34
+ return None
35
+ sig = source[params.start_byte:params.end_byte].decode('utf-8', errors='replace')
36
+ return_type = node.child_by_field_name('return_type')
37
+ if return_type:
38
+ sig += ' -> ' + source[return_type.start_byte:return_type.end_byte].decode('utf-8', errors='replace')
39
+ return sig
40
+
41
+ def extract_import(self, node: TSNode, source: bytes) -> ImportInfo | None:
42
+ if node.type == 'use_declaration':
43
+ text = source[node.start_byte:node.end_byte].decode('utf-8', errors='replace').strip()
44
+ # Extract the first path segment
45
+ arg = node.child_by_field_name('argument')
46
+ if arg:
47
+ module_name = source[arg.start_byte:arg.end_byte].decode('utf-8', errors='replace')
48
+ # Get the top-level crate/module name
49
+ top_level = module_name.split('::')[0]
50
+ return ImportInfo(module_name=top_level, signature=text)
51
+ return None
52
+
53
+ def is_exported(self, node: TSNode, source: bytes) -> bool:
54
+ # Check for 'pub' keyword
55
+ prev = node.prev_sibling
56
+ while prev is not None:
57
+ if prev.type == 'pub':
58
+ return True
59
+ if prev.is_named and prev.type != 'pub':
60
+ break
61
+ prev = prev.prev_sibling
62
+ return False
63
+
64
+ def classify_class_node(self, node: TSNode) -> str:
65
+ # Rust uses `impl` blocks for implementations
66
+ if node.type == 'impl_item':
67
+ return 'class' # Treat impl blocks as containers for methods
68
+ return 'class'
@@ -0,0 +1,59 @@
1
+ """
2
+ Scala language extraction configuration.
3
+ """
4
+ from tree_sitter import Node as TSNode
5
+ from .base import LanguageConfig, ImportInfo
6
+
7
+
8
+ class ScalaConfig(LanguageConfig):
9
+ """Scala extraction configuration."""
10
+
11
+ language_id = 'scala'
12
+
13
+ function_types = ['function_definition']
14
+ class_types = ['class_definition']
15
+ method_types = ['function_definition'] # Functions inside class/object bodies
16
+ interface_types = ['trait_definition']
17
+ struct_types = []
18
+ enum_types = ['enum_definition']
19
+ type_alias_types = ['type_definition']
20
+ import_types = ['import_statement']
21
+ call_types = ['call_expression']
22
+ variable_types = ['val_definition', 'var_definition']
23
+ field_types = ['variable_definition']
24
+ property_types = []
25
+
26
+ name_field = 'name'
27
+ body_field = 'body'
28
+ params_field = 'parameters'
29
+ return_field = 'return_type'
30
+
31
+ def get_signature(self, node: TSNode, source: bytes) -> str | None:
32
+ params = node.child_by_field_name('parameters')
33
+ if not params:
34
+ return None
35
+ sig = source[params.start_byte:params.end_byte].decode('utf-8', errors='replace')
36
+ return_type = node.child_by_field_name('return_type')
37
+ if return_type:
38
+ ret = source[return_type.start_byte:return_type.end_byte].decode('utf-8', errors='replace')
39
+ sig += f': {ret}'
40
+ return sig
41
+
42
+ def extract_import(self, node: TSNode, source: bytes) -> ImportInfo | None:
43
+ if node.type == 'import_statement':
44
+ text = source[node.start_byte:node.end_byte].decode('utf-8', errors='replace').strip()
45
+ path = node.child_by_field_name('path')
46
+ if path:
47
+ module_name = source[path.start_byte:path.end_byte].decode('utf-8', errors='replace')
48
+ return ImportInfo(module_name=module_name, signature=text)
49
+ return None
50
+
51
+ def is_exported(self, node: TSNode, source: bytes) -> bool:
52
+ return True # Scala defs at package level are public by default
53
+
54
+ def is_static(self, node: TSNode) -> bool:
55
+ # Check for 'static' modifier in Scala 3
56
+ for child in node.children:
57
+ if child.type == 'static':
58
+ return True
59
+ return False
@@ -0,0 +1,64 @@
1
+ """
2
+ Swift language extraction configuration.
3
+ """
4
+ from tree_sitter import Node as TSNode
5
+ from .base import LanguageConfig, ImportInfo
6
+
7
+
8
+ class SwiftConfig(LanguageConfig):
9
+ """Swift extraction configuration."""
10
+
11
+ language_id = 'swift'
12
+
13
+ function_types = ['function_declaration']
14
+ class_types = ['class_declaration']
15
+ method_types = ['function_declaration'] # Functions inside class bodies
16
+ interface_types = ['protocol_declaration']
17
+ struct_types = ['struct_declaration']
18
+ enum_types = ['enum_declaration']
19
+ type_alias_types = ['typealias_declaration']
20
+ import_types = ['import_declaration']
21
+ call_types = ['call_expression']
22
+ variable_types = ['variable_declaration']
23
+ field_types = ['property_declaration']
24
+ property_types = []
25
+
26
+ name_field = 'name'
27
+ body_field = 'body'
28
+ params_field = 'parameters'
29
+ return_field = 'return_type'
30
+
31
+ def get_signature(self, node: TSNode, source: bytes) -> str | None:
32
+ params = node.child_by_field_name('parameters')
33
+ if not params:
34
+ return None
35
+ sig = source[params.start_byte:params.end_byte].decode('utf-8', errors='replace')
36
+ return_type = node.child_by_field_name('return_type')
37
+ if return_type:
38
+ sig += ' -> ' + source[return_type.start_byte:return_type.end_byte].decode('utf-8', errors='replace')
39
+ return sig
40
+
41
+ def extract_import(self, node: TSNode, source: bytes) -> ImportInfo | None:
42
+ if node.type == 'import_declaration':
43
+ text = source[node.start_byte:node.end_byte].decode('utf-8', errors='replace').strip()
44
+ # Get the module path (all children after 'import' keyword)
45
+ parts = []
46
+ for child in node.named_children:
47
+ t = source[child.start_byte:child.end_byte].decode('utf-8', errors='replace')
48
+ parts.append(t)
49
+ module_name = '.'.join(parts) if parts else ''
50
+ return ImportInfo(module_name=module_name, signature=text)
51
+ return None
52
+
53
+ def is_exported(self, node: TSNode, source: bytes) -> bool:
54
+ # Check for 'public' or 'open' modifiers
55
+ for child in node.children:
56
+ if child.type in ('public', 'open'):
57
+ return True
58
+ return False
59
+
60
+ def is_static(self, node: TSNode) -> bool:
61
+ for child in node.children:
62
+ if child.type == 'static':
63
+ return True
64
+ return False
@@ -0,0 +1,89 @@
1
+ """
2
+ TypeScript/TSX language extraction configuration.
3
+ """
4
+ from tree_sitter import Node as TSNode
5
+ from .base import LanguageConfig, ImportInfo
6
+
7
+
8
+ def _node_text(node: TSNode) -> str:
9
+ try:
10
+ t = node.text
11
+ if isinstance(t, bytes):
12
+ return t.decode('utf-8', errors='replace')
13
+ return str(t)
14
+ except Exception:
15
+ return ''
16
+
17
+
18
+ class TypeScriptConfig(LanguageConfig):
19
+ """TypeScript/TSX extraction configuration."""
20
+
21
+ language_id = 'typescript'
22
+
23
+ # TS uses 'typescript' grammar, access specific dialects via 'typescript' or 'tsx'
24
+ _tsx = False
25
+
26
+ function_types = ['function_declaration', 'arrow_function', 'generator_function_declaration']
27
+ class_types = ['class_declaration']
28
+ method_types = ['method_definition']
29
+ interface_types = ['interface_declaration']
30
+ struct_types = []
31
+ enum_types = ['enum_declaration']
32
+ type_alias_types = ['type_alias_declaration']
33
+ import_types = ['import_statement']
34
+ call_types = ['call_expression']
35
+ variable_types = ['variable_declaration', 'lexical_declaration']
36
+ field_types = ['property_signature', 'public_field_definition']
37
+ property_types = ['property_identifier']
38
+
39
+ name_field = 'name'
40
+ body_field = 'body'
41
+ params_field = 'parameters'
42
+ return_field = 'type'
43
+
44
+ def get_signature(self, node: TSNode, source: bytes) -> str | None:
45
+ params = node.child_by_field_name('parameters')
46
+ if not params:
47
+ return None
48
+ sig = source[params.start_byte:params.end_byte].decode('utf-8', errors='replace')
49
+ return_type = node.child_by_field_name('return_type')
50
+ if return_type:
51
+ sig += ': ' + source[return_type.start_byte:return_type.end_byte].decode('utf-8', errors='replace')
52
+ return sig
53
+
54
+ def extract_import(self, node: TSNode, source: bytes) -> ImportInfo | None:
55
+ text = source[node.start_byte:node.end_byte].decode('utf-8', errors='replace').strip()
56
+ if node.type == 'import_statement':
57
+ source_node = node.child_by_field_name('source')
58
+ if source_node:
59
+ module_name = source[source_node.start_byte:source_node.end_byte].decode('utf-8', errors='replace')
60
+ module_name = module_name.strip('\'"')
61
+ return ImportInfo(module_name=module_name, signature=text)
62
+ return None
63
+
64
+ def is_exported(self, node: TSNode, source: bytes) -> bool:
65
+ prev = node.prev_sibling
66
+ while prev is not None:
67
+ if prev.type == 'export':
68
+ return True
69
+ if prev.is_named or prev.type in (';', '\n'):
70
+ break
71
+ prev = prev.prev_sibling
72
+ return False
73
+
74
+ def is_async(self, node: TSNode) -> bool:
75
+ prev = node.prev_sibling
76
+ while prev is not None:
77
+ if prev.type == 'async':
78
+ return True
79
+ if prev.is_named:
80
+ break
81
+ prev = prev.prev_sibling
82
+ return False
83
+
84
+ def is_const(self, node: TSNode) -> bool:
85
+ parent = node.parent
86
+ if parent and parent.type == 'variable_declaration':
87
+ kind = _node_text(parent.child(0)) if parent.child(0) else ''
88
+ return kind == 'const'
89
+ return False