codegraphcontext 0.4.4__py3-none-any.whl → 0.4.5__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.
- codegraphcontext/cli/cli_helpers.py +15 -3
- codegraphcontext/cli/main.py +2 -2
- codegraphcontext/core/__init__.py +3 -3
- codegraphcontext/core/database_kuzu.py +24 -4
- codegraphcontext/core/watcher.py +92 -12
- codegraphcontext/tools/code_finder.py +36 -0
- codegraphcontext/tools/indexing/persistence/writer.py +13 -4
- codegraphcontext/tools/indexing/resolution/calls.py +13 -4
- codegraphcontext/tools/languages/dart.py +110 -16
- codegraphcontext/tools/languages/python.py +37 -1
- codegraphcontext/tools/scip_indexer.py +4 -2
- {codegraphcontext-0.4.4.dist-info → codegraphcontext-0.4.5.dist-info}/METADATA +6 -5
- {codegraphcontext-0.4.4.dist-info → codegraphcontext-0.4.5.dist-info}/RECORD +17 -17
- {codegraphcontext-0.4.4.dist-info → codegraphcontext-0.4.5.dist-info}/WHEEL +0 -0
- {codegraphcontext-0.4.4.dist-info → codegraphcontext-0.4.5.dist-info}/entry_points.txt +0 -0
- {codegraphcontext-0.4.4.dist-info → codegraphcontext-0.4.5.dist-info}/licenses/LICENSE +0 -0
- {codegraphcontext-0.4.4.dist-info → codegraphcontext-0.4.5.dist-info}/top_level.txt +0 -0
|
@@ -721,19 +721,31 @@ def watch_helper(path: str, context: Optional[str] = None):
|
|
|
721
721
|
# Add the directory to watch
|
|
722
722
|
if is_indexed:
|
|
723
723
|
console.print("[green]✓[/green] Already indexed (no initial scan needed)")
|
|
724
|
-
watcher.watch_directory(
|
|
724
|
+
watcher.watch_directory(
|
|
725
|
+
str(path_obj),
|
|
726
|
+
perform_initial_scan=False,
|
|
727
|
+
cgcignore_path=ctx.cgcignore_path,
|
|
728
|
+
)
|
|
725
729
|
else:
|
|
726
730
|
console.print("[yellow]⚠[/yellow] Not indexed yet. Performing initial scan...")
|
|
727
731
|
|
|
728
732
|
# Index the repository first (like MCP does)
|
|
729
733
|
async def do_index():
|
|
730
|
-
await graph_builder.build_graph_from_path_async(
|
|
734
|
+
await graph_builder.build_graph_from_path_async(
|
|
735
|
+
path_obj,
|
|
736
|
+
is_dependency=False,
|
|
737
|
+
cgcignore_path=ctx.cgcignore_path,
|
|
738
|
+
)
|
|
731
739
|
|
|
732
740
|
asyncio.run(do_index())
|
|
733
741
|
console.print("[green]✓[/green] Initial scan complete")
|
|
734
742
|
|
|
735
743
|
# Now start watching (without another scan)
|
|
736
|
-
watcher.watch_directory(
|
|
744
|
+
watcher.watch_directory(
|
|
745
|
+
str(path_obj),
|
|
746
|
+
perform_initial_scan=False,
|
|
747
|
+
cgcignore_path=ctx.cgcignore_path,
|
|
748
|
+
)
|
|
737
749
|
|
|
738
750
|
console.print("[bold green]👀 Monitoring for file changes...[/bold green] (Press Ctrl+C to stop)")
|
|
739
751
|
console.print("[dim]💡 Tip: Open a new terminal window to continue working[/dim]\n")
|
codegraphcontext/cli/main.py
CHANGED
|
@@ -854,11 +854,11 @@ def doctor():
|
|
|
854
854
|
elif default_db == "kuzudb":
|
|
855
855
|
from importlib.util import find_spec
|
|
856
856
|
|
|
857
|
-
if find_spec("
|
|
857
|
+
if find_spec("real_ladybug") is not None:
|
|
858
858
|
console.print(f" [green]✓[/green] KuzuDB is installed")
|
|
859
859
|
else:
|
|
860
860
|
console.print(f" [red]✗[/red] KuzuDB is not installed")
|
|
861
|
-
console.print(f" Run: pip install
|
|
861
|
+
console.print(f" Run: pip install real_ladybug")
|
|
862
862
|
all_checks_passed = False
|
|
863
863
|
else:
|
|
864
864
|
# FalkorDB
|
|
@@ -22,7 +22,7 @@ import importlib.util
|
|
|
22
22
|
def _is_kuzudb_available() -> bool:
|
|
23
23
|
"""Check if KùzuDB is installed."""
|
|
24
24
|
try:
|
|
25
|
-
return importlib.util.find_spec("
|
|
25
|
+
return importlib.util.find_spec("real_ladybug") is not None
|
|
26
26
|
except ImportError:
|
|
27
27
|
return False
|
|
28
28
|
|
|
@@ -70,7 +70,7 @@ def get_database_manager(db_path: Optional[str] = None) -> Union['DatabaseManage
|
|
|
70
70
|
db_type = db_type.lower()
|
|
71
71
|
if db_type == 'kuzudb':
|
|
72
72
|
if not _is_kuzudb_available():
|
|
73
|
-
raise ValueError("Database set to 'kuzudb' but Kùzu is not installed.\nRun 'pip install
|
|
73
|
+
raise ValueError("Database set to 'kuzudb' but Kùzu is not installed.\nRun 'pip install real_ladybug'")
|
|
74
74
|
from .database_kuzu import KuzuDBManager
|
|
75
75
|
info_logger(f"Using KùzuDB (explicit) at {db_path or 'default path'}")
|
|
76
76
|
return KuzuDBManager(db_path=db_path)
|
|
@@ -147,7 +147,7 @@ def get_database_manager(db_path: Optional[str] = None) -> Union['DatabaseManage
|
|
|
147
147
|
return DatabaseManager()
|
|
148
148
|
|
|
149
149
|
error_msg = "No database backend available.\n"
|
|
150
|
-
error_msg += "Recommended: Install KùzuDB for zero-config ('pip install
|
|
150
|
+
error_msg += "Recommended: Install KùzuDB for zero-config ('pip install real_ladybug')\n"
|
|
151
151
|
|
|
152
152
|
if platform.system() != "Windows":
|
|
153
153
|
error_msg += "Alternative: Install FalkorDB Lite ('pip install falkordblite')\n"
|
|
@@ -66,7 +66,7 @@ class KuzuDBManager:
|
|
|
66
66
|
if self._conn is None:
|
|
67
67
|
with self._lock:
|
|
68
68
|
if self._conn is None:
|
|
69
|
-
import kuzu
|
|
69
|
+
import real_ladybug as kuzu
|
|
70
70
|
max_retries = 5
|
|
71
71
|
for attempt in range(max_retries):
|
|
72
72
|
try:
|
|
@@ -77,7 +77,7 @@ class KuzuDBManager:
|
|
|
77
77
|
info_logger("KùzuDB connection established and schema verified")
|
|
78
78
|
break
|
|
79
79
|
except ImportError:
|
|
80
|
-
error_logger("KùzuDB is not installed. Run 'pip install
|
|
80
|
+
error_logger("KùzuDB is not installed. Run 'pip install real_ladybug'")
|
|
81
81
|
raise ValueError("KùzuDB missing.")
|
|
82
82
|
except Exception as e:
|
|
83
83
|
if "lock" in str(e).lower() and attempt < max_retries - 1:
|
|
@@ -156,6 +156,26 @@ class KuzuDBManager:
|
|
|
156
156
|
warning_logger(f"Kuzu Schema Rel Error ({table_name}): {e}")
|
|
157
157
|
debug_log(f"Kuzu Schema Rel Error ({table_name}): {e}")
|
|
158
158
|
|
|
159
|
+
self._run_schema_migrations()
|
|
160
|
+
|
|
161
|
+
def _run_schema_migrations(self):
|
|
162
|
+
"""Add columns introduced after older local Kùzu databases were created."""
|
|
163
|
+
migrations = [
|
|
164
|
+
("Module", "full_import_name", "STRING"),
|
|
165
|
+
("IMPORTS", "full_import_name", "STRING"),
|
|
166
|
+
("IMPORTS", "imported_name", "STRING"),
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
for table_name, column_name, column_type in migrations:
|
|
170
|
+
try:
|
|
171
|
+
self._conn.execute(f"ALTER TABLE `{table_name}` ADD {column_name} {column_type}")
|
|
172
|
+
except Exception as e:
|
|
173
|
+
err = str(e).lower()
|
|
174
|
+
if "already exists" in err or "duplicate" in err:
|
|
175
|
+
continue
|
|
176
|
+
warning_logger(f"Kuzu Schema Migration Error ({table_name}.{column_name}): {e}")
|
|
177
|
+
debug_log(f"Kuzu Schema Migration Error ({table_name}.{column_name}): {e}")
|
|
178
|
+
|
|
159
179
|
def close_driver(self):
|
|
160
180
|
"""Closes the connection."""
|
|
161
181
|
if self._conn is not None:
|
|
@@ -188,10 +208,10 @@ class KuzuDBManager:
|
|
|
188
208
|
@staticmethod
|
|
189
209
|
def test_connection(db_path: str = None) -> Tuple[bool, Optional[str]]:
|
|
190
210
|
try:
|
|
191
|
-
import kuzu
|
|
211
|
+
import real_ladybug as kuzu
|
|
192
212
|
return True, None
|
|
193
213
|
except ImportError:
|
|
194
|
-
return False, "KùzuDB is not installed. Run 'pip install
|
|
214
|
+
return False, "KùzuDB is not installed. Run 'pip install real_ladybug'"
|
|
195
215
|
|
|
196
216
|
class KuzuDriverWrapper:
|
|
197
217
|
def __init__(self, conn):
|
codegraphcontext/core/watcher.py
CHANGED
|
@@ -10,9 +10,13 @@ from watchdog.observers import Observer
|
|
|
10
10
|
from watchdog.events import FileSystemEventHandler
|
|
11
11
|
|
|
12
12
|
if typing.TYPE_CHECKING:
|
|
13
|
+
from pathspec import PathSpec
|
|
13
14
|
from codegraphcontext.tools.graph_builder import GraphBuilder
|
|
14
15
|
from codegraphcontext.core.jobs import JobManager
|
|
15
16
|
|
|
17
|
+
from codegraphcontext.core.cgcignore import build_ignore_spec
|
|
18
|
+
from codegraphcontext.tools.indexing.constants import DEFAULT_IGNORE_PATTERNS
|
|
19
|
+
from codegraphcontext.cli.config_manager import get_config_value
|
|
16
20
|
from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger
|
|
17
21
|
|
|
18
22
|
class RepositoryEventHandler(FileSystemEventHandler):
|
|
@@ -23,7 +27,15 @@ class RepositoryEventHandler(FileSystemEventHandler):
|
|
|
23
27
|
to build a baseline and then uses this cached state to perform efficient
|
|
24
28
|
updates when files are changed, created, or deleted.
|
|
25
29
|
"""
|
|
26
|
-
def __init__(
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
graph_builder: "GraphBuilder",
|
|
33
|
+
repo_path: Path,
|
|
34
|
+
debounce_interval=2.0,
|
|
35
|
+
perform_initial_scan: bool = True,
|
|
36
|
+
cgcignore_path: str = None,
|
|
37
|
+
ignore_spec: "PathSpec" = None,
|
|
38
|
+
):
|
|
27
39
|
"""
|
|
28
40
|
Initializes the event handler.
|
|
29
41
|
|
|
@@ -32,12 +44,17 @@ class RepositoryEventHandler(FileSystemEventHandler):
|
|
|
32
44
|
repo_path: The absolute path to the repository directory to watch.
|
|
33
45
|
debounce_interval: The time in seconds to wait for more changes before processing an event.
|
|
34
46
|
perform_initial_scan: Whether to perform an initial scan of the repository.
|
|
47
|
+
cgcignore_path: Optional explicit .cgcignore path from the active context.
|
|
48
|
+
ignore_spec: Optional precompiled ignore spec, useful for tests.
|
|
35
49
|
"""
|
|
36
50
|
super().__init__()
|
|
37
51
|
self.graph_builder = graph_builder
|
|
38
|
-
self.repo_path = repo_path
|
|
52
|
+
self.repo_path = repo_path.resolve()
|
|
39
53
|
self.debounce_interval = debounce_interval
|
|
40
54
|
self.timers = {} # A dictionary to manage debounce timers for file paths.
|
|
55
|
+
self.ignore_root = self.repo_path
|
|
56
|
+
self.ignore_spec = ignore_spec
|
|
57
|
+
self._load_ignore_spec(cgcignore_path)
|
|
41
58
|
|
|
42
59
|
# Caches for the repository's state.
|
|
43
60
|
self.all_file_data = []
|
|
@@ -47,11 +64,65 @@ class RepositoryEventHandler(FileSystemEventHandler):
|
|
|
47
64
|
if perform_initial_scan:
|
|
48
65
|
self._initial_scan()
|
|
49
66
|
|
|
67
|
+
def _load_ignore_spec(self, cgcignore_path: str = None) -> None:
|
|
68
|
+
"""Load .cgcignore rules using the same defaults as repository indexing."""
|
|
69
|
+
if self.ignore_spec is not None:
|
|
70
|
+
return
|
|
71
|
+
try:
|
|
72
|
+
self.ignore_spec, resolved_cgcignore = build_ignore_spec(
|
|
73
|
+
ignore_root=self.ignore_root,
|
|
74
|
+
default_patterns=DEFAULT_IGNORE_PATTERNS,
|
|
75
|
+
explicit_path=cgcignore_path,
|
|
76
|
+
)
|
|
77
|
+
if resolved_cgcignore:
|
|
78
|
+
debug_log(
|
|
79
|
+
f"Watcher using .cgcignore at {resolved_cgcignore} "
|
|
80
|
+
f"(filtering relative to {self.ignore_root})"
|
|
81
|
+
)
|
|
82
|
+
except OSError as e:
|
|
83
|
+
self.ignore_spec = None
|
|
84
|
+
warning_logger(f"Could not load/create watcher .cgcignore: {e}")
|
|
85
|
+
|
|
86
|
+
def _should_ignore(self, path: str | Path) -> bool:
|
|
87
|
+
"""Return True when a path is excluded by .cgcignore or IGNORE_DIRS."""
|
|
88
|
+
path_obj = Path(path).resolve()
|
|
89
|
+
ignore_root = getattr(self, "ignore_root", getattr(self, "repo_path", None))
|
|
90
|
+
|
|
91
|
+
ignore_dirs_str = get_config_value("IGNORE_DIRS") or ""
|
|
92
|
+
if ignore_dirs_str and ignore_root:
|
|
93
|
+
ignore_dirs = {d.strip().lower() for d in ignore_dirs_str.split(",") if d.strip()}
|
|
94
|
+
try:
|
|
95
|
+
parts = {p.lower() for p in path_obj.relative_to(ignore_root).parent.parts}
|
|
96
|
+
if parts.intersection(ignore_dirs):
|
|
97
|
+
return True
|
|
98
|
+
except ValueError:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
ignore_spec = getattr(self, "ignore_spec", None)
|
|
102
|
+
if not ignore_spec or not ignore_root:
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
rel_path = path_obj.relative_to(ignore_root).as_posix()
|
|
107
|
+
except ValueError:
|
|
108
|
+
return False
|
|
109
|
+
return ignore_spec.match_file(rel_path)
|
|
110
|
+
|
|
111
|
+
def _is_supported_code_file(self, path: str | Path) -> bool:
|
|
112
|
+
path_obj = Path(path)
|
|
113
|
+
return path_obj.is_file() and path_obj.suffix in self.graph_builder.parsers and not self._should_ignore(path_obj)
|
|
114
|
+
|
|
115
|
+
def _iter_supported_files(self) -> list[Path]:
|
|
116
|
+
supported_extensions = self.graph_builder.parsers.keys()
|
|
117
|
+
return [
|
|
118
|
+
f for f in self.repo_path.rglob("*")
|
|
119
|
+
if f.is_file() and f.suffix in supported_extensions and not self._should_ignore(f)
|
|
120
|
+
]
|
|
121
|
+
|
|
50
122
|
def _initial_scan(self):
|
|
51
123
|
"""Scans the entire repository, parses all files, and builds the initial graph."""
|
|
52
124
|
info_logger(f"Performing initial scan for watcher: {self.repo_path}")
|
|
53
|
-
|
|
54
|
-
all_files = [f for f in self.repo_path.rglob("*") if f.is_file() and f.suffix in supported_extensions]
|
|
125
|
+
all_files = self._iter_supported_files()
|
|
55
126
|
|
|
56
127
|
# 1. Pre-scan all files to get a global map of where every symbol is defined.
|
|
57
128
|
self.imports_map = self.graph_builder.pre_scan_imports(all_files)
|
|
@@ -126,6 +197,10 @@ class RepositoryEventHandler(FileSystemEventHandler):
|
|
|
126
197
|
"""
|
|
127
198
|
info_logger(f"File change detected (incremental update): {event_path_str}")
|
|
128
199
|
changed_path = Path(event_path_str)
|
|
200
|
+
if self._should_ignore(changed_path):
|
|
201
|
+
debug_log(f"Ignored watcher update based on .cgcignore: {changed_path}")
|
|
202
|
+
return
|
|
203
|
+
|
|
129
204
|
changed_path_str = str(changed_path.resolve())
|
|
130
205
|
supported_extensions = self.graph_builder.parsers.keys()
|
|
131
206
|
|
|
@@ -160,7 +235,7 @@ class RepositoryEventHandler(FileSystemEventHandler):
|
|
|
160
235
|
subset_file_data = []
|
|
161
236
|
for path_str in affected_paths:
|
|
162
237
|
p = Path(path_str)
|
|
163
|
-
if p.exists() and p.suffix in supported_extensions:
|
|
238
|
+
if p.exists() and p.suffix in supported_extensions and not self._should_ignore(p):
|
|
164
239
|
parsed = self.graph_builder.parse_file(self.repo_path, p)
|
|
165
240
|
if "error" not in parsed:
|
|
166
241
|
subset_file_data.append(parsed)
|
|
@@ -177,22 +252,22 @@ class RepositoryEventHandler(FileSystemEventHandler):
|
|
|
177
252
|
|
|
178
253
|
# The following methods are called by the watchdog observer when a file event occurs.
|
|
179
254
|
def on_created(self, event):
|
|
180
|
-
if not event.is_directory and
|
|
255
|
+
if not event.is_directory and self._is_supported_code_file(event.src_path):
|
|
181
256
|
self._debounce(event.src_path, lambda: self._handle_modification(event.src_path))
|
|
182
257
|
|
|
183
258
|
def on_modified(self, event):
|
|
184
|
-
if not event.is_directory and
|
|
259
|
+
if not event.is_directory and self._is_supported_code_file(event.src_path):
|
|
185
260
|
self._debounce(event.src_path, lambda: self._handle_modification(event.src_path))
|
|
186
261
|
|
|
187
262
|
def on_deleted(self, event):
|
|
188
|
-
if not event.is_directory and Path(event.src_path).suffix in self.graph_builder.parsers:
|
|
263
|
+
if not event.is_directory and Path(event.src_path).suffix in self.graph_builder.parsers and not self._should_ignore(event.src_path):
|
|
189
264
|
self._debounce(event.src_path, lambda: self._handle_modification(event.src_path))
|
|
190
265
|
|
|
191
266
|
def on_moved(self, event):
|
|
192
267
|
if not event.is_directory:
|
|
193
|
-
if Path(event.src_path).suffix in self.graph_builder.parsers:
|
|
268
|
+
if Path(event.src_path).suffix in self.graph_builder.parsers and not self._should_ignore(event.src_path):
|
|
194
269
|
self._debounce(event.src_path, lambda: self._handle_modification(event.src_path))
|
|
195
|
-
if Path(event.dest_path).suffix in self.graph_builder.parsers:
|
|
270
|
+
if Path(event.dest_path).suffix in self.graph_builder.parsers and not self._should_ignore(event.dest_path):
|
|
196
271
|
self._debounce(event.dest_path, lambda: self._handle_modification(event.dest_path))
|
|
197
272
|
|
|
198
273
|
|
|
@@ -207,7 +282,7 @@ class CodeWatcher:
|
|
|
207
282
|
self.watched_paths = set() # Keep track of paths already being watched.
|
|
208
283
|
self.watches = {} # Store watch objects to allow unscheduling
|
|
209
284
|
|
|
210
|
-
def watch_directory(self, path: str, perform_initial_scan: bool = True):
|
|
285
|
+
def watch_directory(self, path: str, perform_initial_scan: bool = True, cgcignore_path: str = None):
|
|
211
286
|
"""Schedules a directory to be watched for changes."""
|
|
212
287
|
path_obj = Path(path).resolve()
|
|
213
288
|
path_str = str(path_obj)
|
|
@@ -217,7 +292,12 @@ class CodeWatcher:
|
|
|
217
292
|
return {"message": f"Path already being watched: {path_str}"}
|
|
218
293
|
|
|
219
294
|
# Create a new, dedicated event handler for this specific repository path.
|
|
220
|
-
event_handler = RepositoryEventHandler(
|
|
295
|
+
event_handler = RepositoryEventHandler(
|
|
296
|
+
self.graph_builder,
|
|
297
|
+
path_obj,
|
|
298
|
+
perform_initial_scan=perform_initial_scan,
|
|
299
|
+
cgcignore_path=cgcignore_path,
|
|
300
|
+
)
|
|
221
301
|
|
|
222
302
|
watch = self.observer.schedule(event_handler, path_str, recursive=True)
|
|
223
303
|
self.watches[path_str] = watch
|
|
@@ -864,6 +864,42 @@ class CodeFinder:
|
|
|
864
864
|
"""Find all dependencies and dependents of a module"""
|
|
865
865
|
with self.driver.session() as session:
|
|
866
866
|
repo_filter = "AND file.path STARTS WITH $repo_path" if repo_path else ""
|
|
867
|
+
backend = getattr(self.db_manager, "get_backend_type", lambda: "")()
|
|
868
|
+
|
|
869
|
+
# KuzuDB is stricter about OPTIONAL MATCH variable scoping, and nested
|
|
870
|
+
# repository ownership is already represented in the file path.
|
|
871
|
+
if backend == "kuzudb":
|
|
872
|
+
importers_result = session.run(f"""
|
|
873
|
+
MATCH (file:File)-[imp:IMPORTS]->(module:Module)
|
|
874
|
+
WHERE (module.name = $module_name OR module.full_import_name CONTAINS $module_name) {repo_filter}
|
|
875
|
+
RETURN DISTINCT
|
|
876
|
+
file.path as importer_file_path,
|
|
877
|
+
imp.line_number as import_line_number,
|
|
878
|
+
file.is_dependency as file_is_dependency,
|
|
879
|
+
'' as repository_name
|
|
880
|
+
ORDER BY file_is_dependency ASC, importer_file_path
|
|
881
|
+
LIMIT 50
|
|
882
|
+
""", module_name=module_name, repo_path=repo_path)
|
|
883
|
+
|
|
884
|
+
imports_result = session.run(f"""
|
|
885
|
+
MATCH (file:File)-[:IMPORTS]->(target_module:Module)
|
|
886
|
+
WHERE (target_module.name = $module_name OR target_module.full_import_name CONTAINS $module_name) {repo_filter}
|
|
887
|
+
WITH file, target_module
|
|
888
|
+
MATCH (file)-[imp:IMPORTS]->(other_module:Module)
|
|
889
|
+
WHERE other_module.name <> target_module.name
|
|
890
|
+
RETURN DISTINCT
|
|
891
|
+
other_module.name as imported_module,
|
|
892
|
+
imp.alias as import_alias
|
|
893
|
+
ORDER BY imported_module
|
|
894
|
+
LIMIT 50
|
|
895
|
+
""", module_name=module_name, repo_path=repo_path)
|
|
896
|
+
|
|
897
|
+
return {
|
|
898
|
+
"module_name": module_name,
|
|
899
|
+
"importers": importers_result.data(),
|
|
900
|
+
"imports": imports_result.data()
|
|
901
|
+
}
|
|
902
|
+
|
|
867
903
|
# Find files that import this module (who imports this module)
|
|
868
904
|
importers_result = session.run(f"""
|
|
869
905
|
MATCH (file:File)-[imp:IMPORTS]->(module:Module {{name: $module_name}})
|
|
@@ -278,19 +278,28 @@ class GraphWriter:
|
|
|
278
278
|
js_imports = []
|
|
279
279
|
other_imports = []
|
|
280
280
|
for imp in file_data.get("imports", []):
|
|
281
|
-
if lang
|
|
281
|
+
if lang in {"javascript", "typescript", "tsx"}:
|
|
282
282
|
module_name = imp.get("source")
|
|
283
283
|
if module_name:
|
|
284
284
|
js_imports.append(
|
|
285
285
|
{
|
|
286
286
|
"module_name": module_name,
|
|
287
287
|
"imported_name": imp.get("name", "*"),
|
|
288
|
-
"alias": imp.get("alias"),
|
|
289
|
-
"line_number": imp.get("line_number"),
|
|
288
|
+
"alias": imp.get("alias") or "",
|
|
289
|
+
"line_number": imp.get("line_number") or 0,
|
|
290
290
|
}
|
|
291
291
|
)
|
|
292
292
|
else:
|
|
293
|
-
|
|
293
|
+
module_name = imp.get("name") or imp.get("source") or imp.get("full_import_name")
|
|
294
|
+
if module_name:
|
|
295
|
+
other_imports.append(
|
|
296
|
+
{
|
|
297
|
+
"name": module_name,
|
|
298
|
+
"alias": imp.get("alias") or "",
|
|
299
|
+
"full_import_name": imp.get("full_import_name") or module_name,
|
|
300
|
+
"line_number": imp.get("line_number") or 0,
|
|
301
|
+
}
|
|
302
|
+
)
|
|
294
303
|
|
|
295
304
|
if js_imports:
|
|
296
305
|
session.run(
|
|
@@ -20,6 +20,7 @@ def resolve_function_call(
|
|
|
20
20
|
if called_name in __builtins__:
|
|
21
21
|
return None
|
|
22
22
|
|
|
23
|
+
resolved_called_name = called_name
|
|
23
24
|
resolved_path = None
|
|
24
25
|
full_call = call.get("full_name", called_name)
|
|
25
26
|
base_obj = full_call.split(".")[0] if "." in full_call else None
|
|
@@ -43,6 +44,14 @@ def resolve_function_call(
|
|
|
43
44
|
|
|
44
45
|
if not resolved_path:
|
|
45
46
|
possible_paths = imports_map.get(lookup_name, [])
|
|
47
|
+
if not possible_paths and lookup_name in local_imports:
|
|
48
|
+
imported_name = local_imports[lookup_name]
|
|
49
|
+
alias_paths = imports_map.get(imported_name, [])
|
|
50
|
+
if alias_paths:
|
|
51
|
+
possible_paths = alias_paths
|
|
52
|
+
lookup_name = imported_name
|
|
53
|
+
if called_name == base_obj or called_name == call["name"]:
|
|
54
|
+
resolved_called_name = imported_name
|
|
46
55
|
if len(possible_paths) == 1:
|
|
47
56
|
resolved_path = possible_paths[0]
|
|
48
57
|
elif len(possible_paths) > 1:
|
|
@@ -74,8 +83,8 @@ def resolve_function_call(
|
|
|
74
83
|
if called_name in local_names:
|
|
75
84
|
resolved_path = caller_file_path
|
|
76
85
|
is_unresolved_external = False
|
|
77
|
-
elif
|
|
78
|
-
candidates = imports_map[
|
|
86
|
+
elif resolved_called_name in imports_map and imports_map[resolved_called_name]:
|
|
87
|
+
candidates = imports_map[resolved_called_name]
|
|
79
88
|
for path in candidates:
|
|
80
89
|
for imp_name in local_imports.values():
|
|
81
90
|
if imp_name.replace(".", "/") in path:
|
|
@@ -100,7 +109,7 @@ def resolve_function_call(
|
|
|
100
109
|
"caller_name": caller_name,
|
|
101
110
|
"caller_file_path": caller_file_path,
|
|
102
111
|
"caller_line_number": caller_line_number,
|
|
103
|
-
"called_name":
|
|
112
|
+
"called_name": resolved_called_name,
|
|
104
113
|
"called_file_path": resolved_path,
|
|
105
114
|
"line_number": call["line_number"],
|
|
106
115
|
"args": call.get("args", []),
|
|
@@ -109,7 +118,7 @@ def resolve_function_call(
|
|
|
109
118
|
return {
|
|
110
119
|
"type": "file",
|
|
111
120
|
"caller_file_path": caller_file_path,
|
|
112
|
-
"called_name":
|
|
121
|
+
"called_name": resolved_called_name,
|
|
113
122
|
"called_file_path": resolved_path,
|
|
114
123
|
"line_number": call["line_number"],
|
|
115
124
|
"args": call.get("args", []),
|
|
@@ -51,6 +51,23 @@ DART_QUERIES = {
|
|
|
51
51
|
""",
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
SIGNATURE_TYPES = (
|
|
55
|
+
"function_signature",
|
|
56
|
+
"method_signature",
|
|
57
|
+
"getter_signature",
|
|
58
|
+
"setter_signature",
|
|
59
|
+
"constructor_signature",
|
|
60
|
+
"factory_constructor_signature",
|
|
61
|
+
"operator_signature",
|
|
62
|
+
)
|
|
63
|
+
CONTAINER_TYPES = (
|
|
64
|
+
"class_definition",
|
|
65
|
+
"mixin_declaration",
|
|
66
|
+
"extension_declaration",
|
|
67
|
+
)
|
|
68
|
+
_CALL_PUNCTUATION = {".", "?.", "..", "?..", ";", ",", "(", ")", "[", "]"}
|
|
69
|
+
|
|
70
|
+
|
|
54
71
|
class DartTreeSitterParser:
|
|
55
72
|
"""A Dart-specific parser using tree-sitter, encapsulating language-specific logic."""
|
|
56
73
|
|
|
@@ -65,15 +82,101 @@ class DartTreeSitterParser:
|
|
|
65
82
|
if not node: return ""
|
|
66
83
|
return node.text.decode('utf-8')
|
|
67
84
|
|
|
68
|
-
def _get_parent_context(self, node, types=
|
|
85
|
+
def _get_parent_context(self, node, types=SIGNATURE_TYPES + CONTAINER_TYPES):
|
|
69
86
|
curr = node.parent
|
|
70
87
|
while curr:
|
|
71
88
|
if curr.type in types:
|
|
72
89
|
name_node = curr.child_by_field_name('name')
|
|
90
|
+
if name_node is None:
|
|
91
|
+
for child in curr.children:
|
|
92
|
+
if child.type == "identifier":
|
|
93
|
+
name_node = child
|
|
94
|
+
break
|
|
73
95
|
return self._get_node_text(name_node) if name_node else None, curr.type, curr.start_point[0] + 1
|
|
96
|
+
|
|
97
|
+
# Dart places function_body next to its signature under class_body/program,
|
|
98
|
+
# so calls inside a body cannot find the signature through parent links.
|
|
99
|
+
if curr.type == "function_body":
|
|
100
|
+
parent = curr.parent
|
|
101
|
+
if parent is not None:
|
|
102
|
+
siblings = list(parent.children)
|
|
103
|
+
try:
|
|
104
|
+
idx = siblings.index(curr)
|
|
105
|
+
except ValueError:
|
|
106
|
+
idx = -1
|
|
107
|
+
|
|
108
|
+
for i in range(idx - 1, -1, -1):
|
|
109
|
+
sibling = siblings[i]
|
|
110
|
+
if sibling.type not in types:
|
|
111
|
+
continue
|
|
112
|
+
|
|
113
|
+
target = sibling
|
|
114
|
+
for child in sibling.children:
|
|
115
|
+
if child.type in SIGNATURE_TYPES:
|
|
116
|
+
target = child
|
|
117
|
+
break
|
|
118
|
+
|
|
119
|
+
name_node = target.child_by_field_name("name")
|
|
120
|
+
if name_node is None:
|
|
121
|
+
for child in target.children:
|
|
122
|
+
if child.type == "identifier":
|
|
123
|
+
name_node = child
|
|
124
|
+
break
|
|
125
|
+
if name_node is not None:
|
|
126
|
+
return self._get_node_text(name_node), target.type, target.start_point[0] + 1
|
|
74
127
|
curr = curr.parent
|
|
75
128
|
return None, None, None
|
|
76
129
|
|
|
130
|
+
def _last_identifier_in(self, node):
|
|
131
|
+
"""Return the deepest-last identifier under node."""
|
|
132
|
+
last = None
|
|
133
|
+
for child in node.children:
|
|
134
|
+
if child.type == "identifier":
|
|
135
|
+
last = child
|
|
136
|
+
else:
|
|
137
|
+
deeper = self._last_identifier_in(child)
|
|
138
|
+
if deeper is not None:
|
|
139
|
+
last = deeper
|
|
140
|
+
return last
|
|
141
|
+
|
|
142
|
+
def _name_node_for_call_selector(self, call_node):
|
|
143
|
+
"""Find the receiver/member name paired with a captured argument selector."""
|
|
144
|
+
parent = call_node.parent
|
|
145
|
+
if parent is None:
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
siblings = list(parent.children)
|
|
149
|
+
try:
|
|
150
|
+
idx = siblings.index(call_node)
|
|
151
|
+
except ValueError:
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
for i in range(idx - 1, -1, -1):
|
|
155
|
+
sibling = siblings[i]
|
|
156
|
+
if sibling.type in _CALL_PUNCTUATION:
|
|
157
|
+
continue
|
|
158
|
+
if sibling.type == "identifier":
|
|
159
|
+
return sibling
|
|
160
|
+
name_node = self._last_identifier_in(sibling)
|
|
161
|
+
if name_node is not None:
|
|
162
|
+
return name_node
|
|
163
|
+
break
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
def _has_call_selector_sibling(self, name_node):
|
|
167
|
+
"""Return True if an identifier is a receiver beside a call selector."""
|
|
168
|
+
parent = name_node.parent
|
|
169
|
+
if parent is None:
|
|
170
|
+
return False
|
|
171
|
+
for sibling in parent.children:
|
|
172
|
+
if sibling is name_node:
|
|
173
|
+
continue
|
|
174
|
+
if sibling.type == "selector":
|
|
175
|
+
for child in sibling.children:
|
|
176
|
+
if child.type == "argument_part":
|
|
177
|
+
return True
|
|
178
|
+
return False
|
|
179
|
+
|
|
77
180
|
def _calculate_complexity(self, node):
|
|
78
181
|
complexity_nodes = {
|
|
79
182
|
"if_statement", "for_statement", "while_statement", "do_statement",
|
|
@@ -293,23 +396,14 @@ class DartTreeSitterParser:
|
|
|
293
396
|
|
|
294
397
|
for node, capture_name in execute_query(self.language, query_str, root_node):
|
|
295
398
|
if capture_name in ("name", "call"):
|
|
296
|
-
# Ensure we are at the right node level
|
|
297
|
-
target_node = node
|
|
298
399
|
if capture_name == "call":
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if child.type == 'selector':
|
|
305
|
-
for sub in child.children:
|
|
306
|
-
if sub.type == 'identifier':
|
|
307
|
-
name_node = sub
|
|
308
|
-
break
|
|
309
|
-
if name_node:
|
|
310
|
-
target_node = name_node
|
|
311
|
-
else:
|
|
400
|
+
target_node = self._name_node_for_call_selector(node)
|
|
401
|
+
if target_node is None:
|
|
402
|
+
continue
|
|
403
|
+
else:
|
|
404
|
+
if self._has_call_selector_sibling(node):
|
|
312
405
|
continue
|
|
406
|
+
target_node = node
|
|
313
407
|
|
|
314
408
|
# Deduplicate by start byte
|
|
315
409
|
node_id = target_node.start_byte
|
|
@@ -145,6 +145,7 @@ class PythonTreeSitterParser:
|
|
|
145
145
|
classes = self._find_classes(root_node)
|
|
146
146
|
imports = self._find_imports(root_node)
|
|
147
147
|
function_calls = self._find_calls(root_node)
|
|
148
|
+
self._attach_module_context(functions, function_calls, root_node, index_source)
|
|
148
149
|
variables = self._find_variables(root_node)
|
|
149
150
|
|
|
150
151
|
return {
|
|
@@ -165,6 +166,41 @@ class PythonTreeSitterParser:
|
|
|
165
166
|
os.remove(temp_py_file)
|
|
166
167
|
info_logger(f"Removed temporary file: {temp_py_file}")
|
|
167
168
|
|
|
169
|
+
def _attach_module_context(self, functions, function_calls, root_node, index_source: bool = False):
|
|
170
|
+
"""Represent module-level executable code as Python's <module> frame."""
|
|
171
|
+
module_level_calls = [
|
|
172
|
+
call for call in function_calls
|
|
173
|
+
if not call.get("context") or call["context"][0] is None
|
|
174
|
+
]
|
|
175
|
+
if not module_level_calls:
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
has_module_frame = any(
|
|
179
|
+
func.get("name") == "<module>" and func.get("line_number") == 1
|
|
180
|
+
for func in functions
|
|
181
|
+
)
|
|
182
|
+
if not has_module_frame:
|
|
183
|
+
module_func = {
|
|
184
|
+
"name": "<module>",
|
|
185
|
+
"line_number": 1,
|
|
186
|
+
"end_line": root_node.end_point[0] + 1,
|
|
187
|
+
"args": [],
|
|
188
|
+
"cyclomatic_complexity": 1,
|
|
189
|
+
"context": None,
|
|
190
|
+
"context_type": "module",
|
|
191
|
+
"class_context": None,
|
|
192
|
+
"decorators": [],
|
|
193
|
+
"lang": self.language_name,
|
|
194
|
+
"is_dependency": False,
|
|
195
|
+
}
|
|
196
|
+
if index_source:
|
|
197
|
+
module_func["source"] = self._get_node_text(root_node)
|
|
198
|
+
module_func["docstring"] = self._get_docstring(root_node)
|
|
199
|
+
functions.append(module_func)
|
|
200
|
+
|
|
201
|
+
for call in module_level_calls:
|
|
202
|
+
call["context"] = ("<module>", "module", 1)
|
|
203
|
+
|
|
168
204
|
def _find_lambda_assignments(self, root_node, index_source: bool = False):
|
|
169
205
|
functions = []
|
|
170
206
|
query_str = PY_QUERIES.get('lambda_assignments')
|
|
@@ -573,4 +609,4 @@ def pre_scan_python(files: list[Path], parser_wrapper) -> dict:
|
|
|
573
609
|
finally:
|
|
574
610
|
if temp_py_file and temp_py_file.exists():
|
|
575
611
|
os.remove(temp_py_file)
|
|
576
|
-
return imports_map
|
|
612
|
+
return imports_map
|
|
@@ -226,9 +226,11 @@ class ScipIndexParser:
|
|
|
226
226
|
"""
|
|
227
227
|
try:
|
|
228
228
|
from . import scip_pb2 # type: ignore
|
|
229
|
-
except
|
|
229
|
+
except Exception as e:
|
|
230
230
|
error_logger(
|
|
231
|
-
"
|
|
231
|
+
"Failed to import codegraphcontext.tools.scip_pb2. "
|
|
232
|
+
"Ensure protobuf>=3.20,<3.21 is installed in the CodeGraphContext environment. "
|
|
233
|
+
f"Original error: {e}"
|
|
232
234
|
)
|
|
233
235
|
return {}
|
|
234
236
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codegraphcontext
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.5
|
|
4
4
|
Summary: An MCP server that indexes local code into a graph database to provide context to AI assistants.
|
|
5
5
|
Author-email: Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -52,8 +52,9 @@ Requires-Dist: nbconvert>=7.16.6
|
|
|
52
52
|
Requires-Dist: pathspec>=0.12.1
|
|
53
53
|
Requires-Dist: falkordb>=0.1.0
|
|
54
54
|
Requires-Dist: requests>=2.28.0
|
|
55
|
+
Requires-Dist: protobuf<3.21,>=3.20
|
|
55
56
|
Requires-Dist: falkordblite>=0.1.0; sys_platform != "win32" and python_version >= "3.12"
|
|
56
|
-
Requires-Dist:
|
|
57
|
+
Requires-Dist: real_ladybug; sys_platform == "win32" or (sys_platform != "win32" and python_version >= "3.10")
|
|
57
58
|
Requires-Dist: fastapi>=0.100.0
|
|
58
59
|
Requires-Dist: uvicorn>=0.22.0
|
|
59
60
|
Provides-Extra: parsing
|
|
@@ -165,7 +166,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
|
|
|
165
166
|
---
|
|
166
167
|
|
|
167
168
|
## Project Details
|
|
168
|
-
- **Version:** 0.4.
|
|
169
|
+
- **Version:** 0.4.5
|
|
169
170
|
- **Authors:** Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
|
|
170
171
|
- **License:** MIT License (See [LICENSE](LICENSE) for details)
|
|
171
172
|
- **Website:** [CodeGraphContext](http://codegraphcontext.vercel.app/)
|
|
@@ -228,7 +229,7 @@ CodeGraphContext supports multiple graph database backends to suit your environm
|
|
|
228
229
|
| **Setup** | Zero-config / Embedded | Zero-config / In-process | Docker / External |
|
|
229
230
|
| **Platform** | **All (Windows Native, macOS, Linux)** | Unix-only (Linux/macOS/WSL) | All Platforms |
|
|
230
231
|
| **Use Case** | Desktop, IDE, Local development | Specialized Unix development | Enterprise, Massive graphs |
|
|
231
|
-
| **Requirement**| `pip install
|
|
232
|
+
| **Requirement**| `pip install real_ladybug` | `pip install falkordblite` | Neo4j Server / Docker |
|
|
232
233
|
| **Speed** | ⚡ Extremely Fast | ⚡ Fast | 🚀 Scalable |
|
|
233
234
|
| **Persistence**| Yes (to disk) | Yes (to disk) | Yes (to disk) |
|
|
234
235
|
|
|
@@ -339,7 +340,7 @@ Use CodeGraphContext as an **MCP server** for AI assistants:
|
|
|
339
340
|
|
|
340
341
|
2. **Database Setup (Automatic)**
|
|
341
342
|
|
|
342
|
-
- **KùzuDB (default on Windows):** Runs natively on Windows, macOS, and Linux. On Windows it is the usual embedded choice; `pip install
|
|
343
|
+
- **KùzuDB (default on Windows):** Runs natively on Windows, macOS, and Linux. On Windows it is the usual embedded choice; `pip install real_ladybug` if needed.
|
|
343
344
|
- **FalkorDB Lite (typical default on Unix):** When Python 3.12+ and `falkordblite` are available on Unix/macOS/WSL, the embedded backend prefers FalkorDB Lite; otherwise KùzuDB is used.
|
|
344
345
|
- **Neo4j (Alternative):** To use Neo4j instead, or if you prefer a server-based approach, run: `cgc neo4j setup`
|
|
345
346
|
|
|
@@ -4,30 +4,30 @@ codegraphcontext/prompts.py,sha256=E5P55paM0oHfBcNVfxkxpXRGZnya1kr_mKDg9i49FwM,6
|
|
|
4
4
|
codegraphcontext/server.py,sha256=AMe3BVvon0cNE1uyPB-E2a0XedBTWqSiIZv19KEPZh4,19120
|
|
5
5
|
codegraphcontext/tool_definitions.py,sha256=kDRI9WrfkV9TienmYvetGlimNdb1AdiOWuuYid_ZtAk,13177
|
|
6
6
|
codegraphcontext/cli/__init__.py,sha256=v6CMDVKM5d_sXn3S5nZNf0phXn0IdrnhLazUoen9k9w,38
|
|
7
|
-
codegraphcontext/cli/cli_helpers.py,sha256
|
|
7
|
+
codegraphcontext/cli/cli_helpers.py,sha256=-_7N4rCZuunyDiUsD1G1ik9MS40JWLnP5zItmYxYtuk,32993
|
|
8
8
|
codegraphcontext/cli/config_manager.py,sha256=s13JltwsmHF0jWK65XFD7gM3OIhDNPsBWpm2qNPZrkU,38522
|
|
9
|
-
codegraphcontext/cli/main.py,sha256=
|
|
9
|
+
codegraphcontext/cli/main.py,sha256=_dXQI_PQkqTD_P-iaDfRc4Iz9kuLWkPYg_ZxX3c6YHM,94587
|
|
10
10
|
codegraphcontext/cli/registry_commands.py,sha256=mAJDYw1XUbzhj_SMM9PgO4MzECQj0OR3LU54x-OpPeU,15947
|
|
11
11
|
codegraphcontext/cli/setup_macos.py,sha256=Xjlv_9jk9qv8Gh7stpH1pvlalzC0Fg176y7jc5G1zh0,3575
|
|
12
12
|
codegraphcontext/cli/setup_wizard.py,sha256=jrh8504YwKAp-7b-gOW4fwRTD_yxlBYaVPfRk0TYlvQ,42573
|
|
13
13
|
codegraphcontext/cli/visualizer.py,sha256=YgqXA-o1l3qRABat_s-wT0gTM_rmHmOhpUtxS7Rhcfk,1861
|
|
14
|
-
codegraphcontext/core/__init__.py,sha256=
|
|
14
|
+
codegraphcontext/core/__init__.py,sha256=fOkVEnsA7ikCn3xAhGGSjAokzVn4WgKWJMwBYWDZdEY,7269
|
|
15
15
|
codegraphcontext/core/bundle_registry.py,sha256=WR0apx71czZLFrTP7a8k3l0vXYsDGyZKn-qzRTzuu7o,7866
|
|
16
16
|
codegraphcontext/core/cgc_bundle.py,sha256=lqhOQQegm6fCmdndcag7eoS0DV5KNrF8Sm-2VNZ5HR4,35070
|
|
17
17
|
codegraphcontext/core/cgcignore.py,sha256=uoydGpSR8LVdWYS40C3o0YFkV0s_v9IouxPLF_GsTxY,4172
|
|
18
18
|
codegraphcontext/core/database.py,sha256=2UL8AyE6vX5mVHg1zcD74TYEREmddhKzN7Bjy2THQwM,11435
|
|
19
19
|
codegraphcontext/core/database_falkordb.py,sha256=7jBLK_Y4u4ozeVV59vZr9E90Z3XZ_Cq6p4DUyq3WNnc,19741
|
|
20
20
|
codegraphcontext/core/database_falkordb_remote.py,sha256=aMiuJTB_-2rBUpbAmX8ElZiZrYZbOXK-On3ncgMCyhY,7118
|
|
21
|
-
codegraphcontext/core/database_kuzu.py,sha256=
|
|
21
|
+
codegraphcontext/core/database_kuzu.py,sha256=g_ceVfg0GZUU8UNzvqwI8yL8ETJ9VmHBCUmHbpgzaJQ,32492
|
|
22
22
|
codegraphcontext/core/falkor_worker.py,sha256=bMcTOac6e8IzSPjCd-YulGVh-S7QsNtXs2c8hx6M6gk,4958
|
|
23
23
|
codegraphcontext/core/jobs.py,sha256=d6v_IERdEcDlIsz3CW3p0QMp3N-6dgQICs3FZRPgPgU,4809
|
|
24
|
-
codegraphcontext/core/watcher.py,sha256=
|
|
24
|
+
codegraphcontext/core/watcher.py,sha256=XcBDALfUx3ypMmVPmMcjq4q9khLLVQkNmO-IiNAAbj8,16508
|
|
25
25
|
codegraphcontext/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
26
|
codegraphcontext/tools/advanced_language_query_tool.py,sha256=APtC-KSkXXSrVLwiw3kgi6Q-xaqXl6skLWHPyuNh358,3670
|
|
27
|
-
codegraphcontext/tools/code_finder.py,sha256=
|
|
27
|
+
codegraphcontext/tools/code_finder.py,sha256=hS3_rVxmIplDJyazMNrwQVFTvDvFXg36UekDq3CDYaA,62345
|
|
28
28
|
codegraphcontext/tools/graph_builder.py,sha256=jiHHI1XIvmDJ8-BlWPe_WBNEVtXBUCfwhHTkUka-sAg,13219
|
|
29
29
|
codegraphcontext/tools/package_resolver.py,sha256=KtbdMReTezszjdsqYniL-Xb-QUsrAJWtf1NSiyIPkLI,18704
|
|
30
|
-
codegraphcontext/tools/scip_indexer.py,sha256=
|
|
30
|
+
codegraphcontext/tools/scip_indexer.py,sha256=bVMkSfvemeXciS6XiXrC5ZgFz33YiW80x6OASfU9zwQ,20169
|
|
31
31
|
codegraphcontext/tools/scip_pb2.py,sha256=dwOMNKlu6VyLq5h8kTPZRDqxrwfVL8yw7I7ziokFG48,98229
|
|
32
32
|
codegraphcontext/tools/system.py,sha256=goQOs1A9gvd7SvDPVZB6Jd0DRJKQmjEkn-uiTE40VNM,6046
|
|
33
33
|
codegraphcontext/tools/tree_sitter_parser.py,sha256=x8gDBCQze65r97DwlIovflg02wrY5SKm4nCVxxIja2E,4500
|
|
@@ -46,14 +46,14 @@ codegraphcontext/tools/indexing/schema.py,sha256=Lyzc_06fJx7eMb7a1OiSvEJGzkyXuUX
|
|
|
46
46
|
codegraphcontext/tools/indexing/schema_contract.py,sha256=0705pzAw3h9tO9EIfRbdXl5_WudY2l6drE6zX843120,1054
|
|
47
47
|
codegraphcontext/tools/indexing/scip_pipeline.py,sha256=Y9pvJM4HfbrDQC1nFj7Dgil42nVOwjoNarfIvk7O-vA,5362
|
|
48
48
|
codegraphcontext/tools/indexing/persistence/__init__.py,sha256=-fSSq1MMR2TB0iuzT80cxGAoKs55mzdYkduwyIzXCh0,59
|
|
49
|
-
codegraphcontext/tools/indexing/persistence/writer.py,sha256=
|
|
49
|
+
codegraphcontext/tools/indexing/persistence/writer.py,sha256=41bY9inZKEEtchEP8tYaxK0ciH-oGlKm6k1XDCgb79Q,33538
|
|
50
50
|
codegraphcontext/tools/indexing/resolution/__init__.py,sha256=gsnYNNawrafAyBCKhG7SOF2Um5GblZ-rhgz6S5J2v1s,249
|
|
51
|
-
codegraphcontext/tools/indexing/resolution/calls.py,sha256=
|
|
51
|
+
codegraphcontext/tools/indexing/resolution/calls.py,sha256=0nxb7Em2A6LwPl3DjA7cXADvAC0NRSliD-nT2ssbCgI,8256
|
|
52
52
|
codegraphcontext/tools/indexing/resolution/inheritance.py,sha256=NZsYDwJpWoOdRSMNl8bPrBgP07iaMD5z1wgm2ELel0I,3292
|
|
53
53
|
codegraphcontext/tools/languages/c.py,sha256=mrXQWEvMtzLVElATYNZ7VThNk1ZNZdw2UV8i6r2y2y4,22291
|
|
54
54
|
codegraphcontext/tools/languages/cpp.py,sha256=aXBF_MX43PpRTr5U7UBcn5mZvP6fjP4Q8g21JuCho38,25761
|
|
55
55
|
codegraphcontext/tools/languages/csharp.py,sha256=0ZIpV531i8yhz4vktaKkzbHDg-TCxgSZPC69SBkmfYU,22594
|
|
56
|
-
codegraphcontext/tools/languages/dart.py,sha256=
|
|
56
|
+
codegraphcontext/tools/languages/dart.py,sha256=qt6NkN1IZZWQCcT6lpUqDdpBScXI498dJNjS1ZQPf3k,18705
|
|
57
57
|
codegraphcontext/tools/languages/elixir.py,sha256=mFsMvi_5ZlCsrB5QQ7Kklj94tLo3D6aFU7ukuhGmGSI,18815
|
|
58
58
|
codegraphcontext/tools/languages/go.py,sha256=cBfeM3Qt9W73KKb39VPhS6LlcWLdVJpvrAnnUeSiH4E,20456
|
|
59
59
|
codegraphcontext/tools/languages/haskell.py,sha256=LboJms-iUZVBY32Q5GvWlyHCGXT4ov05JVO-zbdOFlQ,17285
|
|
@@ -62,7 +62,7 @@ codegraphcontext/tools/languages/javascript.py,sha256=XB-icOtzIERAtackWWmaayGAWR
|
|
|
62
62
|
codegraphcontext/tools/languages/kotlin.py,sha256=6HvrClCgCNiGJnTjDhyHtuAy2PyGZwJN2Mx1zOA6T2c,28051
|
|
63
63
|
codegraphcontext/tools/languages/perl.py,sha256=EHFpcGO2NLPPxyx4s0kmtqQ5_ODFLx7QHFDIvwlRb84,10004
|
|
64
64
|
codegraphcontext/tools/languages/php.py,sha256=mqCoahKTrKzc0lsE-1K3S_UBT-pyIMi8_CrCJ2kHCUg,23350
|
|
65
|
-
codegraphcontext/tools/languages/python.py,sha256=
|
|
65
|
+
codegraphcontext/tools/languages/python.py,sha256=abyN-POHLoA2PLkk8NikDgAi3368_II4Lk0-wNjky4Y,27189
|
|
66
66
|
codegraphcontext/tools/languages/ruby.py,sha256=sd803ZpfQbsWuqXlUvX4UShM2NkkgUf9xOkl160X8oM,21993
|
|
67
67
|
codegraphcontext/tools/languages/rust.py,sha256=TD7H4SsSsPWJnIUoThkA8gxIKnQhqL6_cVGnAaOBeEE,11991
|
|
68
68
|
codegraphcontext/tools/languages/scala.py,sha256=-seQcdX0UJfDPiyhgf4kg6kDXJsSNcfVH472aSv1dH8,23003
|
|
@@ -124,9 +124,9 @@ codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm,sha256=hRVATc7tOOHthq
|
|
|
124
124
|
codegraphcontext/viz/dist/wasm/tree-sitter.wasm,sha256=CCeVuI_hXktkBD-DW01xYPv5XoAYVRIqzJUJI5te-RY,196763
|
|
125
125
|
codegraphcontext/viz/dist/wasm/web-tree-sitter.js,sha256=DIaCNqRylrT_PBVw8g4ImeSnhP9uXNe_ycOlUiVGPko,153666
|
|
126
126
|
codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm,sha256=CCeVuI_hXktkBD-DW01xYPv5XoAYVRIqzJUJI5te-RY,196763
|
|
127
|
-
codegraphcontext-0.4.
|
|
128
|
-
codegraphcontext-0.4.
|
|
129
|
-
codegraphcontext-0.4.
|
|
130
|
-
codegraphcontext-0.4.
|
|
131
|
-
codegraphcontext-0.4.
|
|
132
|
-
codegraphcontext-0.4.
|
|
127
|
+
codegraphcontext-0.4.5.dist-info/licenses/LICENSE,sha256=rh8M-bJpQYJnw2vtRVgt0t7piMZXh5QzaKeNEI0vqqA,1061
|
|
128
|
+
codegraphcontext-0.4.5.dist-info/METADATA,sha256=IJH89toSZECngKn505IurSIunzimNBsqsT2Dy_n0MWU,22355
|
|
129
|
+
codegraphcontext-0.4.5.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
130
|
+
codegraphcontext-0.4.5.dist-info/entry_points.txt,sha256=LCxWCWMshdvYGoHBPuQZ8C-e4CiNSHCLXofrNSGHkoE,103
|
|
131
|
+
codegraphcontext-0.4.5.dist-info/top_level.txt,sha256=CBgc6LAPZIO5FS0nSYYkylDifHsZTIqw3Gf5UwDxeGI,17
|
|
132
|
+
codegraphcontext-0.4.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|