github.com/kaptinlin/jsonschema@v0.4.6/format.go (about) 1 package jsonschema 2 3 // EvaluateFormat checks if the data conforms to the format specified in the schema. 4 // According to the JSON Schema Draft 2020-12: 5 // - The "format" keyword defines the data format expected for a value. 6 // - The format must be a string that names a specific format which the value should conform to. 7 // - The function uses custom formats first, then falls back to the global `Formats` map. 8 // - If the format is not supported or not found, it may fall back to a no-op validation depending on configuration. 9 // 10 // This method ensures that data matches the expected format as specified in the schema. 11 // It handles formats as annotations by default, but can assert format validation if configured. 12 // 13 // Reference: https://json-schema.org/draft/2020-12/json-schema-validation#name-format 14 func evaluateFormat(schema *Schema, value interface{}) *EvaluationError { 15 if schema.Format == nil { 16 return nil 17 } 18 19 formatName := *schema.Format 20 var formatDef *FormatDef 21 var customValidator func(interface{}) bool 22 23 // 1. Check compiler-specific custom formats first 24 if schema.compiler != nil { 25 schema.compiler.customFormatsRW.RLock() 26 formatDef = schema.compiler.customFormats[formatName] 27 schema.compiler.customFormatsRW.RUnlock() 28 } 29 30 if formatDef != nil { 31 // Found in custom formats 32 if formatDef.Type != "" { 33 valueType := getDataType(value) 34 if !matchesType(valueType, formatDef.Type) { 35 return nil // Type doesn't match, so skip validation 36 } 37 } 38 customValidator = formatDef.Validate 39 } else if globalValidator, ok := Formats[formatName]; ok { 40 // Fallback to global formats 41 customValidator = globalValidator 42 } 43 44 // If a validator was found (either custom or global) 45 if customValidator != nil { 46 if !customValidator(value) { 47 if schema.compiler != nil && schema.compiler.AssertFormat { 48 return NewEvaluationError("format", "format_mismatch", "Value does not match format '{format}'", map[string]interface{}{"format": formatName}) 49 } 50 } 51 return nil // Validation passed or not asserted 52 } 53 54 // If no validator was found and AssertFormat is true, fail 55 if schema.compiler != nil && schema.compiler.AssertFormat { 56 return NewEvaluationError("format", "unknown_format", "Unknown format '{format}'", map[string]interface{}{"format": formatName}) 57 } 58 59 return nil // Default behavior: ignore unknown formats 60 } 61 62 // matchesType checks if a value type matches the required type 63 func matchesType(valueType, requiredType string) bool { 64 if requiredType == "" { 65 return true // No type restriction 66 } 67 68 // Special handling: integer is also considered number 69 if requiredType == "number" && valueType == "integer" { 70 return true 71 } 72 73 return valueType == requiredType 74 }