use serde_json::{Value, json};
use super::{Labels, state_root};
use crate::canonical::canonical_bytes;
use crate::document::{Document, EdgeTarget, SubjectRole};
use crate::hash::{DocumentHashes, Views};
pub(super) fn render(
document: &Document,
hashes: &DocumentHashes,
views: &Views,
labels: &Labels,
) -> Vec<u8> {
let mut nodes = Vec::new();
document.walk(&mut |node| {
if let Some(id) = node.id() {
nodes.push(json!({
"key": id.key(),
"label": labels.label(id),
"kind": id.kind().as_str(),
"view": views.nodes[&id],
}));
}
});
let decisions: Vec<Value> = views
.decisions
.iter()
.map(|(id, view)| json!({ "key": id.key(), "label": labels.label(*id), "view": view }))
.collect();
let mut edges: Vec<(Vec<u8>, Value)> = document
.edges
.iter()
.map(|edge| {
let target = match edge.target() {
EdgeTarget::Element(element) => json!(element.key()),
EdgeTarget::Former(label) => json!({ "formerLabel": label }),
};
let edge = json!({
"type": edge.kind().as_str(),
"source": edge.source().key(),
"target": target,
"role": edge.role().map(SubjectRole::as_str),
});
(canonical_bytes(&edge), edge)
})
.collect();
edges.sort_by(|left, right| left.0.cmp(&right.0));
let registry = |entries: Vec<(String, String, String)>| {
let mut entries = entries;
entries.sort();
entries
.into_iter()
.map(|(name, key, definition)| json!({ "key": key, "name": name, "definition": definition }))
.collect::<Vec<_>>()
};
let tags = registry(
document
.tags
.iter()
.map(|e| {
(
e.name.to_string(),
e.id.key().to_string(),
e.definition.clone(),
)
})
.collect(),
);
let categories = registry(
document
.categories
.iter()
.map(|e| {
(
e.name.to_string(),
e.id.key().to_string(),
e.definition.clone(),
)
})
.collect(),
);
canonical_bytes(&json!({
"format": crate::FORMAT,
"stateRoot": state_root(hashes),
"nodes": nodes,
"decisions": decisions,
"edges": edges.into_iter().map(|(_, edge)| edge).collect::<Vec<_>>(),
"tags": tags,
"categories": categories,
}))
}