diff --git a/Cargo.lock b/Cargo.lock index c8c1f813..7be794ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -341,9 +341,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "a9689a29b593160de5bc4aacab7b5d54fb52231de70122626c178e6a368994c7" dependencies = [ "clap_builder", "clap_derive", @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "2e5387378c84f6faa26890ebf9f0a92989f8873d4d380467bcd0d8d8620424df" dependencies = [ "anstream", "anstyle", @@ -363,9 +363,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck", "proc-macro2", @@ -375,9 +375,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clru" @@ -4147,9 +4147,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ff33f391015ecab21cd092389215eb265ef9496a9a07b6bee7d3529831deda" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] diff --git a/crates/weaver_forge/README.md b/crates/weaver_forge/README.md index 25180add..33cfc7b1 100644 --- a/crates/weaver_forge/README.md +++ b/crates/weaver_forge/README.md @@ -146,7 +146,11 @@ The following filters are available: - `kebab_case`: Converts a string to kebab-case. - `screaming_kebab_case`: Converts a string to SCREAMING-KEBAB-CASE. - `capitalize_first`: Capitalizes the first letter of a string. -- `semconv_const(case)`: Follows the semantic convention for constants. Underscores are removed and the string is converted to the case provided. +- `kebab_case_const`: Generates kebab-case constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful). +- `pascal_case_const`: Generates PascalCase constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful). +- `camel_case_const`: Generates camelCase constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful). +- `snake_case_const`: Generates snake_case constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful). +- `screaming_snake_case_const`: Generates SCREAMING_SNAKE_CASE constants which follow semantic convention namespacing rules (underscores are ignored, but . is meaningful). - `acronym`: Replaces acronyms in the input string with the full name defined in the `acronyms` section of the `weaver.yaml` configuration file. - `split_ids`: Splits a string by '.' creating a list of nested ids. - `type_mapping`: Converts a semantic convention type to a target type (see weaver.yaml section `type_mapping`). diff --git a/crates/weaver_forge/src/extensions/case.rs b/crates/weaver_forge/src/extensions/case.rs index c2456e82..064ad31d 100644 --- a/crates/weaver_forge/src/extensions/case.rs +++ b/crates/weaver_forge/src/extensions/case.rs @@ -3,7 +3,6 @@ //! Case converter filters used by the template engine. use crate::config::{CaseConvention, TargetConfig}; -use crate::error::Error; use minijinja::Environment; /// Add case converter filters to the environment. @@ -59,77 +58,53 @@ pub fn case_converter(case_convention: CaseConvention) -> fn(&str) -> String { } } -/// Converts a "string" case convention to a function that converts a string to the specified case -/// convention. -/// -/// # Returns -/// -/// Returns an error if the case convention is not recognized or a function that converts a string -/// to the specified case convention. -pub fn str_to_case_converter(case_convention: &str) -> Result String, Error> { - match case_convention { - "lower_case" => Ok(lower_case), - "upper_case" => Ok(upper_case), - "title_case" => Ok(title_case), - "camel_case" => Ok(camel_case), - "pascal_case" => Ok(pascal_case), - "snake_case" => Ok(snake_case), - "screaming_snake_case" => Ok(screaming_snake_case), - "kebab_case" => Ok(kebab_case), - "screaming_kebab_case" => Ok(screaming_kebab_case), - _ => Err(Error::InvalidCaseConvention { - case: case_convention.to_owned(), - }), - } -} - /// Converts input string to lower case -fn lower_case(input: &str) -> String { +pub(crate) fn lower_case(input: &str) -> String { CaseConvention::LowerCase.convert(input) } /// Converts input string to upper case -fn upper_case(input: &str) -> String { +pub(crate) fn upper_case(input: &str) -> String { CaseConvention::UpperCase.convert(input) } /// Converts input string to title case -fn title_case(input: &str) -> String { +pub(crate) fn title_case(input: &str) -> String { CaseConvention::TitleCase.convert(input) } /// Converts input string to camel case -fn camel_case(input: &str) -> String { +pub(crate) fn camel_case(input: &str) -> String { CaseConvention::CamelCase.convert(input) } /// Converts input string to pascal case -fn pascal_case(input: &str) -> String { +pub(crate) fn pascal_case(input: &str) -> String { CaseConvention::PascalCase.convert(input) } /// Converts input string to snake case -fn snake_case(input: &str) -> String { +pub(crate) fn snake_case(input: &str) -> String { CaseConvention::SnakeCase.convert(input) } /// Converts input string to screaming snake case -fn screaming_snake_case(input: &str) -> String { +pub(crate) fn screaming_snake_case(input: &str) -> String { CaseConvention::ScreamingSnakeCase.convert(input) } /// Converts input string to kebab case -fn kebab_case(input: &str) -> String { +pub(crate) fn kebab_case(input: &str) -> String { CaseConvention::KebabCase.convert(input) } /// Converts input string to screaming kebab case -fn screaming_kebab_case(input: &str) -> String { +pub(crate) fn screaming_kebab_case(input: &str) -> String { CaseConvention::ScreamingKebabCase.convert(input) } /// Capitalize the first character of a string. -fn capitalize_first(input: &str) -> String { +pub(crate) fn capitalize_first(input: &str) -> String { let mut chars = input.chars(); let mut result = String::with_capacity(input.len()); diff --git a/crates/weaver_forge/src/extensions/otel.rs b/crates/weaver_forge/src/extensions/otel.rs index 1ab1bbd3..0ca85d7d 100644 --- a/crates/weaver_forge/src/extensions/otel.rs +++ b/crates/weaver_forge/src/extensions/otel.rs @@ -8,7 +8,9 @@ use minijinja::{ErrorKind, Value}; use serde::de::Error; use crate::config::CaseConvention; -use crate::extensions::case::str_to_case_converter; +use crate::extensions::case::{ + camel_case, kebab_case, pascal_case, screaming_snake_case, snake_case, +}; const TEMPLATE_PREFIX: &str = "template["; const TEMPLATE_SUFFIX: &str = "]"; @@ -25,7 +27,11 @@ pub(crate) fn add_tests_and_filters(env: &mut minijinja::Environment<'_>) { env.add_filter("not_required", not_required); env.add_filter("instantiated_type", instantiated_type); env.add_filter("enum_type", enum_type); - env.add_filter("semconv_const", semconv_const); + env.add_filter("kebab_case_const", kebab_case_const); + env.add_filter("pascal_case_const", pascal_case_const); + env.add_filter("camel_case_const", camel_case_const); + env.add_filter("snake_case_const", snake_case_const); + env.add_filter("screaming_snake_case_const", screaming_snake_case_const); env.add_test("stable", is_stable); env.add_test("experimental", is_experimental); @@ -143,15 +149,39 @@ pub(crate) fn attribute_namespace(input: &str) -> Result Result { - let converter = str_to_case_converter(case) - .map_err(|e| minijinja::Error::new(ErrorKind::InvalidOperation, format!("{}", e)))?; - // Remove all _ and convert to the desired case - let converted_input = converter(&input.replace('_', "")); - Ok(converted_input) +/// Converts a semconv id into semconv constant following the namespacing rules and the +/// kebab case convention. +pub(crate) fn kebab_case_const(input: &str) -> String { + // Remove all _ and convert to the kebab case + kebab_case(&input.replace('_', "")) +} + +/// Converts a semconv id into semconv constant following the namespacing rules and the +/// pascal case convention. +pub(crate) fn pascal_case_const(input: &str) -> String { + // Remove all _ and convert to the pascal case + pascal_case(&input.replace('_', "")) +} + +/// Converts a semconv id into semconv constant following the namespacing rules and the +/// camel case convention. +pub(crate) fn camel_case_const(input: &str) -> String { + // Remove all _ and convert to the camel case + camel_case(&input.replace('_', "")) +} + +/// Converts a semconv id into semconv constant following the namespacing rules and the +/// snake case convention. +pub(crate) fn snake_case_const(input: &str) -> String { + // Remove all _ and convert to the snake case + snake_case(&input.replace('_', "")) +} + +/// Converts a semconv id into semconv constant following the namespacing rules and the +/// screaming snake case convention. +pub(crate) fn screaming_snake_case_const(input: &str) -> String { + // Remove all _ and convert to the screaming snake case + screaming_snake_case(&input.replace('_', "")) } /// Compares two attributes by their requirement_level, then name. @@ -1203,7 +1233,7 @@ mod tests { assert_eq!( env.render_str( - "{{ 'messaging.client_id' | semconv_const('screaming_snake_case') }}", + "{{ 'messaging.client_id' | screaming_snake_case_const }}", &ctx, ) .unwrap(), @@ -1211,17 +1241,14 @@ mod tests { ); assert_eq!( - env.render_str( - "{{ 'messaging.client_id' | semconv_const('pascal_case') }}", - &ctx, - ) - .unwrap(), + env.render_str("{{ 'messaging.client_id' | pascal_case_const }}", &ctx,) + .unwrap(), "MessagingClientid" ); assert_eq!( env.render_str( - "{{ 'messaging.client.id' | semconv_const('screaming_snake_case') }}", + "{{ 'messaging.client.id' | screaming_snake_case_const }}", &ctx, ) .unwrap(), @@ -1229,23 +1256,53 @@ mod tests { ); assert_eq!( - env.render_str( - "{{ 'messaging.client.id' | semconv_const('pascal_case') }}", - &ctx, - ) - .unwrap(), + env.render_str("{{ 'messaging.client.id' | pascal_case_const }}", &ctx,) + .unwrap(), "MessagingClientId" ); + assert_eq!( + env.render_str("{{ 'messaging.client.id' | kebab_case_const }}", &ctx,) + .unwrap(), + "messaging-client-id" + ); + + assert_eq!( + env.render_str("{{ 'messaging.client_id' | kebab_case_const }}", &ctx,) + .unwrap(), + "messaging-clientid" + ); + + assert_eq!( + env.render_str("{{ 'messaging.client.id' | camel_case_const }}", &ctx,) + .unwrap(), + "messagingClientId" + ); + + assert_eq!( + env.render_str("{{ 'messaging.client_id' | camel_case_const }}", &ctx,) + .unwrap(), + "messagingClientid" + ); + + assert_eq!( + env.render_str("{{ 'messaging.client.id' | snake_case_const }}", &ctx,) + .unwrap(), + "messaging_client_id" + ); + + assert_eq!( + env.render_str("{{ 'messaging.client_id' | snake_case_const }}", &ctx,) + .unwrap(), + "messaging_clientid" + ); + assert!(env - .render_str( - "{{ 'messaging.client.id' | semconv_const('invalid_case') }}", - &ctx, - ) + .render_str("{{ 'messaging.client.id' | invalid_case_const }}", &ctx,) .is_err()); assert!(env - .render_str("{{ 123 | semconv_const('lower_case') }}", &ctx,) + .render_str("{{ 123 | pascal_case_const }}", &ctx,) .is_err()); } }