vrl/stdlib/casing/
pascalcase.rs

1use crate::compiler::prelude::*;
2
3use crate::stdlib::casing::{ORIGINAL_CASE, into_case};
4use convert_case::Case;
5
6#[derive(Clone, Copy, Debug)]
7pub struct Pascalcase;
8
9impl Function for Pascalcase {
10    fn identifier(&self) -> &'static str {
11        "pascalcase"
12    }
13
14    fn usage(&self) -> &'static str {
15        "Takes the `value` string, and turns it into PascalCase. Optionally, you can pass in the existing case of the function, or else we will try to figure out the case automatically."
16    }
17
18    fn category(&self) -> &'static str {
19        Category::String.as_ref()
20    }
21
22    fn return_kind(&self) -> u16 {
23        kind::BYTES
24    }
25
26    fn parameters(&self) -> &'static [Parameter] {
27        const PARAMETERS: &[Parameter] = &[
28            Parameter::required("value", kind::BYTES, "The string to convert to PascalCase."),
29            ORIGINAL_CASE,
30        ];
31
32        PARAMETERS
33    }
34
35    fn compile(
36        &self,
37        state: &state::TypeState,
38        _ctx: &mut FunctionCompileContext,
39        arguments: ArgumentList,
40    ) -> Compiled {
41        let value = arguments.required("value");
42        let original_case = arguments
43            .optional_enum("original_case", &super::variants(), state)?
44            .map(|b| {
45                into_case(
46                    b.try_bytes_utf8_lossy()
47                        .expect("cant convert to string")
48                        .as_ref(),
49                )
50            })
51            .transpose()?;
52
53        Ok(PascalcaseFn {
54            value,
55            original_case,
56        }
57        .as_expr())
58    }
59
60    fn examples(&self) -> &'static [Example] {
61        &[
62            example! {
63                title: "PascalCase a string without specifying original case",
64                source: r#"pascalcase("input-string")"#,
65                result: Ok("InputString"),
66            },
67            example! {
68                title: "PascalCase a snake_case string",
69                source: r#"pascalcase("foo_bar_baz", "snake_case")"#,
70                result: Ok("FooBarBaz"),
71            },
72            example! {
73                title: "PascalCase specifying the wrong original case (only capitalizes)",
74                source: r#"pascalcase("foo_bar_baz", "kebab-case")"#,
75                result: Ok("Foo_bar_baz"),
76            },
77        ]
78    }
79}
80
81#[derive(Debug, Clone)]
82struct PascalcaseFn {
83    value: Box<dyn Expression>,
84    original_case: Option<Case>,
85}
86
87impl FunctionExpression for PascalcaseFn {
88    fn resolve(&self, ctx: &mut Context) -> Resolved {
89        let value = self.value.resolve(ctx)?;
90        super::convert_case(&value, Case::Pascal, self.original_case)
91    }
92
93    fn type_def(&self, _: &state::TypeState) -> TypeDef {
94        TypeDef::bytes().infallible()
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101    use crate::value;
102
103    test_function![
104        pascalcase => Pascalcase;
105
106        simple {
107            args: func_args![value: value!("input_string"), original_case: "snake_case"],
108            want: Ok(value!("InputString")),
109            tdef: TypeDef::bytes(),
110        }
111
112        no_case {
113            args: func_args![value: value!("input_string")],
114            want: Ok(value!("InputString")),
115            tdef: TypeDef::bytes(),
116        }
117    ];
118}