github.com/kaptinlin/jsonschema@v0.4.6/dependentSchemas.go (about) 1 package jsonschema 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // EvaluateDependentSchemas checks if the data conforms to dependent schemas specified in the 'dependentSchemas' attribute. 9 // According to the JSON Schema Draft 2020-12: 10 // - The "dependentSchemas" keyword's value must be an object, where each value is a valid JSON Schema. 11 // - This validation ensures that if a specific property is present in the instance, then the entire instance must validate against the associated schema. 12 // 13 // This function ensures that the instance meets the conditional constraints defined by the dependent schemas. 14 // If the instance fails to conform to any dependent schema when the associated property is present, it returns a EvaluationError. 15 // 16 // Reference: https://json-schema.org/draft/2020-12/json-schema-core#name-dependentschemas 17 func evaluateDependentSchemas(schema *Schema, instance interface{}, evaluatedProps map[string]bool, evaluatedItems map[int]bool, dynamicScope *DynamicScope) ([]*EvaluationResult, *EvaluationError) { 18 if len(schema.DependentSchemas) == 0 { 19 return nil, nil // No dependentSchemas constraints to validate against. 20 } 21 22 object, ok := instance.(map[string]interface{}) 23 if !ok { 24 return nil, nil // instance is not an object, dependentSchemas do not apply. 25 } 26 invalid_properties := []string{} 27 results := []*EvaluationResult{} 28 29 for propName, depSchema := range schema.DependentSchemas { 30 if _, exists := object[propName]; exists { 31 if depSchema != nil { 32 result, schemaEvaluatedProps, schemaEvaluatedItems := depSchema.evaluate(object, dynamicScope) 33 if result != nil { 34 //nolint:errcheck 35 result.SetEvaluationPath(fmt.Sprintf("/dependentSchemas/%s", propName)). 36 SetSchemaLocation(schema.GetSchemaLocation(fmt.Sprintf("/dependentSchemas/%s", propName))). 37 SetInstanceLocation(fmt.Sprintf("/%s", propName)) 38 } 39 40 if result.IsValid() { 41 // Merge maps only if dependent schema validation is successful 42 mergeStringMaps(evaluatedProps, schemaEvaluatedProps) 43 mergeIntMaps(evaluatedItems, schemaEvaluatedItems) 44 } else { 45 invalid_properties = append(invalid_properties, propName) 46 } 47 } 48 } 49 } 50 51 if len(invalid_properties) == 1 { 52 return results, NewEvaluationError("dependentSchemas", "dependent_schema_mismatch", "Property {property} does not match the dependent schema", map[string]interface{}{ 53 "property": fmt.Sprintf("'%s'", invalid_properties[0]), 54 }) 55 } else if len(invalid_properties) > 1 { 56 quotedProperties := make([]string, len(invalid_properties)) 57 for i, prop := range invalid_properties { 58 quotedProperties[i] = fmt.Sprintf("'%s'", prop) 59 } 60 return results, NewEvaluationError("dependentSchemas", "dependent_schemas_mismatch", "Properties {properties} do not match the dependent schemas", map[string]interface{}{ 61 "properties": strings.Join(quotedProperties, ", "), 62 }) 63 } 64 65 return results, nil 66 }