1use std::collections::HashMap;
2
3use super::element_text::ElementText;
4use crate::{
5 counter::counter_types::CounterType,
6 datacell::{BlockChildType::*, Datacell::*},
7};
8
9#[derive(Debug, Default)]
10pub struct TagInfo {
11 pub name: String,
12 pub indent: usize,
13 pub is_self_closing: bool,
14 pub in_props: bool,
15}
16
17#[derive(Debug)]
18pub struct Emitter<'a> {
19 pub self_closing_tags: Vec<&'a str>,
20}
21
22impl<'a> Emitter<'a> {
23 pub fn new(self_closing_tags: Vec<&'a str>) -> Emitter<'a> {
24 Emitter { self_closing_tags }
25 }
26
27 pub fn emit_json(&mut self, data_cell: &DataCell) -> String {
28 let mut output = String::new();
29
30 match &data_cell.cell_type {
31 CellType::Root(root) => {
32 root.children.iter().for_each(|child| {
33 output.push_str(&self.emit_json(child));
34 });
35 }
36 CellType::Element(el) => {
37 output.push_str(&format!("<{} ", el.name));
38 el.props.iter().for_each(|prop| {
39 if !CounterType::is_valid(&prop.key) {
40 output.push_str(&Self::handle_prop_line(&format!(
41 "{} {}",
42 prop.key, prop.value
43 )));
44 }
45 });
46 if self.self_closing_tags.contains(&el.name.as_str()) {
47 output.push_str(" />");
48 } else {
49 output.push_str(" >");
50
51 el.children.iter().for_each(|child| {
52 output.push_str(&self.emit_json(child));
53 });
54 if el.children.is_empty() {
55 output.push_str("\"\"");
56 }
57 output.push_str(&format!("</{}>", el.name));
58 }
59 }
60 CellType::Block(block) => {
61 let mut text_block = String::new();
62 let mut sub_text_block = String::new();
63
64 block
65 .children
66 .iter()
67 .enumerate()
68 .for_each(|(_, child)| match child {
69 BlockChildType::Text(text) => {
70 sub_text_block.push_str(&text.content);
71 }
72 BlockChildType::Delimited(dl) => {
73 if let Some(_) = &dl.wrapped_with {
74 if !sub_text_block.trim().is_empty() {
75 text_block
76 .push_str(&format!("\"#<{} class=\"text\">r#\"", "span"));
77 let text_el = ElementText::new(sub_text_block.as_str());
78 text_block.push_str(&&text_el.handle_delimeters());
79 text_block.push_str(&format!("\"#</{}>r#\"", "span"));
80 }
81 sub_text_block = "".to_string();
82 sub_text_block.push_str(&dl.open_delimeter);
85 sub_text_block.push_str(&dl.terminal);
86 sub_text_block.push_str(&dl.close_delimeter);
87
88 let text_el = ElementText::new(sub_text_block.as_str());
89 text_block.push_str(&text_el.handle_delimeters());
90 sub_text_block = "".to_string();
92 } else if dl.display_type == DelimitedDisplayType::BLOCK {
93 sub_text_block = "".to_string();
94 sub_text_block.push_str(&dl.open_delimeter);
95 sub_text_block.push_str(&dl.terminal);
96 sub_text_block.push_str(&dl.close_delimeter);
97 let text_el = ElementText::new(sub_text_block.as_str());
98 text_block.push_str(&text_el.handle_delimeters());
99 sub_text_block = "".to_string();
100 } else {
101 sub_text_block.push_str(&dl.open_delimeter);
102 sub_text_block.push_str(&dl.terminal);
103 sub_text_block.push_str(&dl.close_delimeter);
104 }
105 }
106 });
107
108 if !sub_text_block.trim().is_empty() {
109 text_block.push_str(&format!("\"#<{} class=\"text\">r#\"", "span"));
110 let text_el = ElementText::new(sub_text_block.as_str());
111 text_block.push_str(&text_el.handle_delimeters());
112 text_block.push_str(&format!("\"#</{}>r#\"", "span"));
113 }
114
115 output.push_str(&format!("r#\"{}\"#", text_block));
116 }
117 _ => {}
118 }
119
120 output.replace("r#\"\"#", "")
121 }
122
123 pub fn split_and_emit(
124 &mut self,
125 data_cell: &DataCell,
126 split_children_of: &str,
127 ) -> HashMap<String, String> {
128 let mut output = HashMap::new();
129 match &data_cell.cell_type {
130 CellType::Element(el) => {
131 if el.name.contains(&split_children_of) {
132 el.children.iter().for_each(|child| {
133 if let CellType::Element(child_el) = &child.cell_type {
134 output.insert(
135 child_el.name.clone().to_lowercase(),
136 self.emit_json(child),
137 );
138 }
139 });
140 } else {
141 el.children.iter().for_each(|child| {
142 output.extend(self.split_and_emit(child, split_children_of));
143 });
144 }
145 }
146 CellType::Root(root) => {
147 root.children.iter().for_each(|child| {
148 output.extend(self.split_and_emit(child, split_children_of));
149 });
150 }
151 _ => (),
152 }
153 output
154 }
155
156 fn handle_prop_line(line: &str) -> String {
157 let mut prop_line = line.trim().to_string();
158 let prop_value = prop_line.split_once(" ");
160 if let Some((prop_key, prop_value)) = prop_value {
161 let is_number = prop_value.trim().parse::<f32>();
162 let is_bool = prop_value.trim() == "false" || prop_value.trim() == "true";
163 let is_vec = prop_value.trim().starts_with("vec![");
164
165 if is_number.is_err() && !is_bool && !is_vec {
166 prop_line = match prop_key {
167 "src" => format!(" {}=\"/{}\"", prop_key.trim(), prop_value.trim()),
168 _ => format!(" {}=\"{}\"", prop_key.trim(), prop_value.trim()),
169 }
170 } else {
171 prop_line = format!(" {}={}", prop_key.trim(), prop_value.trim())
172 }
173 }
174 prop_line
175 }
176}