mini-docs 0.4.5

A minimal, secure build-time Markdown to HTML generator for the mini-* family.
Documentation
use std::fmt;

/// Errors that can occur while building a Markdown → HTML site.
///
/// This error type is non-exhaustive and may gain new variants in future releases.
///
/// # Variants
///
/// - `Frontmatter`: the `---`-delimited frontmatter block is malformed.
/// - `Markdown`: Markdown rendering failed.
/// - `Template`: Tera template loading or rendering failed.
/// - `Io`: an I/O error occurred (file read, write, or directory walk).
/// - `Escape`: a resolved output path would have written outside `output_dir`.
/// - `Extension`: a processor or analyzer failed; message is prefixed with extension name.
#[derive(Debug)]
#[non_exhaustive]
pub enum DocError {
    /// Malformed frontmatter block.
    Frontmatter(String),
    /// Markdown render failure.
    Markdown(String),
    /// Tera template load/render failure.
    Template(tera::Error),
    /// I/O error from the filesystem.
    Io(std::io::Error),
    /// Output path resolved outside `output_dir`.
    Escape(String),
    /// Extension (processor or analyzer) failure, prefixed with extension name.
    Extension(String),
}

impl fmt::Display for DocError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DocError::Frontmatter(msg) => write!(f, "invalid frontmatter: {msg}"),
            DocError::Markdown(msg) => write!(f, "markdown render error: {msg}"),
            DocError::Template(e) => write!(f, "template error: {e}"),
            DocError::Io(e) => write!(f, "io error: {e}"),
            DocError::Escape(path) => write!(f, "output path escaped root: {path}"),
            DocError::Extension(msg) => write!(f, "extension error: {msg}"),
        }
    }
}

impl std::error::Error for DocError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            DocError::Template(e) => Some(e),
            DocError::Io(e) => Some(e),
            _ => None,
        }
    }
}

impl DocError {
    /// Returns a user-safe error message, never leaking filesystem or template internals.
    pub fn user_message(&self) -> String {
        match self {
            DocError::Frontmatter(_) => "invalid frontmatter".to_string(),
            DocError::Markdown(_) => "could not render markdown".to_string(),
            DocError::Template(_) => "template error".to_string(),
            DocError::Io(_) => "io error".to_string(),
            DocError::Escape(_) => "output path escaped root".to_string(),
            DocError::Extension(_) => "extension error".to_string(),
        }
    }
}

impl From<std::io::Error> for DocError {
    fn from(e: std::io::Error) -> Self {
        DocError::Io(e)
    }
}