pochoir-parser 0.12.2

HTML parser for the pochoir template engine
Documentation
//! Defines types used when parsing data.
//!
//! If you are not writing a new parser, you shouldn't care about these structures and should see
//! [`TreeRef`] instead.
//!
//! [`TreeRef`]: crate::TreeRef
use pochoir_common::Spanned;
use pochoir_template_engine::TemplateBlock;
use std::{borrow::Cow, slice};

pub type AttrKey<'a> = Cow<'a, str>;
pub type AttrVal<'a> = Vec<Spanned<TemplateBlock<'a>>>;
pub type Attr<'a> = (Spanned<AttrKey<'a>>, Spanned<AttrVal<'a>>);

/// The attributes belonging to a [`Node::Element`].
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Attrs<'a>(Vec<Attr<'a>>);

impl<'a> Attrs<'a> {
    pub fn new() -> Self {
        Self(vec![])
    }

    pub fn contains_key<'b, K: Into<AttrKey<'b>>>(&self, key: K) -> bool {
        let key = key.into();
        self.0.iter().any(|a| *a.0 == key)
    }

    pub fn get<'b, K: Into<AttrKey<'b>>>(&self, key: K) -> Option<&AttrVal<'a>> {
        let key = key.into();
        self.0.iter().find(|a| *a.0 == key).map(|a| &*a.1)
    }

    pub fn get_key_value<'b, K: Into<AttrKey<'b>>>(&self, key: K) -> Option<&Attr<'a>> {
        let key = key.into();
        self.0.iter().find(|a| *a.0 == key)
    }

    pub fn get_mut<'b, K: Into<AttrKey<'b>>>(&mut self, key: K) -> Option<&mut AttrVal<'a>> {
        let key = key.into();
        self.0.iter_mut().find(|a| *a.0 == key).map(|a| &mut *a.1)
    }

    pub fn insert<K: Into<AttrKey<'a>>, V: Into<AttrVal<'a>>>(&mut self, key: K, val: V) {
        let key = key.into();
        let val = val.into();

        if let Some(attribute) = self.0.iter_mut().find(|a| *a.0 == key) {
            attribute.0 = Spanned::new(key);
            attribute.1 = Spanned::new(val);
        } else {
            self.0.push((Spanned::new(key), Spanned::new(val)));
        }
    }

    pub fn insert_spanned<K: Into<AttrKey<'a>>, V: Into<AttrVal<'a>>>(
        &mut self,
        key: Spanned<K>,
        val: Spanned<V>,
    ) {
        let key = key.map_spanned(Into::into);
        let val = val.map_spanned(Into::into);

        if let Some(attribute) = self.0.iter_mut().find(|a| a.0 == key) {
            attribute.0 = key;
            attribute.1 = val;
        } else {
            self.0.push((key, val));
        }
    }

    pub fn remove<'b, K: Into<AttrKey<'b>>>(&mut self, key: K) -> Option<Attr<'a>> {
        let key = key.into();

        if let Some(index) = self.0.iter().enumerate().find(|(_, a)| *a.0 == key) {
            Some(self.0.remove(index.0))
        } else {
            None
        }
    }

    #[inline]
    pub fn iter(&self) -> slice::Iter<'_, Attr<'a>> {
        self.0.iter()
    }

    #[inline]
    pub fn iter_mut(&'a mut self) -> slice::IterMut<'a, Attr<'a>> {
        self.0.iter_mut()
    }

    pub fn deep_clone<'b>(self) -> Attrs<'b> {
        self.0
            .into_iter()
            .map(|a| {
                (
                    a.0.map_spanned(|k| Cow::Owned(k.into_owned())),
                    a.1.map_spanned(|v| {
                        v.into_iter()
                            .map(|v| v.map_spanned(TemplateBlock::deep_clone))
                            .collect()
                    }),
                )
            })
            .collect()
    }
}

