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
31 false
32}
33
34fn is_valid_dot_pattern(reference: &str) -> bool {
36 if reference.starts_with('.') || reference.ends_with('.') {
38 return false;
39 }
40
41 let parts: Vec<&str> = reference.split('.').collect();
42
43 if parts.len() < 2 {
45 return false;
46 }
47
48 parts.iter().all(|part| {
50 !part.is_empty()
51 && part.len() <= 50 && is_valid_identifier(part)
53 })
54}
55
56fn is_valid_hyphen_pattern(reference: &str) -> bool {
58 if reference.starts_with('-') || reference.ends_with('-') || reference.contains("--") {
60 return false;
61 }
62
63 if reference.len() < 3 {
65 return false;
66 }
67
68 reference
70 .chars()
71 .all(|c| c.is_ascii_lowercase() || c == '-' || c.is_ascii_digit())
72}
73
74fn is_valid_slash_pattern(reference: &str) -> bool {
76 let parts: Vec<&str> = reference.split('/').collect();
77
78 if parts.len() < 2 {
80 return false;
81 }
82
83 parts.iter().all(|part| {
85 !part.is_empty()
86 && part.len() <= 50 && is_valid_path_component(part)
88 })
89}
90
91fn is_valid_identifier(s: &str) -> bool {
93 if s.is_empty() {
96 return false;
97 }
98
99 let first_char = s.chars().next().unwrap();
100 if !first_char.is_ascii_alphabetic() && first_char != '_' {
101 return false;
102 }
103
104 s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
105}
106
107fn is_valid_path_component(s: &str) -> bool {
109 !s.is_empty()
112 && s.chars()
113 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_valid_dot_patterns() {
122 assert!(is_mkdocs_auto_reference("module.Class"));
124 assert!(is_mkdocs_auto_reference("package.module.function"));
125 assert!(is_mkdocs_auto_reference("__init__.py"));
126 assert!(is_mkdocs_auto_reference("Class.__init__"));
127 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")); }
137
138 #[test]
139 fn test_valid_hyphen_patterns() {
140 assert!(is_mkdocs_auto_reference("getting-started"));
142 assert!(is_mkdocs_auto_reference("api-reference"));
143 assert!(is_mkdocs_auto_reference("section-1"));
144 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")); }
155
156 #[test]
157 fn test_valid_slash_patterns() {
158 assert!(is_mkdocs_auto_reference("api/v1"));
160 assert!(is_mkdocs_auto_reference("docs/reference/guide"));
161 assert!(is_mkdocs_auto_reference("api/module.Class"));
162 assert!(is_mkdocs_auto_reference("a/b")); assert!(!is_mkdocs_auto_reference("/")); assert!(!is_mkdocs_auto_reference("//")); assert!(!is_mkdocs_auto_reference("a//b")); }
169
170 #[test]
171 fn test_length_limits() {
172 let long_input = "a".repeat(201);
174 assert!(!is_mkdocs_auto_reference(&long_input));
175
176 assert!(!is_mkdocs_auto_reference(""));
178 }
179
180 #[test]
181 fn test_edge_cases() {
182 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")); }
199}