use std::collections::HashMap;
use crepuscularity_core::context::TemplateContext;
use serde_json::Value;
use crate::render_from_files;
pub fn render_bundle(bundle_json: &str) -> Result<String, String> {
let root: Value = serde_json::from_str(bundle_json).map_err(|e| format!("bundle JSON: {e}"))?;
let entry = root
.get("entry")
.and_then(|v| v.as_str())
.ok_or_else(|| "bundle missing string field \"entry\"".to_string())?
.to_string();
let files_val = root
.get("files")
.ok_or_else(|| "bundle missing \"files\" object".to_string())?;
let files_obj = files_val
.as_object()
.ok_or_else(|| "\"files\" must be a JSON object".to_string())?;
let mut files = HashMap::new();
for (k, v) in files_obj {
let s = v
.as_str()
.ok_or_else(|| format!("files[{k:?}] must be a string"))?
.to_string();
files.insert(k.clone(), s);
}
let ctx = TemplateContext::new();
render_from_files(&files, &entry, &ctx)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_minimal_bundle() {
let bundle = serde_json::json!({
"entry": "index.crepus",
"files": {
"index.crepus": "div class=\"x\"\n \"hello\""
}
})
.to_string();
let html = render_bundle(&bundle).expect("render");
assert!(html.contains("hello"));
assert!(html.contains("class=\"x\""));
}
#[test]
fn slot_rotate_emits_data_attributes() {
let tpl = r#"slot-rotate interval={2800} text-green-400
"one"
"two"
"#;
let bundle = serde_json::json!({
"entry": "index.crepus",
"files": { "index.crepus": tpl }
})
.to_string();
let html = render_bundle(&bundle).expect("render");
assert!(html.contains("data-slot-words="));
assert!(html.contains("data-slot-interval=\"2800\""));
assert!(html.contains("crepus-slot"));
assert!(html.contains("text-green-400"));
}
}