cobalt/cobalt_model/
collection.rs

1use cobalt_config::Frontmatter;
2use cobalt_config::SortOrder;
3use liquid;
4
5use crate::error::Result;
6
7#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
8pub struct Collection {
9    pub title: liquid::model::KString,
10    pub slug: liquid::model::KString,
11    pub description: Option<liquid::model::KString>,
12    pub dir: cobalt_config::RelPath,
13    pub drafts_dir: Option<cobalt_config::RelPath>,
14    pub order: SortOrder,
15    pub rss: Option<cobalt_config::RelPath>,
16    pub jsonfeed: Option<cobalt_config::RelPath>,
17    pub publish_date_in_filename: bool,
18    pub default: Frontmatter,
19}
20
21impl Collection {
22    pub fn from_page_config(
23        config: cobalt_config::PageCollection,
24        site: &cobalt_config::Site,
25        common_default: &Frontmatter,
26    ) -> Result<Self> {
27        let mut config: cobalt_config::Collection = config.into();
28        // Use `site` because the pages are effectively the site
29        config.title = Some(site.title.clone().unwrap_or_else(|| "".into()));
30        config.description = site.description.clone();
31        Self::from_config(config, "pages", false, common_default)
32    }
33
34    pub fn from_post_config(
35        config: cobalt_config::PostCollection,
36        site: &cobalt_config::Site,
37        include_drafts: bool,
38        common_default: &Frontmatter,
39    ) -> Result<Self> {
40        let mut config: cobalt_config::Collection = config.into();
41        // Default with `site` for people quickly bootstrapping a blog, the blog and site are
42        // effectively equivalent.
43        if config.title.is_none() {
44            config.title = Some(site.title.clone().unwrap_or_else(|| "".into()));
45        }
46        if config.description.is_none() {
47            config.description = site.description.clone();
48        }
49        Self::from_config(config, "posts", include_drafts, common_default)
50    }
51
52    fn from_config(
53        config: cobalt_config::Collection,
54        slug: &str,
55        include_drafts: bool,
56        common_default: &Frontmatter,
57    ) -> Result<Self> {
58        let cobalt_config::Collection {
59            title,
60            description,
61            dir,
62            drafts_dir,
63            order,
64            rss,
65            jsonfeed,
66            default,
67            publish_date_in_filename,
68        } = config;
69
70        let title = title.ok_or_else(|| anyhow::format_err!("Collection is missing a `title`"))?;
71        let slug = liquid::model::KString::from_ref(slug);
72
73        let dir = dir.unwrap_or_else(|| cobalt_config::RelPath::from_unchecked(slug.as_str()));
74        let drafts_dir = if include_drafts { drafts_dir } else { None };
75
76        let default = default.merge(common_default).merge(&Frontmatter {
77            collection: Some(slug.clone()),
78            ..Default::default()
79        });
80
81        let new = Collection {
82            title,
83            slug,
84            description,
85            dir,
86            drafts_dir,
87            order,
88            rss,
89            jsonfeed,
90            publish_date_in_filename,
91            default,
92        };
93        Ok(new)
94    }
95
96    pub fn attributes(&self) -> liquid::Object {
97        let mut attributes: liquid::Object = vec![
98            (
99                "title".into(),
100                liquid::model::Value::scalar(self.title.clone()),
101            ),
102            (
103                "slug".into(),
104                liquid::model::Value::scalar(self.slug.clone()),
105            ),
106            (
107                "description".into(),
108                liquid::model::Value::scalar(self.description.clone().unwrap_or_default()),
109            ),
110        ]
111        .into_iter()
112        .collect();
113        if let Some(rss) = self.rss.as_ref() {
114            attributes.insert(
115                "rss".into(),
116                liquid::model::Value::scalar(rss.as_str().to_owned()),
117            );
118        }
119        if let Some(jsonfeed) = self.jsonfeed.as_ref() {
120            attributes.insert(
121                "jsonfeed".into(),
122                liquid::model::Value::scalar(jsonfeed.as_str().to_owned()),
123            );
124        }
125        attributes
126    }
127}