liquid-json 0.6.1

A Liquid template engine for JSON
Documentation
use base64::Engine;
use liquid_core::Result;
use liquid_core::Runtime;
use liquid_core::{Display_filter, Filter, FilterReflection, ParseFilter};
use liquid_core::{Value, ValueView};

#[derive(Clone, ParseFilter, FilterReflection)]
#[filter(
    name = "base64_decode",
    description = "Decode a base64 encoded string.",
    parsed(Base64DecodeFilter)
)]
pub(crate) struct Base64Decode;

#[derive(Default, Display_filter)]
#[name = "output"]
struct Base64DecodeFilter;

impl std::fmt::Debug for Base64DecodeFilter {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("OutputFilter").finish()
    }
}

impl Filter for Base64DecodeFilter {
    fn evaluate(&self, input: &dyn ValueView, _runtime: &dyn Runtime) -> Result<Value> {
        let input = input.to_value();

        let encoded = String::from_utf8(
            base64::engine::general_purpose::STANDARD
                .decode(&input.to_kstr())
                .map_err(|e| liquid_core::Error::with_msg(e.to_string()))?,
        )
        .map_err(|e| liquid_core::Error::with_msg(e.to_string()))?;

        Ok(Value::Scalar(encoded.into()))
    }
}

#[cfg(test)]
mod tests {
    use crate::LiquidJson;
    use rstest::rstest;
    use serde_json::{json, Value};

    use anyhow::Result;

    #[rstest]
    #[case(json!({"base64":"{{ 'VGhpcyBpcyBteSBtZXNzYWdl' | base64_decode }}"}), json!({}), json!({"base64": "This is my message"}))]
    fn filters(
        #[case] template: Value,
        #[case] data: Value,
        #[case] expected: Value,
    ) -> Result<()> {
        let tmpl = LiquidJson::new(template);
        let actual = tmpl.render(&data)?;
        assert_eq!(actual, expected);
        Ok(())
    }
}