platelet 0.1.2

HTML-first templating language
Documentation
use std::borrow::Cow;

use regex::{Captures, Regex};
use serde_json::Value;

use crate::{
    expression_eval::{eval, EvalError},
    expression_parser::expr,
    types::Type,
};

#[derive(Debug, PartialEq)]
pub enum RenderError {
    EvalError(EvalError),
    ParserError(String),
    RenderError(Type),
}

pub(crate) fn render_text_node<'a>(
    txt: &'a str,
    vars: &Value,
) -> Result<Cow<'a, str>, RenderError> {
    let hole_re = Regex::new(r"\{\{(.*?)\}\}").unwrap();

    let mut error = Ok(());

    let out = hole_re.replace_all(txt, |captures: &Captures| {
        let exp_s = captures[1].to_string();
        match expr(&mut exp_s.as_str()) {
            Ok(exp) => match eval(&exp, vars) {
                Ok(s) => match stringify(&s) {
                    Ok(s) => s,
                    Err(t) => {
                        error = Err(RenderError::RenderError(t));
                        exp_s
                    }
                },
                Err(e) => {
                    error = Err(RenderError::EvalError(e));
                    exp_s
                }
            },
            Err(e) => {
                error = Err(RenderError::ParserError(e.to_string()));
                exp_s
            }
        }
    });

    error.map(|()| out)
}

fn stringify(v: &Value) -> Result<String, Type> {
    match v {
        Value::Null => Ok("".to_owned()),
        Value::Bool(b) => Ok(b.to_string()),
        Value::Number(n) => Ok(n.to_string()),
        Value::String(s) => Ok(s.to_owned()),
        Value::Array(_) => Err(Type::Array),
        Value::Object(_) => Err(Type::Object),
    }
}