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.

168 lines
4.3KB

  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::{Error, Result};
  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(
  66. format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()),
  67. e,
  68. )
  69. })?;
  70. Ok((meta, content))
  71. }
  72. /// Split a file between the front matter and its content
  73. /// Returns a parsed `PageFrontMatter` and the rest of the content
  74. pub fn split_page_content(file_path: &Path, content: &str) -> Result<(PageFrontMatter, String)> {
  75. let (front_matter, content) = split_content(file_path, content)?;
  76. let meta = PageFrontMatter::parse(&front_matter).map_err(|e| {
  77. Error::chain(
  78. format!("Error when parsing front matter of page `{}`", file_path.to_string_lossy()),
  79. e,
  80. )
  81. })?;
  82. Ok((meta, content))
  83. }
  84. #[cfg(test)]
  85. mod tests {
  86. use std::path::Path;
  87. use super::{split_page_content, split_section_content};
  88. #[test]
  89. fn can_split_page_content_valid() {
  90. let content = r#"
  91. +++
  92. title = "Title"
  93. description = "hey there"
  94. date = 2002-10-12
  95. +++
  96. Hello
  97. "#;
  98. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  99. assert_eq!(content, "Hello\n");
  100. assert_eq!(front_matter.title.unwrap(), "Title");
  101. }
  102. #[test]
  103. fn can_split_section_content_valid() {
  104. let content = r#"
  105. +++
  106. paginate_by = 10
  107. +++
  108. Hello
  109. "#;
  110. let (front_matter, content) = split_section_content(Path::new(""), content).unwrap();
  111. assert_eq!(content, "Hello\n");
  112. assert!(front_matter.is_paginated());
  113. }
  114. #[test]
  115. fn can_split_content_with_only_frontmatter_valid() {
  116. let content = r#"
  117. +++
  118. title = "Title"
  119. description = "hey there"
  120. date = 2002-10-12
  121. +++"#;
  122. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  123. assert_eq!(content, "");
  124. assert_eq!(front_matter.title.unwrap(), "Title");
  125. }
  126. #[test]
  127. fn can_split_content_lazily() {
  128. let content = r#"
  129. +++
  130. title = "Title"
  131. description = "hey there"
  132. date = 2002-10-02T15:00:00Z
  133. +++
  134. +++"#;
  135. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  136. assert_eq!(content, "+++");
  137. assert_eq!(front_matter.title.unwrap(), "Title");
  138. }
  139. #[test]
  140. fn errors_if_cannot_locate_frontmatter() {
  141. let content = r#"
  142. +++
  143. title = "Title"
  144. description = "hey there"
  145. date = 2002-10-12"#;
  146. let res = split_page_content(Path::new(""), content);
  147. assert!(res.is_err());
  148. }
  149. }