commit-wizard 0.0.2

A lightweight CLI assistant for Conventional Commits, semantic versioning, and changelog automation.
Documentation
use std::path::{Path, PathBuf};

use crate::engine::{
    config::{ProjectConfig, StandardConfig},
    constants::{CONFIG_FILE_NAME, PROJECT_CONFIG_FILE_NAME, paths::app_config_dir},
    error::{ErrorCode, Result},
};

#[derive(Debug, Clone, Copy)]
pub enum ConfigTarget {
    Project,
    Global,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConfigShowFormat {
    Human,
    Json,
    Toml,
}

pub struct ConfigPathInput<'a> {
    pub cwd: &'a Path,
    pub target: ConfigTarget,
}

pub struct ConfigPathOutput {
    pub path: PathBuf,
}

pub struct ConfigShowInput<'a> {
    pub cwd: &'a Path,
    pub target: ConfigTarget,
    pub explicit_path: Option<&'a Path>,
    pub format: ConfigShowFormat,
}

pub struct ConfigShowOutput {
    pub path: PathBuf,
    pub exists: bool,
    pub content: String,
}

pub fn resolve_config_path(target: ConfigTarget, cwd: &Path) -> Result<PathBuf> {
    match target {
        ConfigTarget::Project => Ok(cwd.join(PROJECT_CONFIG_FILE_NAME)),
        ConfigTarget::Global => Ok(app_config_dir()?.join(CONFIG_FILE_NAME)),
    }
}

pub fn config_path(input: &ConfigPathInput<'_>) -> Result<ConfigPathOutput> {
    Ok(ConfigPathOutput {
        path: resolve_config_path(input.target, input.cwd)?,
    })
}

pub fn config_show(input: &ConfigShowInput<'_>) -> Result<ConfigShowOutput> {
    let path = resolve_config_path(input.target, input.cwd)?;

    if !path.exists() {
        return Err(ErrorCode::ConfigUnreadable
            .error()
            .with_context("path", path.display().to_string())
            .with_context("reason", "config file does not exist"));
    }

    let raw = std::fs::read_to_string(&path)?;

    let content = match input.target {
        ConfigTarget::Project => {
            let parsed = ProjectConfig::from_toml_str(&raw)?;
            match input.format {
                ConfigShowFormat::Human | ConfigShowFormat::Toml => raw,
                ConfigShowFormat::Json => serde_json::to_string_pretty(&parsed).map_err(|err| {
                    ErrorCode::SerializationFailure
                        .error()
                        .with_context("error", err.to_string())
                })?,
            }
        }
        ConfigTarget::Global => {
            let parsed = StandardConfig::from_toml_str(&raw)?;
            match input.format {
                ConfigShowFormat::Human | ConfigShowFormat::Toml => raw,
                ConfigShowFormat::Json => serde_json::to_string_pretty(&parsed).map_err(|err| {
                    ErrorCode::SerializationFailure
                        .error()
                        .with_context("error", err.to_string())
                })?,
            }
        }
    };

    Ok(ConfigShowOutput {
        path,
        exists: true,
        content,
    })
}