use pedant_graph::{
CodeGraph, GraphEdgeOrigin, GraphNode, GraphNodeKind, GraphNodeLocation, GraphReference,
};
use pedant_types::SourceSpan;
pub fn nodes(graph: &CodeGraph) -> Vec<String> {
graph.nodes().iter().map(node).collect()
}
pub fn node(node: &GraphNode) -> String {
format!(
"{}|{:?}|{}|{}|{}",
node.id().index(),
node.language(),
node.name(),
node_kind(node.kind()),
location(node.location()),
)
}
pub fn node_kind(kind: &GraphNodeKind) -> String {
match kind {
GraphNodeKind::File => "file".to_owned(),
GraphNodeKind::Container { level } => format!("container:{level}"),
GraphNodeKind::Function { declaration } => format!("function:{declaration}"),
GraphNodeKind::Type { declaration } => format!("type:{declaration}"),
GraphNodeKind::Value { declaration } => format!("value:{declaration}"),
}
}
pub fn file_path(node: &GraphNode) -> Option<&str> {
match node.location() {
Some(GraphNodeLocation::File { path }) => Some(path),
_ => None,
}
}
pub fn is_file(node: &GraphNode) -> bool {
file_path(node).is_some()
}
pub fn is_definition(node: &GraphNode) -> bool {
matches!(node.location(), Some(GraphNodeLocation::Span { .. }))
}
pub fn location(location: Option<&GraphNodeLocation>) -> String {
match location {
None => "-".to_owned(),
Some(GraphNodeLocation::File { path }) => format!("file:{path}"),
Some(GraphNodeLocation::Span { file, span }) => {
format!("span:{}@{}", file.index(), coordinates(span))
}
}
}
pub fn coordinates(span: &SourceSpan) -> String {
format!(
"{}:{}:{}-{}:{}",
span.file(),
span.start().line(),
span.start().column(),
span.end().line(),
span.end().column(),
)
}
pub fn containment(graph: &CodeGraph) -> Vec<String> {
graph
.containment()
.iter()
.map(|edge| format!("{}>{}", edge.parent().index(), edge.child().index()))
.collect()
}
pub fn reference(reference: &GraphReference) -> String {
format!(
"{}|{}|{}",
reference_site(reference),
joined(reference.gaps().iter().map(|gap| format!("{gap:?}"))),
joined(
reference
.edges()
.iter()
.map(|edge| edge.index().to_string())
),
)
}
pub fn origin(origin: &GraphEdgeOrigin) -> String {
match origin {
GraphEdgeOrigin::Reference { reference } => format!("reference:{}", reference.index()),
GraphEdgeOrigin::Dependency { evidence } => format!(
"dependency:{}:{:?}:{}",
evidence.alias(),
evidence.kind(),
evidence.predicate().unwrap_or("-"),
),
}
}
pub fn reference_sites(graph: &CodeGraph) -> Vec<String> {
graph.references().iter().map(reference_site).collect()
}
pub fn reference_site(reference: &GraphReference) -> String {
format!(
"{}|{}|{:?}|{:?}|{}|{}",
reference.id().index(),
reference.source().index(),
reference.language(),
reference.kind(),
reference.text(),
coordinates(reference.span()),
)
}
fn joined(values: impl Iterator<Item = String>) -> String {
let collected: Vec<String> = values.collect();
match collected.is_empty() {
true => "-".to_owned(),
false => collected.join(","),
}
}