untools/
lib.rs

1use std::fs;
2
3use console::style;
4use utils::{is_camel_or_pascal_case, starts_with_digit};
5
6mod utils;
7/// Converts a camelCase or PascalCase string to snake_case.
8///
9/// If the input string is empty, returns an error message.
10/// If the input string is a digit, returns an error message.
11/// If the input string already contains underscores, returns the input string as-is.
12/// If the input string is not in camelCase format, returns an error message.
13///
14/// # Arguments
15///
16/// * `name` - A string slice that holds the variable name to be converted.
17/// * `is_constant` - A boolean flag indicating if the output should be in all caps.
18///
19/// # Returns
20///
21/// A String containing the snake_case version of the input variable name.
22/// 
23/// # Usage
24///
25/// This converts the the variable "testVariable" from camelcase to snakecase in all caps.
26/// 
27/// ``` 
28/// use untools::camel_to_snake;
29/// assert_eq!(camel_to_snake("testVariable", true), "TEST_VARIABLE")
30/// ```
31///
32pub fn camel_to_snake(name: &str, is_constant: bool) -> String {
33    if name.is_empty() {
34        println!(
35            "{}",
36            style("Input string is empty. Please provide a valid variable name.").color256(208)
37        );
38        return String::new();
39    }
40
41    if !starts_with_digit(name) {
42        println!("{}", style("Input string is a digit.").color256(208));
43        return String::new();
44    }
45
46    if name.contains('_') {
47        return name.to_string();
48    }
49
50    if !is_camel_or_pascal_case(name) {
51        println!(
52            "{}",
53            style("is not in camelCase format. Please provide a valid camelCase variable name.")
54                .color256(208)
55        );
56        return String::new();
57    }
58
59    let mut result = String::new();
60
61    for (i, c) in name.chars().enumerate() {
62        if i > 0 && c.is_uppercase() {
63            result.push('_');
64        }
65        result.push(c.to_lowercase().next().unwrap());
66    }
67
68    if is_constant {
69        return result.to_uppercase();
70    }
71
72    result
73}
74
75/// Batch convert variable names
76///
77/// This function reads variable name data from the specified input file, converts them to the specified naming convention (camelCase or SCREAMING_SNAKE_CASE),
78/// and then writes the converted results to the specified output file.
79///
80/// # Arguments
81/// - `ifile`: The path to the input file
82/// - `ofile`: The path to the output file
83/// - `is_constant`: Whether to convert to SCREAMING_SNAKE_CASE, `true` to convert to SCREAMING_SNAKE_CASE, `false` to convert to camelCase
84/// - `silent`: Whether to supress output
85/// # Example
86///
87/// ```rust
88/// untools::batch_convert("input.txt", "output.txt", true, false);
89/// ```
90pub fn batch_convert(ifile: &str, ofile: &str, is_constant: bool, silent: bool) {
91    let contents = fs::read_to_string(ifile).expect("Unable to read file.");
92
93    let converted_names: Vec<String> = contents
94        .lines()
95        .map(|line| camel_to_snake(line.trim(), is_constant))
96        .collect();
97
98    let output_content = converted_names.join("\n");
99    fs::write(ofile, output_content).expect("Unable to write file.");
100    if !silent {
101        println!("Batch conversion successful! Results written to {}", ofile);
102    }
103}
104
105/// Converts a snake_case string to a camelCase string.
106///
107/// # Arguments
108///
109/// * `name` - A string slice that holds the snake_case variable name to be converted.
110/// * `to_lower_camel` - A boolean indicating whether the output should be in lowerCamelCase (true) or UpperCamelCase (false).
111///
112/// # Returns
113///
114/// * A String containing the camelCase representation of the input string.
115///
116pub fn snake_to_camel(name: &str, upper_case_camel: bool) -> String {
117    let mut camel_case = String::new();
118    let mut capitalize_next = true;
119
120    let mut to_lower_camel = !upper_case_camel;
121    
122    if name.is_empty() {
123        return String::from("Input string is empty. Please provide a valid variable name.");
124    }
125
126    if !starts_with_digit(name) {
127        return String::from("Input string is a digit.");
128    }
129
130    for c in name.chars() {
131        if c == '_' {
132            capitalize_next = true;
133        } else {
134            if capitalize_next {
135                if to_lower_camel {
136                    camel_case.push(c.to_ascii_lowercase());
137                    to_lower_camel = false; // Reset to_lower_camel for the next word
138                } else {
139                    camel_case.push(c.to_ascii_uppercase());
140                }
141                capitalize_next = false;
142            } else {
143                camel_case.push(c);
144            }
145        }
146    }
147    camel_case
148}