1use crate::css::fileinfo::{FileInfo, FileWeakRef};
2use crate::css::node::{NodeRef, NodeWeakRef, StyleNode};
3use crate::css::parse::Parse;
4use crate::css::select_node::SelectorNode;
5use crate::css::style_rule::StyleRuleNode;
6use crate::css::var::VarRuleNode;
7use crate::extend::string::StringExtend;
8use crate::extend::vec_str::VecCharExtend;
9use crate::sourcemap::loc::{Loc, LocMap};
10use crate::style_core::context::ParseContext;
11use crate::style_core::option::OptionExtend;
12use crate::util::str_handle::{merge_spaces, merge_wrap};
13use serde::ser::SerializeStruct;
14use serde::{Serialize, Serializer};
15use serde_json::{Map, Value};
16use std::cell::RefCell;
17use std::collections::HashSet;
18use std::fmt::Write;
19use std::fmt::{Debug, Formatter};
20use std::ops::Deref;
21use std::rc::Rc;
22
23#[derive(Clone)]
24pub struct RuleNode {
25 pub selector: Option<SelectorNode>,
27 pub origin_charlist: Vec<char>,
29 pub loc: Option<Loc>,
31 pub locmap: Option<LocMap>,
33 pub parent: NodeWeakRef,
35 pub weak_self: NodeWeakRef,
37 pub block_node: Vec<StyleNode>,
39 pub file_info: FileWeakRef,
41 pub context: ParseContext,
43}
44
45impl Serialize for RuleNode {
46 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
47 where
48 S: Serializer,
49 {
50 let mut state = serializer.serialize_struct("RuleNode", 4)?;
51 state.serialize_field("content", &self.origin_charlist.poly())?;
52 state.serialize_field("loc", &self.loc)?;
53 state.serialize_field("select", &self.selector.as_ref().unwrap())?;
54 state.serialize_field("block_node", &self.block_node)?;
55 state.end()
56 }
57}
58
59impl Debug for RuleNode {
60 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61 f.debug_struct("RuleNode")
62 .field("content", &self.origin_charlist.poly())
63 .field("loc", &self.loc)
64 .field("select", &self.selector.as_ref().unwrap().value())
65 .field("block_node", &self.block_node)
66 .finish()
67 }
68}
69
70impl RuleNode {
71 pub fn new(
75 charlist: Vec<char>,
76 selector_txt: Vec<char>,
77 loc: Option<Loc>,
78 file_info: FileWeakRef,
79 context: ParseContext,
80 ) -> Result<NodeRef, String> {
81 let mut change_loc: Option<Loc> = loc;
82 let obj = RuleNode {
83 selector: None,
84 origin_charlist: charlist,
85 loc,
86 locmap: None,
87 block_node: vec![],
88 parent: None,
89 weak_self: None,
90 file_info: file_info.clone(),
91 context,
92 };
93 let heapobj = Rc::new(RefCell::new(obj));
94 let wek_self = Rc::downgrade(&heapobj);
95 heapobj.borrow_mut().weak_self = Some(wek_self.clone());
96
97 let selector = match SelectorNode::new(selector_txt, &mut change_loc, Some(wek_self), file_info)
98 {
99 Ok(result) => result,
100 Err(msg) => {
101 return Err(msg);
102 }
103 };
104 heapobj.borrow_mut().selector = Some(selector);
105 if heapobj.deref().borrow().get_options().sourcemap {
106 heapobj.borrow_mut().loc = change_loc.as_ref().cloned();
107 let (calcmap, _) = LocMap::merge(
108 change_loc.as_ref().unwrap(),
109 &heapobj.borrow().origin_charlist,
110 );
111 heapobj.borrow_mut().locmap = Some(calcmap);
112 }
113 heapobj.borrow_mut().parse_heap()?;
114 Ok(heapobj)
115 }
116
117 pub fn deserializer(
121 map: &Map<String, Value>,
122 context: ParseContext,
123 parent: NodeWeakRef,
124 fileinfo: FileWeakRef,
125 ) -> Result<Rc<RefCell<Self>>, String> {
126 let mut rule_node = Self {
127 selector: None,
128 origin_charlist: vec![],
129 loc: None,
130 locmap: None,
131 parent: parent.as_ref().cloned(),
132 weak_self: None,
133 block_node: vec![],
134 file_info: fileinfo.as_ref().cloned(),
135 context: context.clone(),
136 };
137 if let Some(Value::String(content)) = map.get("content") {
138 rule_node.origin_charlist = content.to_char_vec();
139 } else {
140 return Err("deserializer RuleNode has error -> content is empty!".to_string());
141 }
142 if let Some(Value::Object(loc)) = map.get("loc") {
143 rule_node.loc = Some(Loc::deserializer(loc));
144 rule_node.locmap =
145 Some(LocMap::merge(rule_node.loc.as_ref().unwrap(), &rule_node.origin_charlist).0);
146 } else {
147 rule_node.locmap = Some(LocMap::new(&rule_node.origin_charlist));
148 }
149 let heapobj = Rc::new(RefCell::new(rule_node));
150 let weak_self = Rc::downgrade(&heapobj);
151 heapobj.borrow_mut().weak_self = Some(weak_self.clone());
152 let json_block_node = map.get("block_node");
153 let mut block_node_recovery_list = vec![];
154 if let Some(Value::Array(block_nodes)) = json_block_node {
155 for json_node in block_nodes {
156 if let Value::Object(json_stylenode) = json_node {
157 block_node_recovery_list.push(StyleNode::deserializer(
158 json_stylenode,
159 context.clone(),
160 Some(weak_self.clone()),
161 fileinfo.as_ref().cloned(),
162 )?);
163 }
164 }
165 }
166 if let Some(Value::Object(map)) = map.get("select") {
167 heapobj.borrow_mut().selector = Some(SelectorNode::deserializer(
168 map,
169 Some(weak_self),
170 fileinfo.as_ref().cloned(),
171 )?);
172 } else {
173 return Err("deserializer RuleNode has error -> select is empty!".to_string());
174 }
175 heapobj.borrow_mut().block_node = block_node_recovery_list;
176 Ok(heapobj)
177 }
178
179 pub fn parse_select_all_node(&self) -> Result<(), String> {
185 for node in self.block_node.iter() {
186 if let StyleNode::Rule(heapnode) = node {
187 let mut mut_node = heapnode.borrow_mut();
188 if let Some(SelectorNode::Select(s_node)) = mut_node.selector.as_mut() {
189 s_node.parse()?;
190 }
191 drop(mut_node);
192 heapnode.borrow().parse_select_all_node()?;
193 }
194 }
195 Ok(())
196 }
197
198 pub fn visit_mut_file(&self, fileinfo: &mut FileInfo) {
199 self.block_node.iter().for_each(|x| {
200 if let StyleNode::Rule(rule) = x {
201 rule.borrow().visit_mut_file(fileinfo);
202 }
203 });
204 }
205
206 pub fn getrules(&self) -> Vec<NodeRef> {
207 let mut list = vec![];
208
209 self.block_node.iter().for_each(|x| {
210 if let StyleNode::Rule(rule) = x {
211 list.push(rule.clone());
212 }
213 });
214 list
215 }
216
217 pub fn get_style_rule(&self) -> Vec<StyleRuleNode> {
218 let mut list = vec![];
219 self.block_node.iter().for_each(|x| {
220 if let StyleNode::Var(VarRuleNode::StyleRule(style)) = x {
221 list.push(style.clone());
222 }
223 });
224 list
225 }
226
227 pub fn code_gen(&self, content: &mut String, map: &mut HashSet<String>) -> Result<(), String> {
228 let rules = self.get_style_rule();
229 let (select_txt, media_txt) = self.selector.as_ref().unwrap().code_gen(map).unwrap();
230 let mut tab: String = "".to_string();
231 let mut index = 0;
232 let option = self.get_options();
233
234 let mut br_char = "\n";
235 if option.minify {
236 br_char = " ";
237 } else {
238 while index < option.tabspaces {
239 tab += " ";
240 index += 1;
241 }
242 }
243
244 let handle_str = |content: &str| merge_spaces(merge_wrap(content).as_str());
245
246 if select_txt.find('@') == Some(0) {
248 let single_key_rule_content = {
249 if option.minify {
250 handle_str(self.origin_charlist.poly().as_str())
251 } else {
252 self.origin_charlist.poly()
253 }
254 };
255
256 if media_txt.is_empty() {
257 *content += format!(
258 "{}{}{}{}{}{}{}",
259 br_char,
260 select_txt,
261 "{",
262 br_char,
263 tab.clone() + &tab.clone() + single_key_rule_content.as_str(),
264 br_char,
265 "}"
266 )
267 .as_str();
268 } else {
269 *content += format!(
270 "{}{}{}{}{}{}{}{}{}{}{}{}",
271 br_char,
272 media_txt,
273 br_char,
274 "{",
275 tab.clone() + &select_txt,
276 br_char,
277 "{",
278 tab.clone() + &tab.clone() + &tab.clone() + single_key_rule_content.as_str(),
279 br_char,
280 tab.clone() + "}",
281 br_char,
282 "}"
283 )
284 .as_str();
285 }
286
287 return Ok(());
289 } else if !rules.is_empty() {
290 let create_rules = |tab: String| -> Result<String, String> {
291 let mut res: String = "".to_string();
292 for (index, rule_res) in rules.iter().enumerate() {
293 if index != rules.len() - 1 {
294 if !option.minify {
295 writeln!(res, "{}{}", tab.clone(), rule_res.code_gen()?)
296 .expect("write stream has error");
297 } else {
298 write!(res, " {}{}", tab.clone(), rule_res.code_gen()?)
299 .expect("write stream has error");
300 }
301 } else {
302 write!(res, "{}{}", tab.clone(), rule_res.code_gen()?).expect("write stream has error");
303 }
304 }
305 Ok(res)
306 };
307
308 if media_txt.is_empty() {
309 *content += format!(
310 "{}{}{}{}{}{}{}{}",
311 br_char,
312 select_txt,
313 " {",
314 br_char,
315 create_rules(tab)?,
316 br_char,
317 "}",
318 br_char,
319 )
320 .as_ref();
321 } else {
322 *content += format!(
323 "{}{}{}{}{}{}{}{}{}{}{}{}",
324 br_char,
325 media_txt,
326 " {",
327 br_char,
328 tab.clone() + &select_txt,
329 " {",
330 br_char,
331 create_rules(tab.clone() + &tab.clone())?,
332 br_char,
333 " }",
334 br_char,
335 "}"
336 )
337 .as_ref();
338 }
339 }
340
341 for node_ref in self.getrules() {
342 node_ref.deref().borrow().code_gen(content, map)?;
343 }
344
345 Ok(())
346 }
347}