Skip to content

Commit

Permalink
feat: allow to destructure props
Browse files Browse the repository at this point in the history
  • Loading branch information
geovie committed Dec 18, 2024
1 parent f9533ab commit fd6070c
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 16 deletions.
47 changes: 39 additions & 8 deletions leptos_macro/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,14 +655,44 @@ impl Prop {
abort!(e.span(), e.to_string());
});

let name = if let Pat::Ident(i) = *typed.pat {
i
} else {
abort!(
typed.pat,
"only `prop: bool` style types are allowed within the \
`#[component]` macro"
);
let name = match *typed.pat {
Pat::Ident(i) => {
if let Some(name) = &prop_opts.name {
PatIdent {
attrs: vec![],
by_ref: None,
mutability: None,
ident: Ident::new(name, i.span()),
subpat: None,
}
} else {
i
}
}
Pat::Struct(_) | Pat::Tuple(_) | Pat::TupleStruct(_) => {
if let Some(name) = &prop_opts.name {
PatIdent {
attrs: vec![],
by_ref: None,
mutability: None,
ident: Ident::new(name, typed.pat.span()),
subpat: None,
}
} else {
abort!(
typed.pat,
"destructured props must be given a name e.g. \
#[prop(name = \"data\")]"
);
}
}
_ => {
abort!(
typed.pat,
"only `prop: bool` style types are allowed within the \
`#[component]` macro"
);
}
};

Self {
Expand Down Expand Up @@ -865,6 +895,7 @@ struct PropOpt {
default: Option<syn::Expr>,
into: bool,
attrs: bool,
name: Option<String>,
}

struct TypedBuilderOpts {
Expand Down
50 changes: 50 additions & 0 deletions leptos_macro/tests/component.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
use core::num::NonZeroUsize;
use leptos::prelude::*;

#[derive(PartialEq, Debug)]
struct UserInfo {
user_id: String,
email: String,
}

#[derive(PartialEq, Debug)]
struct Admin(bool);

#[component]
fn Component(
#[prop(optional)] optional: bool,
Expand All @@ -10,6 +19,10 @@ fn Component(
#[prop(default = NonZeroUsize::new(10).unwrap())] default: NonZeroUsize,
#[prop(into)] into: String,
impl_trait: impl Fn() -> i32 + 'static,
#[prop(name = "data")] UserInfo { email, user_id }: UserInfo,
#[prop(name = "tuple")] (name, id): (String, i32),
#[prop(name = "tuple_struct")] Admin(is_admin): Admin,
#[prop(name = "outside_name")] inside_name: i32,
) -> impl IntoView {
_ = optional;
_ = optional_into;
Expand All @@ -18,6 +31,12 @@ fn Component(
_ = default;
_ = into;
_ = impl_trait;
_ = email;
_ = user_id;
_ = id;
_ = name;
_ = is_admin;
_ = inside_name;
}

#[test]
Expand All @@ -26,6 +45,13 @@ fn component() {
.into("")
.strip_option(9)
.impl_trait(|| 42)
.data(UserInfo {
email: "em@il".into(),
user_id: "1".into(),
})
.tuple(("Joe".into(), 12))
.tuple_struct(Admin(true))
.outside_name(1)
.build();
assert!(!cp.optional);
assert_eq!(cp.optional_into, None);
Expand All @@ -34,6 +60,16 @@ fn component() {
assert_eq!(cp.default, NonZeroUsize::new(10).unwrap());
assert_eq!(cp.into, "");
assert_eq!((cp.impl_trait)(), 42);
assert_eq!(
cp.data,
UserInfo {
email: "em@il".into(),
user_id: "1".into(),
}
);
assert_eq!(cp.tuple, ("Joe".into(), 12));
assert_eq!(cp.tuple_struct, Admin(true));
assert_eq!(cp.outside_name, 1);
}

#[test]
Expand All @@ -45,12 +81,26 @@ fn component_nostrip() {
strip_option=9
into=""
impl_trait=|| 42
data=UserInfo {
email: "em@il".into(),
user_id: "1".into(),
}
tuple=("Joe".into(), 12)
tuple_struct=Admin(true)
outside_name=1
/>
<Component
nostrip:optional_into=Some("foo")
strip_option=9
into=""
impl_trait=|| 42
data=UserInfo {
email: "em@il".into(),
user_id: "1".into(),
}
tuple=("Joe".into(), 12)
tuple_struct=Admin(true)
outside_name=1
/>
};
}
6 changes: 6 additions & 0 deletions leptos_macro/tests/ui/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ fn default_with_invalid_value(
_ = default;
}

#[component]
fn destructure_without_name((default, value): (bool, i32)) -> impl IntoView {
_ = default;
_ = value;
}

fn main() {}
14 changes: 10 additions & 4 deletions leptos_macro/tests/ui/component.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: supported fields are `optional`, `optional_no_strip`, `strip_option`, `default`, `into` and `attrs`
error: supported fields are `optional`, `optional_no_strip`, `strip_option`, `default`, `into`, `attrs` and `name`
--> tests/ui/component.rs:10:31
|
10 | fn unknown_prop_option(#[prop(hello)] test: bool) -> impl IntoView {
Expand All @@ -8,19 +8,19 @@ error: `optional` conflicts with mutually exclusive `optional_no_strip`
--> tests/ui/component.rs:16:12
|
16 | #[prop(optional, optional_no_strip)] conflicting: bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^

error: `optional` conflicts with mutually exclusive `strip_option`
--> tests/ui/component.rs:23:12
|
23 | #[prop(optional, strip_option)] conflicting: bool,
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^

error: `optional_no_strip` conflicts with mutually exclusive `strip_option`
--> tests/ui/component.rs:30:12
|
30 | #[prop(optional_no_strip, strip_option)] conflicting: bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^

error: unexpected end of input, expected `=` or `(`

Expand All @@ -41,3 +41,9 @@ error: unexpected end of input, expected one of: identifier, `::`, `<`, `_`, lit
| ^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `component` (in Nightly builds, run with -Z macro-backtrace for more info)

error: destructured props must be given a name e.g. #[prop(name = "data")]
--> tests/ui/component.rs:48:29
|
48 | fn destructure_without_name((default, value): (bool, i32)) -> impl IntoView {
| ^^^^^^^^^^^^^^^^
8 changes: 4 additions & 4 deletions leptos_macro/tests/ui/component_absolute.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: supported fields are `optional`, `optional_no_strip`, `strip_option`, `default`, `into` and `attrs`
error: supported fields are `optional`, `optional_no_strip`, `strip_option`, `default`, `into`, `attrs` and `name`
--> tests/ui/component_absolute.rs:5:31
|
5 | fn unknown_prop_option(#[prop(hello)] test: bool) -> impl ::leptos::IntoView {
Expand All @@ -8,19 +8,19 @@ error: `optional` conflicts with mutually exclusive `optional_no_strip`
--> tests/ui/component_absolute.rs:11:12
|
11 | #[prop(optional, optional_no_strip)] conflicting: bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^

error: `optional` conflicts with mutually exclusive `strip_option`
--> tests/ui/component_absolute.rs:18:12
|
18 | #[prop(optional, strip_option)] conflicting: bool,
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^

error: `optional_no_strip` conflicts with mutually exclusive `strip_option`
--> tests/ui/component_absolute.rs:25:12
|
25 | #[prop(optional_no_strip, strip_option)] conflicting: bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^

error: unexpected end of input, expected `=` or `(`

Expand Down

0 comments on commit fd6070c

Please sign in to comment.