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.

162 lines
4.2KB

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