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
use cobalt_config::Frontmatter;
use cobalt_config::SortOrder;
use liquid;

use crate::error::*;

#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
pub struct Collection {
    pub title: liquid::model::KString,
    pub slug: liquid::model::KString,
    pub description: Option<liquid::model::KString>,
    pub dir: cobalt_config::RelPath,
    pub drafts_dir: Option<cobalt_config::RelPath>,
    pub order: SortOrder,
    pub rss: Option<cobalt_config::RelPath>,
    pub jsonfeed: Option<cobalt_config::RelPath>,
    pub publish_date_in_filename: bool,
    pub default: Frontmatter,
}

impl Collection {
    pub fn from_page_config(
        config: cobalt_config::PageCollection,
        site: &cobalt_config::Site,
        common_default: &cobalt_config::Frontmatter,
    ) -> Result<Self> {
        let mut config: cobalt_config::Collection = config.into();
        // Use `site` because the pages are effectively the site
        config.title = Some(site.title.clone().unwrap_or_else(|| "".into()));
        config.description = site.description.clone();
        Self::from_config(config, "pages", false, common_default)
    }

    pub fn from_post_config(
        config: cobalt_config::PostCollection,
        site: &cobalt_config::Site,
        include_drafts: bool,
        common_default: &cobalt_config::Frontmatter,
    ) -> Result<Self> {
        let mut config: cobalt_config::Collection = config.into();
        // Default with `site` for people quickly bootstrapping a blog, the blog and site are
        // effectively equivalent.
        if config.title.is_none() {
            config.title = Some(site.title.clone().unwrap_or_else(|| "".into()));
        }
        if config.description.is_none() {
            config.description = site.description.clone();
        }
        Self::from_config(config, "posts", include_drafts, common_default)
    }

    fn from_config(
        config: cobalt_config::Collection,
        slug: &str,
        include_drafts: bool,
        common_default: &cobalt_config::Frontmatter,
    ) -> Result<Self> {
        let cobalt_config::Collection {
            title,
            description,
            dir,
            drafts_dir,
            order,
            rss,
            jsonfeed,
            default,
            publish_date_in_filename,
        } = config;

        let title = title.ok_or_else(|| anyhow::format_err!("Collection is missing a `title`"))?;
        let slug = liquid::model::KString::from_ref(slug);

        let dir = dir.unwrap_or_else(|| cobalt_config::RelPath::from_unchecked(slug.as_str()));
        let drafts_dir = if include_drafts { drafts_dir } else { None };

        let default = default.merge(common_default).merge(&Frontmatter {
            collection: Some(slug.clone()),
            ..Default::default()
        });

        let new = Collection {
            title,
            slug,
            description,
            dir,
            drafts_dir,
            order,
            rss,
            jsonfeed,
            publish_date_in_filename,
            default,
        };
        Ok(new)
    }

    pub fn attributes(&self) -> liquid::Object {
        let mut attributes: liquid::Object = vec![
            (
                "title".into(),
                liquid::model::Value::scalar(self.title.clone()),
            ),
            (
                "slug".into(),
                liquid::model::Value::scalar(self.slug.clone()),
            ),
            (
                "description".into(),
                liquid::model::Value::scalar(self.description.clone().unwrap_or_default()),
            ),
        ]
        .into_iter()
        .collect();
        if let Some(rss) = self.rss.as_ref() {
            attributes.insert(
                "rss".into(),
                liquid::model::Value::scalar(rss.as_str().to_owned()),
            );
        }
        if let Some(jsonfeed) = self.jsonfeed.as_ref() {
            attributes.insert(
                "jsonfeed".into(),
                liquid::model::Value::scalar(jsonfeed.as_str().to_owned()),
            );
        }
        attributes
    }
}