rshtml_core 0.5.0

RsHtml: A Template Engine for Seamless HTML and Rust Integration.
Documentation
use crate::Node;
use crate::error::E;
use crate::node::{ComponentParameter, ComponentParameterValue};
use crate::parser::{IParser, RsHtmlParser, Rule};
use crate::position::Position;
use pest::error::Error;
use pest::iterators::Pair;

pub struct ComponentParser;

impl IParser for ComponentParser {
    fn parse(parser: &mut RsHtmlParser, pair: Pair<Rule>) -> Result<Node, Box<Error<Rule>>> {
        let pair_span = pair.as_span();
        let position = Position::from(&pair);

        let mut inner_pairs = pair.into_inner();
        let component_name_pair = inner_pairs
            .find(|p| p.as_rule() == Rule::component_tag_identifier)
            .ok_or(E::pos(Rule::component_tag_identifier).span(pair_span))?;

        let component_name = component_name_pair.as_str().to_string();

        let component_parameter_pairs = inner_pairs
            .clone()
            .filter(|p| p.as_rule() == Rule::attribute);

        let mut component_parameters = Vec::new();
        for pair in component_parameter_pairs {
            let pair_name = pair
                .clone()
                .into_inner()
                .find(|p| p.as_rule() == Rule::attribute_name)
                .ok_or(E::pos(Rule::attribute_name).span(pair_span))?;

            let value = match pair
                .clone()
                .into_inner()
                .find(|p| p.as_rule() != Rule::attribute_name)
            {
                Some(pair_value) => Self::build_component_parameter_value(parser, pair_value)?,
                None => ComponentParameterValue::Bool(true),
            };

            let name = pair_name.as_str().to_string();

            component_parameters.push(ComponentParameter {
                name,
                value,
                position: Position::from(&pair),
            });
        }

        let body = match inner_pairs.find(|x| x.as_rule() == Rule::tag_template) {
            Some(tag_template) => parser.build_nodes_from_pairs(tag_template.into_inner())?,
            None => vec![],
        };

        Ok(Node::Component(
            component_name,
            component_parameters,
            body,
            position,
        ))
    }
}

impl ComponentParser {
    pub fn build_component_parameter_value(
        parser: &mut RsHtmlParser,
        pair: Pair<Rule>,
    ) -> Result<ComponentParameterValue, Box<Error<Rule>>> {
        match pair.as_rule() {
            Rule::bool => Ok(ComponentParameterValue::Bool(pair.as_str() == "true")),
            Rule::number => Ok(ComponentParameterValue::Number(pair.as_str().to_string())),
            Rule::string => {
                let raw_str = pair.as_str().trim_matches('"').trim_matches('\'');
                Ok(ComponentParameterValue::String(raw_str.to_string()))
            }
            Rule::rust_expr_simple => Ok(ComponentParameterValue::RustExprSimple(
                pair.as_str().to_string(),
            )),
            Rule::rust_expr_paren => Ok(ComponentParameterValue::RustExprParen(
                pair.as_str().to_string(),
            )),
            Rule::inner_template => {
                let block_nodes = parser.build_nodes_from_pairs(pair.into_inner())?;
                Ok(ComponentParameterValue::Block(block_nodes))
            }
            rule => Err(E::mes(format!("Unexpected rule: {rule:?}")).span(pair.as_span())),
        }
    }
}