rspack_style/css/
codegen.rs1use crate::css::value::ValueNode;
2use crate::extend::vec_str::VecCharExtend;
3use crate::token::ident::IdentType;
4use std::cmp::Ordering;
5
6impl ValueNode {
7 pub fn get_no_var_ident_list(&self) -> Result<Vec<IdentType>, String> {
12 let list = self.word_ident_list.clone();
13 if list.is_empty() {
14 return Err(format!(
15 "code_gen content {} is has error, value ident is empty!",
16 self.charlist.poly()
17 ));
18 }
19 Ok(list)
20 }
21
22 fn get_safe(index: usize, list: &[IdentType]) -> Option<&IdentType> {
23 if index < list.len() {
24 list.get(index)
25 } else {
26 None
27 }
28 }
29
30 fn get_mut_safe(index: usize, list: &mut [IdentType]) -> Option<&mut IdentType> {
31 if index < list.len() {
32 list.get_mut(index)
33 } else {
34 None
35 }
36 }
37
38 fn scan_calc_expr_replace(list: &mut [IdentType]) -> Result<(), String> {
39 let mut index = 0;
41 let mut calc_vec = vec![];
42 while index < list.len() {
43 let current = Self::get_safe(index, list).unwrap();
44 let next = Self::get_safe(index + 1, list);
45 if *current == IdentType::Word("calc".into())
46 && next == Some(&IdentType::Brackets("(".into()))
47 {
48 calc_vec.push(index + 1);
49 }
50 index += 1;
51 }
52 for index in calc_vec {
53 let mut cur = index;
54 let mut level = 0;
55 while cur < list.len() {
56 let current = Self::get_mut_safe(cur, list).unwrap();
57 if current == &IdentType::Brackets("(".into()) {
59 level += 1;
60 } else if current == &IdentType::Brackets(")".into()) {
61 level -= 1;
62 }
63 match level.cmp(&0) {
65 Ordering::Equal => {
66 break;
67 }
68 Ordering::Greater => {
69 if let IdentType::Operator(op) = current {
70 *current = IdentType::Word(op.clone());
71 }
72 }
73 Ordering::Less => {}
74 }
75
76 cur += 1;
77 }
78 }
79
80 Ok(())
81 }
82
83 pub fn code_gen(&self) -> Result<String, String> {
87 let mut no_var_list = self.get_no_var_ident_list()?;
88 Self::scan_calc_expr_replace(&mut no_var_list)?;
89 let res = Self::group_calc_ident_value(no_var_list)?;
90 Ok(res)
91 }
92
93 pub fn group_calc_ident_value(list: Vec<IdentType>) -> Result<String, String> {
98 let mut nature_list: Vec<IdentType> = vec![];
100 let mut calc_list: Vec<IdentType> = vec![];
102 let find_no_space_node_rev = |nlist: &Vec<IdentType>| {
107 for item in nlist.iter().rev() {
108 if !matches!(item, IdentType::Space) {
109 return Some(item.clone());
110 }
111 }
112 None
113 };
114
115 for now in list {
117 match now {
120 IdentType::Operator(op) => {
121 if !calc_list.is_empty() {
122 let last_calc_item = find_no_space_node_rev(&calc_list).unwrap();
123 if matches!(last_calc_item, IdentType::Number(..)) {
124 calc_list.push(IdentType::Operator(op));
125 } else {
126 return Err(format!("operatar char is repeat {}", op));
127 }
128 } else {
129 nature_list.push(IdentType::Word(op));
130 }
131 }
132 IdentType::Number(..) => {
133 if calc_list.is_empty() {
134 calc_list.push(now);
135 } else {
136 let last_calc_item = find_no_space_node_rev(&calc_list).unwrap();
137 if matches!(last_calc_item, IdentType::Operator(..))
138 || matches!(last_calc_item, IdentType::Brackets(..))
139 {
140 calc_list.push(now);
141 } else if matches!(last_calc_item, IdentType::Number(..)) {
142 let calc_number = IdentType::calc_value(&calc_list.clone())?;
143 nature_list.push(calc_number);
144 calc_list.clear();
145 calc_list.push(now);
146 }
147 }
148 }
149 IdentType::Var(_) => {
150 return Err("get_no_var_ident_list -> func has error!".to_string());
151 }
152 IdentType::Prop(_) => {
153 return Err("$abc is not support".to_string());
154 }
155 IdentType::InsertVar(_) => {
156 return Err("@{abc} is not support".to_string());
157 }
158 IdentType::StringConst(op)
159 | IdentType::Word(op)
160 | IdentType::Color(op)
161 | IdentType::KeyWord(op) => {
162 if !calc_list.is_empty() {
163 let calc_number = IdentType::calc_value(&calc_list.clone())?;
164 nature_list.push(calc_number);
165 calc_list.clear();
166 }
167 nature_list.push(IdentType::Word(op));
168 }
169 IdentType::Space => {
170 if !calc_list.is_empty() {
171 calc_list.push(now);
172 } else {
173 nature_list.push(now);
174 }
175 }
176 IdentType::Escaping(_) => {
177 return Err("(min-width: 768px) | ~'min-width: 768px' is not support".to_string());
178 }
179 IdentType::Brackets(br) => {
180 if !calc_list.is_empty() {
181 if br == "(" || br == "[" {
182 calc_list.push(IdentType::Brackets(br));
183 } else {
184 let last_bracket = {
185 let mut ident: Option<&IdentType> = None;
186 for item in calc_list.iter().rev() {
187 if matches!(item, IdentType::Brackets(..)) {
188 ident = Some(item);
189 }
190 }
191 ident
192 };
193 if let Some(IdentType::Brackets(cc)) = last_bracket {
194 if cc == "(" || cc == "[" {
195 calc_list.push(IdentType::Brackets(br));
196 } else {
197 if !calc_list.is_empty() {
198 let calc_number = IdentType::calc_value(&calc_list)?;
199 nature_list.push(calc_number);
200 calc_list.clear();
201 }
202 nature_list.push(IdentType::Brackets(br));
203 }
204 } else {
205 if !calc_list.is_empty() {
206 let calc_number = IdentType::calc_value(&calc_list)?;
207 nature_list.push(calc_number);
208 calc_list.clear();
209 }
210 nature_list.push(IdentType::Brackets(br));
211 }
212 }
213 } else {
214 if !calc_list.is_empty() {
215 let calc_number = IdentType::calc_value(&calc_list)?;
216 nature_list.push(calc_number);
217 calc_list.clear();
218 }
219 nature_list.push(IdentType::Brackets(br));
220 }
221 }
222 }
223 }
225 if !calc_list.is_empty() {
227 let calc_number = IdentType::calc_value(&calc_list)?;
228 nature_list.push(calc_number);
229 calc_list.clear();
230 }
231
232 let mut res = String::new();
233 for (index, item) in nature_list.iter().enumerate() {
234 let last = if index > 0 {
235 Some(nature_list.get(index - 1).unwrap().clone())
236 } else {
237 None
238 };
239 match item {
242 IdentType::Number(value, unit) => {
243 if matches!(last, Some(IdentType::Word(..)))
244 || matches!(last, Some(IdentType::Number(..)))
245 {
246 res += " ";
247 }
248 res.push_str(value);
249 res.push_str(&unit.clone().unwrap_or_default());
250 }
251 IdentType::Word(char) => {
252 if matches!(last, Some(IdentType::Word(..)))
253 || matches!(last, Some(IdentType::Number(..)))
254 {
255 res.push(' ');
256 }
257 res.push_str(char);
258 }
259 IdentType::Space => {
260 if !matches!(last, Some(IdentType::Space)) {
261 res.push(' ');
262 }
263 }
264 IdentType::Brackets(br) => {
265 res.push_str(br);
267 }
268 _ => {}
269 }
270 }
271
272 Ok(res)
273 }
274}