css-knife 0.1.5

A tool for shortening css classes
Documentation
use std::{
    cmp::Ordering,
    collections::{btree_map::Entry, BTreeMap},
    fs,
};

use lightningcss::stylesheet::{PrinterOptions, StyleSheet};

type OneClass = [u8; 5];

pub enum CSSToken {
    Class,
    CustomProperty,
}

#[derive(Default, Clone, PartialEq, Eq)]
pub struct ClassContainer {
    class_name: [ClassIter; 2],
    container: [BTreeMap<String, String>; 2],
}

impl Default for ClassIter {
    fn default() -> Self {
        ClassIter {
            array: [1, 0, 0, 0, 0],
            current_index: 0,
        }
    }
}

impl ClassContainer {
    pub fn add(&mut self, key: String, token: CSSToken) -> Option<String> {
        let index = token as usize;
        if let Some(map) = self.container.get_mut(index) {
            let oldclass = css_to_html(&key);
            match map.entry(oldclass) {
                Entry::Vacant(entry) => {
                    if let Some(new) = self.class_name[index].next() {
                        return Some(entry.insert(new_class(&new)).to_string());
                    }
                }
                Entry::Occupied(entry) => {
                    return Some(entry.get().clone());
                }
            }
        }
        None
    }

    pub fn get(&self, key: String, container: CSSToken) -> Option<String> {
        let index = container as usize;
        if let Some(map) = self.container.get(index) {
            if let Some(v) = map.get(&key) {
                return Some(v.to_string());
            }
        }
        None
    }

    pub fn into_file(&self, stylesheet: StyleSheet) {
        let opt = PrinterOptions {
            minify: true,
            ..Default::default()
        };
        if let Ok(f) = stylesheet.to_css(opt) {
            let _ = fs::write("src/output.css", f.code);
        }
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct ClassIter {
    array: OneClass,
    current_index: usize,
}

impl ClassIter {}

impl Iterator for ClassIter {
    type Item = OneClass;

    fn next(&mut self) -> Option<Self::Item> {
        let current = self.array;
        self.array[self.current_index] += 1;
        if self.array[self.current_index] == 27 {
            self.array[self.current_index] = 1;
            let mut add_new = true;
            for i in (0..self.current_index).rev() {
                let v = self.array[i];
                match v.cmp(&26) {
                    Ordering::Less => {
                        add_new = false;
                        self.array[i] += 1;
                        self.array[self.current_index] = 1;
                        break;
                    }
                    Ordering::Equal => {
                        self.array[i] = 1;
                    }
                    Ordering::Greater => (),
                }
            }
            if add_new {
                if self.current_index == 4 {
                    return None;
                }

                for i in (0..self.current_index).rev() {
                    self.array[i] = 1;
                }

                self.current_index += 1;
                self.array[self.current_index] = 1;
            }
        }
        Some(current)
    }
}

fn css_to_html(old: &str) -> String {
    if old.starts_with('.') {
        let mut chars = old.chars();
        chars.next();
        chars.as_str().replace('\\', "")
    } else {
        String::from(old)
    }
}

fn new_class(new_class: &OneClass) -> String {
    let mut s = String::new();
    for i in new_class {
        if i == &0 {
            break;
        }
        let c = 96_u8 + i;
        s.push(c as char);
    }
    s
}