use-vite 0.0.1

Vite config and framework preset primitives for RustUse
Documentation
#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]

use core::fmt;
use std::error::Error;

macro_rules! text_newtype {
    ($name:ident) => {
        #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
        pub struct $name(String);

        impl $name {
            /// Creates non-empty Vite text metadata.
            ///
            /// # Errors
            ///
            /// Returns [`ViteTextError::Empty`] when `input` is empty after trimming.
            pub fn new(input: &str) -> Result<Self, ViteTextError> {
                let trimmed = input.trim();
                if trimmed.is_empty() {
                    Err(ViteTextError::Empty)
                } else {
                    Ok(Self(trimmed.to_string()))
                }
            }

            /// Returns the stored text.
            #[must_use]
            pub fn as_str(&self) -> &str {
                &self.0
            }
        }
    };
}

/// Common Vite config file labels.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum ViteConfigFile {
    JavaScript,
    TypeScript,
    Mjs,
    Mts,
}

impl ViteConfigFile {
    /// Returns the config file label.
    #[must_use]
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::JavaScript => "vite.config.js",
            Self::TypeScript => "vite.config.ts",
            Self::Mjs => "vite.config.mjs",
            Self::Mts => "vite.config.mts",
        }
    }
}

text_newtype!(ViteMode);
text_newtype!(VitePluginName);

/// Vite framework preset labels.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum ViteFrameworkPreset {
    React,
    Vue,
    Svelte,
    Vanilla,
    Lit,
    Preact,
    Solid,
    Qwik,
}

impl ViteFrameworkPreset {
    /// Returns the preset label.
    #[must_use]
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::React => "react",
            Self::Vue => "vue",
            Self::Svelte => "svelte",
            Self::Vanilla => "vanilla",
            Self::Lit => "lit",
            Self::Preact => "preact",
            Self::Solid => "solid",
            Self::Qwik => "qwik",
        }
    }
}

/// Error returned when Vite text metadata is empty.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ViteTextError {
    Empty,
}

impl fmt::Display for ViteTextError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("Vite metadata text cannot be empty")
    }
}

impl Error for ViteTextError {}

#[cfg(test)]
mod tests {
    use super::{ViteConfigFile, ViteFrameworkPreset, ViteMode};

    #[test]
    fn models_vite_metadata() -> Result<(), Box<dyn std::error::Error>> {
        assert_eq!(ViteConfigFile::TypeScript.as_str(), "vite.config.ts");
        assert_eq!(ViteFrameworkPreset::React.as_str(), "react");
        assert_eq!(ViteMode::new("development")?.as_str(), "development");
        Ok(())
    }
}