Fix tests for autofmt
This commit is contained in:
17 files changed
+287
-177
No files matched your search
@@ -0,0 +1,25 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dioxus_desktop::launch(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app(cx: Scope) -> Element {
|
||||||
|
let a = 123;
|
||||||
|
let b = 456;
|
||||||
|
let c = 789;
|
||||||
|
|
||||||
|
render! {
|
||||||
|
Component { a, b, c }
|
||||||
|
Component { a, ..ComponentProps { a: 1, b: 2, c: 3 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn Component(cx: Scope, a: i32, b: i32, c: i32) -> Element {
|
||||||
|
render! {
|
||||||
|
div { "{a}" }
|
||||||
|
div { "{b}" }
|
||||||
|
div { "{c}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -182,6 +182,9 @@ impl Writer<'_> {
|
|||||||
s.source.as_ref().unwrap().to_token_stream()
|
s.source.as_ref().unwrap().to_token_stream()
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
ContentField::Shorthand(e) => {
|
||||||
|
write!(self.out, "{}", e.to_token_stream())?;
|
||||||
|
}
|
||||||
ContentField::OnHandlerRaw(exp) => {
|
ContentField::OnHandlerRaw(exp) => {
|
||||||
let out = prettyplease::unparse_expr(exp);
|
let out = prettyplease::unparse_expr(exp);
|
||||||
let mut lines = out.split('\n').peekable();
|
let mut lines = out.split('\n').peekable();
|
||||||
@@ -223,6 +226,7 @@ impl Writer<'_> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|field| match &field.content {
|
.map(|field| match &field.content {
|
||||||
ContentField::Formatted(s) => ifmt_to_string(s).len() ,
|
ContentField::Formatted(s) => ifmt_to_string(s).len() ,
|
||||||
|
ContentField::Shorthand(e) => e.to_token_stream().to_string().len(),
|
||||||
ContentField::OnHandlerRaw(exp) | ContentField::ManExpr(exp) => {
|
ContentField::OnHandlerRaw(exp) | ContentField::ManExpr(exp) => {
|
||||||
let formatted = prettyplease::unparse_expr(exp);
|
let formatted = prettyplease::unparse_expr(exp);
|
||||||
let len = if formatted.contains('\n') {
|
let len = if formatted.contains('\n') {
|
||||||
|
|||||||
@@ -232,8 +232,48 @@ impl<'a> Writer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_if_chain(&mut self, ifchain: &IfChain) -> std::fmt::Result {
|
fn write_if_chain(&mut self, ifchain: &IfChain) -> std::fmt::Result {
|
||||||
todo!()
|
// Recurse in place by setting the next chain
|
||||||
// self.write_raw_expr(ifchain.span())
|
let mut branch = Some(ifchain);
|
||||||
|
|
||||||
|
while let Some(chain) = branch {
|
||||||
|
let IfChain {
|
||||||
|
if_token,
|
||||||
|
cond,
|
||||||
|
then_branch,
|
||||||
|
else_if_branch,
|
||||||
|
else_branch,
|
||||||
|
} = chain;
|
||||||
|
|
||||||
|
write!(
|
||||||
|
self.out,
|
||||||
|
"{} {} {{",
|
||||||
|
if_token.to_token_stream(),
|
||||||
|
prettyplease::unparse_expr(cond)
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.write_body_indented(then_branch)?;
|
||||||
|
|
||||||
|
if let Some(else_if_branch) = else_if_branch {
|
||||||
|
// write the closing bracket and else
|
||||||
|
self.out.tabbed_line()?;
|
||||||
|
write!(self.out, "}} else ")?;
|
||||||
|
|
||||||
|
branch = Some(else_if_branch);
|
||||||
|
} else if let Some(else_branch) = else_branch {
|
||||||
|
self.out.tabbed_line()?;
|
||||||
|
write!(self.out, "}} else {{")?;
|
||||||
|
|
||||||
|
self.write_body_indented(else_branch)?;
|
||||||
|
branch = None;
|
||||||
|
} else {
|
||||||
|
branch = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.out.tabbed_line()?;
|
||||||
|
write!(self.out, "}}")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ rsx! {
|
|||||||
"hello world"
|
"hello world"
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
expr1,
|
{expr1},
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
expr2,
|
{expr2},
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
// Comments
|
// Comments
|
||||||
// Comments
|
// Comments
|
||||||
// Comments
|
// Comments
|
||||||
// Comments
|
// Comments
|
||||||
expr3,
|
{expr3},
|
||||||
|
|
||||||
div {
|
div {
|
||||||
// todo some work in here
|
// todo some work in here
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ rsx! {
|
|||||||
to: "{to}",
|
to: "{to}",
|
||||||
span { class: "inline-block mr-3", icons::icon_0 {} }
|
span { class: "inline-block mr-3", icons::icon_0 {} }
|
||||||
span { "{name}" }
|
span { "{name}" }
|
||||||
children.is_some().then(|| rsx! {
|
{children.is_some().then(|| rsx! {
|
||||||
span {
|
span {
|
||||||
class: "inline-block ml-auto hover:bg-gray-500",
|
class: "inline-block ml-auto hover:bg-gray-500",
|
||||||
onclick: move |evt| {
|
onclick: move |evt| {
|
||||||
@@ -27,9 +27,9 @@ rsx! {
|
|||||||
},
|
},
|
||||||
icons::icon_8 {}
|
icons::icon_8 {}
|
||||||
}
|
}
|
||||||
})
|
})}
|
||||||
}
|
}
|
||||||
div { class: "px-4", is_current.then(|| rsx!{ children }) }
|
div { class: "px-4", {is_current.then(|| rsx!{ children })} }
|
||||||
}
|
}
|
||||||
|
|
||||||
// No nesting
|
// No nesting
|
||||||
@@ -48,5 +48,5 @@ rsx! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div { asdbascasdbasd, asbdasbdabsd, asbdabsdbasdbas }
|
div { "asdbascasdbasd", "asbdasbdabsd", {asbdabsdbasdbas} }
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,20 @@ rsx! {
|
|||||||
// Some ifchain
|
// Some ifchain
|
||||||
if a > 10 {
|
if a > 10 {
|
||||||
//
|
//
|
||||||
rsx! { div {} }
|
div {}
|
||||||
|
} else if a > 20 {
|
||||||
|
h1 {}
|
||||||
|
} else if a > 20 {
|
||||||
|
h1 {}
|
||||||
|
} else if a > 20 {
|
||||||
|
h1 {}
|
||||||
|
} else if a > 20 {
|
||||||
|
h1 {}
|
||||||
|
} else if a > 20 {
|
||||||
|
h1 {}
|
||||||
|
} else if a > 20 {
|
||||||
|
h1 {}
|
||||||
|
} else {
|
||||||
|
h3 {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
fn it_works() {
|
fn it_works() {
|
||||||
cx.render(rsx!(()))
|
cx.render(rsx!({()}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ pub fn Explainer<'a>(
|
|||||||
// pt-5 sm:pt-24 lg:pt-24
|
// pt-5 sm:pt-24 lg:pt-24
|
||||||
|
|
||||||
let mut right = rsx! {
|
let mut right = rsx! {
|
||||||
div { class: "relative w-1/2", flasher }
|
div { class: "relative w-1/2", {flasher} }
|
||||||
};
|
};
|
||||||
|
|
||||||
let align = match invert {
|
let align = match invert {
|
||||||
@@ -24,7 +24,7 @@ pub fn Explainer<'a>(
|
|||||||
h2 { class: "mb-6 text-3xl leading-tight md:text-4xl md:leading-tight lg:text-3xl lg:leading-tight font-heading font-mono font-bold",
|
h2 { class: "mb-6 text-3xl leading-tight md:text-4xl md:leading-tight lg:text-3xl lg:leading-tight font-heading font-mono font-bold",
|
||||||
"{title}"
|
"{title}"
|
||||||
}
|
}
|
||||||
content
|
{content}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,8 +34,8 @@ pub fn Explainer<'a>(
|
|||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light",
|
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light",
|
||||||
left,
|
{left},
|
||||||
right
|
{right}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ rsx! {
|
|||||||
section { class: "body-font overflow-hidden dark:bg-ideblack",
|
section { class: "body-font overflow-hidden dark:bg-ideblack",
|
||||||
div { class: "container px-6 mx-auto",
|
div { class: "container px-6 mx-auto",
|
||||||
div { class: "-my-8 divide-y-2 divide-gray-100",
|
div { class: "-my-8 divide-y-2 divide-gray-100",
|
||||||
POSTS.iter().enumerate().map(|(id, post)| rsx! { BlogPostItem { post: post, id: id } })
|
{POSTS.iter().enumerate().map(|(id, post)| rsx! { BlogPostItem { post: post, id: id } })}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,20 +4,20 @@ rsx! {
|
|||||||
div {}
|
div {}
|
||||||
|
|
||||||
// hi
|
// hi
|
||||||
div { abcd, ball, s }
|
div { "abcd", "ball", "s" }
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
div { abcd, ball, s }
|
div { "abcd", "ball", "s" }
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
div {
|
div {
|
||||||
abcd,
|
"abcd"
|
||||||
ball,
|
"ball"
|
||||||
s,
|
"s"
|
||||||
|
|
||||||
//
|
//
|
||||||
"asdasd"
|
"asdasd"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
fn it_works() {
|
fn it_works() {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
span { "Description: ", package.description.as_deref().unwrap_or("❌❌❌❌ missing") }
|
span { "Description: ", {package.description.as_deref().unwrap_or("❌❌❌❌ missing")} }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
fn ItWroks() {
|
fn ItWroks() {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light",
|
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light",
|
||||||
left,
|
{left},
|
||||||
right
|
{right}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fn ItWroks() {
|
fn ItWroks() {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", left, right }
|
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", {left}, {right} }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
fn ItWroks() {
|
fn ItWroks() {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light",
|
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light",
|
||||||
left,
|
{left},
|
||||||
right
|
{right}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fn ItWroks() {
|
fn ItWroks() {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", left, right }
|
div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", {left}, {right} }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+176
-148
@@ -19,6 +19,7 @@ use syn::{
|
|||||||
ext::IdentExt,
|
ext::IdentExt,
|
||||||
parse::{Parse, ParseBuffer, ParseStream},
|
parse::{Parse, ParseBuffer, ParseStream},
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
|
token::Brace,
|
||||||
AngleBracketedGenericArguments, Error, Expr, Ident, LitStr, PathArguments, Result, Token,
|
AngleBracketedGenericArguments, Error, Expr, Ident, LitStr, PathArguments, Result, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,8 +33,90 @@ pub struct Component {
|
|||||||
pub brace: syn::token::Brace,
|
pub brace: syn::token::Brace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Parse for Component {
|
||||||
|
fn parse(stream: ParseStream) -> Result<Self> {
|
||||||
|
let mut name = stream.parse::<syn::Path>()?;
|
||||||
|
Component::validate_component_path(&name)?;
|
||||||
|
|
||||||
|
// extract the path arguments from the path into prop_gen_args
|
||||||
|
let prop_gen_args = normalize_path(&mut name);
|
||||||
|
|
||||||
|
let content: ParseBuffer;
|
||||||
|
let brace = syn::braced!(content in stream);
|
||||||
|
|
||||||
|
let mut fields = Vec::new();
|
||||||
|
let mut children = Vec::new();
|
||||||
|
let mut manual_props = None;
|
||||||
|
|
||||||
|
while !content.is_empty() {
|
||||||
|
// if we splat into a component then we're merging properties
|
||||||
|
if content.peek(Token![..]) {
|
||||||
|
content.parse::<Token![..]>()?;
|
||||||
|
manual_props = Some(content.parse()?);
|
||||||
|
} else
|
||||||
|
//
|
||||||
|
// Fields
|
||||||
|
// Named fields
|
||||||
|
if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
|
||||||
|
fields.push(content.parse()?);
|
||||||
|
} else
|
||||||
|
//
|
||||||
|
// shorthand struct initialization
|
||||||
|
// Not a div {}, mod::Component {}, or web-component {}
|
||||||
|
if content.peek(Ident)
|
||||||
|
&& !content.peek2(Brace)
|
||||||
|
&& !content.peek2(Token![:])
|
||||||
|
&& !content.peek2(Token![-])
|
||||||
|
{
|
||||||
|
fields.push(content.parse()?);
|
||||||
|
} else {
|
||||||
|
children.push(content.parse()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
if content.peek(Token![,]) {
|
||||||
|
let _ = content.parse::<Token![,]>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
name,
|
||||||
|
prop_gen_args,
|
||||||
|
fields,
|
||||||
|
children,
|
||||||
|
manual_props,
|
||||||
|
brace,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for Component {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
let Self {
|
||||||
|
name,
|
||||||
|
prop_gen_args,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
let builder = self
|
||||||
|
.manual_props
|
||||||
|
.as_ref()
|
||||||
|
.map(|props| self.collect_manual_props(props))
|
||||||
|
.unwrap_or_else(|| self.collect_props());
|
||||||
|
|
||||||
|
let fn_name = self.fn_name();
|
||||||
|
|
||||||
|
tokens.append_all(quote! {
|
||||||
|
__cx.component(
|
||||||
|
#name #prop_gen_args,
|
||||||
|
#builder,
|
||||||
|
#fn_name
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Component {
|
impl Component {
|
||||||
pub fn validate_component_path(path: &syn::Path) -> Result<()> {
|
fn validate_component_path(path: &syn::Path) -> Result<()> {
|
||||||
// ensure path segments doesn't have PathArguments, only the last
|
// ensure path segments doesn't have PathArguments, only the last
|
||||||
// segment is allowed to have one.
|
// segment is allowed to have one.
|
||||||
if path
|
if path
|
||||||
@@ -67,134 +150,53 @@ impl Component {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Component {
|
fn collect_manual_props(&self, manual_props: &Expr) -> TokenStream2 {
|
||||||
fn parse(stream: ParseStream) -> Result<Self> {
|
let mut toks = quote! { let mut __manual_props = #manual_props; };
|
||||||
let mut name = stream.parse::<syn::Path>()?;
|
for field in &self.fields {
|
||||||
Component::validate_component_path(&name)?;
|
if field.name == "key" {
|
||||||
|
continue;
|
||||||
// extract the path arguments from the path into prop_gen_args
|
|
||||||
let prop_gen_args = name.segments.last_mut().and_then(|seg| {
|
|
||||||
if let PathArguments::AngleBracketed(args) = seg.arguments.clone() {
|
|
||||||
seg.arguments = PathArguments::None;
|
|
||||||
Some(args)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
});
|
let ComponentField { name, content } = field;
|
||||||
|
toks.append_all(quote! { __manual_props.#name = #content; });
|
||||||
|
}
|
||||||
|
toks.append_all(quote! { __manual_props });
|
||||||
|
quote! {{ #toks }}
|
||||||
|
}
|
||||||
|
|
||||||
let content: ParseBuffer;
|
fn collect_props(&self) -> TokenStream2 {
|
||||||
|
let name = &self.name;
|
||||||
|
|
||||||
// if we see a `{` then we have a block
|
let mut toks = match &self.prop_gen_args {
|
||||||
// else parse as a function-like call
|
Some(gen_args) => quote! { fc_to_builder(__cx, #name #gen_args) },
|
||||||
let brace = syn::braced!(content in stream);
|
None => quote! { fc_to_builder(__cx, #name) },
|
||||||
|
};
|
||||||
let mut fields = Vec::new();
|
for field in &self.fields {
|
||||||
let mut children = Vec::new();
|
match field.name.to_string().as_str() {
|
||||||
let mut manual_props = None;
|
"key" => {}
|
||||||
|
_ => toks.append_all(quote! {#field}),
|
||||||
while !content.is_empty() {
|
|
||||||
// if we splat into a component then we're merging properties
|
|
||||||
if content.peek(Token![..]) {
|
|
||||||
content.parse::<Token![..]>()?;
|
|
||||||
manual_props = Some(content.parse::<Expr>()?);
|
|
||||||
} else if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
|
|
||||||
fields.push(content.parse::<ComponentField>()?);
|
|
||||||
} else {
|
|
||||||
children.push(content.parse::<BodyNode>()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
if content.peek(Token![,]) {
|
|
||||||
let _ = content.parse::<Token![,]>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !self.children.is_empty() {
|
||||||
|
let renderer: TemplateRenderer = TemplateRenderer {
|
||||||
|
roots: &self.children,
|
||||||
|
location: None,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self {
|
toks.append_all(quote! {
|
||||||
name,
|
.children(
|
||||||
prop_gen_args,
|
Some({ #renderer })
|
||||||
fields,
|
)
|
||||||
children,
|
});
|
||||||
manual_props,
|
}
|
||||||
brace,
|
toks.append_all(quote! {
|
||||||
})
|
.build()
|
||||||
|
});
|
||||||
|
toks
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ToTokens for Component {
|
fn fn_name(&self) -> String {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
self.name.segments.last().unwrap().ident.to_string()
|
||||||
let name = &self.name;
|
|
||||||
let prop_gen_args = &self.prop_gen_args;
|
|
||||||
|
|
||||||
let builder = match &self.manual_props {
|
|
||||||
Some(manual_props) => {
|
|
||||||
let mut toks = quote! {
|
|
||||||
let mut __manual_props = #manual_props;
|
|
||||||
};
|
|
||||||
for field in &self.fields {
|
|
||||||
if field.name == "key" {
|
|
||||||
// skip keys
|
|
||||||
} else {
|
|
||||||
let name = &field.name;
|
|
||||||
let val = &field.content;
|
|
||||||
toks.append_all(quote! {
|
|
||||||
__manual_props.#name = #val;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
toks.append_all(quote! {
|
|
||||||
__manual_props
|
|
||||||
});
|
|
||||||
quote! {{
|
|
||||||
#toks
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let mut toks = match prop_gen_args {
|
|
||||||
Some(gen_args) => quote! { fc_to_builder(__cx, #name #gen_args) },
|
|
||||||
None => quote! { fc_to_builder(__cx, #name) },
|
|
||||||
};
|
|
||||||
for field in &self.fields {
|
|
||||||
match field.name.to_string().as_str() {
|
|
||||||
"key" => {}
|
|
||||||
_ => toks.append_all(quote! {#field}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.children.is_empty() {
|
|
||||||
let renderer: TemplateRenderer = TemplateRenderer {
|
|
||||||
roots: &self.children,
|
|
||||||
location: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
toks.append_all(quote! {
|
|
||||||
.children(
|
|
||||||
Some({ #renderer })
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toks.append_all(quote! {
|
|
||||||
.build()
|
|
||||||
});
|
|
||||||
toks
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let fn_name = self.name.segments.last().unwrap().ident.to_string();
|
|
||||||
|
|
||||||
let gen_name = match &self.prop_gen_args {
|
|
||||||
Some(gen) => quote! { #name #gen },
|
|
||||||
None => quote! { #name },
|
|
||||||
};
|
|
||||||
|
|
||||||
tokens.append_all(quote! {
|
|
||||||
__cx.component(
|
|
||||||
#gen_name,
|
|
||||||
#builder,
|
|
||||||
#fn_name
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,21 +209,47 @@ pub struct ComponentField {
|
|||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
pub enum ContentField {
|
pub enum ContentField {
|
||||||
|
Shorthand(Ident),
|
||||||
ManExpr(Expr),
|
ManExpr(Expr),
|
||||||
Formatted(IfmtInput),
|
Formatted(IfmtInput),
|
||||||
OnHandlerRaw(Expr),
|
OnHandlerRaw(Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ContentField {
|
||||||
|
fn new_from_name(name: &Ident, input: ParseStream) -> Result<Self> {
|
||||||
|
if name.to_string().starts_with("on") {
|
||||||
|
return Ok(ContentField::OnHandlerRaw(input.parse()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
if *name == "key" {
|
||||||
|
return Ok(ContentField::Formatted(input.parse()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.peek(LitStr) {
|
||||||
|
let forked = input.fork();
|
||||||
|
let t: LitStr = forked.parse()?;
|
||||||
|
|
||||||
|
// the string literal must either be the end of the input or a followed by a comma
|
||||||
|
let res =
|
||||||
|
match (forked.is_empty() || forked.peek(Token![,])) && is_literal_foramtted(&t) {
|
||||||
|
true => ContentField::Formatted(input.parse()?),
|
||||||
|
false => ContentField::ManExpr(input.parse()?),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ContentField::ManExpr(input.parse()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToTokens for ContentField {
|
impl ToTokens for ContentField {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
match self {
|
match self {
|
||||||
|
ContentField::Shorthand(i) => tokens.append_all(quote! { #i }),
|
||||||
ContentField::ManExpr(e) => e.to_tokens(tokens),
|
ContentField::ManExpr(e) => e.to_tokens(tokens),
|
||||||
ContentField::Formatted(s) => tokens.append_all(quote! {
|
ContentField::Formatted(s) => tokens.append_all(quote! { __cx.raw_text(#s) }),
|
||||||
__cx.raw_text(#s)
|
ContentField::OnHandlerRaw(e) => tokens.append_all(quote! { __cx.event_handler(#e) }),
|
||||||
}),
|
|
||||||
ContentField::OnHandlerRaw(e) => tokens.append_all(quote! {
|
|
||||||
__cx.event_handler(#e)
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,30 +257,21 @@ impl ToTokens for ContentField {
|
|||||||
impl Parse for ComponentField {
|
impl Parse for ComponentField {
|
||||||
fn parse(input: ParseStream) -> Result<Self> {
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
let name = Ident::parse_any(input)?;
|
let name = Ident::parse_any(input)?;
|
||||||
input.parse::<Token![:]>()?;
|
|
||||||
|
|
||||||
let content = {
|
// if the next token is not a colon, then it's a shorthand field
|
||||||
if name.to_string().starts_with("on") {
|
if input.parse::<Token![:]>().is_err() {
|
||||||
ContentField::OnHandlerRaw(input.parse()?)
|
return Ok(Self {
|
||||||
} else if name == "key" {
|
content: ContentField::Shorthand(name.clone()),
|
||||||
let content = ContentField::Formatted(input.parse()?);
|
name,
|
||||||
return Ok(Self { name, content });
|
});
|
||||||
} else if input.peek(LitStr) {
|
|
||||||
let forked = input.fork();
|
|
||||||
let t: LitStr = forked.parse()?;
|
|
||||||
// the string literal must either be the end of the input or a followed by a comma
|
|
||||||
if (forked.is_empty() || forked.peek(Token![,])) && is_literal_foramtted(&t) {
|
|
||||||
ContentField::Formatted(input.parse()?)
|
|
||||||
} else {
|
|
||||||
ContentField::ManExpr(input.parse()?)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ContentField::ManExpr(input.parse()?)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let content = ContentField::new_from_name(&name, input)?;
|
||||||
|
|
||||||
if input.peek(LitStr) || input.peek(Ident) {
|
if input.peek(LitStr) || input.peek(Ident) {
|
||||||
missing_trailing_comma!(content.span());
|
missing_trailing_comma!(content.span());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { name, content })
|
Ok(Self { name, content })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,9 +279,7 @@ impl Parse for ComponentField {
|
|||||||
impl ToTokens for ComponentField {
|
impl ToTokens for ComponentField {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
let ComponentField { name, content, .. } = self;
|
let ComponentField { name, content, .. } = self;
|
||||||
tokens.append_all(quote! {
|
tokens.append_all(quote! { .#name(#content) })
|
||||||
.#name(#content)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,3 +298,14 @@ fn is_literal_foramtted(lit: &LitStr) -> bool {
|
|||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_path(name: &mut syn::Path) -> Option<AngleBracketedGenericArguments> {
|
||||||
|
let seg = name.segments.last_mut()?;
|
||||||
|
match seg.arguments.clone() {
|
||||||
|
PathArguments::AngleBracketed(args) => {
|
||||||
|
seg.arguments = PathArguments::None;
|
||||||
|
Some(args)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -98,7 +98,6 @@ impl Parse for BodyNode {
|
|||||||
// Input::<InputProps<'_, i32> {}
|
// Input::<InputProps<'_, i32> {}
|
||||||
// crate::Input::<InputProps<'_, i32> {}
|
// crate::Input::<InputProps<'_, i32> {}
|
||||||
if body_stream.peek(token::Brace) {
|
if body_stream.peek(token::Brace) {
|
||||||
Component::validate_component_path(&path)?;
|
|
||||||
return Ok(BodyNode::Component(stream.parse()?));
|
return Ok(BodyNode::Component(stream.parse()?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user