use std::path::Path;
pub fn path_to_folder_id<P: AsRef<Path>>(path: P) -> String {
let path_str = path.as_ref().to_string_lossy();
#[cfg(windows)]
let slugified = path_str.replace(['/', '\\', '.', ':'], "-");
#[cfg(not(windows))]
let slugified = path_str.replace(['/', '.'], "-");
let mut result = String::with_capacity(slugified.len());
let mut prev_dash = false;
for c in slugified.chars() {
if c == '-' {
if !prev_dash && !result.is_empty() {
result.push('-');
}
prev_dash = true;
} else {
result.push(c);
prev_dash = false;
}
}
result.trim_end_matches('-').to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_path() {
assert_eq!(
path_to_folder_id("/Users/me/projects/myapp"),
"Users-me-projects-myapp"
);
}
#[test]
fn test_root_path() {
assert_eq!(path_to_folder_id("/"), "");
}
#[test]
fn test_nested_path() {
assert_eq!(
path_to_folder_id("/home/user/dev/rust/cursor-helper"),
"home-user-dev-rust-cursor-helper"
);
}
#[test]
fn test_path_with_dots() {
assert_eq!(
path_to_folder_id("/Users/me/com.example/my-project"),
"Users-me-com-example-my-project"
);
}
#[test]
fn test_hidden_folder() {
assert_eq!(path_to_folder_id("/Users/me/.claude"), "Users-me-claude");
}
#[test]
fn test_multiple_dots() {
assert_eq!(path_to_folder_id("/Users/me/../foo"), "Users-me-foo");
}
#[cfg(windows)]
#[test]
fn test_windows_path() {
assert_eq!(
path_to_folder_id("C:\\com.github\\lucifer1004\\cursor-helper"),
"C-com-github-lucifer1004-cursor-helper"
);
}
#[cfg(windows)]
#[test]
fn test_windows_path_with_dots() {
assert_eq!(
path_to_folder_id("D:\\Users\\me\\.config\\app"),
"D-Users-me-config-app"
);
}
}