Skip to main content

fastskill_core/validation/
field_validation.rs

1//! Skill field validation (required fields, formats, lengths).
2
3use crate::core::skill_manager::SkillDefinition;
4use crate::validation::result::{ErrorSeverity, ValidationResult};
5
6pub(crate) fn is_valid_skill_name(s: &str) -> bool {
7    s.chars()
8        .all(|c| c.is_alphanumeric() || c == '-' || c == '_')
9}
10
11pub(crate) fn is_valid_semver(s: &str) -> bool {
12    semver::Version::parse(s).is_ok()
13}
14
15pub(crate) fn validate_required_fields(
16    skill: &SkillDefinition,
17    mut result: ValidationResult,
18    required_fields: &[String],
19    max_description_length: usize,
20) -> ValidationResult {
21    for field in required_fields {
22        match field.as_str() {
23            "name" => {
24                if skill.name.trim().is_empty() {
25                    result = result.with_error(
26                        "name",
27                        "Skill name cannot be empty",
28                        ErrorSeverity::Critical,
29                    );
30                }
31            }
32            "description" => {
33                if skill.description.trim().is_empty() {
34                    result = result.with_error(
35                        "description",
36                        "Skill description cannot be empty",
37                        ErrorSeverity::Critical,
38                    );
39                } else if skill.description.len() > max_description_length {
40                    result = result.with_warning(
41                        "description",
42                        &format!(
43                            "Description is very long ({} chars, max: {})",
44                            skill.description.len(),
45                            max_description_length
46                        ),
47                    );
48                }
49            }
50            "version" => {
51                if skill.version.trim().is_empty() {
52                    result = result.with_error(
53                        "version",
54                        "Skill version cannot be empty",
55                        ErrorSeverity::Critical,
56                    );
57                }
58            }
59            _ => {}
60        }
61    }
62    result
63}
64
65pub(crate) fn validate_field_formats(
66    skill: &SkillDefinition,
67    mut result: ValidationResult,
68) -> ValidationResult {
69    if !is_valid_skill_name(&skill.name) {
70        result = result.with_warning(
71            "name",
72            "Skill name should only contain alphanumeric characters, hyphens, and underscores",
73        );
74    }
75    if !is_valid_semver(&skill.version) {
76        result = result.with_warning(
77            "version",
78            "Version should follow semantic versioning (e.g., 1.0.0)",
79        );
80    }
81    result
82}