in components/support/nimbus-fml/src/defaults/validator.rs [391:528]
fn validate_string_aliases(
&self,
path: &ErrorPath,
typ: &TypeRef,
value: &Value,
definitions: &HashMap<&str, &PropDef>,
feature_value: &Value,
skip: &Option<TypeRef>,
errors: &mut Vec<FeatureValidationError>,
) {
// As an optimization (to stop validating the definition against itself),
// we want to skip validation on the `skip` type ref: this is only set by the property defining
// a string-alias.
let should_validate = |v: &TypeRef| -> bool { skip.as_ref() != Some(v) };
match (typ, value) {
(TypeRef::StringAlias(_), Value::String(s)) => {
if !is_string_alias_value_valid(typ, s, definitions, feature_value) {
let path = path.final_error_quoted(s);
errors.push(FeatureValidationError {
path,
kind: ErrorKind::invalid_value(typ),
});
}
}
(TypeRef::Option(_), &Value::Null) => (),
(TypeRef::Option(inner), _) => self.validate_string_aliases(
path,
inner,
value,
definitions,
feature_value,
skip,
errors,
),
(TypeRef::List(inner), Value::Array(array)) => {
if should_validate(inner) {
for (index, value) in array.iter().enumerate() {
self.validate_string_aliases(
&path.array_index(index),
inner,
value,
definitions,
feature_value,
skip,
errors,
);
}
}
}
(TypeRef::EnumMap(key_type, value_type), Value::Object(map)) => {
if should_validate(key_type) && matches!(**key_type, TypeRef::StringAlias(_)) {
for key in map.keys() {
if !is_string_alias_value_valid(key_type, key, definitions, feature_value) {
let path = path.final_error_quoted(key);
errors.push(FeatureValidationError {
path,
kind: ErrorKind::invalid_key(key_type, map),
});
}
}
}
if should_validate(value_type) {
for (key, value) in map {
self.validate_string_aliases(
&path.map_key(key),
value_type,
value,
definitions,
feature_value,
skip,
errors,
);
}
}
}
(TypeRef::StringMap(vt), Value::Object(map)) => {
if should_validate(vt) {
for (key, value) in map {
self.validate_string_aliases(
&path.map_key(key),
vt,
value,
definitions,
feature_value,
skip,
errors,
);
}
}
}
(TypeRef::Object(obj_nm), Value::Object(map)) => {
let path = path.object_value(obj_nm);
let obj_def = self.get_object(obj_nm).unwrap();
for prop in &obj_def.props {
let prop_nm = &prop.name;
if let Some(value) = map.get(prop_nm) {
// string-alias definitions aren't allowed in Object definitions,
// so `skip` is None.
self.validate_string_aliases(
&path.property(prop_nm),
&prop.typ,
value,
definitions,
feature_value,
&None,
errors,
);
} else {
// There is no value in the map, so we need to validate the
// default.
let mut suberrors = Default::default();
self.validate_string_aliases(
&ErrorPath::object(obj_nm),
&prop.typ,
&prop.default,
definitions,
feature_value,
&None,
&mut suberrors,
);
// If the default is invalid, then it doesn't really matter
// what the error is, we can just error out.
if !suberrors.is_empty() {
let path = path.open_brace();
errors.push(FeatureValidationError {
path,
kind: ErrorKind::invalid_nested_value(prop_nm, &prop.typ),
});
}
}
}
}
_ => {}
}
}