///|
pub(all) struct GraphEdge {
from : String
to : String
reference : String
} derive(Debug, Eq, ToJson)
///|
pub(all) struct BundleGraph {
nodes : Int
edges : Int
dangling : Int
node_keys : Array[String]
edge_list : Array[GraphEdge]
} derive(Debug, Eq, ToJson)
///|
fn bundle_graph_resources(bundle : Json) -> Array[Json] {
field_array(bundle, "entry")
.unwrap_or([])
.filter_map(fn(entry) { object_get(entry, "resource") })
}
///|
pub fn bundle_graph(bundle : Json) -> BundleGraph {
let resources = bundle_graph_resources(bundle)
let nodes : Map[String, Json] = Map([])
let node_keys : Array[String] = []
for resource in resources {
match bundle_reference_key(resource) {
Some(key) =>
if !nodes.contains(key) {
nodes[key] = resource
node_keys.push(key)
}
None => ()
}
}
let edge_list : Array[GraphEdge] = []
let dangling_keys : Map[String, Bool] = Map([])
for resource in resources {
match bundle_reference_key(resource) {
None => ()
Some(from) =>
for reference in query_resource_references(resource) {
if nodes.contains(reference) {
edge_list.push({ from, to: reference, reference })
} else {
dangling_keys[reference] = true
}
}
}
}
{
nodes: node_keys.length(),
edges: edge_list.length(),
dangling: dangling_keys.length(),
node_keys,
edge_list,
}
}
///|
pub fn bundle_graph_node_keys(bundle : Json) -> Array[String] {
bundle_graph(bundle).node_keys
}
///|
pub fn bundle_graph_edges(bundle : Json) -> Array[GraphEdge] {
bundle_graph(bundle).edge_list
}
///|
pub fn graph_outgoing_edges(
graph : BundleGraph,
key : String,
) -> Array[GraphEdge] {
graph.edge_list.filter(fn(edge) { edge.from == key })
}
///|
pub fn graph_incoming_edges(
graph : BundleGraph,
key : String,
) -> Array[GraphEdge] {
graph.edge_list.filter(fn(edge) { edge.to == key })
}
///|
pub fn bundle_outgoing_references(bundle : Json, key : String) -> Array[String] {
graph_outgoing_edges(bundle_graph(bundle), key).map(fn(edge) { edge.to })
}
///|
pub fn bundle_incoming_references(bundle : Json, key : String) -> Array[String] {
graph_incoming_edges(bundle_graph(bundle), key).map(fn(edge) { edge.from })
}
///|
pub fn bundle_dangling_references(bundle : Json) -> Array[String] {
let stats = analyze_bundle(bundle)
stats.broken_references
}
///|
pub fn bundle_graph_is_acyclic(bundle : Json) -> Bool {
let graph = bundle_graph(bundle)
for edge in graph.edge_list {
if edge.from == edge.to {
return false
}
}
true
}
///|
pub fn bundle_graph_summary(bundle : Json) -> String {
let graph = bundle_graph(bundle)
"nodes=\{graph.nodes} edges=\{graph.edges} dangling=\{graph.dangling}"
}
///|
pub fn bundle_graph_degree(bundle : Json, key : String) -> (Int, Int) {
let graph = bundle_graph(bundle)
(
graph_outgoing_edges(graph, key).length(),
graph_incoming_edges(graph, key).length(),
)
}