ligen_ir/identifier/
naming_convention.rs1use crate::{prelude::*, Identifier};
4
5#[derive(Debug, Clone, Serialize, Deserialize, Display, PartialEq, Eq)]
7pub enum NamingConvention {
8 KebabCase,
10
11 SnakeCase,
13
14 PascalCase,
16
17 CamelCase,
19
20 Unknown,
22}
23
24impl Identifier {
25 pub fn naming_convention(&self) -> NamingConvention {
27 if self.name.contains('-') {
28 NamingConvention::KebabCase
29 } else if self.name.contains('_') {
30 NamingConvention::SnakeCase
31 } else if self.name.chars().next().unwrap().is_uppercase() {
32 NamingConvention::PascalCase
33 } else if self.name.chars().any(|c| c.is_uppercase()) {
34 NamingConvention::CamelCase
35 } else {
36 NamingConvention::Unknown
37 }
38 }
39
40 pub fn to_camel_case(&self) -> Self {
42 let mut result = String::new();
43 let mut first = true;
44 for word in self.words() {
45 if first {
46 result.push_str(word.to_lowercase().as_str());
47 first = false;
48 } else {
49 result.push_str(&word[..1].to_uppercase());
50 result.push_str(&word[1..]);
51 }
52 }
53 result.into()
54 }
55
56 pub fn to_pascal_case(&self) -> Self {
58 let mut result = String::new();
59 for word in self.words() {
60 result.push_str(&word[..1].to_uppercase());
61 result.push_str(&word[1..]);
62 }
63 result.into()
64 }
65
66 pub fn to_snake_case(&self) -> Self {
68 let mut result = String::new();
69 let mut first = true;
70 for word in self.words() {
71 if first {
72 result.push_str(word.to_lowercase().as_str());
73 first = false;
74 } else {
75 result.push('_');
76 result.push_str(word.to_lowercase().as_str());
77 }
78 }
79 result.into()
80 }
81
82 pub fn to_kebab_case(&self) -> Self {
84 let mut result = String::new();
85 let mut first = true;
86 for word in self.words() {
87 if first {
88 result.push_str(word.to_lowercase().as_str());
89 first = false;
90 } else {
91 result.push('-');
92 result.push_str(word.to_lowercase().as_str());
93 }
94 }
95 result.into()
96 }
97
98 pub fn words(&self) -> Vec<&str> {
100 match self.naming_convention() {
101 NamingConvention::SnakeCase => self.name.split('_').collect(),
102 NamingConvention::KebabCase => self.name.split('-').collect(),
103 NamingConvention::PascalCase => {
104 let indices = self
105 .name
106 .chars()
107 .enumerate()
108 .filter(|(_, c)| c.is_uppercase())
109 .map(|(index, _)| index)
110 .chain(std::iter::once(self.name.len()))
111 .collect::<Vec<_>>();
112 (0 .. indices.len() - 1)
113 .map(|i| {
114 &self.name[indices[i]..=(indices[i + 1] - 1)]
115 })
116 .collect()
117 },
118 NamingConvention::CamelCase => {
119 let indices =
120 std::iter::once(0)
121 .chain(self
122 .name
123 .chars()
124 .enumerate()
125 .filter(|(_, c)| c.is_uppercase())
126 .map(|(index, _)| index)
127 .chain(std::iter::once(self.name.len()))
128 ).collect::<Vec<_>>();
129 (0 .. indices.len() - 1)
130 .map(|i| {
131 &self.name[indices[i]..=(indices[i + 1] - 1)]
132 })
133 .collect()
134 },
135 NamingConvention::Unknown => vec![self.name.as_str()],
136 }
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use crate::Identifier;
143
144 use super::*;
145
146 #[test]
147 fn kebab_case() {
148 assert_eq!(Identifier::from("kebab-case").naming_convention(), NamingConvention::KebabCase);
149 }
150
151 #[test]
152 fn snake_case() {
153 assert_eq!(Identifier::from("snake_case").naming_convention(), NamingConvention::SnakeCase);
154 }
155
156 #[test]
157 fn pascal_case() {
158 assert_eq!(Identifier::from("PascalCase").naming_convention(), NamingConvention::PascalCase);
159 }
160
161 #[test]
162 fn camel_case() {
163 assert_eq!(Identifier::from("camelCase").naming_convention(), NamingConvention::CamelCase);
164 }
165
166 #[test]
167 fn words() {
168 assert_eq!(Identifier::from("case").words(), vec!["case"]);
169 assert_eq!(Identifier::from("kebab-case").words(), vec!["kebab", "case"]);
170 assert_eq!(Identifier::from("snake_case").words(), vec!["snake", "case"]);
171 assert_eq!(Identifier::from("PascalCase").words(), vec!["Pascal", "Case"]);
172 assert_eq!(Identifier::from("camelCase").words(), vec!["camel", "Case"]);
173 }
174
175 #[test]
176 fn convertion() {
177 assert_eq!(Identifier::from("kebab-case").to_snake_case(), Identifier::from("kebab_case"));
178 assert_eq!(Identifier::from("kebab-case").to_pascal_case(), Identifier::from("KebabCase"));
179 assert_eq!(Identifier::from("kebab-case").to_camel_case(), Identifier::from("kebabCase"));
180 assert_eq!(Identifier::from("snake_case").to_kebab_case(), Identifier::from("snake-case"));
181 assert_eq!(Identifier::from("snake_case").to_pascal_case(), Identifier::from("SnakeCase"));
182 assert_eq!(Identifier::from("snake_case").to_camel_case(), Identifier::from("snakeCase"));
183 assert_eq!(Identifier::from("PascalCase").to_kebab_case(), Identifier::from("pascal-case"));
184 assert_eq!(Identifier::from("PascalCase").to_snake_case(), Identifier::from("pascal_case"));
185 assert_eq!(Identifier::from("PascalCase").to_camel_case(), Identifier::from("pascalCase"));
186 assert_eq!(Identifier::from("camelCase").to_kebab_case(), Identifier::from("camel-case"));
187 assert_eq!(Identifier::from("camelCase").to_snake_case(), Identifier::from("camel_case"));
188 assert_eq!(Identifier::from("camelCase").to_pascal_case(), Identifier::from("CamelCase"));
189 }
190}