better format
This commit is contained in:
+78
-7
@@ -16,16 +16,23 @@ class LocalGraph:
|
||||
# --- Creation ---
|
||||
def add_node(self, node_id: str | dict, **attrs):
|
||||
"""
|
||||
If a dict is passed instead of a plain string, build the node_id
|
||||
as: <lang>::<type>::<file>::<name>
|
||||
Enhanced add_node that can return the generated node_id
|
||||
"""
|
||||
if isinstance(node_id, dict):
|
||||
lang = node_id.get("lang", "unknown")
|
||||
kind = node_id.get("type", "Symbol")
|
||||
name = node_id.get("name", "unknown")
|
||||
fpath = node_id.get("file", "")
|
||||
lang = node_id.get("lang", "unknown")
|
||||
kind = node_id.get("type", "Symbol")
|
||||
name = node_id.get("name", "unknown")
|
||||
fpath = node_id.get("file", "")
|
||||
node_id = f"{lang}::{kind}::{fpath}::{name}"
|
||||
self.graph.add_node(node_id, **attrs)
|
||||
|
||||
# Merge any additional attributes
|
||||
final_attrs = {}
|
||||
if isinstance(node_id, dict):
|
||||
final_attrs.update(node_id)
|
||||
final_attrs.update(attrs)
|
||||
|
||||
self.graph.add_node(node_id, **final_attrs)
|
||||
return node_id # Return the ID for reference
|
||||
|
||||
def _add_import_edges(self, src: str, imports: list[str]):
|
||||
for imp in imports:
|
||||
@@ -213,3 +220,67 @@ class LocalGraph:
|
||||
except Exception:
|
||||
# swallow; graph should remain usable
|
||||
pass
|
||||
|
||||
def get_node_relationships(self, node_id: str) -> dict:
|
||||
"""
|
||||
Get comprehensive relationships for a node in a structured format.
|
||||
Returns: {
|
||||
'outgoing': [(neighbor_id, edge_type, neighbor_data)],
|
||||
'incoming': [(predecessor_id, edge_type, predecessor_data)],
|
||||
'cross_file': list of cross-file relationships,
|
||||
'same_file': list of same-file relationships
|
||||
}
|
||||
"""
|
||||
if node_id not in self.graph:
|
||||
return {}
|
||||
|
||||
result = {
|
||||
'outgoing': [],
|
||||
'incoming': [],
|
||||
'cross_file': [],
|
||||
'same_file': []
|
||||
}
|
||||
|
||||
node_file = self.graph.nodes[node_id].get('file', '')
|
||||
|
||||
# Outgoing relationships
|
||||
for neighbor_id in self.graph.successors(node_id):
|
||||
edge_data = self.graph.edges[node_id, neighbor_id]
|
||||
neighbor_data = self.graph.nodes[neighbor_id]
|
||||
edge_type = edge_data.get('type', 'related')
|
||||
|
||||
result['outgoing'].append((neighbor_id, edge_type, neighbor_data))
|
||||
|
||||
# Cross-file classification
|
||||
neighbor_file = neighbor_data.get('file', '')
|
||||
rel_info = f"{edge_type}:{neighbor_data.get('type', '')}:{neighbor_data.get('name', '')}"
|
||||
|
||||
if neighbor_file and neighbor_file != node_file:
|
||||
result['cross_file'].append(f"{rel_info}@{neighbor_file}")
|
||||
else:
|
||||
result['same_file'].append(rel_info)
|
||||
|
||||
# Incoming relationships
|
||||
for predecessor_id in self.graph.predecessors(node_id):
|
||||
edge_data = self.graph.edges[predecessor_id, node_id]
|
||||
predecessor_data = self.graph.nodes[predecessor_id]
|
||||
edge_type = edge_data.get('type', 'related')
|
||||
|
||||
result['incoming'].append((predecessor_id, edge_type, predecessor_data))
|
||||
|
||||
return result
|
||||
|
||||
def get_file_entities(self, file_path: str) -> list:
|
||||
"""Get all entities in a file in compact format."""
|
||||
file_node_id = f"file::{file_path}"
|
||||
if file_node_id not in self.graph:
|
||||
return []
|
||||
|
||||
entities = []
|
||||
for neighbor_id, neighbor_data in self.neighbors(file_node_id):
|
||||
entity_type = neighbor_data.get('type', '')
|
||||
entity_name = neighbor_data.get('name', '')
|
||||
if entity_type and entity_name:
|
||||
entities.append(f"{entity_type}:{entity_name}")
|
||||
|
||||
return entities
|
||||
|
||||
Reference in New Issue
Block a user