Skip to content

Commit

Permalink
Fix generic component tags in html macro (yewstack#837)
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry authored and llebout committed Jan 20, 2020
1 parent 793b21b commit 02ffccd
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 212 deletions.
41 changes: 34 additions & 7 deletions crates/macro/src/html_tree/html_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use syn::parse;
use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{Expr, Ident, Index, Path, PathArguments, PathSegment, Token, Type, TypePath};
use syn::{
AngleBracketedGenericArguments, Expr, GenericArgument, Ident, Index, Path, PathArguments,
PathSegment, Token, Type, TypePath,
};

pub struct HtmlComponent {
ty: Type,
Expand Down Expand Up @@ -57,8 +60,8 @@ impl Parse for HtmlComponent {
"this open tag has no corresponding close tag",
));
}
if let Some(typ) = HtmlComponentClose::peek(input.cursor()) {
if open.ty == typ {
if let Some(ty) = HtmlComponentClose::peek(input.cursor()) {
if open.ty == ty {
break;
}
}
Expand Down Expand Up @@ -199,6 +202,26 @@ impl HtmlComponent {
Some(cursor)
}

fn path_arguments(cursor: Cursor) -> Option<(PathArguments, Cursor)> {
let (punct, cursor) = cursor.punct()?;
(punct.as_char() == '<').as_option()?;

let (ty, cursor) = Self::peek_type(cursor)?;

let (punct, cursor) = cursor.punct()?;
(punct.as_char() == '>').as_option()?;

Some((
PathArguments::AngleBracketed(AngleBracketedGenericArguments {
colon2_token: None,
lt_token: Token![<](Span::call_site()),
args: vec![GenericArgument::Type(ty)].into_iter().collect(),
gt_token: Token![>](Span::call_site()),
}),
cursor,
))
}

fn peek_type(mut cursor: Cursor) -> Option<(Type, Cursor)> {
let mut colons_optional = true;
let mut last_ident = None;
Expand All @@ -219,10 +242,14 @@ impl HtmlComponent {
if let Some((ident, c)) = post_colons_cursor.ident() {
cursor = c;
last_ident = Some(ident.clone());
segments.push(PathSegment {
ident,
arguments: PathArguments::None,
});
let arguments = if let Some((args, c)) = Self::path_arguments(cursor) {
cursor = c;
args
} else {
PathArguments::None
};

segments.push(PathSegment { ident, arguments });
} else {
break;
}
Expand Down
47 changes: 25 additions & 22 deletions tests/macro/html-component-fail.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![recursion_limit = "128"]

use std::marker::PhantomData;
use yew::prelude::*;

#[derive(Clone, Properties, PartialEq)]
Expand All @@ -14,21 +15,14 @@ impl Component for Child {
type Message = ();
type Properties = ChildProperties;

fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
Child
}

fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}

fn view(&self) -> Html {
unimplemented!()
}
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self { unimplemented!() }
fn update(&mut self, _: Self::Message) -> ShouldRender { unimplemented!() }
fn view(&self) -> Html { unimplemented!() }
}

#[derive(Clone, Properties)]
pub struct ChildContainerProperties {
#[props(required)]
pub children: ChildrenWithProps<Child>,
}

Expand All @@ -37,17 +31,22 @@ impl Component for ChildContainer {
type Message = ();
type Properties = ChildContainerProperties;

fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
ChildContainer
}
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self { unimplemented!() }
fn update(&mut self, _: Self::Message) -> ShouldRender { unimplemented!() }
fn view(&self) -> Html { unimplemented!() }
}

fn update(&mut self, _: Self::Message) -> ShouldRender {
unimplemented!()
}
pub struct Generic<G> {
marker: PhantomData<G>,
}

fn view(&self) -> Html {
unimplemented!()
}
impl Component for Generic<String> {
type Message = ();
type Properties = ();

fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self { unimplemented!() }
fn update(&mut self, _: Self::Message) -> ShouldRender { unimplemented!() }
fn view(&self) -> Html { unimplemented!() }
}

fn compile_fail() {
Expand Down Expand Up @@ -75,11 +74,15 @@ fn compile_fail() {
html! { <Child><Child></Child> };
html! { <Child></Child><Child></Child> };
html! { <Child>{ "Not allowed" }</Child> };

html! { <ChildContainer /> };
html! { <ChildContainer></ChildContainer> };
html! { <ChildContainer>{ "Not allowed" }</ChildContainer> };
html! { <ChildContainer><></></ChildContainer> };
html! { <ChildContainer><ChildContainer /></ChildContainer> };
html! { <ChildContainer><ChildContainer /></ChildContainer> };
html! { <ChildContainer><Child int=1 /><other /></ChildContainer> };

html! { <Generic<String>></Generic> };
html! { <Generic<String>></Generic<Vec<String>>> };
}

fn main() {}
Loading

0 comments on commit 02ffccd

Please sign in to comment.