vrl/stdlib/
strip_ansi_escape_codes.rs

1use crate::compiler::prelude::*;
2use bytes::Bytes;
3
4fn strip_ansi_escape_codes(bytes: Value) -> Resolved {
5    let bytes = bytes.try_bytes()?;
6    let stripped_bytes = Bytes::from(strip_ansi_escapes::strip(&bytes));
7    Ok(stripped_bytes.into())
8}
9
10#[derive(Clone, Copy, Debug)]
11pub struct StripAnsiEscapeCodes;
12
13impl Function for StripAnsiEscapeCodes {
14    fn identifier(&self) -> &'static str {
15        "strip_ansi_escape_codes"
16    }
17
18    fn usage(&self) -> &'static str {
19        "Strips [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) from `value`."
20    }
21
22    fn category(&self) -> &'static str {
23        Category::String.as_ref()
24    }
25
26    fn return_kind(&self) -> u16 {
27        kind::BYTES
28    }
29
30    fn parameters(&self) -> &'static [Parameter] {
31        const PARAMETERS: &[Parameter] = &[Parameter::required(
32            "value",
33            kind::BYTES,
34            "The string to strip.",
35        )];
36        PARAMETERS
37    }
38
39    fn examples(&self) -> &'static [Example] {
40        &[]
41    }
42
43    fn compile(
44        &self,
45        _state: &state::TypeState,
46        _ctx: &mut FunctionCompileContext,
47        arguments: ArgumentList,
48    ) -> Compiled {
49        let value = arguments.required("value");
50
51        Ok(StripAnsiEscapeCodesFn { value }.as_expr())
52    }
53}
54
55#[derive(Debug, Clone)]
56struct StripAnsiEscapeCodesFn {
57    value: Box<dyn Expression>,
58}
59
60impl FunctionExpression for StripAnsiEscapeCodesFn {
61    fn resolve(&self, ctx: &mut Context) -> Resolved {
62        let bytes = self.value.resolve(ctx)?;
63
64        strip_ansi_escape_codes(bytes)
65    }
66
67    fn type_def(&self, _: &state::TypeState) -> TypeDef {
68        // We're marking this as infallible, because `strip_ansi_escapes` only
69        // fails if it can't write to the buffer, which is highly unlikely to
70        // occur.
71        TypeDef::bytes().infallible()
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    test_function![
80        strip_ansi_escape_codes => StripAnsiEscapeCodes;
81
82        no_codes {
83            args: func_args![value: "foo bar"],
84            want: Ok("foo bar"),
85            tdef: TypeDef::bytes().infallible(),
86        }
87
88        strip_1 {
89            args: func_args![value: "\x1b[3;4Hfoo bar"],
90            want: Ok("foo bar"),
91            tdef: TypeDef::bytes().infallible(),
92        }
93
94        strip_2 {
95            args: func_args![value: "\x1b[46mfoo\x1b[0m bar"],
96            want: Ok("foo bar"),
97            tdef: TypeDef::bytes().infallible(),
98        }
99
100        strip_3 {
101            args: func_args![value: "\x1b[=3lfoo bar"],
102            want: Ok("foo bar"),
103            tdef: TypeDef::bytes().infallible(),
104        }
105    ];
106}