diff --git a/src/node.rs b/src/node.rs index 1e86b73..1acb1ee 100644 --- a/src/node.rs +++ b/src/node.rs @@ -1,3 +1,5 @@ +use crate::Render; +use crate::RenderContext; use crate::{cached_set::CacheId, RootRender, VdomWeak}; use bumpalo::Bump; use std::fmt; @@ -269,3 +271,32 @@ impl Listener<'_> { } } } + +pub fn html_string(component: &R) -> String +where + R: Render, +{ + fn html_string_recursive(cx: &mut RenderContext, s: &mut String, node: &Node) { + match node.kind { + NodeKind::Text(ref t) => s.push_str(t.text), + NodeKind::Element(ref e) => { + s.push_str(e.tag_name); + for c in e.children { + html_string_recursive(cx, s, c); + } + + s.push_str(&format!("", e.tag_name)); + } + NodeKind::Cached(ref c) => { + html_string_recursive(cx, s, cx.cached_set.borrow().get(c.id).0); + } + } + } + + RenderContext::empty(|cx| { + let node = component.render(cx); + let mut s = String::new(); + html_string_recursive(cx, &mut s, &node); + s + }) +} diff --git a/src/render_context.rs b/src/render_context.rs index 34abb63..57c87b4 100644 --- a/src/render_context.rs +++ b/src/render_context.rs @@ -5,6 +5,7 @@ use crate::{ }; use bumpalo::Bump; use fxhash::FxHashMap; +use std::cell::RefCell; use std::fmt; /// Common context available to all `Render` implementations. @@ -58,6 +59,23 @@ impl<'a> RenderContext<'a> { } } } + /// return an empty rendering context + pub_unstable_internal! { + pub(crate) fn empty(f: F) -> T + where F: FnOnce(&mut RenderContext) -> T, + { + let cached_set = &RefCell::new(CachedSet::default()); + let bump = &Bump::new(); + let templates = &mut FxHashMap::default(); + + f(&mut RenderContext { + bump, + cached_set, + templates, + _non_exhaustive: (), + }) + } + } pub(crate) fn cache(&mut self, pinned: bool, template: Option, f: F) -> CacheId where diff --git a/tests/web/render.rs b/tests/web/render.rs index 25d97a5..3d9515b 100644 --- a/tests/web/render.rs +++ b/tests/web/render.rs @@ -1,4 +1,4 @@ -use super::{assert_rendered, before_after, create_element, RenderFn}; +use super::{assert_rendered, before_after, create_element, RenderFn, html_string}; use dodrio::{builder::*, Vdom}; use futures::prelude::*; use std::rc::Rc; @@ -10,7 +10,18 @@ fn render_initial_text() { let container = create_element("div"); let _vdom = Vdom::new(&container, hello.clone()); - assert_rendered(&container, &hello); + assert_rendered(container, &hello); +} + +fn render_to_string() { + let hello = Rc::new(RenderFn(|cx| { + div(&cx) + .attr("id", "hello-world") + .children([text("Hello "), span(&cx).child(text("World!")).finish()]) + .finish() + })); + let string_html = html_string(&hello); + assert!(&string_html, "
Hello World!
"); } #[wasm_bindgen_test]