use camino::{Utf8Path, Utf8PathBuf};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
)]
#[serde(transparent)]
pub struct RepoPath(String);
impl Default for RepoPath {
fn default() -> Self {
RepoPath::new(".")
}
}
impl RepoPath {
pub fn new<S: AsRef<str>>(s: S) -> Self {
let mut v = s.as_ref().replace('\\', "/");
while v.starts_with("./") {
v = v.trim_start_matches("./").to_string();
}
if v.is_empty() {
v = ".".to_string();
}
Self(v)
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn to_utf8_pathbuf(&self) -> Utf8PathBuf {
Utf8PathBuf::from(self.0.clone())
}
pub fn join(&self, segment: &str) -> RepoPath {
let base = Utf8Path::new(self.as_str());
RepoPath::new(base.join(segment).as_str())
}
}
impl From<&Utf8Path> for RepoPath {
fn from(value: &Utf8Path) -> Self {
RepoPath::new(value.as_str())
}
}
impl From<Utf8PathBuf> for RepoPath {
fn from(value: Utf8PathBuf) -> Self {
RepoPath::new(value.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn repo_path_normalizes_separators_and_prefix() {
let path = RepoPath::new(r".\crates\depguard\Cargo.toml");
assert_eq!(path.as_str(), "crates/depguard/Cargo.toml");
let path = RepoPath::new("././Cargo.toml");
assert_eq!(path.as_str(), "Cargo.toml");
}
#[test]
fn repo_path_empty_defaults_to_dot() {
let path = RepoPath::new("");
assert_eq!(path.as_str(), ".");
let path = RepoPath::default();
assert_eq!(path.as_str(), ".");
}
#[test]
fn repo_path_join_uses_forward_slashes() {
let base = RepoPath::new("crates/depguard");
let joined = base.join("src/lib.rs");
assert_eq!(joined.as_str(), "crates/depguard/src/lib.rs");
}
#[test]
fn repo_path_from_utf8_pathbuf() {
let buf = Utf8PathBuf::from("crates/depguard");
let path = RepoPath::from(buf);
assert_eq!(path.as_str(), "crates/depguard");
}
#[test]
fn repo_path_to_utf8_pathbuf() {
let path = RepoPath::new("crates/depguard");
let buf = path.to_utf8_pathbuf();
assert_eq!(buf.as_str(), "crates/depguard");
}
}