use crate::error::{ConfigError, MarsError};
pub fn validate_target(target: &str) -> Result<(), MarsError> {
if target.contains('/') || target.contains('\\') {
return Err(MarsError::Config(ConfigError::Invalid {
message: format!(
"`{target}` looks like a path — TARGET should be a directory name \
like `.claude` or `.codex`. Use `--root` to specify project root."
),
}));
}
if target == "." || target == ".." || target.is_empty() {
return Err(MarsError::Config(ConfigError::Invalid {
message: format!(
"`{target}` is not a valid target name — use a directory name like `.claude` or `.codex`."
),
}));
}
Ok(())
}
pub fn normalize_target_name(target: &str) -> Result<String, MarsError> {
let normalized = target.trim_end_matches('/').trim_end_matches('\\');
if normalized.contains('/') || normalized.contains('\\') {
return Err(MarsError::Link {
target: target.to_string(),
message: "target must be a directory name, not a path".to_string(),
});
}
if normalized.is_empty() || normalized == "." || normalized == ".." {
return Err(MarsError::Link {
target: target.to_string(),
message: "invalid target name".to_string(),
});
}
Ok(normalized.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validate_target_accepts_simple_names() {
assert!(validate_target(".agents").is_ok());
assert!(validate_target(".claude").is_ok());
assert!(validate_target("my-agents").is_ok());
}
#[test]
fn validate_target_rejects_paths() {
assert!(validate_target("./foo").is_err());
assert!(validate_target("foo/bar").is_err());
assert!(validate_target("/absolute/path").is_err());
}
#[test]
fn validate_target_rejects_dots() {
assert!(validate_target(".").is_err());
assert!(validate_target("..").is_err());
}
#[test]
fn validate_target_rejects_empty() {
assert!(validate_target("").is_err());
}
#[test]
fn normalize_strips_trailing_slash() {
assert_eq!(normalize_target_name(".claude/").unwrap(), ".claude");
}
#[test]
fn normalize_rejects_path() {
assert!(normalize_target_name("foo/bar").is_err());
}
#[test]
fn normalize_rejects_empty() {
assert!(normalize_target_name("").is_err());
}
#[test]
fn normalize_rejects_dots() {
assert!(normalize_target_name(".").is_err());
assert!(normalize_target_name("..").is_err());
}
}