rumdl_lib/utils/
mkdocs_patterns.rs1pub fn is_mkdocs_auto_reference(reference: &str) -> bool {
11 if reference.is_empty() || reference.len() > 200 {
13 return false;
14 }
15
16 if reference.contains('/') {
18 return is_valid_slash_pattern(reference);
19 }
20
21 if reference.contains('.') {
23 return is_valid_dot_pattern(reference);
24 }
25
26 if reference.contains('-') && !reference.contains(' ') {
28 return is_valid_hyphen_pattern(reference);
29 }
30 false
31}
32
33fn is_valid_dot_pattern(reference: &str) -> bool {
35 if reference.starts_with('.') || reference.ends_with('.') {
37 return false;
38 }
39
40 let parts: Vec<&str> = reference.split('.').collect();
41
42 if parts.len() < 2 {
44 return false;
45 }
46
47 parts.iter().all(|part| {
49 !part.is_empty()
50 && part.len() <= 50 && is_valid_identifier(part)
52 })
53}
54
55fn is_valid_hyphen_pattern(reference: &str) -> bool {
57 if reference.starts_with('-') || reference.ends_with('-') || reference.contains("--") {
59 return false;
60 }
61
62 if reference.len() < 3 {
64 return false;
65 }
66
67 reference
69 .chars()
70 .all(|c| c.is_ascii_lowercase() || c == '-' || c.is_ascii_digit())
71}
72
73fn is_valid_slash_pattern(reference: &str) -> bool {
75 let parts: Vec<&str> = reference.split('/').collect();
76
77 if parts.len() < 2 {
79 return false;
80 }
81
82 parts.iter().all(|part| {
84 !part.is_empty()
85 && part.len() <= 50 && is_valid_path_component(part)
87 })
88}
89
90fn is_valid_identifier(s: &str) -> bool {
92 if s.is_empty() {
95 return false;
96 }
97
98 let first_char = s.chars().next().unwrap();
99 if !first_char.is_ascii_alphabetic() && first_char != '_' {
100 return false;
101 }
102
103 s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
104}
105
106fn is_valid_path_component(s: &str) -> bool {
108 !s.is_empty()
111 && s.chars()
112 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_valid_dot_patterns() {
121 assert!(is_mkdocs_auto_reference("module.Class"));
123 assert!(is_mkdocs_auto_reference("package.module.function"));
124 assert!(is_mkdocs_auto_reference("__init__.py"));
125 assert!(is_mkdocs_auto_reference("Class.__init__"));
126 assert!(is_mkdocs_auto_reference("a.b")); assert!(!is_mkdocs_auto_reference(".")); assert!(!is_mkdocs_auto_reference("..")); assert!(!is_mkdocs_auto_reference("a.")); assert!(!is_mkdocs_auto_reference(".a")); assert!(!is_mkdocs_auto_reference("a..b")); assert!(!is_mkdocs_auto_reference("127.0.0.1")); }
136
137 #[test]
138 fn test_valid_hyphen_patterns() {
139 assert!(is_mkdocs_auto_reference("getting-started"));
141 assert!(is_mkdocs_auto_reference("api-reference"));
142 assert!(is_mkdocs_auto_reference("section-1"));
143 assert!(is_mkdocs_auto_reference("a-b")); assert!(!is_mkdocs_auto_reference("-")); assert!(!is_mkdocs_auto_reference("--")); assert!(!is_mkdocs_auto_reference("-start")); assert!(!is_mkdocs_auto_reference("end-")); assert!(!is_mkdocs_auto_reference("double--hyphen")); assert!(!is_mkdocs_auto_reference("UPPER-CASE")); assert!(!is_mkdocs_auto_reference("Mixed-Case")); }
154
155 #[test]
156 fn test_valid_slash_patterns() {
157 assert!(is_mkdocs_auto_reference("api/v1"));
159 assert!(is_mkdocs_auto_reference("docs/reference/guide"));
160 assert!(is_mkdocs_auto_reference("api/module.Class"));
161 assert!(is_mkdocs_auto_reference("a/b")); assert!(!is_mkdocs_auto_reference("/")); assert!(!is_mkdocs_auto_reference("//")); assert!(!is_mkdocs_auto_reference("a//b")); }
168
169 #[test]
170 fn test_length_limits() {
171 let long_input = "a".repeat(201);
173 assert!(!is_mkdocs_auto_reference(&long_input));
174
175 assert!(!is_mkdocs_auto_reference(""));
177 }
178
179 #[test]
180 fn test_edge_cases() {
181 assert!(!is_mkdocs_auto_reference("module.class-method")); assert!(is_mkdocs_auto_reference("api/module.Class")); assert!(is_mkdocs_auto_reference("api/module.function")); assert!(!is_mkdocs_auto_reference("module.class!")); assert!(!is_mkdocs_auto_reference("api/module?query")); assert!(!is_mkdocs_auto_reference("header#anchor")); assert!(!is_mkdocs_auto_reference("module .class")); assert!(!is_mkdocs_auto_reference("header -anchor")); assert!(!is_mkdocs_auto_reference("api/ module")); }
198}