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

     1  package jsonschema
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  // EvaluatePropertyNames checks if every property name in the object conforms to the schema specified by the propertyNames attribute.
     9  // According to the JSON Schema Draft 2020-12:
    10  //   - The "propertyNames" keyword must be a valid JSON Schema.
    11  //   - If the instance is an object, this keyword validates if every property name in the instance validates against the provided schema.
    12  //   - The property name that the schema is testing will always be a string.
    13  //   - Omitting this keyword has the same behavior as an empty schema.
    14  //
    15  // This method ensures that each property name in the object instance conforms to the constraints defined in the propertyNames schema.
    16  // If a property name does not conform, it returns a EvaluationError detailing the issue with that specific property name.
    17  //
    18  // Reference: https://json-schema.org/draft/2020-12/json-schema-core#name-propertynames
    19  func evaluatePropertyNames(schema *Schema, object map[string]interface{}, _ map[string]bool, _ map[int]bool, dynamicScope *DynamicScope) ([]*EvaluationResult, *EvaluationError) {
    20  	if schema.PropertyNames == nil {
    21  		// No propertyNames schema defined, equivalent to an empty schema, which means all property names are valid.
    22  		return nil, nil
    23  	}
    24  
    25  	invalid_properties := []string{}
    26  	results := []*EvaluationResult{}
    27  
    28  	if schema.PropertyNames != nil {
    29  		for propName := range object {
    30  			result, _, _ := schema.PropertyNames.evaluate(propName, dynamicScope)
    31  
    32  			if result != nil {
    33  				//nolint:errcheck
    34  				result.SetEvaluationPath(fmt.Sprintf("/propertyNames/%s", propName)).
    35  					SetSchemaLocation(schema.GetSchemaLocation(fmt.Sprintf("/propertyNames/%s", propName))).
    36  					SetInstanceLocation(fmt.Sprintf("/%s", propName))
    37  			}
    38  
    39  			results = append(results, result)
    40  
    41  			if !result.IsValid() {
    42  				invalid_properties = append(invalid_properties, propName)
    43  			}
    44  		}
    45  	}
    46  
    47  	if len(invalid_properties) == 1 {
    48  		return results, NewEvaluationError("propertyNames", "property_name_mismatch", "Property name {property} does not match the schema", map[string]interface{}{
    49  			"property": fmt.Sprintf("'%s'", invalid_properties[0]),
    50  		})
    51  	} else if len(invalid_properties) > 1 {
    52  		quotedProperties := make([]string, len(invalid_properties))
    53  		for i, prop := range invalid_properties {
    54  			quotedProperties[i] = fmt.Sprintf("'%s'", prop)
    55  		}
    56  		return results, NewEvaluationError("propertyNames", "property_names_mismatch", "Property names {properties} do not match the schema", map[string]interface{}{
    57  			"properties": strings.Join(quotedProperties, ", "),
    58  		})
    59  	}
    60  
    61  	return results, nil
    62  }