panrelease 0.19.0

Utility to release software
Documentation
use crate::parser::FormatCodec;
use crate::parser::xml::parsexml::{XMLDocument, XMLNode};
use crate::parser::xml::value::Value;
use crate::utils::get_range;

pub struct XmlString {
    inner: String,
}

impl XmlString {
    pub fn new(input: &str) -> Self {
        Self {
            inner: String::from(input),
        }
    }
}

impl FormatCodec for XmlString {
    fn extract(&self, path: &str) -> anyhow::Result<Option<&str>> {
        let document = XMLDocument::try_from(&self.inner[..])?;

        let path_parts = path.split('/');

        let mut next = &document.content;
        for key in path_parts {
            let Some(XMLNode::Element(_, _, content)) = next.iter().find(|node| has_name(node, key)) else {
                anyhow::bail!("Parsed value is not an object");
            };
            next = content;
        }
        let Some(XMLNode::Text(Value::String(value))) = next.first() else {
            println!("{:?}", next.first());
            anyhow::bail!("Could not find {path}")
        };
        Ok(Some(*value))
    }

    fn replace(&mut self, path: &str, value: &str) -> anyhow::Result<()> {
        let Some(current) = self.extract(path)? else {
            anyhow::bail!("Could not find {path} in given xml")
        };
        let (start, end) = get_range(&self.inner, current);
        self.inner.replace_range(start..end, value);
        Ok(())
    }
}

fn has_name(node: &XMLNode, name: &str) -> bool {
    match node {
        XMLNode::Element(qualname, _, _) => qualname.get_localname().eq(name),
        _ => false
    }
}

impl ToString for XmlString {
    fn to_string(&self) -> String {
        self.inner.clone()
    }
}