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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use std::path::Path;

use crate::{Error, Object, Page, Unreact};

/// Append shared documentation attributes to each function
macro_rules! include_shared_docs {
    (
        $(
            $( #[$attr:meta] )+
            <::>
            $item:item
        )*
    ) => {
        $(
            $( #[$attr] )+
            /// # Examples
            ///
            /// ```,no_run
            /// # use unreact::prelude::*;
            /// # fn main() -> Result<(), Error> {
            ///     # let mut app = Unreact::new(Config::default(), false, "https://example.com")?;
            /// app
            ///     // Create a route to '/some_path' with the template 'page.hbs' and a message
            ///     .route("some_path", "page", object! {message: "this is at '/some_path'"})?
            ///     // Create a route without a template (raw string)
            ///     .route_raw("hello", "this is my hello page".to_string())
            ///     // Create a route without data
            ///     .route("article", "other/article", object! {})?
            ///     // Index page with a message
            ///     .index("page", object! {message: "World"})?
            ///     // 404 page with no data
            ///     .not_found("404", object! {})?;
            /// # app.run()
            /// # }
            /// ```
            ///
            /// # Routing Methods
            ///
            /// - [`route`](struct.Unreact.html#method.route): Create a normal route
            /// - [`route_raw`](struct.Unreact.html#method.route_raw): Create a route without a template
            /// - [`route_raw_html`](struct.Unreact.html#method.route_raw_html): Create a HTML page route without a template
            /// - [`index`](struct.Unreact.html#method.index): Create an index route (`/`)
            /// - [`not_found`](struct.Unreact.html#method.not_found): Create a 404 route (`/404`)
            $item
        )*
    };
}

impl<'a> Unreact<'a> {
    include_shared_docs!(
        /// Create a route
        ///
        /// **NOTE**: Route will only validate if template exists in production. In dev mode, this function **will always pass**, and error will occur during `run` function
        ///
        /// ## Parameters
        ///
        /// - `path`: The folder (relative to build directory) that file should be written in (`{build}/{path}/index.html`)
        /// - `template`: The name of the template to use
        /// - `data`: Data to pass into the template, as an `Object`
        <::>
        pub fn route(&mut self, path: &str, template: &str, data: Object) -> Result<&mut Self, Error> {
            // Check file exists - only if NOT dev mode
            if !self.is_dev{
                let file_path = format!("{}/{}.hbs", self.config.templates, template);
                if !Path::new(&file_path).exists() {
                    return fail!(TemplateNotExist, template.to_string());
                }
            }

            // Create route
            self.routes.insert(
                path.to_string(),
                Page::Template {
                    template: template.to_string(),
                    data,
                },
            );

            Ok(self)
        }

        /// Create a route, with raw page content instead of a template
        ///
        /// ## Parameters
        ///
        /// - `path`: The folder (relative to build directory) that file should be written in (`{build}/{path}/index.html`)
        /// - `content`: The raw file contents to write to the file
        <::>
        pub fn route_raw(&mut self, path: &str, content: impl Into<String>) -> &mut Self {
            self.routes.insert(path.to_string(), Page::Raw(content.into()));
            self
        }

        /// Create a route, with raw page content instead of a template
        ///
        /// Adds HTML boilerplate around content (Unlike [`route_raw`](struct.Unreact.html#method.route_raw))
        ///
        /// ## Parameters
        ///
        /// - `path`: The folder (relative to build directory) that file should be written in (`{build}/{path}/index.html`)
        /// - `content`: The raw file contents to write to the file
        <::>
        pub fn route_raw_html(&mut self, path: &str, content: impl Into<String>) -> &mut Self {
            self.routes.insert(path.to_string(), Page::Raw(format!(include_str!("boilerplate.html"), CONTENT = content.into())));
            self
        }

        /// Create the index route
        ///
        /// Alias of `app.route("", ...)`
        ///
        /// File is written to `{build}/index.html`
        ///
        /// **NOTE**: Route will only validate if template exists in production. In dev mode, this function **will always pass**, and error will occur during `run` function
        ///
        /// ## Parameters
        ///
        /// - `template`: The name of the template to use
        /// - `data`: Data to pass into the template, as an `Object`
        <::>
        pub fn index(&mut self, template: &str, data: Object) -> Result<&mut Self, Error> {
            self.route("", template, data)
        }

        /// Create the 404 route
        ///
        /// Alias of `app.route("404", ...)`.
        /// Used as the 404 page, for a path not found
        ///
        /// File is written to `{build}/404/index.html`
        ///
        /// **NOTE**: Route will only validate if template exists in production. In dev mode, this function **will always pass**, and error will occur during `run` function
        ///
        /// ## Parameters
        ///
        /// - `template`: The name of the template to use
        /// - `data`: Data to pass into the template, as an `Object`
        <::>
        pub fn not_found(&mut self, template: &str, data: Object) -> Result<&mut Self, Error> {
            self.route("404", template, data)
        }
    );
}