content.rs
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
use crate::errors::{ Error, Result }; use serde::{ Deserialize }; use serde_json::{ self }; use std::fs::{ self }; use std::path::{ Path, PathBuf }; #[derive(Debug)] pub(crate) struct Provider { root: PathBuf, metadata: Metadata, } impl Provider { pub(crate) fn new<P: AsRef<Path>>(root: P, metadata_file: &str) -> Result<Provider> { let metadata_json = fs::read_to_string(root.as_ref().join(metadata_file))?; let metadata: Metadata = serde_json::from_str(&metadata_json)?; Ok(Provider { root: root.as_ref().to_path_buf(), metadata, }) } pub(crate) fn contact_email(&self) -> Option<String> { self.metadata.contact_email.clone() } pub(crate) fn site_link(&self) -> String { self.metadata.site.link.clone() } pub(crate) fn site_name(&self) -> String { self.metadata.site.name.clone() } pub(crate)fn site_menu(&self) -> Vec<Link> { self.metadata.site.menu.clone() } pub(crate) fn find_list(&self, list_path: &str) -> Result<List> { let maybe_list = self.metadata.lists .iter() .find(|list| list.slug == list_path); let Some(list) = maybe_list else { return Err(Error::ListNotFound(list_path.to_string())) }; Ok(list.clone()) } pub(crate) fn find_list_items(&self, list: &List) -> Vec<Page> { let mut items = Vec::new(); for page in &self.metadata.pages { if page.slug.starts_with(&list.slug) { items.push(page.clone()); } } items } pub(crate) fn find_page(&self, page_path: &str) -> Result<Page> { let maybe_page = self.metadata.pages .iter() .find(|page| page.slug == page_path); let Some(page) = maybe_page else { return Err(Error::PageNotFound(page_path.to_string())); }; Ok(page.clone()) } pub(crate) fn render_page(&self, page: &Page) -> Result<String> { let content_path = self.root.join("content").join(&page.slug).with_extension("md"); let content = fs::read_to_string(content_path)?; let parser = pulldown_cmark::Parser::new(&content); let mut rendered = String::new(); pulldown_cmark::html::push_html(&mut rendered, parser); Ok(rendered) } } #[derive(Clone, Debug, Deserialize)] pub(crate) struct Metadata { pub(crate) contact_email: Option<String>, pub(crate) site: Site, pub(crate) lists: Vec<List>, pub(crate) pages: Vec<Page>, } #[derive(Clone, Debug, Deserialize)] pub(crate) struct Site { pub(crate) link: String, pub(crate) name: String, pub(crate) menu: Vec<Link>, } #[derive(Clone, Debug, Deserialize)] pub(crate) struct List { pub(crate) name: String, pub(crate) slug: String, } #[derive(Clone, Debug, Deserialize)] pub(crate) struct Page { pub(crate) name: String, pub(crate) slug: String, pub(crate) summary: Option<String>, pub(crate) published: Option<String>, pub(crate) updated: Option<String>, } #[derive(Clone, Debug, Deserialize)] pub(crate) struct Link { pub(crate) link: String, pub(crate) name: String, }