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
use std::path::Path;

use regex::Regex;

use errors::{Result, ResultExt};

mod page;
mod section;

pub use self::page::PageFrontMatter;
pub use self::section::{SectionFrontMatter, InsertAnchor};

lazy_static! {
    static ref PAGE_RE: Regex = Regex::new(r"^[[:space:]]*\+\+\+\r?\n((?s).*?(?-s))\+\+\+\r?\n?((?s).*(?-s))$").unwrap();
}

/// Split a file between the front matter and its content
/// Will return an error if the front matter wasn't found
fn split_content(file_path: &Path, content: &str) -> Result<(String, String)> {
    if !PAGE_RE.is_match(content) {
        bail!("Couldn't find front matter in `{}`. Did you forget to add `+++`?", file_path.to_string_lossy());
    }

    // 2. extract the front matter and the content
    let caps = PAGE_RE.captures(content).unwrap();
    // caps[0] is the full match
    // caps[1] => front matter
    // caps[2] => content
    Ok((caps[1].to_string(), caps[2].to_string()))
}

/// Split a file between the front matter and its content.
/// Returns a parsed `SectionFrontMatter` and the rest of the content
pub fn split_section_content(file_path: &Path, content: &str) -> Result<(SectionFrontMatter, String)> {
    let (front_matter, content) = split_content(file_path, content)?;
    let meta = SectionFrontMatter::parse(&front_matter)
        .chain_err(|| format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()))?;
    Ok((meta, content))
}

/// Split a file between the front matter and its content
/// Returns a parsed `PageFrontMatter` and the rest of the content
pub fn split_page_content(file_path: &Path, content: &str) -> Result<(PageFrontMatter, String)> {
    let (front_matter, content) = split_content(file_path, content)?;
    let meta = PageFrontMatter::parse(&front_matter)
        .chain_err(|| format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()))?;
    Ok((meta, content))
}

#[cfg(test)]
mod tests {
    use std::path::Path;

    use super::{split_section_content, split_page_content};

    #[test]
    fn can_split_page_content_valid() {
        let content = r#"
+++
title = "Title"
description = "hey there"
date = "2002/10/12"
+++
Hello
"#;
        let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
        assert_eq!(content, "Hello\n");
        assert_eq!(front_matter.title.unwrap(), "Title");
    }

    #[test]
    fn can_split_section_content_valid() {
        let content = r#"
+++
paginate_by = 10
+++
Hello
"#;
        let (front_matter, content) = split_section_content(Path::new(""), content).unwrap();
        assert_eq!(content, "Hello\n");
        assert!(front_matter.is_paginated());
    }

    #[test]
    fn can_split_content_with_only_frontmatter_valid() {
        let content = r#"
+++
title = "Title"
description = "hey there"
date = "2002/10/12"
+++"#;
        let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
        assert_eq!(content, "");
        assert_eq!(front_matter.title.unwrap(), "Title");
    }

    #[test]
    fn can_split_content_lazily() {
        let content = r#"
+++
title = "Title"
description = "hey there"
date = "2002-10-02T15:00:00Z"
+++
+++"#;
        let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
        assert_eq!(content, "+++");
        assert_eq!(front_matter.title.unwrap(), "Title");
    }

    #[test]
    fn errors_if_cannot_locate_frontmatter() {
        let content = r#"
+++
title = "Title"
description = "hey there"
date = "2002/10/12""#;
        let res = split_page_content(Path::new(""), content);
        assert!(res.is_err());
    }

}