1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::parser_helpers::{BlockChildType, CellType, DataCell, DelimitedDisplayType};

use super::element_text::ElementText;
use super::helpers::*;
use std::str::Lines;

#[derive(Debug, Default)]
pub struct TagInfo {
    pub name: String,
    pub indent: usize,
    pub is_self_closing: bool,
    pub in_props: bool,
}

#[derive(Debug)]
pub struct Emitter {
    pub self_closing_tags: Vec<&'static str>,
}

impl Emitter {
    pub fn new(self_closing_tags: Vec<&'static str>) -> Emitter {
        Emitter { self_closing_tags }
    }

    pub fn emit_json(&self, data_cell: &DataCell) -> String {
        let mut output = String::new();
        /* let json_tree: DataCell = serde_json::from_str(json).unwrap(); */

        match &data_cell.cell_type {
            CellType::Root(root) => {
                root.children.iter().for_each(|child| {
                    output.push_str(&self.emit_json(child));
                });
            }
            CellType::Element(el) => {
                output.push_str(&format!("<{} ", el.name));
                el.props.iter().for_each(|prop| {
                    output.push_str(&Self::handle_prop_line(&format!(
                        "{} {}",
                        prop.key, prop.value
                    )));
                });
                if self.self_closing_tags.contains(&el.name.as_str()) {
                    output.push_str(" />");
                } else {
                    output.push_str(" >");

                    el.children.iter().for_each(|child| {
                        output.push_str(&self.emit_json(child));
                    });
                    if el.children.is_empty() {
                        output.push_str("\"\"");
                    }
                    output.push_str(&format!("</{}>", el.name));
                }
            }
            CellType::Block(block) => {
                let mut text_block = String::new();
                block.children.iter().for_each(|child| match child {
                    BlockChildType::Text(text) => {
                        text_block.push_str(&text.content);
                    }
                    BlockChildType::Delimited(dl) => {
                        if let Some(wrap_with) = &dl.wrapped_with {
                            text_block.push_str(&format!("\"#<{}>r#\"", wrap_with));
                        }
                        text_block.push_str(&dl.delimeter);
                        text_block.push_str(&dl.terminal);
                        if dl.delimeter == "_|" {
                            text_block.push_str("|_");
                        } else {
                            text_block.push_str(&dl.delimeter);
                        }
                        if let Some(wrap_with) = &dl.wrapped_with {
                            text_block.push_str(&format!("\"#</{}>r#\"", wrap_with));
                        }
                    }
                });
                let text_el = ElementText::new(&text_block);
                output.push_str(&format!("r#\"{}\"#", text_el.handle_delimeters()));
            }
            _ => {}
        }

        output
    }

    fn handle_prop_line(line: &str) -> String {
        let mut prop_line = line.trim().to_string();
        // add quotes to prop value if it's a string
        let prop_value = prop_line.split_once(" ");
        if let Some((prop_key, prop_value)) = prop_value {
            let is_number = prop_value.trim().parse::<f32>();
            let is_bool = prop_value.trim() == "false" || prop_value.trim() == "true";
            let is_vec = prop_value.trim().starts_with("vec![");

            if is_number.is_err() && !is_bool && !is_vec {
                prop_line = match prop_key {
                    "src" => format!(" {}=\"/{}\"", prop_key.trim(), prop_value.trim()),
                    _ => format!(" {}=\"{}\"", prop_key.trim(), prop_value.trim()),
                }
            } else {
                prop_line = format!(" {}={}", prop_key.trim(), prop_value.trim())
            }
        }
        prop_line
    }
}