css_knife/
short_classes.rs

1use std::{
2    cmp::Ordering,
3    collections::{btree_map::Entry, BTreeMap},
4    fs,
5};
6
7use lightningcss::stylesheet::{PrinterOptions, StyleSheet};
8
9type OneClass = [u8; 5];
10
11pub enum CSSToken {
12    Class,
13    CustomProperty,
14}
15
16#[derive(Default, Clone, PartialEq, Eq)]
17pub struct ClassContainer {
18    class_name: [ClassIter; 2],
19    container: [BTreeMap<String, String>; 2],
20}
21
22impl Default for ClassIter {
23    fn default() -> Self {
24        ClassIter {
25            array: [1, 0, 0, 0, 0],
26            current_index: 0,
27        }
28    }
29}
30
31impl ClassContainer {
32    pub fn add(&mut self, key: String, token: CSSToken) -> Option<String> {
33        let index = token as usize;
34        if let Some(map) = self.container.get_mut(index) {
35            let oldclass = css_to_html(&key);
36            match map.entry(oldclass) {
37                Entry::Vacant(entry) => {
38                    if let Some(new) = self.class_name[index].next() {
39                        return Some(entry.insert(new_class(&new)).to_string());
40                    }
41                }
42                Entry::Occupied(entry) => {
43                    return Some(entry.get().clone());
44                }
45            }
46        }
47        None
48    }
49
50    pub fn get(&self, key: String, container: CSSToken) -> Option<String> {
51        let index = container as usize;
52        if let Some(map) = self.container.get(index) {
53            if let Some(v) = map.get(&key) {
54                return Some(v.to_string());
55            }
56        }
57        None
58    }
59
60    pub fn into_file(&self, stylesheet: StyleSheet) {
61        let opt = PrinterOptions {
62            minify: true,
63            ..Default::default()
64        };
65        if let Ok(f) = stylesheet.to_css(opt) {
66            let _ = fs::write("src/output.css", f.code);
67        }
68    }
69}
70
71#[derive(Clone, PartialEq, Eq)]
72pub struct ClassIter {
73    array: OneClass,
74    current_index: usize,
75}
76
77impl ClassIter {}
78
79impl Iterator for ClassIter {
80    type Item = OneClass;
81
82    fn next(&mut self) -> Option<Self::Item> {
83        let current = self.array;
84        self.array[self.current_index] += 1;
85        if self.array[self.current_index] == 27 {
86            self.array[self.current_index] = 1;
87            let mut add_new = true;
88            for i in (0..self.current_index).rev() {
89                let v = self.array[i];
90                match v.cmp(&26) {
91                    Ordering::Less => {
92                        add_new = false;
93                        self.array[i] += 1;
94                        self.array[self.current_index] = 1;
95                        break;
96                    }
97                    Ordering::Equal => {
98                        self.array[i] = 1;
99                    }
100                    Ordering::Greater => (),
101                }
102            }
103            if add_new {
104                if self.current_index == 4 {
105                    return None;
106                }
107
108                for i in (0..self.current_index).rev() {
109                    self.array[i] = 1;
110                }
111
112                self.current_index += 1;
113                self.array[self.current_index] = 1;
114            }
115        }
116        Some(current)
117    }
118}
119
120fn css_to_html(old: &str) -> String {
121    if old.starts_with('.') {
122        let mut chars = old.chars();
123        chars.next();
124        chars.as_str().replace('\\', "")
125    } else {
126        String::from(old)
127    }
128}
129
130fn new_class(new_class: &OneClass) -> String {
131    let mut s = String::new();
132    for i in new_class {
133        if i == &0 {
134            break;
135        }
136        let c = 96_u8 + i;
137        s.push(c as char);
138    }
139    s
140}