use std::path::Path;
pub fn parse_rchignore(path: &Path) -> std::io::Result<Vec<String>> {
let content = std::fs::read_to_string(path)?;
Ok(parse_rchignore_content(&content))
}
pub fn parse_rchignore_content(content: &str) -> Vec<String> {
content
.lines()
.map(|line| line.trim())
.filter(|line| !line.is_empty() && !line.starts_with('#'))
.map(|line| line.to_string())
.collect()
}
fn sanitize_project_id(name: &str) -> String {
if name.is_empty()
|| name == "."
|| name == ".."
|| name.contains("..")
|| name.contains('/')
|| name.contains('\\')
|| name.contains('\0')
|| name.starts_with('-')
{
return "unknown".to_string();
}
let is_safe = name
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
&& !name.starts_with('.');
if is_safe {
name.to_string()
} else {
let sanitized: String = name
.chars()
.map(|c| {
if c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.' {
c
} else {
'_'
}
})
.collect();
let result = sanitized.trim_start_matches('.');
if result.is_empty() {
"unknown".to_string()
} else {
result.to_string()
}
}
}
pub fn project_id_from_path(path: &Path) -> String {
let name = path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown");
sanitize_project_id(name)
}