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.

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