From 95ad37072f4a85a03e744d4512c4bd061b2969a0 Mon Sep 17 00:00:00 2001 From: cophilot Date: Tue, 20 Feb 2024 22:27:26 +0100 Subject: [PATCH] v0.6.0 --- .phil-project | 2 +- CHANGELOG.md | 8 +++ Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 34 ++++++++++--- src/command_storage.rs | 6 +++ src/commands.rs | 9 +--- src/data.rs | 30 ++++++++++- src/formater.rs | 110 +++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/utils.rs | 18 ++----- 11 files changed, 188 insertions(+), 34 deletions(-) create mode 100644 src/formater.rs diff --git a/.phil-project b/.phil-project index 79158bc..7b4686e 100644 --- a/.phil-project +++ b/.phil-project @@ -1,4 +1,4 @@ logo:assets/logo.png logo_small:assets/logo.png description_translate:de -version:0.5.0 +version:0.6.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index d0ec81c..e72fcab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ --- +## [v0.6.0](https://github.com/cophilot/templify/tree/0.6.0) (2024-2-20) + +- Refactoring +- Added placeholder `$$month-name$$` +- Added case conversion support for the `name` placeholder + +--- + ## [v0.5.0](https://github.com/cophilot/templify/tree/0.5.0) (2024-2-17) - Refactoring diff --git a/Cargo.lock b/Cargo.lock index a4ad0f8..bf91835 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -845,7 +845,7 @@ dependencies = [ [[package]] name = "templify" -version = "0.5.0" +version = "0.6.0" dependencies = [ "chrono", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index 7fd7f8f..92aaa9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "templify" -version = "0.5.0" +version = "0.6.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 8559c76..4bc6cbd 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ For a more detailed documentation visit the [templify-docs](https://templify.phi - [list](#list) - [generate](#generate) - [Placeholders](#placeholders) + - [Case conversion](#case-conversion) - [templify-vault](#templify-vault) - [Bugs](#bugs) - [Release Notes](#release-notes) @@ -185,9 +186,29 @@ Generates a file from the given template. ## Placeholders -Placeholders are used to replace parts of the template with the given values. They are defined by surrounding a word with two dollar signs (`$$`): +- `$$name$$`: The name of the new file (This placeholder supports case conversion). +- `$$year$$`: The current year. +- `$$month$$`: The current month as a number. +- `$$month-name$$`: The current month as a name. +- `$$day$$`: The current day. +- `$$git-name$$`: The name of the git user. -- `$$name$$` will be replaced with the given name +### Case conversion + +Case conversion is used to convert placeholders to different case styles. You can use them by adding a `.` and the case style to a placeholder that supports case conversion. + +_Example: `$$name.kebab$$`_ + +You can use the following case conversion: + +- `$$.lower$$`: Lower case (e.g. `mycomponent`) +- `$$.upper$$`: Upper case (e.g. `MYCOMPONENT`) +- `$$.camel$$`: Camel case (e.g. `myComponent`) +- `$$.snake$$`: Snake case (e.g. `my_component`) +- `$$.kebab$$`: Kebab case (e.g. `my-component`) +- `$$.pascal$$`: Pascal case (e.g. `MyComponent`) +- `$$.macro$$`: Macro case (e.g. `MY_COMPONENT`) +- `$$.train$$`: Train case (e.g. `My-Component`) --- @@ -213,14 +234,11 @@ tpy load https://github.com/cophilot/templify-vault/tree/main/React-ts ## [Release Notes](https://github.com/cophilot/templify/blob/master/CHANGELOG.md) -### [v0.5.0](https://github.com/cophilot/templify/tree/0.5.0) +### [v0.6.0](https://github.com/cophilot/templify/tree/0.6.0) - Refactoring -- Added `reload` command -- Added `-name` flag for the `list` command -- Added `-path` flag for the `list` command -- Added `-template` flag for the `load` command -- Support for `.tpykeep` file to prevent a directory from being deleted +- Added placeholder `$$month-name$$` +- Added case conversion support for the `name` placeholder --- diff --git a/src/command_storage.rs b/src/command_storage.rs index 62f32bb..de73c5b 100644 --- a/src/command_storage.rs +++ b/src/command_storage.rs @@ -196,6 +196,12 @@ pub fn get_all_commands() -> Vec { "If enabled the file will not be created and the output will be printed.".to_string(), )); + /* generate_com.add_flag(Flag::new_bool_flag( + vec!["force".to_string(), "f".to_string()], + "If enabled files will be overwritten if they already exist.".to_string(), + )); + */ + commands.push(generate_com); return commands; diff --git a/src/commands.rs b/src/commands.rs index 2309913..2ceb273 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,8 +1,8 @@ use crate::{ + formater, types::{self, Command, Status}, utils, version_control, }; -use chrono::{self, Datelike}; use std::fs::read_dir; pub fn list(command: &Command) -> Status { @@ -179,12 +179,7 @@ pub fn generate(command: &Command) -> Status { ); let meta = types::TemplateMeta::parse(template_name.clone().to_string()); let mut new_path = meta.get_path(); - - new_path = new_path.replace("$$name$$", given_name.as_str()); - new_path = new_path.replace("$$year$$", chrono::Local::now().year().to_string().as_str()); - new_path = new_path.replace("$$month$$", &chrono::Local::now().month().to_string()); - new_path = new_path.replace("$$day$$", &chrono::Local::now().day().to_string()); - new_path = new_path.replace("$$git-name$$", &utils::get_git_name()); + new_path = formater::handle_placeholders(&new_path, &given_name); // create dir and all subdirs if they don't exist if !dry_run { diff --git a/src/data.rs b/src/data.rs index 21e978f..c9fc5eb 100644 --- a/src/data.rs +++ b/src/data.rs @@ -16,7 +16,7 @@ pub fn get_init_readme_content() -> String { # Welcome to templify (v{}) -This is a README file generated by templify. +_This is a README file generated by templify._ --- @@ -75,6 +75,34 @@ This will create a new file from the given template in the current project folde --- +## Placeholders + +- `$$name$$`: The name of the new file (This placeholder supports case conversion). +- `$$year$$`: The current year. +- `$$month$$`: The current month as a number. +- `$$month-name$$`: The current month as a name. +- `$$day$$`: The current day. +- `$$git-name$$`: The name of the git user. + +### Case conversion + +Case conversion is used to convert placeholders to different case styles. You can use them by adding a `.` and the case style to a placeholder that supports case conversion. + +_Example: `$$name.kebab$$`_ + +You can use the following case conversion: + +- `$$.lower$$`: Lower case (e.g. `mycomponent`) +- `$$.upper$$`: Upper case (e.g. `MYCOMPONENT`) +- `$$.camel$$`: Camel case (e.g. `myComponent`) +- `$$.snake$$`: Snake case (e.g. `my_component`) +- `$$.kebab$$`: Kebab case (e.g. `my-component`) +- `$$.pascal$$`: Pascal case (e.g. `MyComponent`) +- `$$.macro$$`: Macro case (e.g. `MY_COMPONENT`) +- `$$.train$$`: Train case (e.g. `My-Component`) + +--- + by [Philipp B.](https://github.com/cophilot) ", env!("CARGO_PKG_VERSION")); diff --git a/src/formater.rs b/src/formater.rs new file mode 100644 index 0000000..e5179c9 --- /dev/null +++ b/src/formater.rs @@ -0,0 +1,110 @@ +use chrono::Datelike; + +pub fn handle_placeholders(s: &str, name: &str) -> String { + let mut s = s.to_string(); + + s = s.replace("$$name$$", name); + s = s.replace("$$name.lower$$", name.to_lowercase().as_str()); + s = s.replace("$$name.upper$$", name.to_uppercase().as_str()); + + let tokens = tokenize_string(name); + s = s.replace("$$name.camel$$", &to_camel_case(tokens.clone())); + s = s.replace("$$name.snake$$", &to_snake_case(tokens.clone())); + s = s.replace("$$name.kebab$$", &to_kebab_case(tokens.clone())); + s = s.replace("$$name.pascal$$", &to_pascal_case(tokens.clone())); + s = s.replace("$$name.macro$$", &to_macro_case(tokens.clone())); + s = s.replace("$$name.train$$", &to_train_case(tokens.clone())); + + s = s.replace("$$year$$", chrono::Local::now().year().to_string().as_str()); + s = s.replace("$$month$$", &chrono::Local::now().month().to_string()); + let month_str = match chrono::Local::now().month() { + 1 => "Jan", + 2 => "Feb", + 3 => "Mar", + 4 => "Apr", + 5 => "May", + 6 => "Jun", + 7 => "Jul", + 8 => "Aug", + 9 => "Sep", + 10 => "Oct", + 11 => "Nov", + 12 => "Dec", + _ => "Unknown", + }; + s = s.replace("$$month-name$$", month_str); + s = s.replace("$$day$$", &chrono::Local::now().day().to_string()); + s = s.replace("$$git-name$$", &crate::utils::get_git_name()); + return s; +} + +fn to_train_case(tokens: Vec) -> String { + let mut result = String::new(); + for (i, token) in tokens.iter().enumerate() { + let newtoken = format!("{}{}", &token[0..1].to_uppercase(), &token[1..]); + if i == 0 { + result.push_str(&newtoken); + } else { + result.push_str(&format!("-{}", newtoken)); + } + } + return result; +} + +fn to_macro_case(tokens: Vec) -> String { + return tokens.join("_").to_uppercase(); +} + +fn to_pascal_case(tokens: Vec) -> String { + let mut result = String::new(); + for token in tokens { + let newtoken = format!("{}{}", &token[0..1].to_uppercase(), &token[1..]); + result.push_str(&newtoken); + } + return result; +} + +fn to_kebab_case(tokens: Vec) -> String { + return tokens.join("-"); +} + +fn to_snake_case(tokens: Vec) -> String { + return tokens.join("_"); +} + +fn to_camel_case(tokens: Vec) -> String { + let mut result = String::new(); + for (i, token) in tokens.iter().enumerate() { + if i == 0 { + result.push_str(&token); + } else { + let newtoken = format!("{}{}", &token[0..1].to_uppercase(), &token[1..]); + result.push_str(&newtoken); + } + } + return result; +} + +fn tokenize_string(input: &str) -> Vec { + let mut result = input.replace('-', " ").replace('_', " ").to_string(); + result = result.replace("_", " "); + + // replace all uppercase letters with lowercase and a space before + result = result + .chars() + .enumerate() + .map(|(i, c)| { + if c.is_uppercase() && i > 0 { + format!(" {}", c.to_lowercase().to_string()) + } else { + c.to_string() + } + }) + .collect::>() + .join(""); + return result + .to_lowercase() + .split_whitespace() + .map(|s| s.to_string()) + .collect(); +} diff --git a/src/main.rs b/src/main.rs index 50f1156..1054f05 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod commands; mod data; mod env; mod executer; +mod formater; mod types; mod utils; mod version_control; diff --git a/src/utils.rs b/src/utils.rs index 01ce8da..a905d7a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,6 @@ -use chrono::{self, Datelike}; use std::{io::Write, path::Path}; -use crate::types::Status; +use crate::{formater, types::Status}; pub fn parse_template_name(name: &mut String, strict: bool) -> Status { let template_name_raw = name.clone().to_string(); @@ -264,13 +263,7 @@ pub fn generate_template_dir(path: &str, new_path: &str, given_name: &str, dry_r continue; } - let mut new_file_name = file_name.replace("$$name$$", given_name); - new_file_name = - new_file_name.replace("$$year$$", chrono::Local::now().year().to_string().as_str()); - new_file_name = - new_file_name.replace("$$month$$", &chrono::Local::now().month().to_string()); - new_file_name = new_file_name.replace("$$day$$", &chrono::Local::now().day().to_string()); - new_file_name = new_file_name.replace("$$git-name$$", &crate::utils::get_git_name()); + let new_file_name = formater::handle_placeholders(file_name, given_name); let new_path = format!("{}/{}", new_path, new_file_name); // check if new_path already exists @@ -295,12 +288,7 @@ pub fn generate_template_dir(path: &str, new_path: &str, given_name: &str, dry_r pub fn generate_template_file(path: &str, new_path: &str, given_name: &str, dry_run: bool) -> bool { let file_content = std::fs::read_to_string(path).unwrap(); - let mut file_content = file_content.replace("$$name$$", given_name); - file_content = - file_content.replace("$$year$$", chrono::Local::now().year().to_string().as_str()); - file_content = file_content.replace("$$month$$", &chrono::Local::now().month().to_string()); - file_content = file_content.replace("$$day$$", &chrono::Local::now().day().to_string()); - file_content = file_content.replace("$$git-name$$", &crate::utils::get_git_name()); + let file_content = formater::handle_placeholders(&file_content, given_name); if Path::new(new_path).exists() { println!("File {} already exists.", new_path);