Skip to content

Commit

Permalink
Allow the use of Rust keywords for element names (#1772)
Browse files Browse the repository at this point in the history
* time for more hygiene

* update corresponding tests

* while I'm at it

* now let's fix the actual issue

* fix the publish examples CI while I'm at it

* resolve clippy warnings
  • Loading branch information
siku2 committed Feb 28, 2021
1 parent bc46062 commit 3740140
Show file tree
Hide file tree
Showing 20 changed files with 166 additions and 158 deletions.
1 change: 1 addition & 0 deletions .github/workflows/publish-examples.yml
Expand Up @@ -36,6 +36,7 @@ jobs:
- name: Build examples
run: |
output="$(pwd)/dist"
mkdir "$output"
for path in examples/*; do
if [[ ! -d $path ]]; then
Expand Down
5 changes: 1 addition & 4 deletions Makefile.toml
Expand Up @@ -37,10 +37,7 @@ category = "Testing"
description = "Run all tests"
dependencies = ["tests-setup"]
env = { CARGO_MAKE_WORKSPACE_SKIP_MEMBERS = ["**/examples/*"] }
run_task = { name = [
"test-flow",
"doc-test-flow",
], fork = true, cleanup_task = "tests-cleanup" }
run_task = { name = ["test-flow", "doc-test-flow"], fork = true }

[tasks.benchmarks]
category = "Testing"
Expand Down
10 changes: 3 additions & 7 deletions examples/dashboard/src/main.rs
Expand Up @@ -53,9 +53,8 @@ pub struct WsResponse {

pub struct Model {
link: ComponentLink<Model>,
fetching: bool,
data: Option<u32>,
ft: Option<FetchTask>,
_ft: Option<FetchTask>,
ws: Option<WebSocketTask>,
}

Expand Down Expand Up @@ -120,22 +119,20 @@ impl Component for Model {
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
Self {
link,
fetching: false,
data: None,
ft: None,
_ft: None,
ws: None,
}
}

fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::FetchData(format, binary) => {
self.fetching = true;
let task = match format {
Format::Json => self.fetch_json(binary),
Format::Toml => self.fetch_toml(binary),
};
self.ft = Some(task);
self._ft = Some(task);
true
}
Msg::WsAction(action) => match action {
Expand Down Expand Up @@ -172,7 +169,6 @@ impl Component for Model {
}
},
Msg::FetchReady(response) => {
self.fetching = false;
self.data = response.map(|data| data.value).ok();
true
}
Expand Down
11 changes: 4 additions & 7 deletions examples/webgl/src/main.rs
Expand Up @@ -9,11 +9,10 @@ pub enum Msg {
}

pub struct Model {
canvas: Option<HtmlCanvasElement>,
gl: Option<GL>,
link: ComponentLink<Self>,
node_ref: NodeRef,
render_loop: Option<RenderTask>,
_render_loop: Option<RenderTask>,
}

impl Component for Model {
Expand All @@ -22,11 +21,10 @@ impl Component for Model {

fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
Self {
canvas: None,
gl: None,
link,
node_ref: NodeRef::default(),
render_loop: None,
_render_loop: None,
}
}

Expand All @@ -44,7 +42,6 @@ impl Component for Model {
.dyn_into()
.unwrap();

self.canvas = Some(canvas);
self.gl = Some(gl);

// In a more complex use-case, there will be additional WebGL initialization that should be
Expand All @@ -59,7 +56,7 @@ impl Component for Model {

// A reference to the handle must be stored, otherwise it is dropped and the render won't
// occur.
self.render_loop = Some(handle);
self._render_loop = Some(handle);
}
}

Expand Down Expand Up @@ -134,7 +131,7 @@ impl Model {
let handle = RenderService::request_animation_frame(render_frame);

// A reference to the new handle must be retained for the next render to run.
self.render_loop = Some(handle);
self._render_loop = Some(handle);
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/yew-macro/src/html_tree/html_element.rs
Expand Up @@ -398,7 +398,7 @@ impl ToTokens for HtmlElement {

#dyn_tag_runtime_checks
#[allow(unused_braces)]
::yew::virtual_dom::VNode::from(#vtag)
<::yew::virtual_dom::VNode as ::std::convert::From<_>>::from(#vtag)
}
});
}
Expand Down
6 changes: 4 additions & 2 deletions packages/yew-macro/src/html_tree/html_list.rs
Expand Up @@ -64,9 +64,11 @@ impl ToTokens for HtmlList {
} = &self;

let key = if let Some(key) = &open.props.key {
quote_spanned! {key.span()=> Some(::std::convert::Into::<::yew::virtual_dom::Key>::into(#key))}
quote_spanned! {key.span()=>
::std::option::Option::Some(::std::convert::Into::<::yew::virtual_dom::Key>::into(#key))
}
} else {
quote! {None}
quote! { ::std::option::Option::None }
};

let spanned = {
Expand Down
8 changes: 4 additions & 4 deletions packages/yew-macro/src/html_tree/mod.rs
Expand Up @@ -84,7 +84,7 @@ impl HtmlTree {
} else if input.peek(Token![::]) {
Some(HtmlType::Component)
} else if input.peek(Ident::peek_any) {
let ident: Ident = input.parse().ok()?;
let ident = Ident::parse_any(&input).ok()?;
let ident_str = ident.to_string();

if input.peek(Token![=]) || (input.peek(Token![?]) && input.peek2(Token![=])) {
Expand Down Expand Up @@ -169,7 +169,7 @@ impl ToTokens for HtmlRootVNode {
let new_tokens = self.0.to_token_stream();
tokens.extend(quote! {{
#[allow(clippy::useless_conversion, unused_braces)]
::yew::virtual_dom::VNode::from(#new_tokens)
<::yew::virtual_dom::VNode as ::std::convert::From<_>>::from(#new_tokens)
}});
}
}
Expand Down Expand Up @@ -226,15 +226,15 @@ impl HtmlChildrenTree {
.iter()
.map(|child| quote_spanned! {child.span()=> ::std::convert::Into::into(#child) });
return quote! {
vec![#(#children_into),*]
::std::vec![#(#children_into),*]
};
}

let vec_ident = Ident::new("__yew_v", Span::call_site());
let add_children_streams = children.iter().map(|child| {
if let Some(node_iterator_stream) = child.to_node_iterator_stream() {
quote! {
#vec_ident.extend(#node_iterator_stream);
::std::iter::Extend::extend(&mut #vec_ident, #node_iterator_stream);
}
} else {
quote_spanned! {child.span()=>
Expand Down
32 changes: 15 additions & 17 deletions packages/yew-macro/tests/html_macro/block-pass.rs
@@ -1,31 +1,29 @@
use yew::prelude::*;
#![no_implicit_prelude]

fn compile_pass() {
html! { <>{ "Hi" }</> };
html! { <>{ format!("Hello") }</> };
html! { <>{ String::from("Hello") }</> };
fn main() {
::yew::html! { <>{ "Hi" }</> };
::yew::html! { <>{ ::std::format!("Hello") }</> };
::yew::html! { <>{ ::std::string::ToString::to_string("Hello") }</> };

let msg = "Hello";
html! { <div>{ msg }</div> };
::yew::html! { <div>{ msg }</div> };

let subview = html! { "subview!" };
html! { <div>{ subview }</div> };
let subview = ::yew::html! { "subview!" };
::yew::html! { <div>{ subview }</div> };

let subview = || html! { "subview!" };
html! { <div>{ subview() }</div> };
let subview = || ::yew::html! { "subview!" };
::yew::html! { <div>{ subview() }</div> };

html! {
::yew::html! {
<ul>
{ for (0..3).map(|num| { html! { <span>{num}</span> }}) }
{ for ::std::iter::Iterator::map(0..3, |num| { ::yew::html! { <span>{ num }</span> }}) }
</ul>
};

let item = |num| html! { <li>{format!("item {}!", num)}</li> };
html! {
let item = |num| ::yew::html! { <li>{ ::std::format!("item {}!", num) }</li> };
::yew::html! {
<ul>
{ for (0..3).map(item) }
{ for ::std::iter::Iterator::map(0..3, item) }
</ul>
};
}

fn main() {}
2 changes: 0 additions & 2 deletions packages/yew-macro/tests/html_macro/component-pass.rs
@@ -1,5 +1,3 @@
#![recursion_limit = "256"]

use yew::html::ChildrenRenderer;
use yew::prelude::*;
use yew::virtual_dom::{VChild, VNode};
Expand Down
@@ -1,5 +1,3 @@
#![recursion_limit = "128"]

use yew::prelude::*;

struct Unimplemented;
Expand Down
@@ -1,17 +1,17 @@
error[E0599]: no function or associated item named `new` found for struct `yew::virtual_dom::vcomp::VChild<Unimplemented>` in the current scope
--> $DIR/component-unimplemented-fail.rs:8:14
--> $DIR/component-unimplemented-fail.rs:6:14
|
5 | struct Unimplemented;
3 | struct Unimplemented;
| --------------------- doesn't satisfy `Unimplemented: yew::html::component::Component`
...
8 | html! { <Unimplemented /> };
6 | html! { <Unimplemented /> };
| ^^^^^^^^^^^^^ function or associated item not found in `yew::virtual_dom::vcomp::VChild<Unimplemented>`
|
= note: the method `new` exists but the following trait bounds were not satisfied:
`Unimplemented: yew::html::component::Component`

error[E0277]: the trait bound `Unimplemented: yew::html::component::Component` is not satisfied
--> $DIR/component-unimplemented-fail.rs:8:14
--> $DIR/component-unimplemented-fail.rs:6:14
|
8 | html! { <Unimplemented /> };
6 | html! { <Unimplemented /> };
| ^^^^^^^^^^^^^ the trait `yew::html::component::Component` is not implemented for `Unimplemented`
27 changes: 27 additions & 0 deletions packages/yew-macro/tests/html_macro/dyn-element-pass.rs
@@ -0,0 +1,27 @@
#![no_implicit_prelude]

fn main() {
let dyn_tag = || ::std::string::ToString::to_string("test");
let mut next_extra_tag = {
let mut it = ::std::iter::IntoIterator::into_iter(::std::vec!["a", "b"]);
move || ::std::option::Option::unwrap(::std::iter::Iterator::next(&mut it))
};

::yew::html! {
<@{ dyn_tag() }>
<@{ next_extra_tag() } class="extra-a"/>
<@{ next_extra_tag() } class="extra-b"/>
</@>
};

::yew::html! {
<@{
let tag = dyn_tag();
if tag == "test" {
"div"
} else {
"a"
}
}/>
};
}
68 changes: 17 additions & 51 deletions packages/yew-macro/tests/html_macro/element-pass.rs
@@ -1,75 +1,41 @@
#![recursion_limit = "768"]
use yew::prelude::*;
#![no_implicit_prelude]

fn compile_pass() {
let onclick = Callback::from(|_: MouseEvent| ());
let parent_ref = NodeRef::default();
fn main() {
let onclick: ::yew::Callback<_> = ::std::convert::From::from(|_: ::yew::MouseEvent| ());
let parent_ref: ::yew::NodeRef = ::std::default::Default::default();

let dyn_tag = || String::from("test");
let mut extra_tags_iter = vec!["a", "b"].into_iter();

html! {
::yew::html! {
<div>
<div data-key="abc"></div>
<div ref=parent_ref class="parent">
<span class="child" value="anything"></span>
<label for="first-name">{"First Name"}</label>
<label for="first-name">{ "First Name" }</label>
<input type="text" id="first-name" value="placeholder" />
<input type="checkbox" checked=true />
<textarea value="write a story" />
<select name="status">
<option selected=true disabled=false value="">{"Selected"}</option>
<option selected=false disabled=true value="">{"Unselected"}</option>
<option selected=true disabled=false value="">{ "Selected" }</option>
<option selected=false disabled=true value="">{ "Unselected" }</option>
</select>
</div>
<svg width="149" height="147" viewBox="0 0 149 147" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z" fill="#DEB819"/>
<path d="M108.361 94.9937L138.708 90.686L115.342 69.8642" stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<g filter="url(#filter0_d)">
<circle cx="75.3326" cy="73.4918" r="55" fill="#FDD630"/>
<circle cx="75.3326" cy="73.4918" r="52.5" stroke="black" stroke-width="5"/>
</g>
<circle cx="71" cy="99" r="5" fill="white" fill-opacity="0.75" stroke="black" stroke-width="3"/>
<defs>
<filter id="filter0_d" x="16.3326" y="18.4918" width="118" height="118" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
</filter>
</defs>
</svg>
<img class=classes!("avatar", "hidden") src="http://pic.com" />
<img class=::yew::classes!("avatar", "hidden") src="http://pic.com" />
<img class="avatar hidden" />
<button onclick=&onclick onclick=onclick />
<a href="http://google.com" />
<custom-tag-a>
<custom-tag-b />
</custom-tag-a>
<@{dyn_tag()}>
<@{extra_tags_iter.next().unwrap()} class="extra-a"/>
<@{extra_tags_iter.next().unwrap()} class="extra-b"/>
</@>

<@{
let tag = dyn_tag();
if tag == "test" {
"div"
} else {
"a"
}
}/>

<a href?=Some("http://google.com") media?=Option::<&str>::None />
<track kind?=Some("subtitles") src?=Option::<&str>::None />
<track kind?=Some(5) mixed="works" />
<input value?=Some("value") onblur?=Some(Callback::from(|_| ())) />
<a href?=::std::option::Option::Some("http://google.com") media?=::std::option::Option::<&str>::None />
<track kind?=::std::option::Option::Some("subtitles") src?=::std::option::Option::<&str>::None />
<track kind?=::std::option::Option::Some(5) mixed="works" />
<input value?=::std::option::Option::Some("value") onblur?=::std::option::Option::Some(<::yew::Callback<_> as ::std::convert::From<_>>::from(|_| ())) />
</div>
};

let children = vec![
html! { <span>{ "Hello" }</span> },
html! { <span>{ "World" }</span> },
let children = ::std::vec![
::yew::html! { <span>{ "Hello" }</span> },
::yew::html! { <span>{ "World" }</span> },
];
html! { <div>{children}</div> };
::yew::html! { <div>{ children }</div> };
}

fn main() {}
2 changes: 0 additions & 2 deletions packages/yew-macro/tests/html_macro/generic-component-fail.rs
@@ -1,5 +1,3 @@
#![recursion_limit = "256"]

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

Expand Down

0 comments on commit 3740140

Please sign in to comment.