weaver-lib 0.3.0

static site generator as a library, markdown and liquid in, HTML out.
Documentation
use std::path::PathBuf;

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub enum TemplateLang {
    #[default]
    Liquid,
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(default)]
pub struct ImageConfig {
    pub quality: u8,
}

impl Default for ImageConfig {
    fn default() -> Self {
        Self { quality: 83 }
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(default)]
pub struct ServeConfig {
    pub watch_excludes: Vec<String>,
    pub address: String,
    pub npm_build: bool,
}

impl Default for ServeConfig {
    fn default() -> Self {
        Self {
            watch_excludes: vec![".git".into(), "node_modules".into(), "site".into()],
            address: "localhost:8080".into(),
            npm_build: false,
        }
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(default)]
pub struct WeaverConfig {
    pub version: String,
    pub base_dir: String,
    pub content_dir: String,
    pub base_url: String,
    pub partials_dir: String,
    pub public_dir: String,
    pub template_dir: String,
    pub build_dir: String,
    pub templating_language: TemplateLang,
    pub image_config: ImageConfig,
    pub serve_config: ServeConfig,
    pub syntax_theme: String,
}

impl Default for WeaverConfig {
    fn default() -> Self {
        let base_path = std::env::var_os("WEAVING_BASE_PATH")
            .unwrap_or(std::env::current_dir().unwrap().as_os_str().to_os_string())
            .to_str()
            .unwrap()
            .to_string();

        let base_url = std::env::var_os("WEAVING_BASE_URL")
            .unwrap_or("http://localhost:8080".into())
            .to_str()
            .unwrap()
            .to_string();

        Self {
            version: "1".into(),
            base_dir: base_path.clone(),
            content_dir: "content".into(),
            base_url,
            partials_dir: "partials".into(),
            public_dir: "public".into(),
            build_dir: "site".into(),
            template_dir: "templates".into(),
            templating_language: TemplateLang::Liquid,
            image_config: Default::default(),
            serve_config: Default::default(),
            syntax_theme: "base16-ocean.dark".into(),
        }
    }
}
impl WeaverConfig {
    pub fn new(base_dir: PathBuf) -> Self {
        let base_dir_str = base_dir.display().to_string();

        let config_file_result = std::fs::read_to_string(format!("{}/weaving.toml", base_dir_str));

        let user_supplied_config: WeaverConfig = if let Ok(config_file) = config_file_result {
            toml::from_str(config_file.as_str()).unwrap()
        } else {
            Self {
                base_dir: base_dir_str.clone(),
                ..Default::default()
            }
        };

        Self {
            base_dir: base_dir_str.clone(),
            content_dir: format!("{}/{}", &base_dir_str, user_supplied_config.content_dir),
            partials_dir: format!("{}/{}", &base_dir_str, user_supplied_config.partials_dir),
            public_dir: format!("{}/{}", &base_dir_str, user_supplied_config.public_dir),
            build_dir: format!("{}/{}", &base_dir_str, user_supplied_config.build_dir),
            template_dir: format!("{}/{}", &base_dir_str, user_supplied_config.template_dir),
            ..user_supplied_config
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn test_defaultyness() {
        let base_path = std::env::current_dir()
            .unwrap()
            .as_os_str()
            .to_os_string()
            .to_str()
            .unwrap()
            .to_string();
        let config = WeaverConfig::new(base_path.clone().into());

        assert_eq!(config.base_dir, base_path);
        assert_eq!(config.content_dir, format!("{}/content", base_path));
        assert_eq!(config.partials_dir, format!("{}/partials", base_path));
        assert_eq!(config.public_dir, format!("{}/public", base_path));
        assert_eq!(config.build_dir, format!("{}/site", base_path));
        assert_eq!(config.base_url, "http://localhost:8080");
    }

    #[test]
    fn test_with_empty_config_file() {
        let base_path_wd = std::env::current_dir()
            .unwrap()
            .as_os_str()
            .to_os_string()
            .to_str()
            .unwrap()
            .to_string();
        let base_path = format!("{}/test_fixtures/config/empty_config", base_path_wd);
        let config = WeaverConfig::new(base_path.clone().into());

        assert_eq!(config.base_dir, base_path);
        assert_eq!(config.content_dir, format!("{}/content", base_path));
        assert_eq!(config.partials_dir, format!("{}/partials", base_path));
        assert_eq!(config.public_dir, format!("{}/public", base_path));
        assert_eq!(config.build_dir, format!("{}/site", base_path));
        assert_eq!(config.base_url, "http://localhost:8080");
    }

    #[test]
    fn test_with_filled_config_file() {
        let base_path_wd = std::env::current_dir().unwrap().display().to_string();
        let base_path = format!("{}/test_fixtures/config/full_config", base_path_wd);
        let config = WeaverConfig::new(base_path.clone().into());

        assert_eq!(config.base_dir, base_path);
        assert_eq!(config.content_dir, format!("{}/content", base_path));
        assert_eq!(config.partials_dir, format!("{}/partials", base_path));
        assert_eq!(config.public_dir, format!("{}/static", base_path));
        assert_eq!(config.build_dir, format!("{}/site", base_path));
        assert_eq!(config.base_url, "localhost:9090");
        assert_eq!(config.image_config.quality, 100);
        assert_eq!(config.serve_config.npm_build, true);
        assert_eq!(config.serve_config.address, "localhost:3030");
    }

    #[test]
    fn test_with_partial_config_file() {
        let base_path_wd = std::env::current_dir().unwrap().display().to_string();
        let base_path = format!("{}/test_fixtures/config/partial_config", base_path_wd);
        let config = WeaverConfig::new(base_path.clone().into());

        assert_eq!(config.base_dir, base_path);
        assert_eq!(config.content_dir, format!("{}/content", base_path));
        assert_eq!(config.partials_dir, format!("{}/partials", base_path));
        assert_eq!(config.public_dir, format!("{}/static", base_path));
        assert_eq!(config.build_dir, format!("{}/site", base_path));
        assert_eq!(config.base_url, "http://localhost:8080");
    }
}