codexa 0.0.3

A Git-native content compiler for building typed public and private knowledge artifacts.
Documentation
mod model;

use std::{fs, io, path::Path};

pub use model::{NotionManifest, NotionManifestPage, NotionPageArtifact};

use crate::compiler::CompiledDocument;

pub fn write_bundle(
    documents: &[CompiledDocument],
    output_dir: &Path,
) -> Result<(), NotionAdapterError> {
    let pages_dir = output_dir.join("pages");
    fs::create_dir_all(&pages_dir)?;
    let mut pages = Vec::new();

    for document in documents
        .iter()
        .filter(|document| document.source.metadata.distribution.notion)
    {
        let id = &document.source.metadata.id;
        let file_name = format!("{id}.json");
        write_json(
            &pages_dir.join(&file_name),
            &NotionPageArtifact::new(document),
        )?;
        pages.push(NotionManifestPage {
            document_id: id.clone(),
            root: document.source.metadata.navigation.root.clone(),
            path: format!("pages/{file_name}"),
        });
    }

    let manifest = NotionManifest {
        schema: "codexa.notion.manifest@2".into(),
        producer: "codexa".into(),
        producer_version: crate::VERSION.into(),
        pages,
    };
    write_json(&output_dir.join("manifest.json"), &manifest)?;
    Ok(())
}

fn write_json<T: serde::Serialize>(path: &Path, value: &T) -> Result<(), NotionAdapterError> {
    let mut bytes = serde_json::to_vec_pretty(value)?;
    bytes.push(b'\n');
    fs::write(path, bytes)?;
    Ok(())
}

#[derive(Debug)]
pub enum NotionAdapterError {
    Io(io::Error),
    Json(serde_json::Error),
}

impl std::fmt::Display for NotionAdapterError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Io(error) => write!(f, "notion artifact I/O error: {error}"),
            Self::Json(error) => write!(f, "notion artifact JSON error: {error}"),
        }
    }
}
impl std::error::Error for NotionAdapterError {}
impl From<io::Error> for NotionAdapterError {
    fn from(v: io::Error) -> Self {
        Self::Io(v)
    }
}
impl From<serde_json::Error> for NotionAdapterError {
    fn from(v: serde_json::Error) -> Self {
        Self::Json(v)
    }
}