use std::collections::BTreeMap;
use zenith_core::{ComponentDef, Document, InstanceNode, LibraryDef, Node, ProvenanceDef};
use super::add::{
AddError, AddOutcome, collect_all_ids, copy_assets, copy_styles, copy_tokens,
load_pack_document, px, target_component_id, unique_id, unknown_package_error,
};
use super::registry::LibraryPack;
pub fn materialize(
target: &mut Document,
packs: &[LibraryPack],
pkg_id: &str,
item: &str,
page_id: &str,
id_base: &str,
at: (f64, f64),
) -> Result<AddOutcome, AddError> {
let (at_x, at_y) = at;
let pack = packs
.iter()
.find(|p| p.id == pkg_id)
.ok_or_else(|| unknown_package_error(pkg_id, packs))?;
let pack_doc = load_pack_document(pack)?;
let comp = pack_doc
.components
.iter()
.find(|c| c.id == item)
.ok_or_else(|| {
let available: Vec<&str> = pack_doc.components.iter().map(|c| c.id.as_str()).collect();
AddError::new(format!(
"unknown item '{}' in package '{}' (available: {})",
item,
pkg_id,
if available.is_empty() {
"none".to_owned()
} else {
available.join(", ")
}
))
})?;
if !target.body.pages.iter().any(|p| p.id == page_id) {
let available: Vec<&str> = target.body.pages.iter().map(|p| p.id.as_str()).collect();
return Err(AddError::new(format!(
"page '{}' not found in target document (available: {})",
page_id,
if available.is_empty() {
"none".to_owned()
} else {
available.join(", ")
}
)));
}
let mut warnings: Vec<String> = Vec::new();
let comp_id = target_component_id(pkg_id, item);
if !target.components.iter().any(|c| c.id == comp_id) {
target.components.push(ComponentDef {
id: comp_id.clone(),
children: comp.children.clone(),
source_span: None,
});
}
if target.tokens.format.is_empty() {
target.tokens.format = pack_doc.tokens.format.clone();
}
copy_tokens(
&pack_doc.tokens.tokens,
&mut target.tokens.tokens,
&mut warnings,
);
copy_styles(
&pack_doc.styles.styles,
&mut target.styles.styles,
&mut warnings,
);
copy_assets(
&pack_doc.assets.assets,
&mut target.assets.assets,
&mut warnings,
);
let mut all_ids = collect_all_ids(target);
let instance_id = unique_id(id_base, &all_ids);
all_ids.insert(instance_id.clone());
let instance = InstanceNode {
id: instance_id.clone(),
name: None,
role: None,
component: comp_id.clone(),
x: Some(px(at_x)),
y: Some(px(at_y)),
opacity: None,
visible: None,
locked: None,
overrides: Vec::new(),
source_span: None,
unknown_props: BTreeMap::new(),
};
if let Some(page) = target.body.pages.iter_mut().find(|p| p.id == page_id) {
page.children.push(Node::Instance(instance));
}
let provenance_id = unique_id(&format!("prov.{}", instance_id), &all_ids);
if !target.libraries.iter().any(|l| l.id == pkg_id) {
target.libraries.push(LibraryDef {
id: pkg_id.to_owned(),
version: pack.version.clone(),
hash: None,
source_span: None,
unknown_props: BTreeMap::new(),
});
}
target.provenance.push(ProvenanceDef {
id: provenance_id.clone(),
node: instance_id.clone(),
library: pkg_id.to_owned(),
item: Some(item.to_owned()),
linked: Some(true),
source_span: None,
unknown_props: BTreeMap::new(),
});
Ok(AddOutcome {
pkg_id: pkg_id.to_owned(),
item: item.to_owned(),
target_component_id: comp_id,
instance_id,
provenance_id,
warnings,
})
}