From 5f988663418be5b75a3bc2decf1baae063edf363 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Wed, 6 Oct 2021 19:16:01 +0900 Subject: [PATCH 1/8] Add Redirect Comp. --- packages/yew-router/src/components/mod.rs | 2 ++ .../yew-router/src/components/redirect.rs | 32 +++++++++++++++++++ packages/yew-router/src/lib.rs | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 packages/yew-router/src/components/redirect.rs diff --git a/packages/yew-router/src/components/mod.rs b/packages/yew-router/src/components/mod.rs index b6808da2757..bcec0215fb9 100644 --- a/packages/yew-router/src/components/mod.rs +++ b/packages/yew-router/src/components/mod.rs @@ -1,4 +1,6 @@ //! Components to interface with [Router][crate::Router]. mod link; +mod redirect; pub use link::*; +pub use redirect::*; diff --git a/packages/yew-router/src/components/redirect.rs b/packages/yew-router/src/components/redirect.rs new file mode 100644 index 00000000000..1e3b46a7abb --- /dev/null +++ b/packages/yew-router/src/components/redirect.rs @@ -0,0 +1,32 @@ +use crate::{service, Routable}; +use std::marker::PhantomData; +use yew::prelude::*; + +/// Props for [`Link`] +#[derive(Properties, Clone, PartialEq)] +pub struct RedirectProps { + /// Route that will be pushed when the component is rendered. + pub to: R, +} + +/// A component that will redirect to specified route when rendered. +pub struct Redirect { + _data: PhantomData, +} + +impl Component for Redirect +where + R: Routable + Clone + PartialEq + 'static, +{ + type Message = (); + type Properties = RedirectProps; + + fn create(_ctx: &Context) -> Self { + Self { _data: PhantomData } + } + + fn view(&self, ctx: &Context) -> Html { + service::push_route(ctx.props().to.clone()); + Html::default() + } +} diff --git a/packages/yew-router/src/lib.rs b/packages/yew-router/src/lib.rs index 80d64dac708..97245e4673d 100644 --- a/packages/yew-router/src/lib.rs +++ b/packages/yew-router/src/lib.rs @@ -74,7 +74,7 @@ pub mod prelude { //! //! This module re-exports the frequently used types from the crate. - pub use crate::components::Link; + pub use crate::components::{Link, Redirect}; #[doc(no_inline)] pub use crate::Routable; pub use crate::Router; From d2935af6a9b7407513c7698ced56a2a758e8fb15 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Sat, 9 Oct 2021 13:50:10 +0900 Subject: [PATCH 2/8] Fix router behaviour. --- packages/yew-router/src/macro_helpers.rs | 21 ++++---- .../yew-router/tests/router_unit_tests.rs | 50 +++++++++++++++++++ 2 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 packages/yew-router/tests/router_unit_tests.rs diff --git a/packages/yew-router/src/macro_helpers.rs b/packages/yew-router/src/macro_helpers.rs index e29cc0dc874..ede9a9b4851 100644 --- a/packages/yew-router/src/macro_helpers.rs +++ b/packages/yew-router/src/macro_helpers.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use crate::utils::{base_url, strip_slash_suffix}; use crate::Routable; @@ -9,16 +11,14 @@ pub fn build_router() -> Router { let base = base_url(); let mut router = Router::new(); R::routes().iter().for_each(|path| { - match &base { - Some(base) => { - let route = format!("{}{}", base, path); - let route = strip_slash_suffix(&route); - router.add(route, path.to_string()); - } - _ => { - router.add(path, path.to_string()); - } + let route = match base { + Some(ref base) => Cow::from(format!("{}{}", base, path)), + _ => (*path).into(), }; + + let stripped_route = strip_slash_suffix(&route); + + router.add(stripped_route, path.to_string()); }); router @@ -30,7 +30,8 @@ pub fn recognize_with_router(router: &Router, pathname: &str) -> Op let matched = router.recognize(pathname); match matched { - Ok(matched) => R::from_path(matched.handler(), &matched.params().into_iter().collect()), + Ok(matched) => R::from_path(matched.handler(), &matched.params().into_iter().collect()) + .or_else(R::not_found_route), Err(_) => R::not_found_route(), } } diff --git a/packages/yew-router/tests/router_unit_tests.rs b/packages/yew-router/tests/router_unit_tests.rs new file mode 100644 index 00000000000..869060643eb --- /dev/null +++ b/packages/yew-router/tests/router_unit_tests.rs @@ -0,0 +1,50 @@ +use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; +use yew_router::prelude::*; + +wasm_bindgen_test_configure!(run_in_browser); + +#[test] +fn router_always_404() { + #[derive(Routable, Debug, Clone, PartialEq)] + enum AppRoute { + #[at("/")] + Home, + #[at("/:id")] + Article { id: u64 }, + #[at("/404")] + #[not_found] + NotFound, + } + + assert_eq!( + Some(AppRoute::NotFound), + AppRoute::recognize("/not/matched/route") + ); + assert_eq!( + Some(AppRoute::NotFound), + AppRoute::recognize("/not-matched-route") + ); +} + +#[test] +fn router_trailing_slash() { + #[derive(Routable, Debug, Clone, PartialEq)] + enum AppRoute { + #[at("/")] + Home, + #[at("/category/:name/")] + Category { name: String }, + #[at("/:id")] + Article { id: u64 }, + #[at("/404")] + #[not_found] + NotFound, + } + + assert_eq!( + Some(AppRoute::Category { + name: "cooking-recipes".to_string() + }), + AppRoute::recognize("/category/cooking-recipes/") + ); +} From 02d1bd5bbe1f6d89987d1446dd4279b77243701c Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Sat, 9 Oct 2021 14:22:31 +0900 Subject: [PATCH 3/8] Fix output. --- .../tests/html_macro/element-fail.stderr | 110 +++++++++--------- .../yew-router/src/components/redirect.rs | 2 +- packages/yew-router/src/macro_helpers.rs | 2 +- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/packages/yew-macro/tests/html_macro/element-fail.stderr b/packages/yew-macro/tests/html_macro/element-fail.stderr index a69e3e4958e..1353c0b9328 100644 --- a/packages/yew-macro/tests/html_macro/element-fail.stderr +++ b/packages/yew-macro/tests/html_macro/element-fail.stderr @@ -1,209 +1,209 @@ error: this opening tag has no corresponding closing tag - --> $DIR/tests/html_macro/element-fail.rs:7:13 + --> $DIR/element-fail.rs:7:13 | 7 | html! {
}; | ^^^^^ error: this opening tag has no corresponding closing tag - --> $DIR/tests/html_macro/element-fail.rs:8:18 + --> $DIR/element-fail.rs:8:18 | 8 | html! {
}; | ^^^^^ error: this opening tag has no corresponding closing tag - --> $DIR/tests/html_macro/element-fail.rs:9:13 + --> $DIR/element-fail.rs:9:13 | 9 | html! {
}; | ^^^^^ error: this closing tag has no corresponding opening tag - --> $DIR/tests/html_macro/element-fail.rs:12:13 + --> $DIR/element-fail.rs:12:13 | 12 | html! {
}; | ^^^^^^ error: this closing tag has no corresponding opening tag - --> $DIR/tests/html_macro/element-fail.rs:13:18 + --> $DIR/element-fail.rs:13:18 | 13 | html! {
}; | ^^^^^^^ error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<>`) - --> $DIR/tests/html_macro/element-fail.rs:14:20 + --> $DIR/element-fail.rs:14:20 | 14 | html! { }; | ^^^^^^ error: this closing tag has no corresponding opening tag - --> $DIR/tests/html_macro/element-fail.rs:17:18 + --> $DIR/element-fail.rs:17:18 | 17 | html! {
}; | ^^^^^^^ error: this closing tag has no corresponding opening tag - --> $DIR/tests/html_macro/element-fail.rs:18:20 + --> $DIR/element-fail.rs:18:20 | 18 | html! { }; | ^^^^^^^^ error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<>`) - --> $DIR/tests/html_macro/element-fail.rs:21:24 + --> $DIR/element-fail.rs:21:24 | 21 | html! {
}; | ^^^^^^^^^^^ error: expected a valid html element - --> $DIR/tests/html_macro/element-fail.rs:23:18 + --> $DIR/element-fail.rs:23:18 | 23 | html! {
Invalid
}; | ^^^^^^^ error: `attr` can only be specified once but is given here again - --> $DIR/tests/html_macro/element-fail.rs:26:27 + --> $DIR/element-fail.rs:26:27 | 26 | html! { }; | ^^^^ error: `value` can only be specified once but is given here again - --> $DIR/tests/html_macro/element-fail.rs:27:32 + --> $DIR/element-fail.rs:27:32 | 27 | html! { }; | ^^^^^ error: `kind` can only be specified once but is given here again - --> $DIR/tests/html_macro/element-fail.rs:28:36 + --> $DIR/element-fail.rs:28:36 | 28 | html! { }; | ^^^^ error: `checked` can only be specified once but is given here again - --> $DIR/tests/html_macro/element-fail.rs:29:33 + --> $DIR/element-fail.rs:29:33 | 29 | html! { }; | ^^^^^^^ error: `disabled` can only be specified once but is given here again - --> $DIR/tests/html_macro/element-fail.rs:30:34 + --> $DIR/element-fail.rs:30:34 | 30 | html! { }; | ^^^^^^^^ error: `selected` can only be specified once but is given here again - --> $DIR/tests/html_macro/element-fail.rs:31:35 + --> $DIR/element-fail.rs:31:35 | 31 | html! {