rspack_style/css/
codegen.rs

1use crate::css::value::ValueNode;
2use crate::extend::vec_str::VecCharExtend;
3use crate::token::ident::IdentType;
4use std::cmp::Ordering;
5
6impl ValueNode {
7  ///
8  /// 代码转化 都 转化成 无变量 实参
9  /// 用于 (变量计算)
10  ///
11  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    // 寻找可能的锚点
40    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        // 增减开始
58        if current == &IdentType::Brackets("(".into()) {
59          level += 1;
60        } else if current == &IdentType::Brackets(")".into()) {
61          level -= 1;
62        }
63        // 处理逻辑
64        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  ///
84  /// 代码生成
85  ///
86  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  ///
94  /// 计算 提纯后 根据所有 词的 性质进行组合
95  /// 用于 (运算)
96  ///
97  pub fn group_calc_ident_value(list: Vec<IdentType>) -> Result<String, String> {
98    // 非计算词性
99    let mut nature_list: Vec<IdentType> = vec![];
100    // 计算词性
101    let mut calc_list: Vec<IdentType> = vec![];
102    // 下标
103
104    // 逆向查找第一个 非空格 的元素
105    // 左值 重要
106    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    // 遍历 范式
116    for now in list {
117      // 比对词性
118      // let now = list.get(index).unwrap().clone();
119      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      // index += 1;
224    }
225    // while index < list.len() {}
226    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      // let last = Some(nature_list.get(index - 1).unwrap().clone());
240
241      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          // todo fix single number situation
266          res.push_str(br);
267        }
268        _ => {}
269      }
270    }
271
272    Ok(res)
273  }
274}