handbar 0.0.5

Fork of Handlebars.
use serde::Serialize;
use serde_json::value::Value as Json;

use crate::context::Context;
use crate::error::RenderError;
use crate::helpers::HelperDef;
use crate::json::value::ScopedJson;
use crate::registry::Registry;
use crate::render::{Helper, RenderContext};

#[derive(Clone, Copy)]
pub struct JsonHelper;

impl HelperDef for JsonHelper {
    fn call_inner<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'rc>,
        _: &'reg Registry<'reg>,
        _: &'rc Context,
        _: &mut RenderContext<'reg, 'rc>,
    ) -> Result<ScopedJson<'rc>, RenderError> {
        let value = h
            .param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"json\""))?
            .value();

        if let None = h.param(1) {
            return Ok(Json::String(value.to_string()).into());
        }

        let indent = match h.param(1).unwrap().value().as_str() {
            None => Err(RenderError::new(
                "Param invalid for helper \"json\": indent must be string",
            )),
            Some(indent) => Ok(indent.as_bytes()),
        }?;

        let formatter = serde_json::ser::PrettyFormatter::with_indent(indent);

        let mut buf = Vec::new();
        let mut ser = serde_json::Serializer::with_formatter(&mut buf, formatter);

        value.serialize(&mut ser).unwrap();

        Ok(match String::from_utf8(buf) {
            Ok(js) => Json::String(js).into(),
            Err(_) => Json::Null.into(),
        })
    }
}

pub static JSON_HELPER: JsonHelper = JsonHelper;

#[cfg(test)]
mod test {
    #[test]
    fn test_json() {
        assert_renders![
            (r##"{{ json "foo" }}"##, r##""foo""##),
            (r##"{{ json this }}"##, r##"{"test":5}"##),
            (r##"{{ json this "  " }}"##, "{\n  \"test\": 5\n}"),
            @&json!({
                "test": 5
            }),
        ];
    }
}