elm_parser/
emitter.rs

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                                //text_block.push_str(&format!("\"#<{}>r#\"", wrap_with));
83
84                                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                                //text_block.push_str(&format!("\"#</{}>r#\"", wrap_with));
91                                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        // add quotes to prop value if it's a string
159        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}