use serde_json::{Map, Value};
pub(crate) fn is_draft(frontmatter: &Value) -> bool {
frontmatter
.get("draft")
.and_then(Value::as_bool)
.unwrap_or(false)
}
pub(crate) fn page_entry(id: &str, title: &str, url: &str, frontmatter: &Value) -> Value {
let string_field = |key: &str| -> String {
frontmatter
.get(key)
.and_then(Value::as_str)
.unwrap_or("")
.to_string()
};
let tags: Vec<Value> = frontmatter
.get("tags")
.and_then(Value::as_array)
.map(|items| {
items
.iter()
.filter_map(Value::as_str)
.map(|s| Value::String(s.to_string()))
.collect()
})
.unwrap_or_default();
let pinned = frontmatter
.get("pinned")
.and_then(Value::as_bool)
.unwrap_or(false);
let mut entry = Map::new();
entry.insert("id".to_string(), Value::String(id.to_string()));
entry.insert("title".to_string(), Value::String(title.to_string()));
entry.insert("date".to_string(), Value::String(string_field("date")));
entry.insert(
"updated".to_string(),
Value::String(string_field("updated")),
);
entry.insert(
"version".to_string(),
Value::String(string_field("version")),
);
entry.insert("url".to_string(), Value::String(url.to_string()));
entry.insert(
"summary".to_string(),
Value::String(string_field("summary")),
);
entry.insert("tags".to_string(), Value::Array(tags));
entry.insert("pinned".to_string(), Value::Bool(pinned));
Value::Object(entry)
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn draft_true_is_detected() {
assert!(is_draft(&json!({"draft": true})));
}
#[test]
fn missing_draft_key_defaults_to_false() {
assert!(!is_draft(&json!({})));
}
#[test]
fn entry_fills_in_every_field_when_frontmatter_has_them_all() {
let frontmatter = json!({
"date": "2026-07-14",
"updated": "2026-07-15",
"version": "2",
"summary": "A short summary.",
"tags": ["rust", "docs"],
"pinned": true,
});
let entry = page_entry(
"design-review-sync",
"Design review sync",
"/design-review-sync",
&frontmatter,
);
assert_eq!(
entry,
json!({
"id": "design-review-sync",
"title": "Design review sync",
"date": "2026-07-14",
"updated": "2026-07-15",
"version": "2",
"url": "/design-review-sync",
"summary": "A short summary.",
"tags": ["rust", "docs"],
"pinned": true,
})
);
}
#[test]
fn entry_defaults_missing_fields_when_frontmatter_is_empty() {
let entry = page_entry(
"weekly-eng-report",
"Weekly eng report",
"/weekly-eng-report",
&json!({}),
);
assert_eq!(
entry,
json!({
"id": "weekly-eng-report",
"title": "Weekly eng report",
"date": "",
"updated": "",
"version": "",
"url": "/weekly-eng-report",
"summary": "",
"tags": [],
"pinned": false,
})
);
}
#[test]
fn non_string_tag_items_are_dropped_silently() {
let frontmatter = json!({"tags": ["rust", true, "docs"]});
let entry = page_entry("id", "Title", "/id", &frontmatter);
assert_eq!(entry["tags"], json!(["rust", "docs"]));
}
}