use crate::vdom::{VElement, VNode};
pub struct SimpleRenderer {
output: Vec<String>,
}
impl SimpleRenderer {
pub fn new() -> Self {
Self { output: Vec::new() }
}
pub fn render(&mut self, vnode: &VNode) {
self.output.clear();
self.render_node(vnode, 0);
}
fn render_node(&mut self, vnode: &VNode, depth: usize) {
let indent = " ".repeat(depth);
match vnode {
VNode::Element(element) => {
self.render_element(element, depth);
}
VNode::Text(text) => {
self.output
.push(format!("{}Text: {}", indent, text.content));
}
VNode::Component(component) => {
self.output
.push(format!("{}Component: {}", indent, component.name));
}
VNode::Empty => {
}
}
}
fn render_element(&mut self, element: &VElement, depth: usize) {
let indent = " ".repeat(depth);
let mut tag_str = format!("{}<{}", indent, element.tag);
for (key, value) in &element.attrs {
tag_str.push_str(&format!(" {}=\"{}\"", key, value));
}
tag_str.push('>');
self.output.push(tag_str);
for child in &element.children {
self.render_node(child, depth + 1);
}
self.output.push(format!("{}</{}>", indent, element.tag));
}
pub fn get_output(&self) -> String {
self.output.join("\n")
}
pub fn print(&self) {
println!("{}", self.get_output());
}
}
impl Default for SimpleRenderer {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::vdom::{VComponent, VElement, VText};
use std::collections::HashMap;
#[test]
fn test_render_text() {
let mut renderer = SimpleRenderer::new();
let vnode = VNode::Text(VText::new("Hello, World!"));
renderer.render(&vnode);
let output = renderer.get_output();
assert!(output.contains("Hello, World!"));
}
#[test]
fn test_render_element() {
let mut renderer = SimpleRenderer::new();
let element = VElement {
tag: "div".to_string(),
attrs: HashMap::new(),
children: vec![VNode::Text(VText::new("Content"))],
};
renderer.render(&VNode::Element(element));
let output = renderer.get_output();
assert!(output.contains("<div>"));
assert!(output.contains("Content"));
assert!(output.contains("</div>"));
}
#[test]
fn test_render_component() {
let mut renderer = SimpleRenderer::new();
let component = VComponent {
name: "Counter".to_string(),
props: HashMap::new(),
};
renderer.render(&VNode::Component(component));
let output = renderer.get_output();
assert!(output.contains("Component: Counter"));
}
}
#[cfg(target_arch = "wasm32")]
pub fn render_to_html(vnode: &crate::simple_vnode::VNode) -> String {
use crate::simple_vnode::{VAttr, VNode};
match vnode {
VNode::Element {
tag,
attrs,
children,
} => {
let mut html = format!("<{}", tag);
for (key, value) in attrs {
match value {
VAttr::Static(v) | VAttr::Dynamic(v) => {
html.push_str(&format!(" {}=\"{}\"", key, v));
}
VAttr::Event(_) => {
}
}
}
html.push('>');
for child in children {
html.push_str(&render_to_html(child));
}
html.push_str(&format!("</{}>", tag));
html
}
VNode::Text(text) => text.clone(),
}
}