rshtml_core 0.2.0

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

pub struct IncludeDirectiveParser;

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

        let path_pair = pair
            .into_inner()
            .find(|p| p.as_rule() == Rule::string_line)
            .ok_or(Error::new_from_span(
                ErrorVariant::CustomError {
                    message: "Error: Expected a path to the included file".to_string(),
                },
                pair_span,
            ))?;

        let path = path_pair
            .as_str()
            .trim_matches('"')
            .trim_matches('\'')
            .to_string();

        let view_path = parser.config.views.0.join(&path);

        let canonical_path = view_path
            .canonicalize()
            .unwrap_or_default()
            .to_string_lossy()
            .to_string();

        if parser.included_templates.contains(&canonical_path) {
            return Err(Box::new(Error::new_from_span(
                ErrorVariant::CustomError {
                    message: format!("Error: Circular include detected for file '{path}'"),
                },
                path_pair.as_span(),
            )));
        }

        parser.included_templates.insert(canonical_path.clone());

        let inner_template = match parser.parse_template(&path) {
            Ok(node) => node,
            Err(err) => {
                let include_template_error = Error::new_from_span(
                    ErrorVariant::CustomError {
                        message: format!("Error parsing included file '{path}': {err}"),
                    },
                    pair_span,
                );

                return Err(Box::new(include_template_error));
            }
        };

        parser.included_templates.remove(&canonical_path);

        let nodes = match inner_template {
            Node::Template(nodes) => nodes,
            _ => {
                return Err(Box::new(Error::new_from_span(
                    ErrorVariant::CustomError {
                        message: format!(
                            "Error: Expected a template in the included file '{path}', found {inner_template:?}"
                        ),
                    },
                    path_pair.as_span(),
                )));
            }
        };

        Ok(Node::Template(nodes))
    }
}