1use crate::{attributes, node::*, text::Text};
8use attributes::{Attribute, Value};
9use std::collections::HashMap;
10
11impl<'a> From<Node<'a>> for String {
12 fn from(value: Node<'a>) -> Self {
13 match value {
14 Node::Text(t) => text_to_string(t),
15 Node::Comment(c) => comment_to_string(c),
16 Node::Element(e) => element(e),
17 Node::Void(v) => void_element(v),
18 }
19 }
20}
21
22fn text_to_string(value: Text) -> String {
23 value.into()
24}
25
26fn comment_to_string(value: Comment) -> String {
27 let text: String = value.into();
28 format!("<!--{}-->", text)
29}
30
31fn attributes_to_string<'a>(
32 value: HashMap<attributes::Attribute<'a>, Option<attributes::Value>>,
33) -> Option<String> {
34 let seperator = " ";
35 let joiner = "=";
36 let property = |arg: (&Attribute, &Option<Value>)| -> String {
37 let (key, value) = arg;
38 match value {
39 None => format!("{}", key),
40 Some(value) => format!("{}{}\"{}\"", key, joiner, value),
41 }
42 };
43
44 match value.len() {
45 0 => None,
46 _ => value
47 .iter()
48 .map(property)
49 .collect::<Vec<String>>()
50 .join(seperator)
51 .into(),
52 }
53}
54
55fn void_element(value: Element<()>) -> String {
56 let tag: &str = value.name.into();
57 let attributes = attributes_to_string(value.attributes);
58 match attributes {
59 None => format!("<{}/>", tag),
60 Some(attributes) => format!("<{} {} />", tag, attributes),
61 }
62}
63
64fn element(value: Element<Vec<Node>>) -> String {
65 let tag: &str = value.name.into();
66 let attributes = attributes_to_string(value.attributes);
67 let string_child = |node: &Node| -> String { node.clone().into() };
68 let child_sep = "";
69 let children = value
70 .children
71 .iter()
72 .map(string_child)
73 .collect::<Vec<String>>()
74 .join(child_sep);
75 match attributes {
76 None => format!("<{}>{}</{}>", tag, children, tag),
77 Some(attr) => format!("<{} {}>{}</{}>", tag, attr, children, tag),
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::tag::Tag;
85 use attributes::{Attribute, Value};
86 #[test]
87 fn render_text() {
88 let text = Node::text("Hello");
89 let rendered: String = text.into();
90 let expected = "Hello";
91 assert_eq!(rendered, expected);
92 }
93
94 #[test]
95 fn render_comment() {
96 let text = Node::comment("Hello");
97 let rendered: String = text.into();
98 let expected = "<!--Hello-->";
99 assert_eq!(rendered, expected);
100 }
101
102 #[test]
103 fn render_element_void() {
104 let element: Node = Element::<()>::create(Tag::BR).into();
105 let expected = "<br/>";
106 let render: String = element.into();
107 assert_eq!(render, expected);
108 }
109
110 #[test]
111 fn render_element_void_with_attributes() {
112 let mut element = Element::<()>::create(Tag::BR);
113 element.set_attribute(Attribute::CLASS, Value::create("test").unwrap());
114 let expected = r#"<br class="test" />"#;
115 let node: Node = element.into();
116 let render: String = node.into();
117 assert_eq!(render, expected);
118 }
119
120 #[test]
121 fn render_element_open() {
122 let mut element = Element::<Vec<Node>>::create(Tag::A);
123 let nested: Node = Text::create("Link").into();
124 element.push(nested);
125 let node: Node = element.into();
126 let rendered: String = node.into();
127 let expected = "<a>Link</a>";
128 assert_eq!(rendered, expected);
129 }
130
131 #[test]
132 fn render_element_multi_nested() {
133 let div = Element::<Vec<Node>>::create(Tag::DIV);
134 let mut div2 = div.clone();
135 let mut div3 = div.clone();
136 div2.push(div);
137 div3.push(div2);
138
139 let node: Node = div3.into();
140 let rendered: String = node.into();
141 let expected = "<div><div><div></div></div></div>";
142 assert_eq!(rendered, expected);
143 }
144
145 #[test]
146 fn render_element_two_children() {
147 let div = Element::<Vec<Node>>::create(Tag::DIV);
148 let div2 = div.clone();
149 let mut div3 = div.clone();
150 div3.push(div);
151 div3.push(div2);
152
153 let node: Node = div3.into();
154 let rendered: String = node.into();
155 let expected = "<div><div></div><div></div></div>";
156 assert_eq!(rendered, expected);
157 }
158
159 #[test]
160 fn render_element_open_but_empty() {
161 let element = Element::<Vec<Node>>::create(Tag::A);
162 let node: Node = element.into();
163 let rendered: String = node.into();
164 let expected = "<a></a>";
165 assert_eq!(rendered, expected);
166 }
167
168 #[test]
169 fn render_element_open_with_attributes() {
170 let mut element = Element::<Vec<Node>>::create(Tag::A);
171 element.set_attribute(Attribute::CLASS, Value::create("test").unwrap());
172 let nested: Node = Text::create("Link").into();
173 element.push(nested);
174 let node: Node = element.into();
175 let rendered: String = node.into();
176 let expected = r#"<a class="test">Link</a>"#;
177 assert_eq!(rendered, expected);
178 }
179}