result.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // author xeipuuv
  15. // author-github https://github.com/xeipuuv
  16. // author-mail xeipuuv@gmail.com
  17. //
  18. // repository-name gojsonschema
  19. // repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
  20. //
  21. // description Result and ResultError implementations.
  22. //
  23. // created 01-01-2015
  24. package gojsonschema
  25. import (
  26. "fmt"
  27. "strings"
  28. )
  29. type (
  30. // ErrorDetails is a map of details specific to each error.
  31. // While the values will vary, every error will contain a "field" value
  32. ErrorDetails map[string]interface{}
  33. // ResultError is the interface that library errors must implement
  34. ResultError interface {
  35. // Field returns the field name without the root context
  36. // i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName
  37. Field() string
  38. // SetType sets the error-type
  39. SetType(string)
  40. // Type returns the error-type
  41. Type() string
  42. // SetContext sets the JSON-context for the error
  43. SetContext(*JsonContext)
  44. // Context returns the JSON-context of the error
  45. Context() *JsonContext
  46. // SetDescription sets a description for the error
  47. SetDescription(string)
  48. // Description returns the description of the error
  49. Description() string
  50. // SetDescriptionFormat sets the format for the description in the default text/template format
  51. SetDescriptionFormat(string)
  52. // DescriptionFormat returns the format for the description in the default text/template format
  53. DescriptionFormat() string
  54. // SetValue sets the value related to the error
  55. SetValue(interface{})
  56. // Value returns the value related to the error
  57. Value() interface{}
  58. // SetDetails sets the details specific to the error
  59. SetDetails(ErrorDetails)
  60. // Details returns details about the error
  61. Details() ErrorDetails
  62. // String returns a string representation of the error
  63. String() string
  64. }
  65. // ResultErrorFields holds the fields for each ResultError implementation.
  66. // ResultErrorFields implements the ResultError interface, so custom errors
  67. // can be defined by just embedding this type
  68. ResultErrorFields struct {
  69. errorType string // A string with the type of error (i.e. invalid_type)
  70. context *JsonContext // Tree like notation of the part that failed the validation. ex (root).a.b ...
  71. description string // A human readable error message
  72. descriptionFormat string // A format for human readable error message
  73. value interface{} // Value given by the JSON file that is the source of the error
  74. details ErrorDetails
  75. }
  76. // Result holds the result of a validation
  77. Result struct {
  78. errors []ResultError
  79. // Scores how well the validation matched. Useful in generating
  80. // better error messages for anyOf and oneOf.
  81. score int
  82. }
  83. )
  84. // Field returns the field name without the root context
  85. // i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName
  86. func (v *ResultErrorFields) Field() string {
  87. return strings.TrimPrefix(v.context.String(), STRING_ROOT_SCHEMA_PROPERTY+".")
  88. }
  89. // SetType sets the error-type
  90. func (v *ResultErrorFields) SetType(errorType string) {
  91. v.errorType = errorType
  92. }
  93. // Type returns the error-type
  94. func (v *ResultErrorFields) Type() string {
  95. return v.errorType
  96. }
  97. // SetContext sets the JSON-context for the error
  98. func (v *ResultErrorFields) SetContext(context *JsonContext) {
  99. v.context = context
  100. }
  101. // Context returns the JSON-context of the error
  102. func (v *ResultErrorFields) Context() *JsonContext {
  103. return v.context
  104. }
  105. // SetDescription sets a description for the error
  106. func (v *ResultErrorFields) SetDescription(description string) {
  107. v.description = description
  108. }
  109. // Description returns the description of the error
  110. func (v *ResultErrorFields) Description() string {
  111. return v.description
  112. }
  113. // SetDescriptionFormat sets the format for the description in the default text/template format
  114. func (v *ResultErrorFields) SetDescriptionFormat(descriptionFormat string) {
  115. v.descriptionFormat = descriptionFormat
  116. }
  117. // DescriptionFormat returns the format for the description in the default text/template format
  118. func (v *ResultErrorFields) DescriptionFormat() string {
  119. return v.descriptionFormat
  120. }
  121. // SetValue sets the value related to the error
  122. func (v *ResultErrorFields) SetValue(value interface{}) {
  123. v.value = value
  124. }
  125. // Value returns the value related to the error
  126. func (v *ResultErrorFields) Value() interface{} {
  127. return v.value
  128. }
  129. // SetDetails sets the details specific to the error
  130. func (v *ResultErrorFields) SetDetails(details ErrorDetails) {
  131. v.details = details
  132. }
  133. // Details returns details about the error
  134. func (v *ResultErrorFields) Details() ErrorDetails {
  135. return v.details
  136. }
  137. // String returns a string representation of the error
  138. func (v ResultErrorFields) String() string {
  139. // as a fallback, the value is displayed go style
  140. valueString := fmt.Sprintf("%v", v.value)
  141. // marshal the go value value to json
  142. if v.value == nil {
  143. valueString = TYPE_NULL
  144. } else {
  145. if vs, err := marshalToJSONString(v.value); err == nil {
  146. if vs == nil {
  147. valueString = TYPE_NULL
  148. } else {
  149. valueString = *vs
  150. }
  151. }
  152. }
  153. return formatErrorDescription(Locale.ErrorFormat(), ErrorDetails{
  154. "context": v.context.String(),
  155. "description": v.description,
  156. "value": valueString,
  157. "field": v.Field(),
  158. })
  159. }
  160. // Valid indicates if no errors were found
  161. func (v *Result) Valid() bool {
  162. return len(v.errors) == 0
  163. }
  164. // Errors returns the errors that were found
  165. func (v *Result) Errors() []ResultError {
  166. return v.errors
  167. }
  168. // AddError appends a fully filled error to the error set
  169. // SetDescription() will be called with the result of the parsed err.DescriptionFormat()
  170. func (v *Result) AddError(err ResultError, details ErrorDetails) {
  171. if _, exists := details["context"]; !exists && err.Context() != nil {
  172. details["context"] = err.Context().String()
  173. }
  174. err.SetDescription(formatErrorDescription(err.DescriptionFormat(), details))
  175. v.errors = append(v.errors, err)
  176. }
  177. func (v *Result) addInternalError(err ResultError, context *JsonContext, value interface{}, details ErrorDetails) {
  178. newError(err, context, value, Locale, details)
  179. v.errors = append(v.errors, err)
  180. v.score -= 2 // results in a net -1 when added to the +1 we get at the end of the validation function
  181. }
  182. // Used to copy errors from a sub-schema to the main one
  183. func (v *Result) mergeErrors(otherResult *Result) {
  184. v.errors = append(v.errors, otherResult.Errors()...)
  185. v.score += otherResult.score
  186. }
  187. func (v *Result) incrementScore() {
  188. v.score++
  189. }