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.

156 lines
4.2KB

  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. /// Most recent to oldest
  26. Date,
  27. /// Lower order comes last
  28. Order,
  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!("Couldn't find front matter in `{}`. Did you forget to add `+++`?", file_path.to_string_lossy());
  46. }
  47. // 2. extract the front matter and the content
  48. let caps = PAGE_RE.captures(content).unwrap();
  49. // caps[0] is the full match
  50. // caps[1] => front matter
  51. // caps[2] => content
  52. Ok((caps[1].to_string(), caps[2].to_string()))
  53. }
  54. /// Split a file between the front matter and its content.
  55. /// Returns a parsed `SectionFrontMatter` and the rest of the content
  56. pub fn split_section_content(file_path: &Path, content: &str) -> Result<(SectionFrontMatter, String)> {
  57. let (front_matter, content) = split_content(file_path, content)?;
  58. let meta = SectionFrontMatter::parse(&front_matter)
  59. .chain_err(|| format!("Error when parsing front matter of section `{}`", file_path.to_string_lossy()))?;
  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)
  67. .chain_err(|| format!("Error when parsing front matter of page `{}`", file_path.to_string_lossy()))?;
  68. Ok((meta, content))
  69. }
  70. #[cfg(test)]
  71. mod tests {
  72. use std::path::Path;
  73. use super::{split_section_content, split_page_content};
  74. #[test]
  75. fn can_split_page_content_valid() {
  76. let content = r#"
  77. +++
  78. title = "Title"
  79. description = "hey there"
  80. date = "2002/10/12"
  81. +++
  82. Hello
  83. "#;
  84. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  85. assert_eq!(content, "Hello\n");
  86. assert_eq!(front_matter.title.unwrap(), "Title");
  87. }
  88. #[test]
  89. fn can_split_section_content_valid() {
  90. let content = r#"
  91. +++
  92. paginate_by = 10
  93. +++
  94. Hello
  95. "#;
  96. let (front_matter, content) = split_section_content(Path::new(""), content).unwrap();
  97. assert_eq!(content, "Hello\n");
  98. assert!(front_matter.is_paginated());
  99. }
  100. #[test]
  101. fn can_split_content_with_only_frontmatter_valid() {
  102. let content = r#"
  103. +++
  104. title = "Title"
  105. description = "hey there"
  106. date = "2002/10/12"
  107. +++"#;
  108. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  109. assert_eq!(content, "");
  110. assert_eq!(front_matter.title.unwrap(), "Title");
  111. }
  112. #[test]
  113. fn can_split_content_lazily() {
  114. let content = r#"
  115. +++
  116. title = "Title"
  117. description = "hey there"
  118. date = "2002-10-02T15:00:00Z"
  119. +++
  120. +++"#;
  121. let (front_matter, content) = split_page_content(Path::new(""), content).unwrap();
  122. assert_eq!(content, "+++");
  123. assert_eq!(front_matter.title.unwrap(), "Title");
  124. }
  125. #[test]
  126. fn errors_if_cannot_locate_frontmatter() {
  127. let content = r#"
  128. +++
  129. title = "Title"
  130. description = "hey there"
  131. date = "2002/10/12""#;
  132. let res = split_page_content(Path::new(""), content);
  133. assert!(res.is_err());
  134. }
  135. }