tiefdownlib 0.10.0

A library to manage and convert TiefDown projects.
Documentation
use std::path::PathBuf;

use crate::{manifest_model::MetadataField, project_management::load_and_convert_manifest};
use color_eyre::eyre::{Result, eyre};
use log::debug;
use toml::{Table, Value};

/// Sets the shared metadata fields for a TiefDown project.
///
/// # Arguments
///
/// * `project` - The path to the project directory (relative or absolute).
///   * Defaults to the current directory if not provided.
/// * `key` - The key of the metadata field to set.
/// * `value` - The value to set for the metadata field.
///
/// # Returns
///
/// A Result containing either an error or nothing.
pub fn set_metadata(project: Option<PathBuf>, key: String, value: String) -> Result<()> {
    debug!("metadata.set: key='{}'", key);
    let project = project.unwrap_or(PathBuf::from("."));
    let manifest_path = project.join("manifest.toml");

    let mut manifest = load_and_convert_manifest(&manifest_path)?;

    manifest
        .shared_metadata
        .get_or_insert_with(&mut || Table::new())
        .insert(key, Value::String(value));

    let manifest_content = toml::to_string(&manifest)?;
    std::fs::write(&manifest_path, manifest_content)?;
    debug!(
        "metadata.set: updated manifest at '{}'",
        manifest_path.display()
    );

    Ok(())
}

/// Removes a metadata field from the shared metadata of a TiefDown project.
///
/// # Arguments
///
/// * `project` - The path to the project directory (relative or absolute).
///   * Defaults to the current directory if not provided.
/// * `key` - The key of the metadata field to remove.
///
/// # Returns
///
/// A Result containing either an error or nothing.
pub fn remove_metadata(project: Option<PathBuf>, key: String) -> Result<()> {
    debug!("metadata.remove: key='{}'", key);
    let project = project.unwrap_or(PathBuf::from("."));
    let manifest_path = project.join("manifest.toml");

    let mut manifest = load_and_convert_manifest(&manifest_path)?;

    let shared_metadata = manifest
        .shared_metadata
        .as_mut()
        .ok_or(eyre!("No shared metadata found."))?;

    if !shared_metadata.contains_key(&key) {
        return Err(eyre!("Metadata field '{}' not found.", key));
    }

    shared_metadata.remove(&key);

    let manifest_content = toml::to_string(&manifest)?;
    std::fs::write(&manifest_path, manifest_content)?;
    debug!(
        "metadata.remove: updated manifest at '{}'",
        manifest_path.display()
    );

    Ok(())
}

/// Retrieves the shared metadata fields for a TiefDown project.
///
/// # Arguments
///
/// * `project` - The path to the project directory (relative or absolute).
///   * Defaults to the current directory if not provided.
///
/// # Returns
///
/// A Result containing either an error or a Vec of MetadataField.
pub fn get_metadata(project: Option<PathBuf>) -> Result<Vec<MetadataField>> {
    let project = project.unwrap_or(PathBuf::from("."));
    let manifest_path = project.join("manifest.toml");

    let manifest = load_and_convert_manifest(&manifest_path)?;

    let metadata_fields = manifest.shared_metadata.unwrap_or_default();
    debug!("metadata.get: {} entries", metadata_fields.len());

    Ok(metadata_fields
        .iter()
        .map(|e| MetadataField {
            key: e.0.clone(),
            value: e.1.clone().to_string(),
        })
        .collect())
}