Skip to main content

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// Example 2: Multi-word PascalCase
66/// ```rust
67/// use crate::Maintain::Source::Build::WordsFromPascal;
68/// let words = WordsFromPascal("NodeEnvironment");
69/// assert_eq!(words, vec!["node", "environment"]);
70/// ```
71// Example 3: Acronyms
72/// ```rust
73/// use crate::Maintain::Source::Build::WordsFromPascal;
74/// let words = WordsFromPascal("TauriAppsTauri");
75/// assert_eq!(words, vec!["tauri", "apps", "tauri"]);
76/// ```
77//
78//=============================================================================//
79// IMPLEMENTATION
80//=============================================================================//
81
82/// Converts a `PascalCase` string into a vector of its lowercase constituent
83/// words.
84///
85/// This function splits PascalCase strings into their individual words by
86/// detecting word boundaries where lowercase letters appear after uppercase
87/// letters. It handles common cases including:
88///
89/// - Simple words: `"Hello"` → `["hello"]`
90/// - Standard PascalCase: `"HelloWorld"` → `["hello", "world"]`
91/// - Multi-letter acronyms: `"TauriApps"` → `["tauri", "apps"]`
92///
93/// The algorithm tracks when transitions occur from lowercase to uppercase
94/// to determine word boundaries.
95///
96/// # Parameters
97///
98/// * `Text` - The PascalCase string to split
99///
100/// # Returns
101///
102/// A vector of lowercase strings representing the constituent words.
103///
104/// # Behavior
105///
106/// - Splits at boundaries where lowercase letters are followed by uppercase
107/// - Handles consecutive uppercase letters as part of the same word
108/// - Converts all words to lowercase
109/// - Returns an empty vector for empty strings
110///
111/// # Examples
112///
113/// ```
114/// use crate::Maintain::Source::Build::WordsFromPascal;
115/// assert_eq!(WordsFromPascal("Hello"), vec!["hello"]);
116/// assert_eq!(WordsFromPascal("HelloWorld"), vec!["hello", "world"]);
117/// assert_eq!(WordsFromPascal("NodeEnvironment"), vec!["node", "environment"]);
118/// assert_eq!(WordsFromPascal("TauriAppsTauri"), vec!["tauri", "apps", "tauri"]);
119/// assert_eq!(WordsFromPascal(""), Vec::<String>::new());
120/// ```
121///
122/// # Edge Cases
123///
124/// - Empty string returns an empty vector
125/// - Single character strings work correctly
126/// - Strings with all lowercase are treated as a single word
127/// - Strings with all uppercase are treated as a single word
128///
129/// # Algorithm
130///
131/// The function iterates through each character:
132/// 1. If the character is uppercase:
133///    - If we have accumulated lowercase characters, end the current word
134///    - Add the uppercase character to the current word
135///    - Track that we're processing uppercase characters
136/// 2. If the character is lowercase:
137///    - Add to the current word
138///    - Track that we're processing lowercase characters
139/// 3. After iteration, add the final word
140///
141/// This ensures that multi-letter sequences like "Apps" stay together while
142/// properly splitting "HelloWorld" into "hello" and "world".
143pub fn WordsFromPascal(Text:&str) -> Vec<String> {
144	if Text.is_empty() {
145		return Vec::new();
146	}
147
148	let mut Words = Vec::new();
149
150	let mut CurrentWord = String::new();
151
152	let mut LastCharWasUppercase = false;
153
154	for Char in Text.chars() {
155		if Char.is_uppercase() {
156			if !CurrentWord.is_empty() && !LastCharWasUppercase {
157				Words.push(CurrentWord.to_ascii_lowercase());
158
159				CurrentWord.clear();
160			}
161
162			CurrentWord.push(Char);
163
164			LastCharWasUppercase = true;
165		} else {
166			CurrentWord.push(Char);
167
168			LastCharWasUppercase = false;
169		}
170	}
171
172	if !CurrentWord.is_empty() {
173		Words.push(CurrentWord.to_ascii_lowercase());
174	}
175
176	Words
177}
178
179#[cfg(test)]
180mod tests {
181	use super::*;
182
183	#[test]
184	fn test_single_word() {
185		assert_eq!(WordsFromPascal("Hello"), vec!["hello"]);
186		assert_eq!(WordsFromPascal("World"), vec!["world"]);
187	}
188
189	#[test]
190	fn test_two_words() {
191		assert_eq!(WordsFromPascal("HelloWorld"), vec!["hello", "world"]);
192		assert_eq!(WordsFromPascal("NodeEnvironment"), vec!["node", "environment"]);
193	}
194
195	#[test]
196	fn test_multiple_words() {
197		assert_eq!(WordsFromPascal("TauriAppsTauri"), vec!["tauri", "apps", "tauri"]);
198		assert_eq!(WordsFromPascal("MyAwesomeAppName"), vec!["my", "awesome", "app", "name"]);
199	}
200
201	#[test]
202	fn test_empty_string() {
203		assert_eq!(WordsFromPascal(""), Vec::<String>::new());
204	}
205
206	#[test]
207	fn test_all_lowercase() {
208		assert_eq!(WordsFromPascal("hello"), vec!["hello"]);
209	}
210
211	#[test]
212	fn test_all_uppercase() {
213		assert_eq!(WordsFromPascal("HELLO"), vec!["hello"]);
214	}
215
216	#[test]
217	fn test_single_character() {
218		assert_eq!(WordsFromPascal("A"), vec!["a"]);
219		assert_eq!(WordsFromPascal("a"), vec!["a"]);
220	}
221}