1use wasm_bindgen::prelude::*;
3
4#[derive(PartialEq, Copy, Clone)]
5enum CaseType {
6 Lcase,
8 Ucase,
10 FstUcase,
12}
13
14fn get_case(txt: &str) -> CaseType {
16 let mut cnt_lcase: usize = 0;
17 let mut cnt_ucase: usize = 0;
18
19 let alph = txt
20 .chars()
21 .filter(|c| c.is_alphabetic())
22 .collect::<Vec<char>>();
23
24 alph.iter().for_each(|c| {
25 if c.is_uppercase() {
26 cnt_ucase += 1;
27 }
28 if c.is_lowercase() {
29 cnt_lcase += 1;
30 }
31 });
32
33 if alph.len() == 0 {
34 return CaseType::Lcase; } else if cnt_lcase > 0 && cnt_ucase == 0 {
36 return CaseType::Lcase;
37 } else if cnt_lcase == 0 && cnt_ucase > 0 {
38 return CaseType::Ucase;
39 } else if alph[0].is_uppercase() && alph[1].is_lowercase() {
40 return CaseType::FstUcase;
42 }
43
44 CaseType::Lcase
45}
46
47fn restore_case(txt: String, case: CaseType) -> String {
48 match case {
49 CaseType::FstUcase => txt
50 .to_lowercase()
51 .chars()
52 .enumerate()
53 .map(|(pos, c)| {
54 if pos == 0 {
55 c.to_ascii_uppercase()
56 } else {
57 c.to_ascii_lowercase()
58 }
59 })
60 .collect::<String>(),
61 CaseType::Lcase => txt.to_lowercase(),
62 CaseType::Ucase => txt.to_uppercase(),
63 }
64}
65
66#[wasm_bindgen]
68pub fn schmfy(source: &str) -> String {
69 if source.len() == 1 && !source.chars().next().unwrap().is_alphabetic() {
71 return String::from(source);
72 }
73
74 let case = get_case(source);
75
76 if source.to_lowercase().starts_with("schm") {
78 return String::from(source);
79 }
80
81 if source.len() == 0 {
83 return String::from(source);
84 }
85
86 let mut current_substr: Vec<char> = vec![];
88 let mut substrings: Vec<String> = vec![];
89 source.chars().for_each(|c| {
90 if c.is_alphabetic() {
91 current_substr.push(c)
92 } else {
93 if current_substr.len() > 0 {
94 substrings.push(current_substr.iter().collect::<String>());
95 current_substr.clear();
96 }
97 substrings.push(c.to_string())
98 }
99 });
100 if current_substr.len() > 0 {
101 substrings.push(current_substr.iter().collect::<String>());
102 }
103
104 if substrings.len() > 1 {
105 return substrings
106 .iter()
107 .map(|txt| schmfy(txt))
108 .collect::<Vec<String>>()
109 .join("");
110 }
111
112 let source = substrings[0].to_lowercase();
114
115 if !source.chars().next().unwrap().is_alphabetic() {
116 return String::from(source);
117 }
118
119 if source.len() <= 3 && case != CaseType::FstUcase {
121 let first_c_size = source.chars().next().unwrap().len_utf8();
122 let (prefix, suffix) = source.split_at(first_c_size);
123 let c = prefix.chars().next().unwrap_or('-');
124 return restore_case(schmfy_char(c) + suffix, case);
125 }
126
127 let vok_pos = source.find(|c| "aeiouäöü".contains(c)).unwrap_or(0);
130
131 let (_, suffix) = source.split_at(vok_pos);
132
133 restore_case(String::from("schm") + suffix, case)
134}
135
136fn schmfy_char(c: char) -> String {
138 let mut ret = String::from("schm");
139 match c {
140 'a' | 'e' | 'i' | 'o' | 'u' | 'ä' | 'ö' | 'ü' => {
141 ret.push(c);
142 }
143 'b' | 'c' | 'd' | 'g' | 'p' | 't' | 'w' => ret.push('e'),
144 'f' | 'l' | 'm' | 'n' | 'r' | 's' => {
145 ret.push('e');
146 ret.push(c)
147 }
148 'h' | 'k' => ret.push('a'),
149 'j' => {
150 ret.push('o');
151 ret.push('t')
152 }
153 'q' => ret.push('u'),
154 'v' => {
155 ret.push('a');
156 ret.push('u')
157 }
158 'x' => {
159 ret.push('i');
160 ret.push('x')
161 }
162 'y' => ret.push(c),
163 'z' => {
164 ret.push('e');
165 ret.push('t')
166 }
167 _ => ret.push(c),
168 }
169
170 ret
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn schmfy_plaintext_tests() {
179 assert_eq!(schmfy("test"), "schmest");
180 assert_eq!(schmfy("Hello"), "Schmello");
181 assert_eq!(schmfy("HELLO"), "SCHMELLO");
182 assert_eq!(schmfy("hello"), "schmello");
183 assert_eq!(schmfy("Bar"), "Schmar");
184 }
185
186 #[test]
187 fn schmfy_mixtext_tests() {
188 assert_eq!(schmfy(">Test"), ">Schmest");
189 assert_eq!(schmfy(">tesT"), ">schmest");
190 assert_eq!(schmfy("One&Two"), "Schmone&Schmo");
191 assert_eq!(
192 schmfy("<span>Entry<br></span>"),
193 "<schman>Schmentry<schmer></schman>"
194 );
195 assert_eq!(schmfy("foo/bar/baz"), "schmefoo/schmear/schmeaz");
196 assert_eq!(
197 schmfy("long/Longer/LONGESTTT"),
198 "schmong/Schmonger/SCHMONGESTTT"
199 );
200 }
201
202 #[test]
203 fn schmfy_sentences_tests() {
204 assert_eq!(
205 schmfy("Today I am VERY tired."),
206 "Schmoday SCHMI schmam SCHMERY schmired."
207 );
208 assert_eq!(
209 schmfy("Lorem ipsum dolor sit amet, consetetur sadipscing elitr"),
210 "Schmorem schmipsum schmolor schmesit schmamet, schmonsetetur schmadipscing schmelitr"
211 );
212 }
213
214 #[test]
215 fn schmfy_code_tests() {
216 assert_eq!(
217 schmfy(
218 "#include <stdio.h>
219#include <sys/types.h>
220
221int main()
222{
223 while(1)
224 fork();
225 return 0;
226}"
227 ),
228 "#schminclude <schmio.schma>
229#schminclude <schmesys/schmes.schma>
230
231schmint schmain()
232{
233 schmile(1)
234 schmork();
235 schmeturn 0;
236}"
237 );
238
239 assert_eq!(
240 schmfy(
241 "
242```
243This is a Markdown codebox
244```
245| This | is |
246|---|---|
247| a | Markdown |
248| table | ! |"
249 ),
250 "
251```
252Schmis schmis schma Schmarkdown schmodebox
253```
254| Schmis | schmis |
255|---|---|
256| schma | Schmarkdown |
257| schmable | ! |"
258 )
259 }
260}