use heck::{ToLowerCamelCase, ToPascalCase, ToShoutySnakeCase, ToSnakeCase};
pub fn to_python_name(name: &str) -> String {
name.to_snake_case()
}
pub fn to_node_name(name: &str) -> String {
name.to_lower_camel_case()
}
pub fn to_ruby_name(name: &str) -> String {
name.to_snake_case()
}
pub fn to_php_name(name: &str) -> String {
name.to_lower_camel_case()
}
pub fn to_elixir_name(name: &str) -> String {
name.to_snake_case()
}
const INITIALISMS: &[&str] = &[
"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "FTP", "GID", "GraphQL", "GUI", "HTML", "HTTP", "HTTPS", "ID", "IMAP",
"IP", "JSON", "LHS", "MFA", "POP", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SQL", "SSH", "SSL", "TCP", "TLS",
"TTL", "UDP", "UI", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS",
];
fn apply_initialisms(name: &str, list: &[&str]) -> String {
if name.is_empty() {
return name.to_string();
}
let mut words: Vec<&str> = Vec::new();
let mut word_start = 0;
let bytes = name.as_bytes();
for i in 1..bytes.len() {
if bytes[i].is_ascii_uppercase() {
words.push(&name[word_start..i]);
word_start = i;
}
}
words.push(&name[word_start..]);
let mut result = String::with_capacity(name.len());
let mut i = 0;
while i < words.len() {
let mut matched = false;
for span in (1..=(words.len() - i)).rev() {
let candidate: String = words[i..i + span].concat();
let candidate_upper = candidate.to_ascii_uppercase();
if let Some(&canonical) = list.iter().find(|&&s| s.to_ascii_uppercase() == candidate_upper) {
result.push_str(canonical);
i += span;
matched = true;
break;
}
}
if !matched {
result.push_str(words[i]);
i += 1;
}
}
result
}
fn apply_go_acronyms(name: &str) -> String {
apply_initialisms(name, INITIALISMS)
}
pub fn to_go_name(name: &str) -> String {
apply_go_acronyms(&name.to_pascal_case())
}
pub fn go_type_name(name: &str) -> String {
apply_go_acronyms(name)
}
pub fn go_param_name(name: &str) -> String {
let pascal = apply_go_acronyms(&name.to_pascal_case());
if pascal.is_empty() {
return pascal;
}
let bytes = pascal.as_bytes();
let first_lower = bytes.iter().position(|b| b.is_ascii_lowercase());
match first_lower {
None => {
pascal.to_lowercase()
}
Some(0) => {
pascal
}
Some(pos) => {
let word_end = if pos > 1 { pos - 1 } else { 1 };
let lower_prefix = pascal[..word_end].to_lowercase();
format!("{}{}", lower_prefix, &pascal[word_end..])
}
}
}
pub fn to_java_name(name: &str) -> String {
name.to_lower_camel_case()
}
pub fn to_csharp_name(name: &str) -> String {
apply_initialisms(&name.to_pascal_case(), INITIALISMS)
}
pub fn csharp_type_name(name: &str) -> String {
apply_initialisms(name, INITIALISMS)
}
pub fn to_c_name(prefix: &str, name: &str) -> String {
format!("{}_{}", prefix, name.to_snake_case())
}
pub fn to_class_name(name: &str) -> String {
name.to_pascal_case()
}
pub fn to_constant_name(name: &str) -> String {
name.to_shouty_snake_case()
}
pub fn pascal_to_snake(name: &str) -> String {
if name.is_empty() {
return String::new();
}
let chars: Vec<char> = name.chars().collect();
let n = chars.len();
let mut out = String::with_capacity(n + 4);
let mut i = 0;
while i < n {
let ch = chars[i];
if ch.is_ascii_uppercase() {
let run_start = i;
while i < n && chars[i].is_ascii_uppercase() {
i += 1;
}
let run_end = i;
let run_len = run_end - run_start;
if run_len == 1 {
if !out.is_empty() {
out.push('_');
}
out.extend(chars[run_start].to_lowercase());
} else {
let split = if i < n && chars[i].is_ascii_lowercase() {
run_len - 1
} else {
run_len
};
if !out.is_empty() {
out.push('_');
}
for &c in chars.iter().skip(run_start).take(split) {
out.extend(c.to_lowercase());
}
if split < run_len {
out.push('_');
out.extend(chars[run_start + split].to_lowercase());
}
}
} else {
out.push(ch);
i += 1;
}
}
out
}
pub fn pascal_to_screaming_snake(name: &str) -> String {
pascal_to_snake(name).to_ascii_uppercase()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_go_name_html_initialism() {
assert_eq!(to_go_name("html"), "HTML");
}
#[test]
fn test_to_go_name_url_initialism() {
assert_eq!(to_go_name("url"), "URL");
}
#[test]
fn test_to_go_name_id_initialism() {
assert_eq!(to_go_name("id"), "ID");
}
#[test]
fn test_to_go_name_plain_word() {
assert_eq!(to_go_name("links"), "Links");
}
#[test]
fn test_to_go_name_user_id() {
assert_eq!(to_go_name("user_id"), "UserID");
}
#[test]
fn test_to_go_name_request_url() {
assert_eq!(to_go_name("request_url"), "RequestURL");
}
#[test]
fn test_to_go_name_http_status() {
assert_eq!(to_go_name("http_status"), "HTTPStatus");
}
#[test]
fn test_to_go_name_json_body() {
assert_eq!(to_go_name("json_body"), "JSONBody");
}
#[test]
fn test_go_param_name_base_url() {
assert_eq!(go_param_name("base_url"), "baseURL");
}
#[test]
fn test_go_param_name_user_id() {
assert_eq!(go_param_name("user_id"), "userID");
}
#[test]
fn test_go_param_name_api_key() {
assert_eq!(go_param_name("api_key"), "apiKey");
}
#[test]
fn test_go_param_name_plain() {
assert_eq!(go_param_name("json"), "json");
}
#[test]
fn pascal_to_snake_normal_case() {
assert_eq!(pascal_to_snake("MyType"), "my_type");
}
#[test]
fn pascal_to_snake_rdfa() {
assert_eq!(pascal_to_snake("Rdfa"), "rdfa");
}
#[test]
fn pascal_to_snake_html_parser() {
assert_eq!(pascal_to_snake("HTMLParser"), "html_parser");
}
#[test]
fn pascal_to_snake_xml_http_request() {
assert_eq!(pascal_to_snake("XMLHttpRequest"), "xml_http_request");
}
#[test]
fn pascal_to_snake_io_error() {
assert_eq!(pascal_to_snake("IOError"), "io_error");
}
#[test]
fn pascal_to_snake_url_path() {
assert_eq!(pascal_to_snake("URLPath"), "url_path");
}
#[test]
fn pascal_to_snake_jsonld_all_caps() {
assert_eq!(pascal_to_snake("JSONLD"), "jsonld");
}
#[test]
fn pascal_to_snake_camel_case() {
assert_eq!(pascal_to_snake("myField"), "my_field");
}
#[test]
fn pascal_to_snake_already_snake() {
assert_eq!(pascal_to_snake("already_snake"), "already_snake");
}
#[test]
fn pascal_to_snake_empty() {
assert_eq!(pascal_to_snake(""), "");
}
#[test]
fn pascal_to_screaming_snake_rdfa() {
assert_eq!(pascal_to_screaming_snake("Rdfa"), "RDFA");
}
#[test]
fn pascal_to_screaming_snake_html_parser() {
assert_eq!(pascal_to_screaming_snake("HTMLParser"), "HTML_PARSER");
}
#[test]
fn pascal_to_screaming_snake_my_type() {
assert_eq!(pascal_to_screaming_snake("MyType"), "MY_TYPE");
}
#[test]
fn test_to_csharp_name_graphql_route_config() {
assert_eq!(to_csharp_name("graphql_route_config"), "GraphQLRouteConfig");
}
#[test]
fn test_to_csharp_name_http_status() {
assert_eq!(to_csharp_name("http_status"), "HTTPStatus");
}
#[test]
fn test_to_csharp_name_plain() {
assert_eq!(to_csharp_name("my_field"), "MyField");
}
#[test]
fn test_csharp_type_name_heck_corrupted() {
assert_eq!(csharp_type_name("GraphQlRouteConfig"), "GraphQLRouteConfig");
}
#[test]
fn test_csharp_type_name_already_correct() {
assert_eq!(csharp_type_name("GraphQLRouteConfig"), "GraphQLRouteConfig");
}
#[test]
fn test_csharp_type_name_http_status() {
assert_eq!(csharp_type_name("HttpStatus"), "HTTPStatus");
}
}