1use camino::{Utf8Path, Utf8PathBuf};
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4
5#[derive(
12 Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
13)]
14#[serde(transparent)]
15pub struct RepoPath(String);
16
17impl Default for RepoPath {
18 fn default() -> Self {
19 RepoPath::new(".")
20 }
21}
22
23impl RepoPath {
24 pub fn new<S: AsRef<str>>(s: S) -> Self {
25 let mut v = s.as_ref().replace('\\', "/");
26 while v.starts_with("./") {
27 v = v.trim_start_matches("./").to_string();
28 }
29 if v.is_empty() {
31 v = ".".to_string();
32 }
33 Self(v)
34 }
35
36 pub fn as_str(&self) -> &str {
37 &self.0
38 }
39
40 pub fn to_utf8_pathbuf(&self) -> Utf8PathBuf {
41 Utf8PathBuf::from(self.0.clone())
42 }
43
44 pub fn join(&self, segment: &str) -> RepoPath {
45 let base = Utf8Path::new(self.as_str());
46 RepoPath::new(base.join(segment).as_str())
47 }
48}
49
50impl From<&Utf8Path> for RepoPath {
51 fn from(value: &Utf8Path) -> Self {
52 RepoPath::new(value.as_str())
53 }
54}
55
56impl From<Utf8PathBuf> for RepoPath {
57 fn from(value: Utf8PathBuf) -> Self {
58 RepoPath::new(value.as_str())
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn repo_path_normalizes_separators_and_prefix() {
68 let path = RepoPath::new(r".\crates\depguard\Cargo.toml");
69 assert_eq!(path.as_str(), "crates/depguard/Cargo.toml");
70
71 let path = RepoPath::new("././Cargo.toml");
72 assert_eq!(path.as_str(), "Cargo.toml");
73 }
74
75 #[test]
76 fn repo_path_empty_defaults_to_dot() {
77 let path = RepoPath::new("");
78 assert_eq!(path.as_str(), ".");
79
80 let path = RepoPath::default();
81 assert_eq!(path.as_str(), ".");
82 }
83
84 #[test]
85 fn repo_path_join_uses_forward_slashes() {
86 let base = RepoPath::new("crates/depguard");
87 let joined = base.join("src/lib.rs");
88 assert_eq!(joined.as_str(), "crates/depguard/src/lib.rs");
89 }
90
91 #[test]
92 fn repo_path_from_utf8_pathbuf() {
93 let buf = Utf8PathBuf::from("crates/depguard");
94 let path = RepoPath::from(buf);
95 assert_eq!(path.as_str(), "crates/depguard");
96 }
97
98 #[test]
99 fn repo_path_to_utf8_pathbuf() {
100 let path = RepoPath::new("crates/depguard");
101 let buf = path.to_utf8_pathbuf();
102 assert_eq!(buf.as_str(), "crates/depguard");
103 }
104}