use serde_json::Value;
use std::collections::BTreeMap;
use crate::errors::ValidationError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FieldType {
String,
Number,
Boolean,
Array(Box<FieldType>),
Enum(Vec<String>),
Count,
Value,
}
impl FieldType {
pub fn display_name(&self) -> String {
match self {
FieldType::String => "string".to_string(),
FieldType::Number => "number".to_string(),
FieldType::Boolean => "boolean".to_string(),
FieldType::Array(_) => "array".to_string(),
FieldType::Enum(values) => values.join("|"),
FieldType::Count => "count".to_string(),
FieldType::Value => "value".to_string(),
}
}
}
#[derive(Debug, Clone)]
pub struct FieldMeta {
pub name: &'static str,
pub cli_name: String,
pub description: Option<&'static str>,
pub field_type: FieldType,
pub required: bool,
pub default: Option<Value>,
pub alias: Option<char>,
pub deprecated: bool,
pub env_name: Option<&'static str>,
}
pub trait IncurSchema: Sized {
fn fields() -> Vec<FieldMeta>;
fn from_raw(raw: &BTreeMap<String, Value>) -> std::result::Result<Self, ValidationError>;
fn field_names() -> Vec<&'static str> {
Self::fields().iter().map(|f| f.name).collect()
}
}
pub fn to_kebab(name: &str) -> String {
let mut result = String::with_capacity(name.len());
for (i, ch) in name.chars().enumerate() {
if ch == '_' {
result.push('-');
} else if ch.is_uppercase() {
if i > 0 {
result.push('-');
}
result.push(ch.to_lowercase().next().unwrap_or(ch));
} else {
result.push(ch);
}
}
result
}
pub fn to_snake(name: &str) -> String {
name.replace('-', "_")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_kebab() {
assert_eq!(to_kebab("filter_output"), "filter-output");
assert_eq!(to_kebab("tokenLimit"), "token-limit");
assert_eq!(to_kebab("simple"), "simple");
}
#[test]
fn test_to_snake() {
assert_eq!(to_snake("filter-output"), "filter_output");
assert_eq!(to_snake("simple"), "simple");
}
}