krik 0.1.23

A fast static site generator written in Rust with internationalization, theming, and modern web features
Documentation
use crate::error::{GenerationError, GenerationErrorKind, KrikError, KrikResult};
use crate::i18n::I18nManager;
use crate::parser::Document;
use crate::site::SiteConfig;
use crate::theme::Theme;
use chrono::{DateTime, Utc};
use std::path::Path;

/// Phase: scan the content directory and build the in-memory document list
pub struct ScanPhase;

impl ScanPhase {
    pub fn scan(&self, source_dir: &Path) -> KrikResult<Vec<Document>> {
        let mut documents = Vec::new();
        super::markdown::scan_files(source_dir, &mut documents).map_err(|e| match e {
            KrikError::Generation(gen_err) => KrikError::Generation(gen_err),
            other => other,
        })?;
        Ok(documents)
    }
}

/// Phase: apply transformations and enrichments to parsed documents before rendering
pub struct TransformPhase;

impl TransformPhase {
    /// Apply non-rendering transformations (mutates in place)
    /// Currently: set missing dates from file modification time when available
    pub fn transform(&self, documents: &mut [Document], source_dir: &Path) {
        for doc in documents.iter_mut() {
            if doc.front_matter.date.is_none() {
                let file_path = source_dir.join(&doc.file_path);
                if let Ok(metadata) = std::fs::metadata(&file_path) {
                    if let Ok(modified) = metadata.modified() {
                        let dt: DateTime<Utc> = modified.into();
                        doc.front_matter.date = Some(dt);
                    }
                }
            }
        }
    }
}

/// Phase: render HTML for pages and index using the theme
pub struct RenderPhase;

impl RenderPhase {
    pub fn render_pages(
        &self,
        documents: &[Document],
        theme: &Theme,
        i18n: &I18nManager,
        site_config: &SiteConfig,
        output_dir: &Path,
    ) -> KrikResult<()> {
        super::templates::generate_pages(documents, theme, i18n, site_config, output_dir)
            .map_err(|e| KrikError::Generation(GenerationError {
                kind: GenerationErrorKind::OutputDirError(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    format!("Page generation failed: {e}"),
                )),
                context: "Generating HTML pages from documents".to_string(),
            }))
    }

    pub fn render_index(
        &self,
        documents: &[Document],
        theme: &Theme,
        site_config: &SiteConfig,
        i18n: &I18nManager,
        output_dir: &Path,
    ) -> KrikResult<()> {
        super::templates::generate_index(documents, theme, site_config, i18n, output_dir)
            .map_err(|e| KrikError::Generation(GenerationError {
                kind: GenerationErrorKind::OutputDirError(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    format!("Index page generation failed: {e}"),
                )),
                context: "Generating index page with post listings".to_string(),
            }))
    }
}

/// Phase: emit non-HTML artifacts and copy assets
pub struct EmitPhase;

impl EmitPhase {
    pub fn ensure_output_dir(&self, output_dir: &Path) -> KrikResult<()> {
        if !output_dir.exists() {
            std::fs::create_dir_all(output_dir).map_err(|e| KrikError::Generation(GenerationError {
                kind: GenerationErrorKind::OutputDirError(e),
                context: format!("Creating output directory: {}", output_dir.display()),
            }))?;
        }
        Ok(())
    }

    pub fn copy_assets(&self, source_dir: &Path, theme: &Theme, output_dir: &Path) -> KrikResult<()> {
        super::assets::copy_non_markdown_files(source_dir, output_dir).map_err(|e| {
            KrikError::Generation(GenerationError {
                kind: GenerationErrorKind::AssetCopyError {
                    source: source_dir.to_path_buf(),
                    target: output_dir.to_path_buf(),
                    error: std::io::Error::new(std::io::ErrorKind::Other, format!("Asset copy failed: {e}")),
                },
                context: "Copying non-markdown assets".to_string(),
            })
        })?;

        super::assets::copy_theme_assets(theme, output_dir).map_err(|e| {
            KrikError::Generation(GenerationError {
                kind: GenerationErrorKind::AssetCopyError {
                    source: theme.theme_path.clone(),
                    target: output_dir.to_path_buf(),
                    error: std::io::Error::new(
                        std::io::ErrorKind::Other,
                        format!("Theme asset copy failed: {e}"),
                    ),
                },
                context: "Copying theme assets".to_string(),
            })
        })
    }

    pub fn emit_feed(&self, documents: &[Document], site_config: &SiteConfig, output_dir: &Path) -> KrikResult<()> {
        super::feeds::generate_feed(documents, site_config, output_dir).map_err(|e| KrikError::Generation(
            GenerationError { kind: GenerationErrorKind::FeedError(format!("Atom feed generation failed: {e}")), context: "Generating Atom feed for posts".to_string() }
        ))
    }

    pub fn emit_sitemap(&self, documents: &[Document], site_config: &SiteConfig, output_dir: &Path) -> KrikResult<()> {
        super::sitemap::generate_sitemap(documents, site_config, output_dir).map_err(|e| KrikError::Generation(
            GenerationError { kind: GenerationErrorKind::SitemapError(format!("XML sitemap generation failed: {e}")), context: "Generating XML sitemap with multilingual support".to_string() }
        ))
    }

    pub fn emit_robots(&self, site_config: &SiteConfig, output_dir: &Path) -> KrikResult<()> {
        super::robots::generate_robots(site_config, output_dir).map_err(|e| KrikError::Generation(GenerationError {
            kind: GenerationErrorKind::OutputDirError(std::io::Error::new(
                std::io::ErrorKind::Other,
                format!("robots.txt generation failed: {e}"),
            )),
            context: "Generating robots.txt with sitemap reference".to_string(),
        }))
    }
}