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 if is_valid_identifier(reference) {
33 return true;
34 }
35
36 false
37}
38
39fn is_valid_dot_pattern(reference: &str) -> bool {
41 if reference.starts_with('.') || reference.ends_with('.') {
43 return false;
44 }
45
46 let parts: Vec<&str> = reference.split('.').collect();
47
48 if parts.len() < 2 {
50 return false;
51 }
52
53 parts.iter().all(|part| {
55 !part.is_empty()
56 && part.len() <= 50 && is_valid_identifier(part)
58 })
59}
60
61fn is_valid_hyphen_pattern(reference: &str) -> bool {
63 if reference.starts_with('-') || reference.ends_with('-') || reference.contains("--") {
65 return false;
66 }
67
68 if reference.len() < 3 {
70 return false;
71 }
72
73 reference
75 .chars()
76 .all(|c| c.is_ascii_lowercase() || c == '-' || c.is_ascii_digit())
77}
78
79fn is_valid_slash_pattern(reference: &str) -> bool {
81 let parts: Vec<&str> = reference.split('/').collect();
82
83 if parts.len() < 2 {
85 return false;
86 }
87
88 parts.iter().all(|part| {
90 !part.is_empty()
91 && part.len() <= 50 && is_valid_path_component(part)
93 })
94}
95
96fn is_valid_identifier(s: &str) -> bool {
98 if s.is_empty() {
101 return false;
102 }
103
104 let first_char = s.chars().next().unwrap();
105 if !first_char.is_ascii_alphabetic() && first_char != '_' {
106 return false;
107 }
108
109 s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
110}
111
112fn is_valid_path_component(s: &str) -> bool {
114 !s.is_empty()
117 && s.chars()
118 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_valid_dot_patterns() {
127 assert!(is_mkdocs_auto_reference("module.Class"));
129 assert!(is_mkdocs_auto_reference("package.module.function"));
130 assert!(is_mkdocs_auto_reference("__init__.py"));
131 assert!(is_mkdocs_auto_reference("Class.__init__"));
132 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")); }
142
143 #[test]
144 fn test_valid_hyphen_patterns() {
145 assert!(is_mkdocs_auto_reference("getting-started"));
147 assert!(is_mkdocs_auto_reference("api-reference"));
148 assert!(is_mkdocs_auto_reference("section-1"));
149 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")); }
160
161 #[test]
162 fn test_valid_slash_patterns() {
163 assert!(is_mkdocs_auto_reference("api/v1"));
165 assert!(is_mkdocs_auto_reference("docs/reference/guide"));
166 assert!(is_mkdocs_auto_reference("api/module.Class"));
167 assert!(is_mkdocs_auto_reference("a/b")); assert!(!is_mkdocs_auto_reference("/")); assert!(!is_mkdocs_auto_reference("//")); assert!(!is_mkdocs_auto_reference("a//b")); }
174
175 #[test]
176 fn test_length_limits() {
177 let long_input = "a".repeat(201);
179 assert!(!is_mkdocs_auto_reference(&long_input));
180
181 assert!(!is_mkdocs_auto_reference(""));
183 }
184
185 #[test]
186 fn test_edge_cases() {
187 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")); }
204}