use crate::component::VersionTarget;
use crate::error::{Error, Result};
use regex::Regex;
pub fn validate_version_target_conflict(
existing: &[VersionTarget],
new_file: &str,
new_pattern: &str,
_component_id: &str,
) -> Result<()> {
for target in existing {
if target.file == new_file {
let existing_pattern = target.pattern.as_deref().unwrap_or("");
if existing_pattern == new_pattern {
return Ok(());
}
}
}
Ok(())
}
pub fn validate_version_pattern(pattern: &str) -> Result<()> {
if pattern.contains("{version}") {
return Err(Error::validation_invalid_argument(
"version_target.pattern",
format!(
"Pattern '{}' uses template syntax ({{version}}), but a regex with a capture group is required. Example: 'Version: (\\d+\\.\\d+\\.\\d+)'",
pattern
),
Some(pattern.to_string()),
None,
));
}
let re = Regex::new(&crate::engine::text::ensure_multiline(pattern)).map_err(|e| {
Error::validation_invalid_argument(
"version_target.pattern",
format!("Invalid regex pattern '{}': {}", pattern, e),
Some(pattern.to_string()),
None,
)
})?;
if re.captures_len() < 2 {
return Err(Error::validation_invalid_argument(
"version_target.pattern",
format!(
"Pattern '{}' has no capture group. Wrap the version portion in parentheses. Example: 'Version: (\\d+\\.\\d+\\.\\d+)'",
pattern
),
Some(pattern.to_string()),
None,
));
}
Ok(())
}
pub fn normalize_version_pattern(pattern: &str) -> String {
if pattern.contains("\\\\") {
pattern.replace("\\\\", "\\")
} else {
pattern.to_string()
}
}
pub fn parse_version_targets(targets: &[String]) -> Result<Vec<VersionTarget>> {
let mut parsed = Vec::new();
for target in targets {
let mut parts = target.splitn(2, "::");
let file = parts
.next()
.map(str::trim)
.filter(|s| !s.is_empty())
.ok_or_else(|| {
Error::validation_invalid_argument(
"version_target",
"Invalid version target format (expected 'file' or 'file::pattern')",
None,
None,
)
})?;
let pattern = parts.next().map(str::trim).filter(|s| !s.is_empty());
if let Some(p) = pattern {
let normalized = normalize_version_pattern(p);
validate_version_pattern(&normalized)?;
parsed.push(VersionTarget {
file: file.to_string(),
pattern: Some(normalized),
});
} else {
parsed.push(VersionTarget {
file: file.to_string(),
pattern: None,
});
}
}
Ok(parsed)
}