use anyhow::Context;
use std::collections::BTreeMap;
pub fn split_frontmatter(
raw: &str,
) -> anyhow::Result<(BTreeMap<String, serde_json::Value>, String)> {
let mut lines = raw.lines();
if lines.next() != Some("---") {
return Ok((BTreeMap::new(), raw.to_string()));
}
let mut yaml = Vec::new();
let mut body = Vec::new();
let mut in_frontmatter = true;
for line in raw.lines().skip(1) {
if in_frontmatter && line == "---" {
in_frontmatter = false;
continue;
}
if in_frontmatter {
yaml.push(line);
} else {
body.push(line);
}
}
if in_frontmatter {
anyhow::bail!("frontmatter started with --- but was not closed with ---");
}
let yaml_str = yaml.join("\n");
if yaml_str.trim().is_empty() {
return Ok((BTreeMap::new(), body.join("\n")));
}
let yaml_value = serde_yaml::from_str::<serde_yaml::Value>(&yaml_str)
.with_context(|| "failed to parse frontmatter yaml")?;
let parsed = match yaml_value {
serde_yaml::Value::Null => BTreeMap::new(),
other => {
let json_value = serde_json::to_value(other)
.with_context(|| "failed to convert frontmatter yaml to json")?;
serde_json::from_value(json_value)
.with_context(|| "failed to deserialize frontmatter object")?
}
};
Ok((parsed, body.join("\n")))
}