liquid-json 0.6.1

A Liquid template engine for JSON
Documentation
use crate::PARSER;
use liquid_core::parser::FilterArguments;
use liquid_core::Expression;
use liquid_core::Object;
use liquid_core::Result;
use liquid_core::Runtime;
use liquid_core::{
    Display_filter, Filter, FilterParameters, FilterReflection, FromFilterParameters, ParseFilter,
};
use liquid_core::{Value, ValueView};

use super::invalid_input;

#[derive(Debug, FilterParameters)]
struct EachArgs {
    #[parameter(
        description = "The template to apply to each element.",
        arg_type = "str"
    )]
    template: Expression,
}

#[derive(Clone, FilterReflection)]
#[filter(
    name = "each",
    description = "Iterates over an array, applying a template to each element.",
    parameters(EachArgs),
    parsed(EachFilter)
)]
pub(crate) struct Each {}

impl ParseFilter for Each {
    fn parse(&self, arguments: FilterArguments) -> Result<Box<dyn Filter>> {
        let args = EachArgs::from_args(arguments)?;

        Ok(Box::new(EachFilter { args }))
    }

    fn reflection(&self) -> &dyn FilterReflection {
        self
    }
}

impl Each {
    pub(crate) fn new() -> Self {
        Self {}
    }
}

#[derive(FromFilterParameters, Display_filter)]
#[name = "each"]
struct EachFilter {
    #[parameters]
    args: EachArgs,
}

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

impl Filter for EachFilter {
    fn evaluate(&self, input: &dyn ValueView, runtime: &dyn Runtime) -> Result<Value> {
        let args = self.args.evaluate(runtime)?;

        let template = PARSER.parse(&args.template)?;

        let input = input
            .as_array()
            .ok_or_else(|| invalid_input("Array expected"))?;

        let output: Vec<_> = input
            .values()
            .map(|x| {
                let mut global = Object::new();
                global.insert("el".into(), x.to_value());
                Ok(Value::Scalar(template.render(&global)?.into()))
            })
            .collect::<Result<_, _>>()?;
        Ok(Value::array(output))
    }
}