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