use super::args::RememberArgs;
use crate::constants::{MAX_MEMORY_DESCRIPTION_LEN, MAX_MEMORY_NAME_LEN};
use crate::errors::AppError;
pub(super) struct ResolvedName {
pub(super) original: String,
pub(super) normalized: String,
pub(super) was_normalized: bool,
}
pub(super) fn resolve(args: &RememberArgs) -> Result<ResolvedName, AppError> {
let original_name = args.name.clone();
let normalized_name = {
let lower = args.name.to_lowercase().replace(['_', ' '], "-");
let trimmed = lower.trim_matches('-').to_string();
if trimmed != args.name {
tracing::warn!(target: "remember",
original = %args.name,
normalized = %trimmed,
"name auto-normalized to kebab-case"
);
}
trimmed
};
let name_was_normalized = normalized_name != original_name;
if args.strict_name && name_was_normalized {
return Err(AppError::Validation(
crate::i18n::validation::strict_name_not_canonical(&original_name, &normalized_name),
));
}
if normalized_name.is_empty() {
return Err(AppError::Validation(
crate::i18n::validation::name_empty_after_normalization(),
));
}
if normalized_name.len() > MAX_MEMORY_NAME_LEN {
return Err(AppError::LimitExceeded(
crate::i18n::validation::name_length(MAX_MEMORY_NAME_LEN),
));
}
if normalized_name.starts_with("__") {
return Err(AppError::Validation(
crate::i18n::validation::reserved_name(),
));
}
{
let slug_re = crate::constants::name_slug_regex();
if !slug_re.is_match(&normalized_name) {
return Err(AppError::Validation(crate::i18n::validation::name_kebab(
&normalized_name,
)));
}
}
if let Some(ref desc) = args.description {
if desc.len() > MAX_MEMORY_DESCRIPTION_LEN {
return Err(AppError::Validation(
crate::i18n::validation::description_exceeds(MAX_MEMORY_DESCRIPTION_LEN),
));
}
}
Ok(ResolvedName {
original: original_name,
normalized: normalized_name,
was_normalized: name_was_normalized,
})
}