github.com/kaptinlin/jsonschema@v0.4.6/unevaluatedProperties.go (about) 1 package jsonschema 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // EvaluateUnevaluatedProperties checks if the unevaluated properties of the data object conform to the unevaluatedProperties schema specified in the schema. 9 // This is in accordance with the JSON Schema Draft 2020-12 specification which dictates that: 10 // - The value of "unevaluatedProperties" must be a valid JSON Schema. 11 // - This keyword's behavior is contingent on the annotations from "properties", "patternProperties", and "additionalProperties". 12 // - Validation applies only to properties that do not appear in the annotations resulting from the aforementioned keywords. 13 // - The validation succeeds if such properties conform to the "unevaluatedProperties" schema. 14 // - The annotations influence the evaluation order, meaning all related properties and applicators must be processed first. 15 // 16 // Reference: https://json-schema.org/draft/2020-12/json-schema-core#name-unevaluatedproperties 17 func evaluateUnevaluatedProperties(schema *Schema, data interface{}, evaluatedProps map[string]bool, _ map[int]bool, dynamicScope *DynamicScope) ([]*EvaluationResult, *EvaluationError) { 18 if schema.UnevaluatedProperties == nil { 19 return nil, nil // If "unevaluatedProperties" is not defined, all properties are considered evaluated. 20 } 21 22 invalid_properties := []string{} 23 results := []*EvaluationResult{} 24 25 object, ok := data.(map[string]interface{}) 26 if !ok { 27 return nil, nil // If data is not an object, then skip the unevaluatedProperties validation. 28 } 29 30 // Loop through all properties of the object to find unevaluated properties. 31 for propName, propValue := range object { 32 if _, evaluated := evaluatedProps[propName]; !evaluated { 33 // If property has not been evaluated, validate it against the "unevaluatedProperties" schema. 34 result, _, _ := schema.UnevaluatedProperties.evaluate(propValue, dynamicScope) 35 if result != nil { 36 //nolint:errcheck 37 result.SetEvaluationPath("/unevaluatedProperties"). 38 SetSchemaLocation(schema.GetSchemaLocation("/unevaluatedProperties")). 39 SetInstanceLocation(fmt.Sprintf("/%s", propName)) 40 41 results = append(results, result) 42 43 if !result.IsValid() { 44 invalid_properties = append(invalid_properties, propName) 45 } 46 } 47 evaluatedProps[propName] = true 48 } 49 } 50 51 if len(invalid_properties) == 1 { 52 return results, NewEvaluationError("properties", "unevaluated_property_mismatch", "Property {property} does not match the unevaluatedProperties 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("properties", "unevaluated_properties_mismatch", "Properties {properties} do not match the unevaluatedProperties schema", map[string]interface{}{ 61 "properties": strings.Join(quotedProperties, ", "), 62 }) 63 } 64 65 return results, nil 66 }