fn validate_string_aliases()

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),
                            });
                        }
                    }
                }
            }
            _ => {}
        }
    }