cobalt/cobalt_model/
permalink.rs1use std::sync::LazyLock;
2
3use liquid;
4
5use crate::error::Result;
6
7pub fn explode_permalink<S: AsRef<str>>(
8 permalink: S,
9 attributes: &liquid::Object,
10) -> Result<String> {
11 explode_permalink_string(permalink.as_ref(), attributes)
12}
13
14fn explode_permalink_string(permalink: &str, attributes: &liquid::Object) -> Result<String> {
15 static PERMALINK_PARSER: LazyLock<liquid::Parser> = LazyLock::new(liquid::Parser::new);
16 let p = PERMALINK_PARSER.parse(permalink)?;
17 let mut p = p.render(attributes)?;
18
19 p = p.replace('\\', "/");
21
22 p = p.replace("//", "/");
24
25 if p.starts_with('/') {
26 p.remove(0);
27 }
28
29 Ok(p)
30}
31
32pub fn format_url_as_file<S: AsRef<str>>(permalink: S) -> relative_path::RelativePathBuf {
33 format_url_as_file_str(permalink.as_ref())
34}
35
36fn format_url_as_file_str(permalink: &str) -> relative_path::RelativePathBuf {
37 let mut path = std::path::Path::new(&permalink);
38
39 if path.has_root() {
41 let mut components = path.components();
42 components.next();
43 path = components.as_path();
44 }
45
46 let mut path_buf = relative_path::RelativePathBuf::from_path(path).unwrap();
47
48 if path_buf.extension().is_none() {
50 path_buf.push("index.html");
51 }
52
53 path_buf
54}
55
56#[cfg(test)]
57mod test {
58 use super::*;
59
60 #[test]
61 fn explode_permalink_relative() {
62 let attributes = liquid::Object::new();
63 let actual = explode_permalink("relative/path", &attributes).unwrap();
64 assert_eq!(actual, "relative/path");
65 }
66
67 #[test]
68 fn explode_permalink_absolute() {
69 let attributes = liquid::Object::new();
70 let actual = explode_permalink("/abs/path", &attributes).unwrap();
71 assert_eq!(actual, "abs/path");
72 }
73
74 #[test]
75 fn explode_permalink_blank_substitution() {
76 let attributes = liquid::Object::new();
77 let actual = explode_permalink("//path/middle//end", &attributes).unwrap();
78 assert_eq!(actual, "path/middle/end");
79 }
80
81 #[test]
82 fn format_url_as_file_absolute() {
83 let actual = format_url_as_file("/hello/world.html");
84 assert_eq!(
85 actual,
86 relative_path::RelativePath::from_path("hello/world.html").unwrap()
87 );
88 }
89
90 #[test]
91 fn format_url_as_file_no_explode() {
92 let actual = format_url_as_file("/hello/world.custom");
93 assert_eq!(
94 actual,
95 relative_path::RelativePath::from_path("hello/world.custom").unwrap()
96 );
97 }
98
99 #[test]
100 fn format_url_as_file_explode() {
101 let actual = format_url_as_file("/hello/world");
102 assert_eq!(
103 actual,
104 relative_path::RelativePath::from_path("hello/world/index.html").unwrap()
105 );
106 }
107}