From ce4fe632a2bb916050a2ad227b82568c897cd652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=C3=85str=C3=B6m?= Date: Sat, 29 Jun 2024 22:15:39 +0200 Subject: [PATCH] Destructuring `let` (0.7) (#2655) * Use `let()` syntax for bindings This lets users use destructuring when binding more complex values, and we also get better IDE support. * Update rstml --- leptos_hot_reload/Cargo.toml | 2 +- leptos_macro/Cargo.toml | 2 +- leptos_macro/src/view/component_builder.rs | 34 +++++++++++++++++----- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/leptos_hot_reload/Cargo.toml b/leptos_hot_reload/Cargo.toml index 2027d288ac..429098cc5b 100644 --- a/leptos_hot_reload/Cargo.toml +++ b/leptos_hot_reload/Cargo.toml @@ -20,7 +20,7 @@ syn = { version = "2", features = [ "printing", ] } quote = "1" -rstml = "0.11.0" +rstml = "0.11.2" proc-macro2 = { version = "1", features = ["span-locations", "nightly"] } parking_lot = "0.12" walkdir = "2" diff --git a/leptos_macro/Cargo.toml b/leptos_macro/Cargo.toml index 4866cdbd45..f498040b78 100644 --- a/leptos_macro/Cargo.toml +++ b/leptos_macro/Cargo.toml @@ -22,7 +22,7 @@ proc-macro-error = { version = "1", default-features = false } proc-macro2 = "1" quote = "1" syn = { version = "2", features = ["full"] } -rstml = "0.11.0" +rstml = "0.11.2" leptos_hot_reload = { workspace = true } server_fn_macro = { workspace = true } convert_case = "0.6.0" diff --git a/leptos_macro/src/view/component_builder.rs b/leptos_macro/src/view/component_builder.rs index b7707130bf..b611ac5a30 100644 --- a/leptos_macro/src/view/component_builder.rs +++ b/leptos_macro/src/view/component_builder.rs @@ -2,9 +2,9 @@ use super::{fragment_to_tokens, TagType}; use crate::view::attribute_absolute; use proc_macro2::{Ident, TokenStream, TokenTree}; use quote::{format_ident, quote, quote_spanned}; -use rstml::node::{NodeAttribute, NodeBlock, NodeElement}; +use rstml::node::{KeyedAttributeValue, NodeAttribute, NodeBlock, NodeElement, NodeName}; use std::collections::HashMap; -use syn::{spanned::Spanned, Expr, ExprRange, RangeLimits, Stmt}; +use syn::{spanned::Spanned, Expr, ExprRange, RangeLimits, Stmt, ExprPath}; pub(crate) fn component_to_tokens( node: &NodeElement, @@ -56,7 +56,7 @@ pub(crate) fn component_to_tokens( .filter(|(idx, attr)| { idx < &spread_marker && { let attr_key = attr.key.to_string(); - !attr_key.starts_with("let:") + !is_attr_let(&attr.key) && !attr_key.starts_with("clone:") && !attr_key.starts_with("class:") && !attr_key.starts_with("style:") @@ -86,10 +86,20 @@ pub(crate) fn component_to_tokens( let items_to_bind = attrs .clone() .filter_map(|attr| { - attr.key - .to_string() - .strip_prefix("let:") - .map(|ident| format_ident!("{ident}", span = attr.key.span())) + if !is_attr_let(&attr.key) { + return None; + } + + let KeyedAttributeValue::Binding(binding) = &attr.possible_value else { + if let Some(ident) = attr.key.to_string().strip_prefix("let:") { + let ident1 = format_ident!("{ident}", span = attr.key.span()); + return Some(quote! { #ident1 }); + } else { + return None; + } + }; + let inputs = &binding.inputs; + Some(quote! { #inputs }) }) .collect::>(); @@ -286,3 +296,13 @@ pub(crate) fn component_to_tokens( component } + +fn is_attr_let(key: &NodeName) -> bool { + if key.to_string().starts_with("let:") { + true + } else if let NodeName::Path(ExprPath { path, .. }) = key { + path.segments.len() == 1 && path.segments[0].ident == "let" + } else { + false + } +}