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.

157 lines
4.2KB

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