rust-less 0.1.0

A LESS to CSS parser and converter library written in Rust
Documentation
use pest::iterators::Pair;
use crate::parser::Rule;
use crate::utils::{get_attr_and_variable, get_select_name};
use crate::selects::{Attr, Variable, ToCss};

#[derive(Debug)]
pub struct Select {
    pub select_name: String,
    pub select_value: String,
    pub span: (usize, usize),
    pub attr_list: Vec<Attr>,
    pub variable_list: Vec<Variable>,
    pub children: Box<Vec<Select>>,
    pub parent_select_names: Vec<String>,
    pub ancestor_variable_list: Vec<Variable>,
}

impl Select {
    pub fn new(pair: &Pair<Rule>, parents: Vec<String>, ancestor_variable_list: Vec<Variable>) -> Self {
        let rule = pair.as_rule();
        if rule != Rule::select {
            panic!("Not a select");
        } else {
            let select_name = get_select_name(&pair);

            let span = (pair.as_span().start(), pair.as_span().end());

            let child_pairs = pair.clone().into_inner();

            let mut children = vec![];

            let (attr_list, variable_list) = get_attr_and_variable(pair);

            for child_pair in child_pairs {
                if child_pair.as_rule() == Rule::select {
                    let mut p = parents.clone();
                    p.push(select_name.clone());

                    let mut new_ancestor_variable_list = vec![];
                    for item in ancestor_variable_list.clone() {
                        new_ancestor_variable_list.insert(0, item);
                    }

                    for item in variable_list.clone() {
                        new_ancestor_variable_list.insert(0, item);
                    }

                    children.push(Select::new(&child_pair, p, new_ancestor_variable_list));
                }
            }

            let select = Select {
                select_name,
                span,
                select_value: pair.as_span().as_str().to_string(),
                children: Box::new(children),
                parent_select_names: parents.clone(),
                variable_list,
                attr_list,
                ancestor_variable_list,
            };
            return select;
        }
    }

    pub fn clear_value(&mut self) {
        let mut need_removes: Vec<(usize, usize)> = vec![];
        for child in self.children.as_mut_slice() {
            let remove = (child.span.0 - self.span.0, child.span.1 - self.span.0);
            need_removes.push(remove);
            child.clear_value();
        }

        let mut diff = 0;
        for (mut start, mut end) in need_removes {
            start = start - diff;
            end = end - diff;
            diff = diff + end - start;
            self.select_value.replace_range(start..end, "");
        }
    }

    pub fn find_variable(&self, name: &str) -> Option<String> {
        let variable_list = &self.variable_list;
        let ancestor_variable_list = &self.ancestor_variable_list;

        let result = variable_list.iter().find(|&item| {
            if item.0 == *name {
                return true;
            }
            return false;
        });

        if let Some(res) = result {
            return Some(res.1.clone());
        } else {
            let result = ancestor_variable_list.iter().find(|&item| {
                if item.0 == *name {
                    return true;
                }
                return false;
            });
            if let Some(res) = result {
                Some(res.1.clone())
            } else {
                None
            }
        }
    }
}

impl ToCss for Select {
    fn to_css(&self) -> String {
        let mut result = String::from("");

        let mut full_class_name = String::from("");
        let parent_class_name = self.parent_select_names.join(" ");
        if self.select_name.contains('&') && &self.select_name != "&" {
            full_class_name.push_str(&self.select_name.replace("&", &parent_class_name));
        } else {
            full_class_name.push_str(&parent_class_name);
            if self.parent_select_names.len() > 0 {
                full_class_name.push(' ');
            }
            full_class_name.push_str(&self.select_name);
        }

        let mut value = String::from("");

        value.push_str(&full_class_name);
        value.push(' ');
        value.push('{');
        value.push('\n');

        for attr in &self.attr_list {
            let mut attr_s = String::from("  ");
            attr_s.push_str(&attr.0);
            attr_s.push_str(": ");
            if let Some(res) = self.find_variable(&attr.1) {
                attr_s.push_str(&res);
            } else {
                attr_s.push_str(&attr.1);
            }
            attr_s.push_str(";\n");

            value.push_str(&attr_s);
        }

        value.push_str("}\n");

        result.push_str(&value);

        result.push('\n');

        for child in self.children.as_slice() {
            result.push_str(&child.to_css());
        }

        return result;
    }
}