impl<'a> FromIterator<Attr<'a>> for Attrs<'a> {
    fn from_iter<T: IntoIterator<Item = Attr<'a>>>(iter: T) -> Self {
        Self(iter.into_iter().collect())
    }
}
impl<'a> FromIterator<(AttrKey<'a>, AttrVal<'a>)> for Attrs<'a> {
    fn from_iter<T: IntoIterator<Item = (AttrKey<'a>, AttrVal<'a>)>>(iter: T) -> Self {
        Self(
            iter.into_iter()
                .map(|(k, v)| (Spanned::new(k), Spanned::new(v)))
                .collect(),
        )
    }
}

impl<'a, 'b> IntoIterator for &'a Attrs<'b> {
    type Item = &'a Attr<'b>;
    type IntoIter = slice::Iter<'a, Attr<'b>>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl<'a, 'b> IntoIterator for &'a mut Attrs<'b> {
    type Item = &'a mut Attr<'b>;
    type IntoIter = slice::IterMut<'a, Attr<'b>>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter_mut()
    }
}

impl<'a> From<Vec<Attr<'a>>> for Attrs<'a> {
    fn from(v: Vec<Attr<'a>>) -> Self {
        Self(v)
    }
}

impl<'a> From<&[Attr<'a>]> for Attrs<'a> {
    fn from(v: &[Attr<'a>]) -> Self {
        Self(v.to_vec())
    }
}

impl<'a, const N: usize> From<[Attr<'a>; N]> for Attrs<'a> {
    fn from(v: [Attr<'a>; N]) -> Self {
        Self(v.to_vec())
    }
}

/// A node returned by a parser and later stored in a tree.
#[derive(Debug, Clone, PartialEq)]
pub enum Node<'a> {
    Element(Cow<'a, str>, Attrs<'a>),
    Comment(Cow<'a, str>),
    Doctype(Cow<'a, str>),
    TemplateBlock(TemplateBlock<'a>),
    Root,
}

impl<'a> Node<'a> {
    pub(crate) fn node_type(&self) -> &'static str {
        match self {
            Node::Element(_, _) => "Element",
            Node::Comment(_) => "Comment",
            Node::Doctype(_) => "Doctype",
            Node::TemplateBlock(_) => "TemplateBlock",
            Node::Root => "Root",
        }
    }

    /// Make a new "simple" element from its name and a list of plain string key/value pairs.
    ///
    /// This method does not support using interpreted expressions or statements inside attributes.
    pub fn new_simple_element<
        S1: Into<Cow<'a, str>>,
        S2: Into<Cow<'a, str>>,
        S3: Into<Cow<'a, str>>,
        I: IntoIterator<Item = (S2, S3)>,
    >(
        element_name: S1,
        attrs: I,
    ) -> Self {
        Self::Element(
            element_name.into(),
            attrs
                .into_iter()
                .map(|(k, v)| {
                    (
                        k.into(),
                        vec![Spanned::new(TemplateBlock::RawText(v.into()))],
                    )
                })
                .collect::<Attrs>(),
        )
    }

    // Make a new element without any attributes.
    pub fn new_element_without_attrs<S: Into<Cow<'a, str>>>(element_name: S) -> Self {
        Self::Element(element_name.into(), Attrs::new())
    }

    pub fn new_comment<S: Into<Cow<'a, str>>>(comment_value: S) -> Self {
        Self::Comment(comment_value.into())
    }

    pub fn new_doctype<S: Into<Cow<'a, str>>>(doctype_value: S) -> Self {
        Self::Doctype(doctype_value.into())
    }
}

impl Node<'_> {
    pub fn deep_clone<'b>(self) -> Node<'b> {
        match self {
            Node::Element(a, b) => Node::Element(Cow::Owned(a.into_owned()), b.deep_clone()),
            Node::Comment(a) => Node::Comment(Cow::Owned(a.into_owned())),
            Node::Doctype(a) => Node::Doctype(Cow::Owned(a.into_owned())),
            Node::TemplateBlock(a) => Node::TemplateBlock(a.deep_clone()),
            Node::Root => Node::Root,
        }
    }
}

pub type ParsedNode<'a> = Spanned<Node<'a>>;