use std::fs;
use std::path::{Path, PathBuf};
const NON_LOCAL_PREFIXES: &[&str] = &[
"npm:",
"git:",
"github:",
"http:",
"https:",
"ssh:",
];
pub fn canonicalize_path(path: impl AsRef<Path>) -> PathBuf {
match fs::canonicalize(path.as_ref()) {
Ok(canonical) => canonical,
Err(_) => path.as_ref().to_path_buf(),
}
}
pub fn is_local_path(value: &str) -> bool {
let trimmed = value.trim();
for prefix in NON_LOCAL_PREFIXES {
if trimmed.starts_with(prefix) {
return false;
}
}
true
}
pub fn expand_tilde(path: &str) -> PathBuf {
if path == "~" {
dirs::home_dir().unwrap_or_else(|| PathBuf::from("~"))
} else if let Some(suffix) = path.strip_prefix("~/") {
dirs::home_dir()
.map(|home| home.join(suffix))
.unwrap_or_else(|| PathBuf::from(path))
} else {
PathBuf::from(path)
}
}
pub fn normalize_path(path: &str) -> PathBuf {
expand_tilde(path)
}
pub fn is_file(path: impl AsRef<Path>) -> bool {
path.as_ref().is_file()
}
pub fn is_dir(path: impl AsRef<Path>) -> bool {
path.as_ref().is_dir()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_local_path() {
assert!(is_local_path("my-file.txt"));
assert!(is_local_path("./relative/path"));
assert!(is_local_path("../parent/path"));
assert!(is_local_path("/absolute/path"));
assert!(is_local_path("src/main.rs"));
assert!(!is_local_path("npm:package-name"));
assert!(!is_local_path("git:github.com/user/repo"));
assert!(!is_local_path("github:user/repo"));
assert!(!is_local_path("http://example.com"));
assert!(!is_local_path("https://example.com"));
assert!(!is_local_path("ssh:git@github.com/user/repo"));
assert!(!is_local_path(" npm:package"));
assert!(!is_local_path("npm:package "));
}
#[test]
fn test_expand_tilde() {
let home = dirs::home_dir().unwrap();
let expected = home.join("some/path");
assert_eq!(expand_tilde("~"), home);
assert_eq!(expand_tilde("~/some/path"), expected);
assert_eq!(expand_tilde("/absolute/path"), PathBuf::from("/absolute/path"));
}
}