ironic 1.0.9

A batteries-included, type-safe application framework for Rust
Documentation
use convert_case::{Case, Casing};

use crate::CliError;

#[derive(Debug)]
pub(crate) struct Names {
    pub(crate) snake: String,
    pub(crate) pascal: String,
    pub(crate) kebab: String,
}

impl Names {
    pub(crate) fn parse(value: &str) -> Result<Self, CliError> {
        if !value.chars().any(char::is_alphabetic) {
            return Err(CliError::InvalidName {
                name: value.to_owned(),
            });
        }
        let safe_source = value
            .chars()
            .map(|character| {
                if character.is_alphanumeric() {
                    character
                } else {
                    ' '
                }
            })
            .collect::<String>();
        let snake = safe_source.to_case(Case::Snake);
        let pascal = safe_source.to_case(Case::Pascal);
        let kebab = safe_source.to_case(Case::Kebab);
        if snake.is_empty()
            || pascal.is_empty()
            || kebab.is_empty()
            || is_keyword(&snake)
            || snake.starts_with(|character: char| character.is_ascii_digit())
        {
            return Err(CliError::InvalidName {
                name: value.to_owned(),
            });
        }
        Ok(Self {
            snake,
            pascal,
            kebab,
        })
    }
}

fn is_keyword(value: &str) -> bool {
    matches!(
        value,
        "as" | "async"
            | "await"
            | "break"
            | "const"
            | "continue"
            | "crate"
            | "dyn"
            | "else"
            | "enum"
            | "extern"
            | "false"
            | "fn"
            | "for"
            | "if"
            | "impl"
            | "in"
            | "let"
            | "loop"
            | "match"
            | "mod"
            | "move"
            | "mut"
            | "pub"
            | "ref"
            | "return"
            | "self"
            | "static"
            | "struct"
            | "super"
            | "trait"
            | "true"
            | "type"
            | "unsafe"
            | "use"
            | "where"
            | "while"
    )
}