vertigo/css/transform_css/
mod.rs1use super::{get_selector::get_selector, next_id::NextId};
2
3mod splits;
4use splits::{css_row_split_to_pair, css_split_rows, find_brackets};
5
6#[cfg(test)]
7mod tests;
8
9pub fn transform_css_animation_value(
10 css: &str,
11 next_id: &NextId,
12) -> (String, Option<(String, String)>) {
13 let brackets = find_brackets(css);
14
15 if let Some((start_word, central_word, end_word)) = brackets {
16 let id = next_id.get_next_id();
17 let selector = get_selector(&id);
18
19 let keyframe_name = ["@keyframes ", &selector].concat();
20 let keyframe_content = central_word;
21
22 let new_css = [start_word, &selector, end_word].join(" ");
23
24 return (new_css, Some((keyframe_name, keyframe_content.into())));
25 }
26
27 (css.into(), None)
28}
29
30pub fn transform_css_selector_value(row: &str, parent_selector: &str) -> Option<(String, String)> {
31 let brackets = find_brackets(row);
32
33 if let Some((pseudo_selector, rules, trash)) = brackets {
34 if !trash.trim().is_empty() {
35 log::error!("Unexpected input after pseudo-selector rule set, missing semi-colon?");
36 }
37 let new_selector = [parent_selector, pseudo_selector].concat();
38 return Some((new_selector, rules.into()));
39 }
40
41 None
42}
43
44pub fn transform_css_media_query(
45 row: &str,
46 parent_selector: &str,
47 css_documents: &mut Vec<(String, String)>,
48) {
49 let brackets = find_brackets(row);
50
51 if let Some((query, rules_input, trash)) = brackets {
52 if !trash.trim().is_empty() {
53 log::error!("Unexpected input after media query, missing semicolon?");
54 }
55
56 let mut regular_rules = vec![];
58 let mut rules_in_pseudo = vec![];
60
61 for row in css_split_rows(rules_input) {
62 if row.starts_with(':') {
63 let extra_rule = transform_css_selector_value(row, parent_selector);
65
66 if let Some(extra_rule) = extra_rule {
67 rules_in_pseudo.push([&extra_rule.0, " { ", &extra_rule.1, " }"].concat());
68 }
69 } else {
70 regular_rules.push(row);
73 }
74 }
75
76 if !regular_rules.is_empty() || !rules_in_pseudo.is_empty() {
77 let mut media_content = "".to_string();
78 if !regular_rules.is_empty() {
80 media_content.push_str(parent_selector);
82 media_content.push_str(" { ");
83 media_content.push_str(®ular_rules.join(";"));
84 media_content.push_str(" }");
85 }
86 for set in &rules_in_pseudo {
88 if !media_content.is_empty() {
89 media_content.push('\n');
90 }
91 media_content.push_str(set);
92 }
93 css_documents.push((query.into(), media_content));
94 }
95 }
96}
97
98pub fn transform_css(css: &str, next_id: &NextId) -> (u64, Vec<(String, String)>) {
99 let class_id = next_id.get_next_id();
100 let selector = [".", &get_selector(&class_id)].concat();
101
102 let mut css_out: Vec<String> = Vec::new();
103 let mut css_documents: Vec<(String, String)> = Vec::new();
104
105 for row in css_split_rows(css) {
106 if row.starts_with([':', '[']) {
107 let extra_rule = transform_css_selector_value(row, &selector);
109
110 if let Some(extra_rule) = extra_rule {
111 css_documents.push(extra_rule);
112 }
113 } else if row.starts_with("@media") {
114 if !css_out.is_empty() {
117 css_documents.push((selector.clone(), css_out.join("; ")));
118 css_out.clear();
119 }
120 transform_css_media_query(row, &selector, &mut css_documents);
121 } else {
122 match css_row_split_to_pair(row) {
124 Some((name, value)) => {
125 let value_parsed = if name.trim() == "animation" {
126 let (value_parsed, extra_animation) =
128 transform_css_animation_value(&value, next_id);
129
130 if let Some(extra_animation) = extra_animation {
131 css_documents.push(extra_animation);
132 }
133
134 value_parsed
135 } else {
136 value
138 };
139
140 css_out.push([name, ": ", &value_parsed].concat());
141 }
142 None => {
143 css_out.push(row.into());
144 }
145 }
146 }
147 }
148
149 if !css_out.is_empty() {
151 let css_out: String = css_out.join("; ");
152 css_documents.push((selector, css_out));
153 }
154
155 (class_id, css_documents)
156}