Maintain/Build/WordsFromPascal.rs
1//=============================================================================//
2// File Path: Element/Maintain/Source/Build/WordsFromPascal.rs
3//=============================================================================//
4// Module: WordsFromPascal
5//
6// Brief Description: Converts PascalCase strings into lowercase word vectors.
7//
8// RESPONSIBILITIES:
9// ================
10//
11// Primary:
12// - Convert PascalCase strings to lowercase word vectors
13// - Split PascalCase into constituent words
14// - Handle multi-letter uppercase sequences
15//
16// Secondary:
17// - None
18//
19// ARCHITECTURAL ROLE:
20// ===================
21//
22// Position:
23// - Infrastructure/Utility layer
24// - String transformation utilities
25//
26// Dependencies (What this module requires):
27// - External crates: None
28// - Internal modules: None
29// - Traits implemented: None
30//
31// Dependents (What depends on this module):
32// - Build orchestration functions
33// - Bundle identifier generation logic
34//
35// IMPLEMENTATION DETAILS:
36// =======================
37//
38// Design Patterns:
39// - String transformation pattern
40// - Functional pattern
41//
42// Performance Considerations:
43// - Complexity: O(n) - where n is the length of the input string
44// - Memory usage patterns: Creates new String for each word
45// - Hot path optimizations: None needed
46//
47// Thread Safety:
48// - Thread-safe: Yes (pure function with immutable input and output)
49// - Synchronization mechanisms used: None
50// - Interior mutability considerations: None
51//
52// Error Handling:
53// - Error types returned: None
54// - Recovery strategies: Not applicable
55//
56// EXAMPLES:
57// =========
58//
59// Example 1: Simple PascalCase
60/// ```rust
61/// use crate::Maintain::Source::Build::WordsFromPascal;
62/// let words = WordsFromPascal("Development");
63/// assert_eq!(words, vec!["development"]);
64/// ```
65//
66// Example 2: Multi-word PascalCase
67/// ```rust
68/// use crate::Maintain::Source::Build::WordsFromPascal;
69/// let words = WordsFromPascal("NodeEnvironment");
70/// assert_eq!(words, vec!["node", "environment"]);
71/// ```
72//
73// Example 3: Acronyms
74/// ```rust
75/// use crate::Maintain::Source::Build::WordsFromPascal;
76/// let words = WordsFromPascal("TauriAppsTauri");
77/// assert_eq!(words, vec!["tauri", "apps", "tauri"]);
78/// ```
79//
80//=============================================================================//
81// IMPLEMENTATION
82//=============================================================================//
83
84/// Converts a `PascalCase` string into a vector of its lowercase constituent
85/// words.
86///
87/// This function splits PascalCase strings into their individual words by
88/// detecting word boundaries where lowercase letters appear after uppercase
89/// letters. It handles common cases including:
90///
91/// - Simple words: `"Hello"` → `["hello"]`
92/// - Standard PascalCase: `"HelloWorld"` → `["hello", "world"]`
93/// - Multi-letter acronyms: `"TauriApps"` → `["tauri", "apps"]`
94///
95/// The algorithm tracks when transitions occur from lowercase to uppercase
96/// to determine word boundaries.
97///
98/// # Parameters
99///
100/// * `Text` - The PascalCase string to split
101///
102/// # Returns
103///
104/// A vector of lowercase strings representing the constituent words.
105///
106/// # Behavior
107///
108/// - Splits at boundaries where lowercase letters are followed by uppercase
109/// - Handles consecutive uppercase letters as part of the same word
110/// - Converts all words to lowercase
111/// - Returns an empty vector for empty strings
112///
113/// # Examples
114///
115/// ```
116/// use crate::Maintain::Source::Build::WordsFromPascal;
117/// assert_eq!(WordsFromPascal("Hello"), vec!["hello"]);
118/// assert_eq!(WordsFromPascal("HelloWorld"), vec!["hello", "world"]);
119/// assert_eq!(WordsFromPascal("NodeEnvironment"), vec!["node", "environment"]);
120/// assert_eq!(WordsFromPascal("TauriAppsTauri"), vec!["tauri", "apps", "tauri"]);
121/// assert_eq!(WordsFromPascal(""), Vec::<String>::new());
122/// ```
123///
124/// # Edge Cases
125///
126/// - Empty string returns an empty vector
127/// - Single character strings work correctly
128/// - Strings with all lowercase are treated as a single word
129/// - Strings with all uppercase are treated as a single word
130///
131/// # Algorithm
132///
133/// The function iterates through each character:
134/// 1. If the character is uppercase:
135/// - If we have accumulated lowercase characters, end the current word
136/// - Add the uppercase character to the current word
137/// - Track that we're processing uppercase characters
138/// 2. If the character is lowercase:
139/// - Add to the current word
140/// - Track that we're processing lowercase characters
141/// 3. After iteration, add the final word
142///
143/// This ensures that multi-letter sequences like "Apps" stay together while
144/// properly splitting "HelloWorld" into "hello" and "world".
145pub fn WordsFromPascal(Text: &str) -> Vec<String> {
146 if Text.is_empty() {
147 return Vec::new();
148 }
149
150 let mut Words = Vec::new();
151
152 let mut CurrentWord = String::new();
153
154 let mut LastCharWasUppercase = false;
155
156 for Char in Text.chars() {
157 if Char.is_uppercase() {
158 if !CurrentWord.is_empty() && !LastCharWasUppercase {
159 Words.push(CurrentWord.to_ascii_lowercase());
160
161 CurrentWord.clear();
162 }
163
164 CurrentWord.push(Char);
165
166 LastCharWasUppercase = true;
167 } else {
168 CurrentWord.push(Char);
169
170 LastCharWasUppercase = false;
171 }
172 }
173
174 if !CurrentWord.is_empty() {
175 Words.push(CurrentWord.to_ascii_lowercase());
176 }
177
178 Words
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn test_single_word() {
187 assert_eq!(WordsFromPascal("Hello"), vec!["hello"]);
188 assert_eq!(WordsFromPascal("World"), vec!["world"]);
189 }
190
191 #[test]
192 fn test_two_words() {
193 assert_eq!(WordsFromPascal("HelloWorld"), vec!["hello", "world"]);
194 assert_eq!(WordsFromPascal("NodeEnvironment"), vec!["node", "environment"]);
195 }
196
197 #[test]
198 fn test_multiple_words() {
199 assert_eq!(
200 WordsFromPascal("TauriAppsTauri"),
201 vec!["tauri", "apps", "tauri"]
202 );
203 assert_eq!(
204 WordsFromPascal("MyAwesomeAppName"),
205 vec!["my", "awesome", "app", "name"]
206 );
207 }
208
209 #[test]
210 fn test_empty_string() {
211 assert_eq!(WordsFromPascal(""), Vec::<String>::new());
212 }
213
214 #[test]
215 fn test_all_lowercase() {
216 assert_eq!(WordsFromPascal("hello"), vec!["hello"]);
217 }
218
219 #[test]
220 fn test_all_uppercase() {
221 assert_eq!(WordsFromPascal("HELLO"), vec!["hello"]);
222 }
223
224 #[test]
225 fn test_single_character() {
226 assert_eq!(WordsFromPascal("A"), vec!["a"]);
227 assert_eq!(WordsFromPascal("a"), vec!["a"]);
228 }
229}