mod default;
mod explicit;
use std::borrow::Cow;
use inflector::Inflector;
use proc_macro2::Ident as Ident2;
use quote::format_ident;
use crate::config::MetaType;
use crate::models::meta::MetaTypeVariant;
use crate::models::schema::MaxOccurs;
use crate::TypeIdent;
use super::Name;
pub use self::default::{NameBuilder, Naming};
pub use self::explicit::{ExplicitNameBuilder, ExplicitNaming};
pub fn make_type_name<X>(naming: &X, postfixes: &[String], ty: &MetaType, ident: &TypeIdent) -> Name
where
X: crate::traits::Naming,
{
if let MetaTypeVariant::Reference(ti) = &ty.variant {
if ident.name.is_generated() && ti.type_.name.is_named() {
let s = naming.format_type_name(ti.type_.name.as_str());
if ti.max_occurs > MaxOccurs::Bounded(1) {
return Name::new_generated(format!("{s}List"));
} else if ti.min_occurs == 0 {
return Name::new_generated(format!("{s}Opt"));
}
}
}
let postfix = postfixes
.get(ident.type_ as usize)
.map_or("", |s| s.as_str());
let s = naming.format_type_name(ident.name.as_str());
if s.ends_with(postfix) {
ident.name.clone()
} else {
Name::new_generated(format!("{s}{postfix}"))
}
}
#[must_use]
pub fn unify_string(s: &str) -> String {
let mut done = true;
let s = s.replace(
|c: char| {
let replace = !c.is_alphanumeric();
if c != '_' && !replace {
done = false;
}
c != '_' && replace
},
"_",
);
if done {
s
} else {
s.to_screaming_snake_case().to_pascal_case()
}
}
#[must_use]
pub fn format_unknown_variant(id: usize) -> Ident2 {
format_ident!("Unknown{id}")
}
#[must_use]
pub fn format_ident<'a, S>(s: S) -> String
where
S: Into<Cow<'a, str>>,
{
let mut s = s.into();
if let Ok(idx) = KEYWORDS.binary_search_by(|(key, _)| key.cmp(&&*s)) {
s = Cow::Borrowed(KEYWORDS[idx].1);
}
if s.starts_with(char::is_numeric) {
s = Cow::Owned(format!("_{s}"));
}
s.replace(|c: char| !c.is_alphanumeric(), "_")
}
const KEYWORDS: &[(&str, &str)] = &[
("Self", "Self_"),
("abstract", "abstract_"),
("as", "as_"),
("become", "become_"),
("box", "box_"),
("break", "break_"),
("const", "const_"),
("continue", "continue_"),
("crate", "crate_"),
("do", "do_"),
("else", "else_"),
("enum", "enum_"),
("extern", "extern_"),
("false", "false_"),
("final", "final_"),
("fn", "fn_"),
("for", "for_"),
("if", "if_"),
("impl", "impl_"),
("in", "in_"),
("let", "let_"),
("loop", "loop_"),
("macro", "macro_"),
("match", "match_"),
("mod", "mod_"),
("move", "move_"),
("mut", "mut_"),
("override", "override_"),
("priv", "priv_"),
("pub", "pub_"),
("ref", "ref_"),
("return", "return_"),
("self", "self_"),
("static", "static_"),
("struct", "struct_"),
("super", "super_"),
("trait", "trait_"),
("true", "true_"),
("try", "try_"),
("type", "type_"),
("typeof", "typeof_"),
("union", "union_"),
("unsafe", "unsafe_"),
("unsized", "unsized_"),
("use", "use_"),
("virtual", "virtual_"),
("where", "where_"),
("while", "while_"),
("yield", "yield_"),
];
#[cfg(test)]
mod tests {
use super::KEYWORDS;
#[test]
fn verify_keyword_order() {
for i in 1..KEYWORDS.len() {
assert!(dbg!(KEYWORDS[i - 1].0) < dbg!(KEYWORDS[i].0));
}
}
}