use std::path::PathBuf;
pub fn to_folder_slug(absolute_path: &str) -> String {
let cleaned = absolute_path.trim_start_matches(['/', '\\']);
let cleaned = cleaned.trim_end_matches(['/', '\\']);
let mut result = String::with_capacity(cleaned.len());
let mut last_was_sep = false;
for c in cleaned.chars() {
if c == ':' {
continue;
}
if c == '/' || c == '\\' {
if !last_was_sep {
result.push('-');
}
last_was_sep = true;
} else {
result.push(c);
last_was_sep = false;
}
}
result
}
pub fn get_project_storage_dir(absolute_path: &str) -> PathBuf {
let slug = to_folder_slug(absolute_path);
let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("~"));
home.join(".routa").join("projects").join(slug)
}
pub fn get_sessions_dir(absolute_path: &str) -> PathBuf {
get_project_storage_dir(absolute_path).join("sessions")
}
pub fn get_traces_dir(absolute_path: &str) -> PathBuf {
get_project_storage_dir(absolute_path).join("traces")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_unix_path() {
assert_eq!(
to_folder_slug("/Users/john/my-project"),
"Users-john-my-project"
);
}
#[test]
fn test_windows_path() {
assert_eq!(
to_folder_slug("C:\\Users\\john\\project"),
"C-Users-john-project"
);
}
#[test]
fn test_consecutive_separators() {
assert_eq!(
to_folder_slug("/Users//john///project"),
"Users-john-project"
);
}
#[test]
fn test_mixed_separators() {
assert_eq!(to_folder_slug("/Users/john\\project"), "Users-john-project");
}
#[test]
fn test_trailing_separator() {
assert_eq!(to_folder_slug("/Users/john/project/"), "Users-john-project");
}
#[test]
fn test_trailing_slash_consistency() {
assert_eq!(
to_folder_slug("/Users/john/project/"),
to_folder_slug("/Users/john/project")
);
}
#[test]
fn test_deterministic() {
let path = "/Users/john/my-project";
assert_eq!(to_folder_slug(path), to_folder_slug(path));
}
#[test]
fn test_get_project_storage_dir() {
let dir = get_project_storage_dir("/Users/john/my-project");
let dir_str = dir.to_string_lossy();
assert!(dir_str.contains("Users-john-my-project"));
assert!(
dir_str.contains(".routa/projects") || dir_str.contains(".routa\\projects"),
"path should contain .routa/projects or .routa\\projects, got: {}",
dir_str
);
}
#[test]
fn test_windows_drive_letter_colon_stripped() {
assert_eq!(to_folder_slug("E:\\routa"), "E-routa");
assert_eq!(
to_folder_slug("D:\\my-workspace\\app"),
"D-my-workspace-app"
);
}
#[test]
fn test_windows_drive_colon_consistency() {
let slug = to_folder_slug("E:\\routa\\.routa\\repos\\keepongo--routa-project");
assert!(!slug.contains(':'), "slug must not contain colons: {slug}");
assert_eq!(slug, "E-routa-.routa-repos-keepongo--routa-project");
}
#[test]
fn test_multiple_colons_stripped() {
assert_eq!(to_folder_slug("C:\\foo:bar\\baz"), "C-foobar-baz");
}
}