vrl/stdlib/casing/
screamingsnakecase.rs1use crate::compiler::prelude::*;
2
3use crate::stdlib::casing::{ORIGINAL_CASE, into_case};
4use convert_case::Case;
5
6#[derive(Clone, Copy, Debug)]
7pub struct ScreamingSnakecase;
8
9impl Function for ScreamingSnakecase {
10 fn identifier(&self) -> &'static str {
11 "screamingsnakecase"
12 }
13
14 fn usage(&self) -> &'static str {
15 "Takes the `value` string, and turns it into SCREAMING_SNAKE case. 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(
29 "value",
30 kind::BYTES,
31 "The string to convert to SCREAMING_SNAKE case.",
32 ),
33 ORIGINAL_CASE,
34 ];
35
36 PARAMETERS
37 }
38
39 fn compile(
40 &self,
41 state: &state::TypeState,
42 _ctx: &mut FunctionCompileContext,
43 arguments: ArgumentList,
44 ) -> Compiled {
45 let value = arguments.required("value");
46 let original_case = arguments
47 .optional_enum("original_case", &super::variants(), state)?
48 .map(|b| {
49 into_case(
50 b.try_bytes_utf8_lossy()
51 .expect("cant convert to string")
52 .as_ref(),
53 )
54 })
55 .transpose()?;
56
57 Ok(ScreamingSnakecaseFn {
58 value,
59 original_case,
60 }
61 .as_expr())
62 }
63
64 fn examples(&self) -> &'static [Example] {
65 &[
66 example! {
67 title: "SCREAMING_SNAKE_CASE a string without specifying original case",
68 source: r#"screamingsnakecase("input-string")"#,
69 result: Ok("INPUT_STRING"),
70 },
71 example! {
72 title: "SCREAMING_SNAKE_CASE a snake_case string",
73 source: r#"screamingsnakecase("foo_bar_baz", "snake_case")"#,
74 result: Ok("FOO_BAR_BAZ"),
75 },
76 example! {
77 title: "SCREAMING_SNAKE_CASE specifying the wrong original case (capitalizes but doesn't include `_` properly)",
78 source: r#"screamingsnakecase("FooBarBaz", "kebab-case")"#,
79 result: Ok("FOOBARBAZ"),
80 },
81 ]
82 }
83}
84
85#[derive(Debug, Clone)]
86struct ScreamingSnakecaseFn {
87 value: Box<dyn Expression>,
88 original_case: Option<Case>,
89}
90
91impl FunctionExpression for ScreamingSnakecaseFn {
92 fn resolve(&self, ctx: &mut Context) -> Resolved {
93 let value = self.value.resolve(ctx)?;
94 super::convert_case(&value, Case::Constant, self.original_case)
95 }
96
97 fn type_def(&self, _: &state::TypeState) -> TypeDef {
98 TypeDef::bytes().infallible()
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::value;
106
107 test_function![
108 screamingsnakecase => ScreamingSnakecase;
109
110 simple {
111 args: func_args![value: value!("input_string"), original_case: "snake_case"],
112 want: Ok(value!("INPUT_STRING")),
113 tdef: TypeDef::bytes(),
114 }
115
116 no_case {
117 args: func_args![value: value!("input_string")],
118 want: Ok(value!("INPUT_STRING")),
119 tdef: TypeDef::bytes(),
120 }
121 ];
122}