github.com/kaptinlin/jsonschema@v0.4.6/conditional.go (about)

     1  package jsonschema
     2  
     3  // EvaluateConditional evaluates the data against conditional subschemas defined by 'if', 'then', and 'else'.
     4  // According to the JSON Schema Draft 2020-12:
     5  //   - The "if" keyword specifies a subschema to conditionally validate data.
     6  //   - If data validates against the "if" subschema, "then" subschema must also validate the data if "then" is present.
     7  //   - If data does not validate against the "if" subschema, "else" subschema must validate the data if "else" is present.
     8  //   - This function ensures data conformity based on the provided conditional subschemaschema.
     9  //   - The function ignores "then" and "else" if "if" is not present.
    10  //
    11  // This function serves as a central feature for conditional logic application in JSON Schema validation.
    12  //
    13  // Reference: https://json-schema.org/draft/2020-12/json-schema-core#name-if
    14  func evaluateConditional(schema *Schema, instance interface{}, evaluatedProps map[string]bool, evaluatedItems map[int]bool, dynamicScope *DynamicScope) ([]*EvaluationResult, *EvaluationError) {
    15  	if schema.If == nil {
    16  		// If there's no 'if' condition defined, nothing to validate conditionally.
    17  		return nil, nil
    18  	}
    19  
    20  	// Evaluate the 'if' condition
    21  	ifResult, ifEvaluatedProps, ifEvaluatedItems := schema.If.evaluate(instance, dynamicScope)
    22  
    23  	results := []*EvaluationResult{}
    24  
    25  	if ifResult != nil {
    26  		//nolint:errcheck
    27  		ifResult.SetEvaluationPath("/if").
    28  			SetSchemaLocation(schema.GetSchemaLocation("/if")).
    29  			SetInstanceLocation("")
    30  
    31  		results = append(results, ifResult)
    32  
    33  		if ifResult.IsValid() {
    34  			// Merge maps only if 'if' condition is successfully validated
    35  			mergeStringMaps(evaluatedProps, ifEvaluatedProps)
    36  			mergeIntMaps(evaluatedItems, ifEvaluatedItems)
    37  
    38  			if schema.Then != nil {
    39  				thenResult, thenEvaluatedProps, thenEvaluatedItems := schema.Then.evaluate(instance, dynamicScope)
    40  
    41  				if thenResult != nil {
    42  					//nolint:errcheck
    43  					thenResult.SetEvaluationPath("/then").
    44  						SetSchemaLocation(schema.GetSchemaLocation("/then")).
    45  						SetInstanceLocation("")
    46  
    47  					results = append(results, thenResult)
    48  
    49  					if !thenResult.IsValid() {
    50  						return results, NewEvaluationError("then", "if_then_mismatch",
    51  							"Value meets the 'if' condition but does not match the 'then' schema")
    52  					} else {
    53  						// Merge maps only if 'then' condition is successfully validated
    54  						mergeStringMaps(evaluatedProps, thenEvaluatedProps)
    55  						mergeIntMaps(evaluatedItems, thenEvaluatedItems)
    56  					}
    57  				}
    58  			}
    59  		} else if schema.Else != nil {
    60  			elseResult, elseEvaluatedProps, elseEvaluatedItems := schema.Else.evaluate(instance, dynamicScope)
    61  			if elseResult != nil {
    62  				results = append(results, elseResult)
    63  
    64  				if !elseResult.IsValid() {
    65  					return results, NewEvaluationError("else", "if_else_mismatch",
    66  						"Value fails the 'if' condition and does not match the 'else' schema")
    67  				} else {
    68  					// Merge maps only if 'else' condition is successfully validated
    69  					mergeStringMaps(evaluatedProps, elseEvaluatedProps)
    70  					mergeIntMaps(evaluatedItems, elseEvaluatedItems)
    71  				}
    72  			}
    73  		}
    74  	}
    75  
    76  	return results, nil
    77  }