fronma 0.2.0

Front Matter parser.
Documentation
use crate::engines::{Engine, Yaml};
use crate::error::Error;
use crate::result::Result;

#[cfg(feature = "default")]
pub fn parse<T>(text: &str) -> Result<ParsedData<T>>
where
    T: serde::de::DeserializeOwned,
{
    parse_with_engine::<T, Yaml>(text)
}

pub fn parse_with_engine<T, E>(text: &str) -> Result<ParsedData<T>>
where
    T: serde::de::DeserializeOwned,
    E: Engine<T>,
{
    let line_pattern_lf = "---\n";
    let line_pattern_crlf = "---\r\n";

    if let Some(slice) = text.strip_prefix(line_pattern_lf) {
        let index_of_ending_line = slice
            .find(line_pattern_lf)
            .ok_or(Error::MissingEndingLine)?;
        let headers = E::parse(&slice[..index_of_ending_line])?;
        let body = &slice[(index_of_ending_line + line_pattern_lf.len())..];
        Ok(ParsedData { body, headers })
    } else if let Some(slice) = text.strip_prefix(line_pattern_crlf) {
        let index_of_ending_line = slice
            .find(line_pattern_crlf)
            .ok_or(Error::MissingEndingLine)?;
        let headers = E::parse(&slice[..index_of_ending_line])?;
        let body = &slice[(index_of_ending_line + line_pattern_crlf.len())..];
        Ok(ParsedData { body, headers })
    } else {
        Err(Error::MissingBeginningLine)
    }
}

#[derive(Debug)]
pub struct ParsedData<'a, T: serde::de::DeserializeOwned> {
    pub body: &'a str,
    pub headers: T,
}

#[cfg(feature = "default")]
#[cfg(test)]
mod tests {
    use crate::error::Error;
    use crate::parser::parse;
    use serde::Deserialize;

    #[derive(Debug, Deserialize)]
    struct Headers {
        title: String,
    }

    #[test]
    fn parse_with_missing_beginning_line() {
        let text = "";
        let result = parse::<Headers>(text);
        assert!(matches!(result, Err(Error::MissingBeginningLine)));
    }

    #[test]
    fn parse_with_missing_ending_line() {
        let text = "---\n";
        let result = parse::<Headers>(text);
        assert!(matches!(result, Err(Error::MissingEndingLine)));
    }

    #[test]
    fn parse_with_missing_ending_line_crlf() {
        let text = "---\r\n";
        let result = parse::<Headers>(text);
        assert!(matches!(result, Err(Error::MissingEndingLine)));
    }

    #[test]
    fn parse_with_empty_frontmatter() {
        let text = "---\n---\n";
        let result = parse::<Headers>(text);
        assert!(matches!(result, Err(Error::SerdeYaml(_))));
    }

    #[test]
    fn parse_with_empty_frontmatter_crlf() {
        let text = "---\r\n---\r\n";
        let result = parse::<Headers>(text);
        assert!(matches!(result, Err(Error::SerdeYaml(_))));
    }

    #[test]
    fn parse_with_missing_known_field() {
        let text = "---\ndate: 2000-01-01\n---\n";
        let result = parse::<Headers>(text);
        assert!(matches!(result, Err(Error::SerdeYaml(_))));
    }

    #[test]
    fn parse_with_missing_known_field_crlf() {
        let text = "---\r\ndate: 2000-01-01\r\n---\r\n";
        let result = parse::<Headers>(text);
        assert!(matches!(result, Err(Error::SerdeYaml(_))));
    }

    #[test]
    fn parse_with_unknown_field() {
        let text = "---\ndate: 2000-01-01\ntitle: dummy_title\n---\n";
        let result = parse::<Headers>(text);
        dbg!(&result);
        assert!(matches!(result, Ok(_)));
    }

    #[test]
    fn parse_with_unknown_field_crlf() {
        let text = "---\r\ndate: 2000-01-01\r\ntitle: dummy_title\r\n---\r\n";
        let result = parse::<Headers>(text);
        dbg!(&result);
        assert!(matches!(result, Ok(_)));
    }

    #[test]
    fn parse_with_empty_known_field() {
        let text = "---\ntitle:\n---\n";
        let result = parse::<Headers>(text).unwrap();
        assert_eq!(result.headers.title, "~");
        assert_eq!(result.body, "");
    }

    #[test]
    fn parse_with_empty_known_field_crlf() {
        let text = "---\r\ntitle:\r\n---\r\n";
        let result = parse::<Headers>(text).unwrap();
        assert_eq!(result.headers.title, "~");
        assert_eq!(result.body, "");
    }

    #[test]
    fn parse_with_valid_frontmatter() {
        let text = "---\ntitle: dummy_title---\ndummy_body";
        let result = parse::<Headers>(text).unwrap();
        assert_eq!(result.headers.title, "dummy_title");
        assert_eq!(result.body, "dummy_body");
    }
    #[test]
    fn parse_with_valid_frontmatter_crlf() {
        let text = "---\r\ntitle: dummy_title---\r\ndummy_body";
        let result = parse::<Headers>(text).unwrap();
        assert_eq!(result.headers.title, "dummy_title");
        assert_eq!(result.body, "dummy_body");
    }
}