Files
IdeA/crates/domain/src/validation.rs
Blomios 307ae71857 feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
2026-06-06 01:27:01 +02:00

60 lines
1.9 KiB
Rust

//! Small pure validation helpers shared across value objects.
use crate::error::DomainError;
/// Returns the trimmed string if non-empty, otherwise [`DomainError::EmptyField`].
pub(crate) fn non_empty(value: &str, field: &'static str) -> Result<(), DomainError> {
if value.trim().is_empty() {
Err(DomainError::EmptyField { field })
} else {
Ok(())
}
}
/// Validates that `var` is a syntactically valid environment-variable identifier:
/// non-empty, starts with a letter or `_`, and contains only ASCII alphanumeric
/// characters or `_`.
pub(crate) fn valid_env_var(var: &str) -> Result<(), DomainError> {
let invalid = || DomainError::InvalidEnvVar {
value: var.to_string(),
};
let mut chars = var.chars();
match chars.next() {
Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
_ => return Err(invalid()),
}
if chars.all(|c| c.is_ascii_alphanumeric() || c == '_') {
Ok(())
} else {
Err(invalid())
}
}
/// Validates that a path is relative and does not escape its root via `..`.
///
/// Used for [`crate::profile::ContextInjection::ConventionFile`] targets and
/// manifest `.md` paths, which must stay inside the project / `.ideai/` tree.
pub(crate) fn relative_safe(path: &str) -> Result<(), DomainError> {
let err = || DomainError::PathNotRelativeSafe {
path: path.to_string(),
};
if path.is_empty() {
return Err(err());
}
// Reject absolute POSIX paths and Windows drive / UNC paths.
let bytes = path.as_bytes();
if bytes[0] == b'/' || bytes[0] == b'\\' {
return Err(err());
}
if path.len() >= 2 && bytes[1] == b':' && bytes[0].is_ascii_alphabetic() {
return Err(err());
}
// Reject any `..` traversal component (handle both separators).
for component in path.split(['/', '\\']) {
if component == ".." {
return Err(err());
}
}
Ok(())
}