1#![deny(unsafe_code)]
7#![warn(missing_docs)]
8#![warn(clippy::all)]
9
10use url::Url;
11
12#[must_use]
17pub fn uri_key(uri: &str) -> String {
18 if let Ok(parsed) = Url::parse(uri) {
19 let value = parsed.as_str().to_string();
20 if let Some(rest) = value.strip_prefix("file:///")
21 && rest.len() > 1
22 && rest.as_bytes()[1] == b':'
23 && rest.as_bytes()[0].is_ascii_alphabetic()
24 {
25 return format!("file:///{}{}", rest[0..1].to_ascii_lowercase(), &rest[1..]);
26 }
27 value
28 } else {
29 uri.to_string()
30 }
31}
32
33#[must_use]
35pub fn is_file_uri(uri: &str) -> bool {
36 uri.starts_with("file://")
37}
38
39#[must_use]
41pub fn is_special_scheme(uri: &str) -> bool {
42 if let Ok(url) = Url::parse(uri) {
43 url.scheme() != "file"
44 } else {
45 uri.starts_with("untitled:")
46 || uri.starts_with("git:")
47 || uri.starts_with("vscode-notebook:")
48 || uri.starts_with("vscode-vfs:")
49 }
50}
51
52#[must_use]
54pub fn uri_extension(uri: &str) -> Option<&str> {
55 let path_part = uri.rsplit('/').next()?;
56 let path_part = path_part.split('?').next()?;
57 let path_part = path_part.split('#').next()?;
58 let dot_pos = path_part.rfind('.')?;
59 let ext = &path_part[dot_pos + 1..];
60 if ext.is_empty() { None } else { Some(ext) }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::{is_file_uri, is_special_scheme, uri_extension, uri_key};
66
67 #[test]
68 fn normalizes_uri_keys() {
69 assert_eq!(uri_key("file:///tmp/test.pl"), "file:///tmp/test.pl");
70 assert_eq!(uri_key("file:///C:/Users/test.pl"), "file:///c:/Users/test.pl");
71 }
72
73 #[test]
74 fn preserves_invalid_uri_values() {
75 assert_eq!(uri_key("not-a-uri"), "not-a-uri");
76 }
77
78 #[test]
79 fn detects_file_uris() {
80 assert!(is_file_uri("file:///tmp/test.pl"));
81 assert!(!is_file_uri("https://example.com"));
82 }
83
84 #[test]
85 fn detects_special_schemes() {
86 assert!(is_special_scheme("untitled:Untitled-1"));
87 assert!(is_special_scheme("git:/foo/bar"));
88 assert!(!is_special_scheme("file:///tmp/test.pl"));
89 }
90
91 #[test]
92 fn extracts_extensions() {
93 assert_eq!(uri_extension("file:///tmp/test.pl"), Some("pl"));
94 assert_eq!(uri_extension("file:///tmp/file.pl?query=1"), Some("pl"));
95 assert_eq!(uri_extension("file:///tmp/no-extension"), None);
96 }
97}