in components/support/nimbus-fml/src/defaults/validator.rs [239:345]
fn validate_types(
&self,
path: &ErrorPath,
type_ref: &TypeRef,
default: &Value,
errors: &mut Vec<FeatureValidationError>,
) {
match (type_ref, default) {
(TypeRef::Boolean, Value::Bool(_))
| (TypeRef::BundleImage, Value::String(_))
| (TypeRef::BundleText, Value::String(_))
| (TypeRef::String, Value::String(_))
| (TypeRef::StringAlias(_), Value::String(_))
| (TypeRef::Int, Value::Number(_))
| (TypeRef::Option(_), Value::Null) => (),
(TypeRef::Option(inner), v) => {
self.validate_types(path, inner, v, errors)
}
(TypeRef::Enum(enum_name), Value::String(s)) => {
let enum_def = self
.get_enum(enum_name)
// If this is thrown, there's a problem in validate_type_ref.
.unwrap_or_else(|| {
unreachable!("Enum {enum_name} is not defined in the manifest")
});
let mut valid = HashSet::new();
for variant in enum_def.variants() {
let name = variant.name();
if *s == name {
return;
}
valid.insert(name);
}
let path = path.final_error_quoted(s);
errors.push(FeatureValidationError {
path,
kind: ErrorKind::invalid_value(type_ref),
});
}
(TypeRef::EnumMap(enum_type, map_type), Value::Object(map))
if matches!(**enum_type, TypeRef::Enum(_)) =>
{
let enum_name = enum_type.name().unwrap();
let enum_def = self
.get_enum(enum_name)
// If this is thrown, there's a problem in validate_type_ref.
.unwrap_or_else(|| {
unreachable!("Enum {enum_name} is not defined in the manifest")
});
// We first validate that the keys of the map cover all all the enum variants, and no more or less
let mut valid = HashSet::new();
for variant in &enum_def.variants {
let nm = &variant.name;
valid.insert(nm.clone());
let map_value = map.get(nm);
match (map_type.as_ref(), map_value) {
(TypeRef::Option(_), None) => (),
(_, Some(inner)) => {
self.validate_types(&path.enum_map_key(enum_name, nm), map_type, inner, errors);
}
_ => ()
}
}
for (map_key, map_value) in map {
if !valid.contains(map_key) {
let path = path.map_key(map_key);
errors.push(FeatureValidationError {
path,
kind: ErrorKind::invalid_key(enum_type, map),
});
}
self.validate_types(&path.enum_map_key(&enum_def.name, map_key), map_type, map_value, errors);
}
}
(TypeRef::EnumMap(_, map_type), Value::Object(map)) // Map<string-alias, T>
| (TypeRef::StringMap(map_type), Value::Object(map)) => {
for (key, value) in map {
self.validate_types(&path.map_key(key), map_type, value, errors);
}
}
(TypeRef::List(list_type), Value::Array(arr)) => {
for (index, value) in arr.iter().enumerate() {
self.validate_types(&path.array_index(index), list_type, value, errors);
}
}
(TypeRef::Object(obj_name), Value::Object(map)) => {
let obj_def = self
.get_object(obj_name)
// If this is thrown, there's a problem in validate_type_ref.
.unwrap_or_else(|| {
unreachable!("Object {obj_name} is not defined in the manifest")
});
self.validate_props_types(&path.object_value(obj_name), &obj_def.props, map, errors);
}
_ => {
let path = path.final_error_value(default);
errors.push(FeatureValidationError {
path,
kind: ErrorKind::type_mismatch(type_ref),
});
}
};
}