123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- package gojsonschema
- import (
- "bytes"
- "sync"
- "text/template"
- )
- var errorTemplates = errorTemplate{template.New("errors-new"), sync.RWMutex{}}
- // template.Template is not thread-safe for writing, so some locking is done
- // sync.RWMutex is used for efficiently locking when new templates are created
- type errorTemplate struct {
- *template.Template
- sync.RWMutex
- }
- type (
- // FalseError. ErrorDetails: -
- FalseError struct {
- ResultErrorFields
- }
- // RequiredError indicates that a required field is missing
- // ErrorDetails: property string
- RequiredError struct {
- ResultErrorFields
- }
- // InvalidTypeError indicates that a field has the incorrect type
- // ErrorDetails: expected, given
- InvalidTypeError struct {
- ResultErrorFields
- }
- // NumberAnyOfError is produced in case of a failing "anyOf" validation
- // ErrorDetails: -
- NumberAnyOfError struct {
- ResultErrorFields
- }
- // NumberOneOfError is produced in case of a failing "oneOf" validation
- // ErrorDetails: -
- NumberOneOfError struct {
- ResultErrorFields
- }
- // NumberAllOfError is produced in case of a failing "allOf" validation
- // ErrorDetails: -
- NumberAllOfError struct {
- ResultErrorFields
- }
- // NumberNotError is produced if a "not" validation failed
- // ErrorDetails: -
- NumberNotError struct {
- ResultErrorFields
- }
- // MissingDependencyError is produced in case of a "missing dependency" problem
- // ErrorDetails: dependency
- MissingDependencyError struct {
- ResultErrorFields
- }
- // InternalError indicates an internal error
- // ErrorDetails: error
- InternalError struct {
- ResultErrorFields
- }
- // ConstError indicates a const error
- // ErrorDetails: allowed
- ConstError struct {
- ResultErrorFields
- }
- // EnumError indicates an enum error
- // ErrorDetails: allowed
- EnumError struct {
- ResultErrorFields
- }
- // ArrayNoAdditionalItemsError is produced if additional items were found, but not allowed
- // ErrorDetails: -
- ArrayNoAdditionalItemsError struct {
- ResultErrorFields
- }
- // ArrayMinItemsError is produced if an array contains less items than the allowed minimum
- // ErrorDetails: min
- ArrayMinItemsError struct {
- ResultErrorFields
- }
- // ArrayMaxItemsError is produced if an array contains more items than the allowed maximum
- // ErrorDetails: max
- ArrayMaxItemsError struct {
- ResultErrorFields
- }
- // ItemsMustBeUniqueError is produced if an array requires unique items, but contains non-unique items
- // ErrorDetails: type, i, j
- ItemsMustBeUniqueError struct {
- ResultErrorFields
- }
- // ArrayContainsError is produced if an array contains invalid items
- // ErrorDetails:
- ArrayContainsError struct {
- ResultErrorFields
- }
- // ArrayMinPropertiesError is produced if an object contains less properties than the allowed minimum
- // ErrorDetails: min
- ArrayMinPropertiesError struct {
- ResultErrorFields
- }
- // ArrayMaxPropertiesError is produced if an object contains more properties than the allowed maximum
- // ErrorDetails: max
- ArrayMaxPropertiesError struct {
- ResultErrorFields
- }
- // AdditionalPropertyNotAllowedError is produced if an object has additional properties, but not allowed
- // ErrorDetails: property
- AdditionalPropertyNotAllowedError struct {
- ResultErrorFields
- }
- // InvalidPropertyPatternError is produced if an pattern was found
- // ErrorDetails: property, pattern
- InvalidPropertyPatternError struct {
- ResultErrorFields
- }
- // InvalidPropertyNameError is produced if an invalid-named property was found
- // ErrorDetails: property
- InvalidPropertyNameError struct {
- ResultErrorFields
- }
- // StringLengthGTEError is produced if a string is shorter than the minimum required length
- // ErrorDetails: min
- StringLengthGTEError struct {
- ResultErrorFields
- }
- // StringLengthLTEError is produced if a string is longer than the maximum allowed length
- // ErrorDetails: max
- StringLengthLTEError struct {
- ResultErrorFields
- }
- // DoesNotMatchPatternError is produced if a string does not match the defined pattern
- // ErrorDetails: pattern
- DoesNotMatchPatternError struct {
- ResultErrorFields
- }
- // DoesNotMatchFormatError is produced if a string does not match the defined format
- // ErrorDetails: format
- DoesNotMatchFormatError struct {
- ResultErrorFields
- }
- // MultipleOfError is produced if a number is not a multiple of the defined multipleOf
- // ErrorDetails: multiple
- MultipleOfError struct {
- ResultErrorFields
- }
- // NumberGTEError is produced if a number is lower than the allowed minimum
- // ErrorDetails: min
- NumberGTEError struct {
- ResultErrorFields
- }
- // NumberGTError is produced if a number is lower than, or equal to the specified minimum, and exclusiveMinimum is set
- // ErrorDetails: min
- NumberGTError struct {
- ResultErrorFields
- }
- // NumberLTEError is produced if a number is higher than the allowed maximum
- // ErrorDetails: max
- NumberLTEError struct {
- ResultErrorFields
- }
- // NumberLTError is produced if a number is higher than, or equal to the specified maximum, and exclusiveMaximum is set
- // ErrorDetails: max
- NumberLTError struct {
- ResultErrorFields
- }
- // ConditionThenError is produced if a condition's "then" validation is invalid
- // ErrorDetails: -
- ConditionThenError struct {
- ResultErrorFields
- }
- // ConditionElseError is produced if a condition's "else" condition is invalid
- // ErrorDetails: -
- ConditionElseError struct {
- ResultErrorFields
- }
- )
- // newError takes a ResultError type and sets the type, context, description, details, value, and field
- func newError(err ResultError, context *JsonContext, value interface{}, locale locale, details ErrorDetails) {
- var t string
- var d string
- switch err.(type) {
- case *FalseError:
- t = "false"
- d = locale.False()
- case *RequiredError:
- t = "required"
- d = locale.Required()
- case *InvalidTypeError:
- t = "invalid_type"
- d = locale.InvalidType()
- case *NumberAnyOfError:
- t = "number_any_of"
- d = locale.NumberAnyOf()
- case *NumberOneOfError:
- t = "number_one_of"
- d = locale.NumberOneOf()
- case *NumberAllOfError:
- t = "number_all_of"
- d = locale.NumberAllOf()
- case *NumberNotError:
- t = "number_not"
- d = locale.NumberNot()
- case *MissingDependencyError:
- t = "missing_dependency"
- d = locale.MissingDependency()
- case *InternalError:
- t = "internal"
- d = locale.Internal()
- case *ConstError:
- t = "const"
- d = locale.Const()
- case *EnumError:
- t = "enum"
- d = locale.Enum()
- case *ArrayNoAdditionalItemsError:
- t = "array_no_additional_items"
- d = locale.ArrayNoAdditionalItems()
- case *ArrayMinItemsError:
- t = "array_min_items"
- d = locale.ArrayMinItems()
- case *ArrayMaxItemsError:
- t = "array_max_items"
- d = locale.ArrayMaxItems()
- case *ItemsMustBeUniqueError:
- t = "unique"
- d = locale.Unique()
- case *ArrayContainsError:
- t = "contains"
- d = locale.ArrayContains()
- case *ArrayMinPropertiesError:
- t = "array_min_properties"
- d = locale.ArrayMinProperties()
- case *ArrayMaxPropertiesError:
- t = "array_max_properties"
- d = locale.ArrayMaxProperties()
- case *AdditionalPropertyNotAllowedError:
- t = "additional_property_not_allowed"
- d = locale.AdditionalPropertyNotAllowed()
- case *InvalidPropertyPatternError:
- t = "invalid_property_pattern"
- d = locale.InvalidPropertyPattern()
- case *InvalidPropertyNameError:
- t = "invalid_property_name"
- d = locale.InvalidPropertyName()
- case *StringLengthGTEError:
- t = "string_gte"
- d = locale.StringGTE()
- case *StringLengthLTEError:
- t = "string_lte"
- d = locale.StringLTE()
- case *DoesNotMatchPatternError:
- t = "pattern"
- d = locale.DoesNotMatchPattern()
- case *DoesNotMatchFormatError:
- t = "format"
- d = locale.DoesNotMatchFormat()
- case *MultipleOfError:
- t = "multiple_of"
- d = locale.MultipleOf()
- case *NumberGTEError:
- t = "number_gte"
- d = locale.NumberGTE()
- case *NumberGTError:
- t = "number_gt"
- d = locale.NumberGT()
- case *NumberLTEError:
- t = "number_lte"
- d = locale.NumberLTE()
- case *NumberLTError:
- t = "number_lt"
- d = locale.NumberLT()
- case *ConditionThenError:
- t = "condition_then"
- d = locale.ConditionThen()
- case *ConditionElseError:
- t = "condition_else"
- d = locale.ConditionElse()
- }
- err.SetType(t)
- err.SetContext(context)
- err.SetValue(value)
- err.SetDetails(details)
- err.SetDescriptionFormat(d)
- details["field"] = err.Field()
- if _, exists := details["context"]; !exists && context != nil {
- details["context"] = context.String()
- }
- err.SetDescription(formatErrorDescription(err.DescriptionFormat(), details))
- }
- // formatErrorDescription takes a string in the default text/template
- // format and converts it to a string with replacements. The fields come
- // from the ErrorDetails struct and vary for each type of error.
- func formatErrorDescription(s string, details ErrorDetails) string {
- var tpl *template.Template
- var descrAsBuffer bytes.Buffer
- var err error
- errorTemplates.RLock()
- tpl = errorTemplates.Lookup(s)
- errorTemplates.RUnlock()
- if tpl == nil {
- errorTemplates.Lock()
- tpl = errorTemplates.New(s)
- if ErrorTemplateFuncs != nil {
- tpl.Funcs(ErrorTemplateFuncs)
- }
- tpl, err = tpl.Parse(s)
- errorTemplates.Unlock()
- if err != nil {
- return err.Error()
- }
- }
- err = tpl.Execute(&descrAsBuffer, details)
- if err != nil {
- return err.Error()
- }
- return descrAsBuffer.String()
- }
|