Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
60 lines
1.9 KiB
Rust
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(())
|
|
}
|