use convert_case::{Case, Casing};
pub fn to_snake_case(name: &str) -> String {
name.to_case(Case::Snake)
}
pub fn to_pascal_case(name: &str) -> String {
name.to_case(Case::Pascal)
}
pub fn to_enum_variant(s: &str) -> String {
let pascal = s.to_case(Case::Pascal);
if pascal.is_empty() {
"Empty".to_string()
} else {
pascal
}
}
pub fn dedup_names(names: &mut [String]) {
use std::collections::HashMap;
let mut counts: HashMap<String, usize> = HashMap::new();
for name in names.iter_mut() {
let count = counts.entry(name.clone()).or_insert(0);
*count += 1;
if *count > 1 {
*name = format!("{name}_{count}");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_snake_case() {
assert_eq!(to_snake_case("getUserById"), "get_user_by_id");
assert_eq!(to_snake_case("HTMLElement"), "html_element");
assert_eq!(to_snake_case("send"), "send");
}
#[test]
fn test_pascal_case() {
assert_eq!(to_pascal_case("readableStream"), "ReadableStream");
assert_eq!(to_pascal_case("my_type"), "MyType");
}
#[test]
fn test_keywords_not_escaped() {
assert_eq!(to_snake_case("type"), "type");
assert_eq!(to_snake_case("match"), "match");
assert_eq!(to_snake_case("return"), "return");
assert_eq!(to_snake_case("raw"), "raw");
}
#[test]
fn test_enum_variant() {
assert_eq!(to_enum_variant("text"), "Text");
assert_eq!(to_enum_variant("bytes"), "Bytes");
assert_eq!(to_enum_variant("json"), "Json");
}
#[test]
fn test_dedup_names_no_collision() {
let mut names = vec!["Foo".to_string(), "Bar".to_string(), "Baz".to_string()];
dedup_names(&mut names);
assert_eq!(names, &["Foo", "Bar", "Baz"]);
}
#[test]
fn test_dedup_names_collision() {
let mut names = vec![
"TextPlain".to_string(),
"TextPlain".to_string(),
"Other".to_string(),
];
dedup_names(&mut names);
assert_eq!(names, &["TextPlain", "TextPlain_2", "Other"]);
}
#[test]
fn test_dedup_names_triple_collision() {
let mut names = vec!["A".to_string(), "A".to_string(), "A".to_string()];
dedup_names(&mut names);
assert_eq!(names, &["A", "A_2", "A_3"]);
}
}