From 7461a14cb45d9032b29058c7a0816ada81550a74 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 8 Mar 2024 13:57:46 -0800 Subject: [PATCH] fix 2020: return None if the root nodes are empty in rsx (#2026) --- packages/core-macro/src/lib.rs | 3 +-- packages/core/tests/diff_element.rs | 25 +++++++++++++++++++++++++ packages/rsx/src/lib.rs | 26 +++++++++++++++----------- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs index a469eb04c..f9a29c0b1 100644 --- a/packages/core-macro/src/lib.rs +++ b/packages/core-macro/src/lib.rs @@ -4,7 +4,6 @@ use proc_macro::TokenStream; use quote::ToTokens; -use rsx::RenderCallBody; use syn::parse::Parser; use syn::punctuated::Punctuated; use syn::{parse_macro_input, Path, Token}; @@ -42,7 +41,7 @@ pub fn derive_typed_builder(input: TokenStream) -> TokenStream { pub fn rsx(tokens: TokenStream) -> TokenStream { match syn::parse::(tokens) { Err(err) => err.to_compile_error().into(), - Ok(body) => RenderCallBody(body).into_token_stream().into(), + Ok(body) => body.into_token_stream().into(), } } diff --git a/packages/core/tests/diff_element.rs b/packages/core/tests/diff_element.rs index afcda800d..c6b8391d9 100644 --- a/packages/core/tests/diff_element.rs +++ b/packages/core/tests/diff_element.rs @@ -181,3 +181,28 @@ fn attribute_diff() { ] ); } + +#[test] +fn diff_empty() { + fn app() -> Element { + match generation() % 2 { + 0 => rsx! { div { "hello" } }, + 1 => rsx! {}, + _ => unreachable!(), + } + } + + let mut vdom = VirtualDom::new(app); + vdom.rebuild(&mut NoOpMutations); + + vdom.mark_dirty(ScopeId::ROOT); + let edits = vdom.render_immediate_to_vec().santize().edits; + + assert_eq!( + edits, + [ + CreatePlaceholder { id: ElementId(2,) }, + ReplaceWith { id: ElementId(1,), m: 1 }, + ] + ) +} diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 58d96810d..3d689dda0 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -84,10 +84,13 @@ impl CallBody { location: Some(location), }; + // Empty templates just are placeholders for "none" + if self.roots.is_empty() { + return quote! { None }; + } + quote! { - Some({ - #body - }) + Some({ #body }) } } } @@ -110,20 +113,20 @@ impl Parse for CallBody { } } -#[derive(Default, Debug)] -pub struct RenderCallBody(pub CallBody); - -impl ToTokens for RenderCallBody { +impl ToTokens for CallBody { fn to_tokens(&self, out_tokens: &mut TokenStream2) { let body: TemplateRenderer = TemplateRenderer { - roots: &self.0.roots, + roots: &self.roots, location: None, }; + // Empty templates just are placeholders for "none" + if self.roots.is_empty() { + return out_tokens.append_all(quote! { None }); + } + out_tokens.append_all(quote! { - Some({ - #body - }) + Some({ #body }) }) } } @@ -145,6 +148,7 @@ impl<'a> TemplateRenderer<'a> { let mut context = DynamicContext::default(); let mut roots = Vec::new(); + for (idx, root) in self.roots.iter().enumerate() { context.current_path.push(idx as u8); roots.push(context.update_node::(root, &mut mapping)?);