feat: basic parsing and read structure implemented
This commit is contained in:
66
src/files/mod.rs
Normal file
66
src/files/mod.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use std::{env, fs, path::PathBuf};
|
||||
|
||||
const ENV_KEY: &str = "BLUEPRINTS_PATHS";
|
||||
const DEFAULT_PATH: &str = "./.blueprints";
|
||||
|
||||
// ╭────────────────────────╮
|
||||
// │- Read from filesystem -│
|
||||
// ╰────────────────────────╯
|
||||
pub fn get_template_options(base_paths: Vec<String>) -> Vec<String> {
|
||||
let mut type_options: Vec<String> = vec![];
|
||||
|
||||
for base_path in base_paths {
|
||||
let type_dirs = get_valid_dirs_paths(&base_path);
|
||||
// TODO: prettify this in one line
|
||||
for type_dir in type_dirs {
|
||||
type_options.push(type_dir);
|
||||
}
|
||||
}
|
||||
|
||||
type_options
|
||||
}
|
||||
|
||||
pub fn get_valid_dirs_paths(dir: &str) -> Vec<String> {
|
||||
// FIXME: this panics when the directory does not exist
|
||||
let paths = fs::read_dir(dir).unwrap();
|
||||
|
||||
let mut valid_dirs: Vec<String> = vec![];
|
||||
|
||||
for path in paths {
|
||||
let _path = path.unwrap().path();
|
||||
if is_template_path_valid(&_path) {
|
||||
valid_dirs.push(_path.display().to_string());
|
||||
}
|
||||
}
|
||||
return valid_dirs;
|
||||
}
|
||||
|
||||
pub fn is_template_path_valid(path: &PathBuf) -> bool {
|
||||
path.is_dir()
|
||||
}
|
||||
|
||||
pub fn get_base_template_paths() -> Vec<String> {
|
||||
let mut base_paths: Vec<String> = vec![];
|
||||
|
||||
match env::var(ENV_KEY) {
|
||||
Ok(value) => {
|
||||
let env_path_list = value.split(";");
|
||||
for raw_path in env_path_list {
|
||||
base_paths.push(raw_path.to_string());
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
base_paths.push(DEFAULT_PATH.to_string());
|
||||
println!(
|
||||
"${} is not set. Falling back to default './.blueprints' route.",
|
||||
ENV_KEY
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
base_paths
|
||||
}
|
||||
|
||||
// ╭───────────────────────╮
|
||||
// │- Write to filesystem -│
|
||||
// ╰───────────────────────╯
|
||||
38
src/main.rs
Normal file
38
src/main.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
mod files;
|
||||
mod parsers;
|
||||
|
||||
use files::*;
|
||||
use inquire::{Select, Text};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "./parsers/test/parsers_tests.rs"]
|
||||
mod test;
|
||||
|
||||
fn main() {
|
||||
println!(
|
||||
"╭──────────────────╮
|
||||
│- Code Templates -│
|
||||
╰──────────────────╯"
|
||||
);
|
||||
let base_paths = get_base_template_paths();
|
||||
let template_type_options = get_template_options(base_paths);
|
||||
let template_type_result =
|
||||
Select::new("Select a template variant:", template_type_options).prompt();
|
||||
|
||||
if let Ok(template_type) = template_type_result {
|
||||
let template_file_options = get_template_options(vec![template_type]);
|
||||
let template_file_result =
|
||||
Select::new("Select a template:", template_file_options).prompt();
|
||||
|
||||
if let Ok(template_file) = template_file_result {
|
||||
let target_name_result = Text::new("Insert the desired name:").prompt();
|
||||
|
||||
if let Ok(target_name) = target_name_result {
|
||||
// TODO: decide if the path should be inserted automatically of with a loop of selections -> Maybe better the loop
|
||||
let target_path_result = Text::new("Insert the target path:").prompt();
|
||||
|
||||
if let Ok(target_path) = target_path_result {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/parsers/expressions.rs
Normal file
23
src/parsers/expressions.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
pub const FILENAME_EXPRESSIONS: [&str; 9] = [
|
||||
"__name__",
|
||||
"__upperCase_name__",
|
||||
"__lowerCase_name__",
|
||||
"__camelCase_name__",
|
||||
"__pascalCase_name__",
|
||||
"__snakeCase_name__",
|
||||
"__upperSnakeCase_name__",
|
||||
"__kebabCase_name__",
|
||||
"__lowerDotCase_name__",
|
||||
];
|
||||
|
||||
pub const TEMPLATE_EXPRESSIONS: [&str; 9] = [
|
||||
"{{name}}",
|
||||
"{{upperCase name}}",
|
||||
"{{lowerCase name}}",
|
||||
"{{camelCase name}}",
|
||||
"{{pascalCase name}}",
|
||||
"{{snakeCase name}}",
|
||||
"{{upperSnakeCase name}}",
|
||||
"{{kebabCase name}}",
|
||||
"{{lowerDotCase name}}",
|
||||
];
|
||||
85
src/parsers/mod.rs
Normal file
85
src/parsers/mod.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use regex::Regex;
|
||||
|
||||
pub mod expressions;
|
||||
|
||||
pub fn apply_filename_template(template: &str, filename: &str) -> String {
|
||||
match template {
|
||||
"__name__" => filename.to_string(),
|
||||
"__upperCase_name__" => filename.to_uppercase().to_string(),
|
||||
"__lowerCase_name__" => filename.to_lowercase().to_string(),
|
||||
"__camelCase_name__" => parse_camel_case(filename),
|
||||
"__pascalCase_name__" => parse_pascal_case(filename),
|
||||
"__snakeCase_name__" => parse_snake_case(filename),
|
||||
"__upperSnakeCase_name__" => parse_snake_case(filename).to_uppercase(),
|
||||
"__kebabCase_name__" => parse_snake_case(filename).replace("_", "-"),
|
||||
"__lowerDotCase_name__" => parse_snake_case(filename).replace("_", "."),
|
||||
_ => filename.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_camel_case(filename: &str) -> String {
|
||||
let first_char_regex = Regex::new(r"^[A-Z]").unwrap();
|
||||
let filename = parse_pascal_case(filename);
|
||||
let filename = first_char_regex
|
||||
.replace_all(&filename, |captured: ®ex::Captures| {
|
||||
captured[0].to_lowercase()
|
||||
})
|
||||
.into_owned();
|
||||
filename
|
||||
}
|
||||
|
||||
fn parse_pascal_case(filename: &str) -> String {
|
||||
let char_after_space_regex = Regex::new(r" ([a-z])").unwrap();
|
||||
let first_char_regex = Regex::new(r"^[a-z]").unwrap();
|
||||
|
||||
// Change all separators by " " to facilitate regex parsing
|
||||
let filename = filename.replace("-", " ").replace("_", " ");
|
||||
|
||||
let filename = char_after_space_regex
|
||||
.replace_all(&filename, |captured: ®ex::Captures| {
|
||||
format!(" {}", captured[1].to_uppercase())
|
||||
})
|
||||
.into_owned();
|
||||
let filename = first_char_regex
|
||||
.replace_all(&filename, |captured: ®ex::Captures| {
|
||||
captured[0].to_uppercase()
|
||||
})
|
||||
.into_owned();
|
||||
|
||||
let filename = filename.replace(" ", "");
|
||||
|
||||
filename
|
||||
}
|
||||
|
||||
fn parse_snake_case(filename: &str) -> String {
|
||||
let highlight_regex = Regex::new(r"[\s\_\-A-Z]([A-Za-z])").unwrap();
|
||||
|
||||
let splited_filename = filename.split_at(1);
|
||||
let rest_filename = splited_filename.1.to_string();
|
||||
let rest_filename = highlight_regex
|
||||
.replace_all(&rest_filename, |captured: ®ex::Captures| {
|
||||
let valid_char_regex = Regex::new(r"^[A-Za-z]$").unwrap();
|
||||
|
||||
let discarded = captured[0].to_string().chars().nth(0);
|
||||
let mut left_side = "".to_string();
|
||||
|
||||
if let Some(discarded_first) = discarded {
|
||||
if valid_char_regex.is_match(&discarded_first.to_string()) {
|
||||
left_side = discarded_first.to_string();
|
||||
}
|
||||
}
|
||||
format!(
|
||||
"_{}{}",
|
||||
left_side.to_lowercase(),
|
||||
captured[1].to_lowercase()
|
||||
)
|
||||
})
|
||||
.into_owned();
|
||||
let filename = format!(
|
||||
"{}{}",
|
||||
splited_filename.0.to_lowercase(),
|
||||
rest_filename.to_lowercase()
|
||||
);
|
||||
|
||||
filename.to_string()
|
||||
}
|
||||
26
src/parsers/test/parsers_tests.rs
Normal file
26
src/parsers/test/parsers_tests.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::parsers::{apply_filename_template, expressions::FILENAME_EXPRESSIONS};
|
||||
|
||||
#[test]
|
||||
fn test_apply_filename_template() {
|
||||
const FILENAME: &str = "this_is a-TeSt";
|
||||
|
||||
let expected_filename_output = [
|
||||
"this_is a-TeSt", // normal
|
||||
"THIS_IS A-TEST", // upper
|
||||
"this_is a-test", // lower
|
||||
"thisIsATeSt", // camel
|
||||
"ThisIsATeSt", // Pascal
|
||||
"this_is_a_te_st", // snake
|
||||
"THIS_IS_A_TE_ST", // snake upper
|
||||
"this-is-a-te-st", // kebab
|
||||
"this.is.a.te.st", // lower dot
|
||||
];
|
||||
|
||||
for (i, expression) in FILENAME_EXPRESSIONS.into_iter().enumerate() {
|
||||
let output = apply_filename_template(expression, FILENAME);
|
||||
assert_eq!(output, expected_filename_output[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user