1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use super::{match_route, RouteVerdict};
use crate::{reactor::Reactor, template::BrowserNodeType};
use sycamore::prelude::Scope;
use sycamore_router::Route;

/// The Perseus route system, which implements Sycamore `Route`, but adds
/// additional data for Perseus' processing system.
pub(crate) struct PerseusRoute<'cx> {
    /// The current route verdict. The initialization value of this is
    /// completely irrelevant (it will be overridden immediately by the internal
    /// routing logic).
    pub verdict: RouteVerdict,
    /// The Sycamore scope that allows us to access the render context.
    ///
    /// This will *always* be `Some(_)` in actual applications.
    pub cx: Option<Scope<'cx>>,
}
// Sycamore would only use this if we were processing dynamic routes, which
// we're not
// In other words, it's fine that these values would break everything
// if they were used, they're just compiler appeasement
impl<'cx> Default for PerseusRoute<'cx> {
    fn default() -> Self {
        Self {
            verdict: RouteVerdict::NotFound {
                locale: "xx-XX".to_string(),
            },
            // Again, this will never be accessed
            cx: None,
        }
    }
}
impl<'cx> PerseusRoute<'cx> {
    /// Gets the current route verdict.
    pub fn get_verdict(&self) -> &RouteVerdict {
        &self.verdict
    }
}
impl<'cx> Route for PerseusRoute<'cx> {
    fn match_route(&self, path: &[&str]) -> Self {
        // Decode the path (we can't do this in `match_route` because of how it's called
        // by initial view, and we don't want to double-decode!)
        let path = path.join("/");
        let path = js_sys::decode_uri_component(&path)
            .unwrap()
            .as_string()
            .unwrap();
        let path_segments = path
            .split('/')
            .filter(|s| !s.is_empty())
            .collect::<Vec<&str>>(); // This parsing is identical to the Sycamore router's

        let reactor = Reactor::<BrowserNodeType>::from_cx(self.cx.unwrap()); // We know the scope will always exist
        let verdict = match_route(
            &path_segments,
            &reactor.render_cfg,
            &reactor.entities,
            &reactor.locales,
        );
        Self {
            verdict,
            cx: self.cx,
        }
    }
}