Skip to main content

docrawl/
save.rs

1use std::fs;
2use std::io::Write;
3use std::path::Path;
4
5use crate::util::{ensure_parent_dir, now_rfc3339};
6
7pub fn write_markdown_with_frontmatter(
8    path: &Path,
9    title: &str,
10    url: &str,
11    body_md: &str,
12    security_flags: &[String],
13) -> std::io::Result<()> {
14    ensure_parent_dir(path)?;
15
16    let mut file = fs::File::create(path)?;
17    writeln!(file, "---")?;
18    writeln!(file, "title: {}", escape_yaml(title))?;
19    writeln!(file, "source_url: {}", escape_yaml(url))?;
20    writeln!(file, "fetched_at: {}", now_rfc3339())?;
21    if !security_flags.is_empty() {
22        writeln!(file, "quarantined: true")?;
23        writeln!(file, "security_flags:")?;
24        for f in security_flags {
25            writeln!(file, "  - {}", escape_yaml(f))?;
26        }
27    }
28    writeln!(file, "---\n")?;
29    file.write_all(body_md.as_bytes())?;
30    Ok(())
31}
32
33// Always double-quote to handle all YAML special cases:
34// booleans (true/yes/on), nulls, numbers, colons, hashes,
35// flow indicators ([]{}), anchors (&*), and reserved chars.
36fn escape_yaml(s: &str) -> String {
37    format!("\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\""))
38}