Skip to content

Commit

Permalink
feat(forge): Add case*_const filters.
Browse files Browse the repository at this point in the history
  • Loading branch information
lquerel committed Jun 7, 2024
1 parent 806070e commit fb90c08
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 74 deletions.
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion crates/weaver_forge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`).
Expand Down
45 changes: 10 additions & 35 deletions crates/weaver_forge/src/extensions/case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<fn(&str) -> 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());

Expand Down
113 changes: 85 additions & 28 deletions crates/weaver_forge/src/extensions/otel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "]";
Expand All @@ -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);
Expand Down Expand Up @@ -143,15 +149,39 @@ pub(crate) fn attribute_namespace(input: &str) -> Result<String, minijinja::Erro
Ok(parts[0].to_owned())
}

/// Converts a semconv id into semconv constant following the namespacing rules.
///
/// A [`minijinja::Error`] if the case is not supported.
pub(crate) fn semconv_const(input: &str, case: &str) -> Result<String, minijinja::Error> {
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.
Expand Down Expand Up @@ -1203,49 +1233,76 @@ mod tests {

assert_eq!(
env.render_str(
"{{ 'messaging.client_id' | semconv_const('screaming_snake_case') }}",
"{{ 'messaging.client_id' | screaming_snake_case_const }}",
&ctx,
)
.unwrap(),
"MESSAGING_CLIENTID"
);

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(),
"MESSAGING_CLIENT_ID"
);

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());
}
}

0 comments on commit fb90c08

Please sign in to comment.