You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
4.1KB

  1. #[macro_use]
  2. extern crate lazy_static;
  3. #[macro_use]
  4. extern crate serde_derive;
  5. extern crate serde;
  6. extern crate toml;
  7. extern crate regex;
  8. extern crate tera;
  9. extern crate chrono;
  10. #[macro_use]
  11. extern crate errors;
  12. use std::path::Path;
  13. use regex::Regex;
  14. use errors::{Result, ResultExt};
  15. mod page;
  16. mod section;
  17. pub use page::PageFrontMatter;
  18. pub use section::SectionFrontMatter;
  19. lazy_static! {
  20. static ref PAGE_RE: Regex = Regex::new(r"^[[:space:]]*\+\+\+\r?\n((?s).*?(?-s))\+\+\+\r?\n?((?s).*(?-s))$").unwrap();
  21. }
  22. #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
  23. #[serde(rename_all = "lowercase")]
  24. pub enum SortBy {
  25. Date,
  26. Order,
  27. Weight,
  28. None,
  29. }
  30. #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
  31. #[serde(rename_all = "lowercase")]
  32. pub enum InsertAnchor {
  33. Left,
  34. Right,
  35. None,
  36. }
  37. /// Split a file between the front matter and its content
  38. /// Will return an error if the front matter wasn't found
  39. fn split_content(file_path: &Path, content: &str) -> Result<(String, String)> {
  40. if !PAGE_RE.is_match(content) {
  41. bail!("Couldn't find front matter in `{}`. Did you forget to add `+++`?", file_path.to_string_lossy());
  42. }
  43. // 2. extract the front matter and the content
  44. let caps = PAGE_RE.captures(content).unwrap();
  45. // caps[0] is the full match
  46. // caps[1] => front matter
  47. // caps[2] => content
  48. Ok((caps[1].to_string(), caps[2].to_string()))
  49. }
  50. /// Split a file between the front matter and its content.
  51. /// Returns a parsed `SectionFrontMatter` and the rest of the content
  52. pub fn split_section_content(file_path: &Path, content: &str) -> Result<(SectionFrontMatter, String)> {
  53. let (front_matter, content) = split_content(file_path, content)?;
  54. let meta = SectionFrontMatter::parse(&front_matter)
  55. .chain_err(|| format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()))?;
  56. Ok((meta, content))
  57. }
  58. /// Split a file between the front matter and its content
  59. /// Returns a parsed `PageFrontMatter` and the rest of the content
  60. pub fn split_page_content(file_path: &Path, content: &str) -> Result<(PageFrontMatter, String)> {
  61. let (front_matter, content) = split_content(file_path, content)?;
  62. let meta = PageFrontMatter::parse(&front_matter)
  63. .chain_err(|| format!("Error when parsing front matter of page `{}`", file_path.to_string_lossy()))?;
  64. Ok((meta, content))
  65. }
  66. #[cfg(test)]
  67. mod tests {
  68. use std::path::Path;
  69. use super::{split_section_content, split_page_content};
  70. #[test]
  71. fn can_split_page_content_valid() {
  72. let content = r#"
  73. +++
  74. title = "Title"
  75. description = "hey there"
  76. date = "2002/10/12"
  77. +++
  78. Hello
  79. "#;
  80. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  81. assert_eq!(content, "Hello\n");
  82. assert_eq!(front_matter.title.unwrap(), "Title");
  83. }
  84. #[test]
  85. fn can_split_section_content_valid() {
  86. let content = r#"
  87. +++
  88. paginate_by = 10
  89. +++
  90. Hello
  91. "#;
  92. let (front_matter, content) = split_section_content(Path::new(""), content).unwrap();
  93. assert_eq!(content, "Hello\n");
  94. assert!(front_matter.is_paginated());
  95. }
  96. #[test]
  97. fn can_split_content_with_only_frontmatter_valid() {
  98. let content = r#"
  99. +++
  100. title = "Title"
  101. description = "hey there"
  102. date = "2002/10/12"
  103. +++"#;
  104. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  105. assert_eq!(content, "");
  106. assert_eq!(front_matter.title.unwrap(), "Title");
  107. }
  108. #[test]
  109. fn can_split_content_lazily() {
  110. let content = r#"
  111. +++
  112. title = "Title"
  113. description = "hey there"
  114. date = "2002-10-02T15:00:00Z"
  115. +++
  116. +++"#;
  117. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  118. assert_eq!(content, "+++");
  119. assert_eq!(front_matter.title.unwrap(), "Title");
  120. }
  121. #[test]
  122. fn errors_if_cannot_locate_frontmatter() {
  123. let content = r#"
  124. +++
  125. title = "Title"
  126. description = "hey there"
  127. date = "2002/10/12""#;
  128. let res = split_page_content(Path::new(""), content);
  129. assert!(res.is_err());
  130. }
  131. }