use crate::model::archive::Archive;
use crate::parse::task_serializer::serialize_tasks;
pub fn serialize_archive(archive: &Archive) -> String {
let mut lines = archive.header.clone();
lines.extend(serialize_tasks(&archive.tasks, 0));
lines.extend(archive.trailing.iter().cloned());
if lines.is_empty() {
return String::new();
}
let mut out = lines.join("\n");
out.push('\n');
archive.eol.apply(out)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse::{LineEnding, parse_archive};
#[test]
fn a_crlf_archive_comes_back_crlf() {
let source = "# Archive — main\r\n\r\n- [x] `MAI-001` task\r\n";
let archive = parse_archive(source);
assert_eq!(archive.eol, LineEnding::Crlf);
assert_eq!(serialize_archive(&archive), source);
}
#[test]
fn a_write_leaves_exactly_one_terminal_newline() {
let once = serialize_archive(&parse_archive("# Archive — m\n\n- [x] `M-1` t"));
assert!(once.ends_with("- [x] `M-1` t\n"), "{once:?}");
assert_eq!(serialize_archive(&parse_archive(&once)), once);
}
#[test]
fn an_empty_archive_serializes_to_nothing() {
assert_eq!(serialize_archive(&parse_archive("")), "");
}
#[test]
fn an_archive_heading_is_never_separated_from_its_tasks() {
let mut archive = parse_archive("# Archive \u{2014} main\n");
assert!(archive.tasks.is_empty());
archive.tasks = parse_archive("# A\n\n- [x] `M-1` t\n").tasks;
assert_eq!(
serialize_archive(&archive),
"# Archive \u{2014} main\n- [x] `M-1` t\n"
);
let stranded = "# Archive \u{2014} main\n - resolved: 2025-05-14\n- [x] `M-1` t\n";
assert_eq!(serialize_archive(&parse_archive(stranded)), stranded);
}
#[test]
fn a_dirty_task_does_not_disturb_the_header_or_the_tail() {
let source = "\
# Archive — main
> hand-written note in the header
- [x] `MAI-001` task
- resolved: 2026-08-05
<!-- end -->
";
let mut archive = parse_archive(source);
archive.tasks[0].dirty = true;
archive.tasks[0].title = "renamed".to_string();
let out = serialize_archive(&archive);
assert!(
out.starts_with("# Archive — main\n> hand-written note"),
"{out:?}"
);
assert!(out.contains("`MAI-001` renamed"), "{out:?}");
assert!(out.ends_with("<!-- end -->\n"), "{out:?}");
}
}