aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/xeipuuv/gojsonschema
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/xeipuuv/gojsonschema')
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt202
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/README.md294
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/errors.go283
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/format_checkers.go250
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/internalLog.go37
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/jsonContext.go72
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go341
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/locales.go286
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/result.go172
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/schema.go928
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/schemaPool.go109
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go67
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/schemaType.go83
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/subSchema.go227
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/types.go58
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/utils.go208
-rw-r--r--vendor/github.com/xeipuuv/gojsonschema/validation.go844
17 files changed, 4461 insertions, 0 deletions
diff --git a/vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt b/vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt
new file mode 100644
index 000000000..55ede8a42
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2015 xeipuuv
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/xeipuuv/gojsonschema/README.md b/vendor/github.com/xeipuuv/gojsonschema/README.md
new file mode 100644
index 000000000..e02976bc6
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/README.md
@@ -0,0 +1,294 @@
+[![Build Status](https://travis-ci.org/xeipuuv/gojsonschema.svg)](https://travis-ci.org/xeipuuv/gojsonschema)
+
+# gojsonschema
+
+## Description
+
+An implementation of JSON Schema, based on IETF's draft v4 - Go language
+
+References :
+
+* http://json-schema.org
+* http://json-schema.org/latest/json-schema-core.html
+* http://json-schema.org/latest/json-schema-validation.html
+
+## Installation
+
+```
+go get github.com/xeipuuv/gojsonschema
+```
+
+Dependencies :
+* [github.com/xeipuuv/gojsonpointer](https://github.com/xeipuuv/gojsonpointer)
+* [github.com/xeipuuv/gojsonreference](https://github.com/xeipuuv/gojsonreference)
+* [github.com/stretchr/testify/assert](https://github.com/stretchr/testify#assert-package)
+
+## Usage
+
+### Example
+
+```go
+
+package main
+
+import (
+ "fmt"
+ "github.com/xeipuuv/gojsonschema"
+)
+
+func main() {
+
+ schemaLoader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json")
+ documentLoader := gojsonschema.NewReferenceLoader("file:///home/me/document.json")
+
+ result, err := gojsonschema.Validate(schemaLoader, documentLoader)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ if result.Valid() {
+ fmt.Printf("The document is valid\n")
+ } else {
+ fmt.Printf("The document is not valid. see errors :\n")
+ for _, desc := range result.Errors() {
+ fmt.Printf("- %s\n", desc)
+ }
+ }
+
+}
+
+
+```
+
+#### Loaders
+
+There are various ways to load your JSON data.
+In order to load your schemas and documents,
+first declare an appropriate loader :
+
+* Web / HTTP, using a reference :
+
+```go
+loader := gojsonschema.NewReferenceLoader("http://www.some_host.com/schema.json")
+```
+
+* Local file, using a reference :
+
+```go
+loader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json")
+```
+
+References use the URI scheme, the prefix (file://) and a full path to the file are required.
+
+* JSON strings :
+
+```go
+loader := gojsonschema.NewStringLoader(`{"type": "string"}`)
+```
+
+* Custom Go types :
+
+```go
+m := map[string]interface{}{"type": "string"}
+loader := gojsonschema.NewGoLoader(m)
+```
+
+And
+
+```go
+type Root struct {
+ Users []User `json:"users"`
+}
+
+type User struct {
+ Name string `json:"name"`
+}
+
+...
+
+data := Root{}
+data.Users = append(data.Users, User{"John"})
+data.Users = append(data.Users, User{"Sophia"})
+data.Users = append(data.Users, User{"Bill"})
+
+loader := gojsonschema.NewGoLoader(data)
+```
+
+#### Validation
+
+Once the loaders are set, validation is easy :
+
+```go
+result, err := gojsonschema.Validate(schemaLoader, documentLoader)
+```
+
+Alternatively, you might want to load a schema only once and process to multiple validations :
+
+```go
+schema, err := gojsonschema.NewSchema(schemaLoader)
+...
+result1, err := schema.Validate(documentLoader1)
+...
+result2, err := schema.Validate(documentLoader2)
+...
+// etc ...
+```
+
+To check the result :
+
+```go
+ if result.Valid() {
+ fmt.Printf("The document is valid\n")
+ } else {
+ fmt.Printf("The document is not valid. see errors :\n")
+ for _, err := range result.Errors() {
+ // Err implements the ResultError interface
+ fmt.Printf("- %s\n", err)
+ }
+ }
+```
+
+## Working with Errors
+
+The library handles string error codes which you can customize by creating your own gojsonschema.locale and setting it
+```go
+gojsonschema.Locale = YourCustomLocale{}
+```
+
+However, each error contains additional contextual information.
+
+**err.Type()**: *string* Returns the "type" of error that occurred. Note you can also type check. See below
+
+Note: An error of RequiredType has an err.Type() return value of "required"
+
+ "required": RequiredError
+ "invalid_type": InvalidTypeError
+ "number_any_of": NumberAnyOfError
+ "number_one_of": NumberOneOfError
+ "number_all_of": NumberAllOfError
+ "number_not": NumberNotError
+ "missing_dependency": MissingDependencyError
+ "internal": InternalError
+ "enum": EnumError
+ "array_no_additional_items": ArrayNoAdditionalItemsError
+ "array_min_items": ArrayMinItemsError
+ "array_max_items": ArrayMaxItemsError
+ "unique": ItemsMustBeUniqueError
+ "array_min_properties": ArrayMinPropertiesError
+ "array_max_properties": ArrayMaxPropertiesError
+ "additional_property_not_allowed": AdditionalPropertyNotAllowedError
+ "invalid_property_pattern": InvalidPropertyPatternError
+ "string_gte": StringLengthGTEError
+ "string_lte": StringLengthLTEError
+ "pattern": DoesNotMatchPatternError
+ "multiple_of": MultipleOfError
+ "number_gte": NumberGTEError
+ "number_gt": NumberGTError
+ "number_lte": NumberLTEError
+ "number_lt": NumberLTError
+
+**err.Value()**: *interface{}* Returns the value given
+
+**err.Context()**: *gojsonschema.jsonContext* Returns the context. This has a String() method that will print something like this: (root).firstName
+
+**err.Field()**: *string* Returns the fieldname in the format firstName, or for embedded properties, person.firstName. This returns the same as the String() method on *err.Context()* but removes the (root). prefix.
+
+**err.Description()**: *string* The error description. This is based on the locale you are using. See the beginning of this section for overwriting the locale with a custom implementation.
+
+**err.Details()**: *gojsonschema.ErrorDetails* Returns a map[string]interface{} of additional error details specific to the error. For example, GTE errors will have a "min" value, LTE will have a "max" value. See errors.go for a full description of all the error details. Every error always contains a "field" key that holds the value of *err.Field()*
+
+Note in most cases, the err.Details() will be used to generate replacement strings in your locales, and not used directly. These strings follow the text/template format i.e.
+```
+{{.field}} must be greater than or equal to {{.min}}
+```
+
+The library allows you to specify custom template functions, should you require more complex error message handling.
+```go
+gojsonschema.ErrorTemplateFuncs = map[string]interface{}{
+ "allcaps": func(s string) string {
+ return strings.ToUpper(s)
+ },
+}
+```
+
+Given the above definition, you can use the custom function `"allcaps"` in your localization templates:
+```
+{{allcaps .field}} must be greater than or equal to {{.min}}
+```
+
+The above error message would then be rendered with the `field` value in capital letters. For example:
+```
+"PASSWORD must be greater than or equal to 8"
+```
+
+Learn more about what types of template functions you can use in `ErrorTemplateFuncs` by referring to Go's [text/template FuncMap](https://golang.org/pkg/text/template/#FuncMap) type.
+
+## Formats
+JSON Schema allows for optional "format" property to validate instances against well-known formats. gojsonschema ships with all of the formats defined in the spec that you can use like this:
+````json
+{"type": "string", "format": "email"}
+````
+Available formats: date-time, hostname, email, ipv4, ipv6, uri, uri-reference.
+
+For repetitive or more complex formats, you can create custom format checkers and add them to gojsonschema like this:
+
+```go
+// Define the format checker
+type RoleFormatChecker struct {}
+
+// Ensure it meets the gojsonschema.FormatChecker interface
+func (f RoleFormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ return strings.HasPrefix("ROLE_", asString)
+}
+
+// Add it to the library
+gojsonschema.FormatCheckers.Add("role", RoleFormatChecker{})
+````
+
+Now to use in your json schema:
+````json
+{"type": "string", "format": "role"}
+````
+
+Another example would be to check if the provided integer matches an id on database:
+
+JSON schema:
+```json
+{"type": "integer", "format": "ValidUserId"}
+```
+
+```go
+// Define the format checker
+type ValidUserIdFormatChecker struct {}
+
+// Ensure it meets the gojsonschema.FormatChecker interface
+func (f ValidUserIdFormatChecker) IsFormat(input interface{}) bool {
+
+ asFloat64, ok := input.(float64) // Numbers are always float64 here
+ if ok == false {
+ return false
+ }
+
+ // XXX
+ // do the magic on the database looking for the int(asFloat64)
+
+ return true
+}
+
+// Add it to the library
+gojsonschema.FormatCheckers.Add("ValidUserId", ValidUserIdFormatChecker{})
+````
+
+
+
+## Uses
+
+gojsonschema uses the following test suite :
+
+https://github.com/json-schema/JSON-Schema-Test-Suite
diff --git a/vendor/github.com/xeipuuv/gojsonschema/errors.go b/vendor/github.com/xeipuuv/gojsonschema/errors.go
new file mode 100644
index 000000000..d39f01959
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/errors.go
@@ -0,0 +1,283 @@
+package gojsonschema
+
+import (
+ "bytes"
+ "sync"
+ "text/template"
+)
+
+var errorTemplates errorTemplate = 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 (
+ // RequiredError. ErrorDetails: property string
+ RequiredError struct {
+ ResultErrorFields
+ }
+
+ // InvalidTypeError. ErrorDetails: expected, given
+ InvalidTypeError struct {
+ ResultErrorFields
+ }
+
+ // NumberAnyOfError. ErrorDetails: -
+ NumberAnyOfError struct {
+ ResultErrorFields
+ }
+
+ // NumberOneOfError. ErrorDetails: -
+ NumberOneOfError struct {
+ ResultErrorFields
+ }
+
+ // NumberAllOfError. ErrorDetails: -
+ NumberAllOfError struct {
+ ResultErrorFields
+ }
+
+ // NumberNotError. ErrorDetails: -
+ NumberNotError struct {
+ ResultErrorFields
+ }
+
+ // MissingDependencyError. ErrorDetails: dependency
+ MissingDependencyError struct {
+ ResultErrorFields
+ }
+
+ // InternalError. ErrorDetails: error
+ InternalError struct {
+ ResultErrorFields
+ }
+
+ // EnumError. ErrorDetails: allowed
+ EnumError struct {
+ ResultErrorFields
+ }
+
+ // ArrayNoAdditionalItemsError. ErrorDetails: -
+ ArrayNoAdditionalItemsError struct {
+ ResultErrorFields
+ }
+
+ // ArrayMinItemsError. ErrorDetails: min
+ ArrayMinItemsError struct {
+ ResultErrorFields
+ }
+
+ // ArrayMaxItemsError. ErrorDetails: max
+ ArrayMaxItemsError struct {
+ ResultErrorFields
+ }
+
+ // ItemsMustBeUniqueError. ErrorDetails: type
+ ItemsMustBeUniqueError struct {
+ ResultErrorFields
+ }
+
+ // ArrayMinPropertiesError. ErrorDetails: min
+ ArrayMinPropertiesError struct {
+ ResultErrorFields
+ }
+
+ // ArrayMaxPropertiesError. ErrorDetails: max
+ ArrayMaxPropertiesError struct {
+ ResultErrorFields
+ }
+
+ // AdditionalPropertyNotAllowedError. ErrorDetails: property
+ AdditionalPropertyNotAllowedError struct {
+ ResultErrorFields
+ }
+
+ // InvalidPropertyPatternError. ErrorDetails: property, pattern
+ InvalidPropertyPatternError struct {
+ ResultErrorFields
+ }
+
+ // StringLengthGTEError. ErrorDetails: min
+ StringLengthGTEError struct {
+ ResultErrorFields
+ }
+
+ // StringLengthLTEError. ErrorDetails: max
+ StringLengthLTEError struct {
+ ResultErrorFields
+ }
+
+ // DoesNotMatchPatternError. ErrorDetails: pattern
+ DoesNotMatchPatternError struct {
+ ResultErrorFields
+ }
+
+ // DoesNotMatchFormatError. ErrorDetails: format
+ DoesNotMatchFormatError struct {
+ ResultErrorFields
+ }
+
+ // MultipleOfError. ErrorDetails: multiple
+ MultipleOfError struct {
+ ResultErrorFields
+ }
+
+ // NumberGTEError. ErrorDetails: min
+ NumberGTEError struct {
+ ResultErrorFields
+ }
+
+ // NumberGTError. ErrorDetails: min
+ NumberGTError struct {
+ ResultErrorFields
+ }
+
+ // NumberLTEError. ErrorDetails: max
+ NumberLTEError struct {
+ ResultErrorFields
+ }
+
+ // NumberLTError. ErrorDetails: max
+ NumberLTError 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 *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 *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 *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 *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()
+ }
+
+ err.SetType(t)
+ err.SetContext(context)
+ err.SetValue(value)
+ err.SetDetails(details)
+ details["field"] = err.Field()
+
+ if _, exists := details["context"]; !exists && context != nil {
+ details["context"] = context.String()
+ }
+
+ err.SetDescription(formatErrorDescription(d, 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()
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/format_checkers.go b/vendor/github.com/xeipuuv/gojsonschema/format_checkers.go
new file mode 100644
index 000000000..c6a07923b
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/format_checkers.go
@@ -0,0 +1,250 @@
+package gojsonschema
+
+import (
+ "net"
+ "net/url"
+ "regexp"
+ "strings"
+ "time"
+)
+
+type (
+ // FormatChecker is the interface all formatters added to FormatCheckerChain must implement
+ FormatChecker interface {
+ IsFormat(input interface{}) bool
+ }
+
+ // FormatCheckerChain holds the formatters
+ FormatCheckerChain struct {
+ formatters map[string]FormatChecker
+ }
+
+ // EmailFormatter verifies email address formats
+ EmailFormatChecker struct{}
+
+ // IPV4FormatChecker verifies IP addresses in the ipv4 format
+ IPV4FormatChecker struct{}
+
+ // IPV6FormatChecker verifies IP addresses in the ipv6 format
+ IPV6FormatChecker struct{}
+
+ // DateTimeFormatChecker verifies date/time formats per RFC3339 5.6
+ //
+ // Valid formats:
+ // Partial Time: HH:MM:SS
+ // Full Date: YYYY-MM-DD
+ // Full Time: HH:MM:SSZ-07:00
+ // Date Time: YYYY-MM-DDTHH:MM:SSZ-0700
+ //
+ // Where
+ // YYYY = 4DIGIT year
+ // MM = 2DIGIT month ; 01-12
+ // DD = 2DIGIT day-month ; 01-28, 01-29, 01-30, 01-31 based on month/year
+ // HH = 2DIGIT hour ; 00-23
+ // MM = 2DIGIT ; 00-59
+ // SS = 2DIGIT ; 00-58, 00-60 based on leap second rules
+ // T = Literal
+ // Z = Literal
+ //
+ // Note: Nanoseconds are also suported in all formats
+ //
+ // http://tools.ietf.org/html/rfc3339#section-5.6
+ DateTimeFormatChecker struct{}
+
+ // URIFormatChecker validates a URI with a valid Scheme per RFC3986
+ URIFormatChecker struct{}
+
+ // URIReferenceFormatChecker validates a URI or relative-reference per RFC3986
+ URIReferenceFormatChecker struct{}
+
+ // HostnameFormatChecker validates a hostname is in the correct format
+ HostnameFormatChecker struct{}
+
+ // UUIDFormatChecker validates a UUID is in the correct format
+ UUIDFormatChecker struct{}
+
+ // RegexFormatChecker validates a regex is in the correct format
+ RegexFormatChecker struct{}
+)
+
+var (
+ // Formatters holds the valid formatters, and is a public variable
+ // so library users can add custom formatters
+ FormatCheckers = FormatCheckerChain{
+ formatters: map[string]FormatChecker{
+ "date-time": DateTimeFormatChecker{},
+ "hostname": HostnameFormatChecker{},
+ "email": EmailFormatChecker{},
+ "ipv4": IPV4FormatChecker{},
+ "ipv6": IPV6FormatChecker{},
+ "uri": URIFormatChecker{},
+ "uri-reference": URIReferenceFormatChecker{},
+ "uuid": UUIDFormatChecker{},
+ "regex": RegexFormatChecker{},
+ },
+ }
+
+ // Regex credit: https://github.com/asaskevich/govalidator
+ rxEmail = regexp.MustCompile("^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$")
+
+ // Regex credit: https://www.socketloop.com/tutorials/golang-validate-hostname
+ rxHostname = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`)
+
+ rxUUID = regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")
+)
+
+// Add adds a FormatChecker to the FormatCheckerChain
+// The name used will be the value used for the format key in your json schema
+func (c *FormatCheckerChain) Add(name string, f FormatChecker) *FormatCheckerChain {
+ c.formatters[name] = f
+
+ return c
+}
+
+// Remove deletes a FormatChecker from the FormatCheckerChain (if it exists)
+func (c *FormatCheckerChain) Remove(name string) *FormatCheckerChain {
+ delete(c.formatters, name)
+
+ return c
+}
+
+// Has checks to see if the FormatCheckerChain holds a FormatChecker with the given name
+func (c *FormatCheckerChain) Has(name string) bool {
+ _, ok := c.formatters[name]
+
+ return ok
+}
+
+// IsFormat will check an input against a FormatChecker with the given name
+// to see if it is the correct format
+func (c *FormatCheckerChain) IsFormat(name string, input interface{}) bool {
+ f, ok := c.formatters[name]
+
+ if !ok {
+ return false
+ }
+
+ return f.IsFormat(input)
+}
+
+func (f EmailFormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ return rxEmail.MatchString(asString)
+}
+
+// Credit: https://github.com/asaskevich/govalidator
+func (f IPV4FormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ ip := net.ParseIP(asString)
+ return ip != nil && strings.Contains(asString, ".")
+}
+
+// Credit: https://github.com/asaskevich/govalidator
+func (f IPV6FormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ ip := net.ParseIP(asString)
+ return ip != nil && strings.Contains(asString, ":")
+}
+
+func (f DateTimeFormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ formats := []string{
+ "15:04:05",
+ "15:04:05Z07:00",
+ "2006-01-02",
+ time.RFC3339,
+ time.RFC3339Nano,
+ }
+
+ for _, format := range formats {
+ if _, err := time.Parse(format, asString); err == nil {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (f URIFormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ u, err := url.Parse(asString)
+ if err != nil || u.Scheme == "" {
+ return false
+ }
+
+ return true
+}
+
+func (f URIReferenceFormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ _, err := url.Parse(asString)
+ return err == nil
+}
+
+func (f HostnameFormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ return rxHostname.MatchString(asString) && len(asString) < 256
+}
+
+func (f UUIDFormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ return rxUUID.MatchString(asString)
+}
+
+// IsFormat implements FormatChecker interface.
+func (f RegexFormatChecker) IsFormat(input interface{}) bool {
+
+ asString, ok := input.(string)
+ if ok == false {
+ return false
+ }
+
+ if asString == "" {
+ return true
+ }
+ _, err := regexp.Compile(asString)
+ if err != nil {
+ return false
+ }
+ return true
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/internalLog.go b/vendor/github.com/xeipuuv/gojsonschema/internalLog.go
new file mode 100644
index 000000000..4ef7a8d03
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/internalLog.go
@@ -0,0 +1,37 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Very simple log wrapper.
+// Used for debugging/testing purposes.
+//
+// created 01-01-2015
+
+package gojsonschema
+
+import (
+ "log"
+)
+
+const internalLogEnabled = false
+
+func internalLog(format string, v ...interface{}) {
+ log.Printf(format, v...)
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/jsonContext.go b/vendor/github.com/xeipuuv/gojsonschema/jsonContext.go
new file mode 100644
index 000000000..fcc8d9d6f
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/jsonContext.go
@@ -0,0 +1,72 @@
+// Copyright 2013 MongoDB, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author tolsen
+// author-github https://github.com/tolsen
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Implements a persistent (immutable w/ shared structure) singly-linked list of strings for the purpose of storing a json context
+//
+// created 04-09-2013
+
+package gojsonschema
+
+import "bytes"
+
+// jsonContext implements a persistent linked-list of strings
+type jsonContext struct {
+ head string
+ tail *jsonContext
+}
+
+func newJsonContext(head string, tail *jsonContext) *jsonContext {
+ return &jsonContext{head, tail}
+}
+
+// String displays the context in reverse.
+// This plays well with the data structure's persistent nature with
+// Cons and a json document's tree structure.
+func (c *jsonContext) String(del ...string) string {
+ byteArr := make([]byte, 0, c.stringLen())
+ buf := bytes.NewBuffer(byteArr)
+ c.writeStringToBuffer(buf, del)
+
+ return buf.String()
+}
+
+func (c *jsonContext) stringLen() int {
+ length := 0
+ if c.tail != nil {
+ length = c.tail.stringLen() + 1 // add 1 for "."
+ }
+
+ length += len(c.head)
+ return length
+}
+
+func (c *jsonContext) writeStringToBuffer(buf *bytes.Buffer, del []string) {
+ if c.tail != nil {
+ c.tail.writeStringToBuffer(buf, del)
+
+ if len(del) > 0 {
+ buf.WriteString(del[0])
+ } else {
+ buf.WriteString(".")
+ }
+ }
+
+ buf.WriteString(c.head)
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go b/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go
new file mode 100644
index 000000000..a77a81e40
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go
@@ -0,0 +1,341 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Different strategies to load JSON files.
+// Includes References (file and HTTP), JSON strings and Go types.
+//
+// created 01-02-2015
+
+package gojsonschema
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+
+ "github.com/xeipuuv/gojsonreference"
+)
+
+var osFS = osFileSystem(os.Open)
+
+// JSON loader interface
+
+type JSONLoader interface {
+ JsonSource() interface{}
+ LoadJSON() (interface{}, error)
+ JsonReference() (gojsonreference.JsonReference, error)
+ LoaderFactory() JSONLoaderFactory
+}
+
+type JSONLoaderFactory interface {
+ New(source string) JSONLoader
+}
+
+type DefaultJSONLoaderFactory struct {
+}
+
+type FileSystemJSONLoaderFactory struct {
+ fs http.FileSystem
+}
+
+func (d DefaultJSONLoaderFactory) New(source string) JSONLoader {
+ return &jsonReferenceLoader{
+ fs: osFS,
+ source: source,
+ }
+}
+
+func (f FileSystemJSONLoaderFactory) New(source string) JSONLoader {
+ return &jsonReferenceLoader{
+ fs: f.fs,
+ source: source,
+ }
+}
+
+// osFileSystem is a functional wrapper for os.Open that implements http.FileSystem.
+type osFileSystem func(string) (*os.File, error)
+
+func (o osFileSystem) Open(name string) (http.File, error) {
+ return o(name)
+}
+
+// JSON Reference loader
+// references are used to load JSONs from files and HTTP
+
+type jsonReferenceLoader struct {
+ fs http.FileSystem
+ source string
+}
+
+func (l *jsonReferenceLoader) JsonSource() interface{} {
+ return l.source
+}
+
+func (l *jsonReferenceLoader) JsonReference() (gojsonreference.JsonReference, error) {
+ return gojsonreference.NewJsonReference(l.JsonSource().(string))
+}
+
+func (l *jsonReferenceLoader) LoaderFactory() JSONLoaderFactory {
+ return &FileSystemJSONLoaderFactory{
+ fs: l.fs,
+ }
+}
+
+// NewReferenceLoader returns a JSON reference loader using the given source and the local OS file system.
+func NewReferenceLoader(source string) *jsonReferenceLoader {
+ return &jsonReferenceLoader{
+ fs: osFS,
+ source: source,
+ }
+}
+
+// NewReferenceLoaderFileSystem returns a JSON reference loader using the given source and file system.
+func NewReferenceLoaderFileSystem(source string, fs http.FileSystem) *jsonReferenceLoader {
+ return &jsonReferenceLoader{
+ fs: fs,
+ source: source,
+ }
+}
+
+func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
+
+ var err error
+
+ reference, err := gojsonreference.NewJsonReference(l.JsonSource().(string))
+ if err != nil {
+ return nil, err
+ }
+
+ refToUrl := reference
+ refToUrl.GetUrl().Fragment = ""
+
+ var document interface{}
+
+ if reference.HasFileScheme {
+
+ filename := strings.Replace(refToUrl.GetUrl().Path, "file://", "", -1)
+ if runtime.GOOS == "windows" {
+ // on Windows, a file URL may have an extra leading slash, use slashes
+ // instead of backslashes, and have spaces escaped
+ if strings.HasPrefix(filename, "/") {
+ filename = filename[1:]
+ }
+ filename = filepath.FromSlash(filename)
+ }
+
+ document, err = l.loadFromFile(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ } else {
+
+ document, err = l.loadFromHTTP(refToUrl.String())
+ if err != nil {
+ return nil, err
+ }
+
+ }
+
+ return document, nil
+
+}
+
+func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) {
+
+ resp, err := http.Get(address)
+ if err != nil {
+ return nil, err
+ }
+
+ // must return HTTP Status 200 OK
+ if resp.StatusCode != http.StatusOK {
+ return nil, errors.New(formatErrorDescription(Locale.HttpBadStatus(), ErrorDetails{"status": resp.Status}))
+ }
+
+ bodyBuff, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ return decodeJsonUsingNumber(bytes.NewReader(bodyBuff))
+
+}
+
+func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) {
+ f, err := l.fs.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ bodyBuff, err := ioutil.ReadAll(f)
+ if err != nil {
+ return nil, err
+ }
+
+ return decodeJsonUsingNumber(bytes.NewReader(bodyBuff))
+
+}
+
+// JSON string loader
+
+type jsonStringLoader struct {
+ source string
+}
+
+func (l *jsonStringLoader) JsonSource() interface{} {
+ return l.source
+}
+
+func (l *jsonStringLoader) JsonReference() (gojsonreference.JsonReference, error) {
+ return gojsonreference.NewJsonReference("#")
+}
+
+func (l *jsonStringLoader) LoaderFactory() JSONLoaderFactory {
+ return &DefaultJSONLoaderFactory{}
+}
+
+func NewStringLoader(source string) *jsonStringLoader {
+ return &jsonStringLoader{source: source}
+}
+
+func (l *jsonStringLoader) LoadJSON() (interface{}, error) {
+
+ return decodeJsonUsingNumber(strings.NewReader(l.JsonSource().(string)))
+
+}
+
+// JSON bytes loader
+
+type jsonBytesLoader struct {
+ source []byte
+}
+
+func (l *jsonBytesLoader) JsonSource() interface{} {
+ return l.source
+}
+
+func (l *jsonBytesLoader) JsonReference() (gojsonreference.JsonReference, error) {
+ return gojsonreference.NewJsonReference("#")
+}
+
+func (l *jsonBytesLoader) LoaderFactory() JSONLoaderFactory {
+ return &DefaultJSONLoaderFactory{}
+}
+
+func NewBytesLoader(source []byte) *jsonBytesLoader {
+ return &jsonBytesLoader{source: source}
+}
+
+func (l *jsonBytesLoader) LoadJSON() (interface{}, error) {
+ return decodeJsonUsingNumber(bytes.NewReader(l.JsonSource().([]byte)))
+}
+
+// JSON Go (types) loader
+// used to load JSONs from the code as maps, interface{}, structs ...
+
+type jsonGoLoader struct {
+ source interface{}
+}
+
+func (l *jsonGoLoader) JsonSource() interface{} {
+ return l.source
+}
+
+func (l *jsonGoLoader) JsonReference() (gojsonreference.JsonReference, error) {
+ return gojsonreference.NewJsonReference("#")
+}
+
+func (l *jsonGoLoader) LoaderFactory() JSONLoaderFactory {
+ return &DefaultJSONLoaderFactory{}
+}
+
+func NewGoLoader(source interface{}) *jsonGoLoader {
+ return &jsonGoLoader{source: source}
+}
+
+func (l *jsonGoLoader) LoadJSON() (interface{}, error) {
+
+ // convert it to a compliant JSON first to avoid types "mismatches"
+
+ jsonBytes, err := json.Marshal(l.JsonSource())
+ if err != nil {
+ return nil, err
+ }
+
+ return decodeJsonUsingNumber(bytes.NewReader(jsonBytes))
+
+}
+
+type jsonIOLoader struct {
+ buf *bytes.Buffer
+}
+
+func NewReaderLoader(source io.Reader) (*jsonIOLoader, io.Reader) {
+ buf := &bytes.Buffer{}
+ return &jsonIOLoader{buf: buf}, io.TeeReader(source, buf)
+}
+
+func NewWriterLoader(source io.Writer) (*jsonIOLoader, io.Writer) {
+ buf := &bytes.Buffer{}
+ return &jsonIOLoader{buf: buf}, io.MultiWriter(source, buf)
+}
+
+func (l *jsonIOLoader) JsonSource() interface{} {
+ return l.buf.String()
+}
+
+func (l *jsonIOLoader) LoadJSON() (interface{}, error) {
+ return decodeJsonUsingNumber(l.buf)
+}
+
+func (l *jsonIOLoader) JsonReference() (gojsonreference.JsonReference, error) {
+ return gojsonreference.NewJsonReference("#")
+}
+
+func (l *jsonIOLoader) LoaderFactory() JSONLoaderFactory {
+ return &DefaultJSONLoaderFactory{}
+}
+
+func decodeJsonUsingNumber(r io.Reader) (interface{}, error) {
+
+ var document interface{}
+
+ decoder := json.NewDecoder(r)
+ decoder.UseNumber()
+
+ err := decoder.Decode(&document)
+ if err != nil {
+ return nil, err
+ }
+
+ return document, nil
+
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/locales.go b/vendor/github.com/xeipuuv/gojsonschema/locales.go
new file mode 100644
index 000000000..ee41484a7
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/locales.go
@@ -0,0 +1,286 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Contains const string and messages.
+//
+// created 01-01-2015
+
+package gojsonschema
+
+type (
+ // locale is an interface for defining custom error strings
+ locale interface {
+ Required() string
+ InvalidType() string
+ NumberAnyOf() string
+ NumberOneOf() string
+ NumberAllOf() string
+ NumberNot() string
+ MissingDependency() string
+ Internal() string
+ Enum() string
+ ArrayNotEnoughItems() string
+ ArrayNoAdditionalItems() string
+ ArrayMinItems() string
+ ArrayMaxItems() string
+ Unique() string
+ ArrayMinProperties() string
+ ArrayMaxProperties() string
+ AdditionalPropertyNotAllowed() string
+ InvalidPropertyPattern() string
+ StringGTE() string
+ StringLTE() string
+ DoesNotMatchPattern() string
+ DoesNotMatchFormat() string
+ MultipleOf() string
+ NumberGTE() string
+ NumberGT() string
+ NumberLTE() string
+ NumberLT() string
+
+ // Schema validations
+ RegexPattern() string
+ GreaterThanZero() string
+ MustBeOfA() string
+ MustBeOfAn() string
+ CannotBeUsedWithout() string
+ CannotBeGT() string
+ MustBeOfType() string
+ MustBeValidRegex() string
+ MustBeValidFormat() string
+ MustBeGTEZero() string
+ KeyCannotBeGreaterThan() string
+ KeyItemsMustBeOfType() string
+ KeyItemsMustBeUnique() string
+ ReferenceMustBeCanonical() string
+ NotAValidType() string
+ Duplicated() string
+ HttpBadStatus() string
+ ParseError() string
+
+ // ErrorFormat
+ ErrorFormat() string
+ }
+
+ // DefaultLocale is the default locale for this package
+ DefaultLocale struct{}
+)
+
+func (l DefaultLocale) Required() string {
+ return `{{.property}} is required`
+}
+
+func (l DefaultLocale) InvalidType() string {
+ return `Invalid type. Expected: {{.expected}}, given: {{.given}}`
+}
+
+func (l DefaultLocale) NumberAnyOf() string {
+ return `Must validate at least one schema (anyOf)`
+}
+
+func (l DefaultLocale) NumberOneOf() string {
+ return `Must validate one and only one schema (oneOf)`
+}
+
+func (l DefaultLocale) NumberAllOf() string {
+ return `Must validate all the schemas (allOf)`
+}
+
+func (l DefaultLocale) NumberNot() string {
+ return `Must not validate the schema (not)`
+}
+
+func (l DefaultLocale) MissingDependency() string {
+ return `Has a dependency on {{.dependency}}`
+}
+
+func (l DefaultLocale) Internal() string {
+ return `Internal Error {{.error}}`
+}
+
+func (l DefaultLocale) Enum() string {
+ return `{{.field}} must be one of the following: {{.allowed}}`
+}
+
+func (l DefaultLocale) ArrayNoAdditionalItems() string {
+ return `No additional items allowed on array`
+}
+
+func (l DefaultLocale) ArrayNotEnoughItems() string {
+ return `Not enough items on array to match positional list of schema`
+}
+
+func (l DefaultLocale) ArrayMinItems() string {
+ return `Array must have at least {{.min}} items`
+}
+
+func (l DefaultLocale) ArrayMaxItems() string {
+ return `Array must have at most {{.max}} items`
+}
+
+func (l DefaultLocale) Unique() string {
+ return `{{.type}} items must be unique`
+}
+
+func (l DefaultLocale) ArrayMinProperties() string {
+ return `Must have at least {{.min}} properties`
+}
+
+func (l DefaultLocale) ArrayMaxProperties() string {
+ return `Must have at most {{.max}} properties`
+}
+
+func (l DefaultLocale) AdditionalPropertyNotAllowed() string {
+ return `Additional property {{.property}} is not allowed`
+}
+
+func (l DefaultLocale) InvalidPropertyPattern() string {
+ return `Property "{{.property}}" does not match pattern {{.pattern}}`
+}
+
+func (l DefaultLocale) StringGTE() string {
+ return `String length must be greater than or equal to {{.min}}`
+}
+
+func (l DefaultLocale) StringLTE() string {
+ return `String length must be less than or equal to {{.max}}`
+}
+
+func (l DefaultLocale) DoesNotMatchPattern() string {
+ return `Does not match pattern '{{.pattern}}'`
+}
+
+func (l DefaultLocale) DoesNotMatchFormat() string {
+ return `Does not match format '{{.format}}'`
+}
+
+func (l DefaultLocale) MultipleOf() string {
+ return `Must be a multiple of {{.multiple}}`
+}
+
+func (l DefaultLocale) NumberGTE() string {
+ return `Must be greater than or equal to {{.min}}`
+}
+
+func (l DefaultLocale) NumberGT() string {
+ return `Must be greater than {{.min}}`
+}
+
+func (l DefaultLocale) NumberLTE() string {
+ return `Must be less than or equal to {{.max}}`
+}
+
+func (l DefaultLocale) NumberLT() string {
+ return `Must be less than {{.max}}`
+}
+
+// Schema validators
+func (l DefaultLocale) RegexPattern() string {
+ return `Invalid regex pattern '{{.pattern}}'`
+}
+
+func (l DefaultLocale) GreaterThanZero() string {
+ return `{{.number}} must be strictly greater than 0`
+}
+
+func (l DefaultLocale) MustBeOfA() string {
+ return `{{.x}} must be of a {{.y}}`
+}
+
+func (l DefaultLocale) MustBeOfAn() string {
+ return `{{.x}} must be of an {{.y}}`
+}
+
+func (l DefaultLocale) CannotBeUsedWithout() string {
+ return `{{.x}} cannot be used without {{.y}}`
+}
+
+func (l DefaultLocale) CannotBeGT() string {
+ return `{{.x}} cannot be greater than {{.y}}`
+}
+
+func (l DefaultLocale) MustBeOfType() string {
+ return `{{.key}} must be of type {{.type}}`
+}
+
+func (l DefaultLocale) MustBeValidRegex() string {
+ return `{{.key}} must be a valid regex`
+}
+
+func (l DefaultLocale) MustBeValidFormat() string {
+ return `{{.key}} must be a valid format {{.given}}`
+}
+
+func (l DefaultLocale) MustBeGTEZero() string {
+ return `{{.key}} must be greater than or equal to 0`
+}
+
+func (l DefaultLocale) KeyCannotBeGreaterThan() string {
+ return `{{.key}} cannot be greater than {{.y}}`
+}
+
+func (l DefaultLocale) KeyItemsMustBeOfType() string {
+ return `{{.key}} items must be {{.type}}`
+}
+
+func (l DefaultLocale) KeyItemsMustBeUnique() string {
+ return `{{.key}} items must be unique`
+}
+
+func (l DefaultLocale) ReferenceMustBeCanonical() string {
+ return `Reference {{.reference}} must be canonical`
+}
+
+func (l DefaultLocale) NotAValidType() string {
+ return `has a primitive type that is NOT VALID -- given: {{.given}} Expected valid values are:{{.expected}}`
+}
+
+func (l DefaultLocale) Duplicated() string {
+ return `{{.type}} type is duplicated`
+}
+
+func (l DefaultLocale) HttpBadStatus() string {
+ return `Could not read schema from HTTP, response status is {{.status}}`
+}
+
+// Replacement options: field, description, context, value
+func (l DefaultLocale) ErrorFormat() string {
+ return `{{.field}}: {{.description}}`
+}
+
+//Parse error
+func (l DefaultLocale) ParseError() string {
+ return `Expected: %expected%, given: Invalid JSON`
+}
+
+const (
+ STRING_NUMBER = "number"
+ STRING_ARRAY_OF_STRINGS = "array of strings"
+ STRING_ARRAY_OF_SCHEMAS = "array of schemas"
+ STRING_SCHEMA = "schema"
+ STRING_SCHEMA_OR_ARRAY_OF_STRINGS = "schema or array of strings"
+ STRING_PROPERTIES = "properties"
+ STRING_DEPENDENCY = "dependency"
+ STRING_PROPERTY = "property"
+ STRING_UNDEFINED = "undefined"
+ STRING_CONTEXT_ROOT = "(root)"
+ STRING_ROOT_SCHEMA_PROPERTY = "(root)"
+)
diff --git a/vendor/github.com/xeipuuv/gojsonschema/result.go b/vendor/github.com/xeipuuv/gojsonschema/result.go
new file mode 100644
index 000000000..6ad56ae86
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/result.go
@@ -0,0 +1,172 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Result and ResultError implementations.
+//
+// created 01-01-2015
+
+package gojsonschema
+
+import (
+ "fmt"
+ "strings"
+)
+
+type (
+ // ErrorDetails is a map of details specific to each error.
+ // While the values will vary, every error will contain a "field" value
+ ErrorDetails map[string]interface{}
+
+ // ResultError is the interface that library errors must implement
+ ResultError interface {
+ Field() string
+ SetType(string)
+ Type() string
+ SetContext(*jsonContext)
+ Context() *jsonContext
+ SetDescription(string)
+ Description() string
+ SetValue(interface{})
+ Value() interface{}
+ SetDetails(ErrorDetails)
+ Details() ErrorDetails
+ String() string
+ }
+
+ // ResultErrorFields holds the fields for each ResultError implementation.
+ // ResultErrorFields implements the ResultError interface, so custom errors
+ // can be defined by just embedding this type
+ ResultErrorFields struct {
+ errorType string // A string with the type of error (i.e. invalid_type)
+ context *jsonContext // Tree like notation of the part that failed the validation. ex (root).a.b ...
+ description string // A human readable error message
+ value interface{} // Value given by the JSON file that is the source of the error
+ details ErrorDetails
+ }
+
+ Result struct {
+ errors []ResultError
+ // Scores how well the validation matched. Useful in generating
+ // better error messages for anyOf and oneOf.
+ score int
+ }
+)
+
+// Field outputs the field name without the root context
+// i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName
+func (v *ResultErrorFields) Field() string {
+ if p, ok := v.Details()["property"]; ok {
+ if str, isString := p.(string); isString {
+ return str
+ }
+ }
+
+ return strings.TrimPrefix(v.context.String(), STRING_ROOT_SCHEMA_PROPERTY+".")
+}
+
+func (v *ResultErrorFields) SetType(errorType string) {
+ v.errorType = errorType
+}
+
+func (v *ResultErrorFields) Type() string {
+ return v.errorType
+}
+
+func (v *ResultErrorFields) SetContext(context *jsonContext) {
+ v.context = context
+}
+
+func (v *ResultErrorFields) Context() *jsonContext {
+ return v.context
+}
+
+func (v *ResultErrorFields) SetDescription(description string) {
+ v.description = description
+}
+
+func (v *ResultErrorFields) Description() string {
+ return v.description
+}
+
+func (v *ResultErrorFields) SetValue(value interface{}) {
+ v.value = value
+}
+
+func (v *ResultErrorFields) Value() interface{} {
+ return v.value
+}
+
+func (v *ResultErrorFields) SetDetails(details ErrorDetails) {
+ v.details = details
+}
+
+func (v *ResultErrorFields) Details() ErrorDetails {
+ return v.details
+}
+
+func (v ResultErrorFields) String() string {
+ // as a fallback, the value is displayed go style
+ valueString := fmt.Sprintf("%v", v.value)
+
+ // marshal the go value value to json
+ if v.value == nil {
+ valueString = TYPE_NULL
+ } else {
+ if vs, err := marshalToJsonString(v.value); err == nil {
+ if vs == nil {
+ valueString = TYPE_NULL
+ } else {
+ valueString = *vs
+ }
+ }
+ }
+
+ return formatErrorDescription(Locale.ErrorFormat(), ErrorDetails{
+ "context": v.context.String(),
+ "description": v.description,
+ "value": valueString,
+ "field": v.Field(),
+ })
+}
+
+func (v *Result) Valid() bool {
+ return len(v.errors) == 0
+}
+
+func (v *Result) Errors() []ResultError {
+ return v.errors
+}
+
+func (v *Result) addError(err ResultError, context *jsonContext, value interface{}, details ErrorDetails) {
+ newError(err, context, value, Locale, details)
+ v.errors = append(v.errors, err)
+ v.score -= 2 // results in a net -1 when added to the +1 we get at the end of the validation function
+}
+
+// Used to copy errors from a sub-schema to the main one
+func (v *Result) mergeErrors(otherResult *Result) {
+ v.errors = append(v.errors, otherResult.Errors()...)
+ v.score += otherResult.score
+}
+
+func (v *Result) incrementScore() {
+ v.score++
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/schema.go b/vendor/github.com/xeipuuv/gojsonschema/schema.go
new file mode 100644
index 000000000..2cac71e9b
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/schema.go
@@ -0,0 +1,928 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Defines Schema, the main entry to every subSchema.
+// Contains the parsing logic and error checking.
+//
+// created 26-02-2013
+
+package gojsonschema
+
+import (
+ // "encoding/json"
+ "errors"
+ "reflect"
+ "regexp"
+ "text/template"
+
+ "github.com/xeipuuv/gojsonreference"
+)
+
+var (
+ // Locale is the default locale to use
+ // Library users can overwrite with their own implementation
+ Locale locale = DefaultLocale{}
+
+ // ErrorTemplateFuncs allows you to define custom template funcs for use in localization.
+ ErrorTemplateFuncs template.FuncMap
+)
+
+func NewSchema(l JSONLoader) (*Schema, error) {
+ ref, err := l.JsonReference()
+ if err != nil {
+ return nil, err
+ }
+
+ d := Schema{}
+ d.pool = newSchemaPool(l.LoaderFactory())
+ d.documentReference = ref
+ d.referencePool = newSchemaReferencePool()
+
+ var doc interface{}
+ if ref.String() != "" {
+ // Get document from schema pool
+ spd, err := d.pool.GetDocument(d.documentReference)
+ if err != nil {
+ return nil, err
+ }
+ doc = spd.Document
+ } else {
+ // Load JSON directly
+ doc, err = l.LoadJSON()
+ if err != nil {
+ return nil, err
+ }
+ d.pool.SetStandaloneDocument(doc)
+ }
+
+ err = d.parse(doc)
+ if err != nil {
+ return nil, err
+ }
+
+ return &d, nil
+}
+
+type Schema struct {
+ documentReference gojsonreference.JsonReference
+ rootSchema *subSchema
+ pool *schemaPool
+ referencePool *schemaReferencePool
+}
+
+func (d *Schema) parse(document interface{}) error {
+ d.rootSchema = &subSchema{property: STRING_ROOT_SCHEMA_PROPERTY}
+ return d.parseSchema(document, d.rootSchema)
+}
+
+func (d *Schema) SetRootSchemaName(name string) {
+ d.rootSchema.property = name
+}
+
+// Parses a subSchema
+//
+// Pretty long function ( sorry :) )... but pretty straight forward, repetitive and boring
+// Not much magic involved here, most of the job is to validate the key names and their values,
+// then the values are copied into subSchema struct
+//
+func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema) error {
+
+ if !isKind(documentNode, reflect.Map) {
+ return errors.New(formatErrorDescription(
+ Locale.ParseError(),
+ ErrorDetails{
+ "expected": STRING_SCHEMA,
+ },
+ ))
+ }
+
+ m := documentNode.(map[string]interface{})
+
+ if currentSchema == d.rootSchema {
+ currentSchema.ref = &d.documentReference
+ }
+
+ // $subSchema
+ if existsMapKey(m, KEY_SCHEMA) {
+ if !isKind(m[KEY_SCHEMA], reflect.String) {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_STRING,
+ "given": KEY_SCHEMA,
+ },
+ ))
+ }
+ schemaRef := m[KEY_SCHEMA].(string)
+ schemaReference, err := gojsonreference.NewJsonReference(schemaRef)
+ currentSchema.subSchema = &schemaReference
+ if err != nil {
+ return err
+ }
+ }
+
+ // $ref
+ if existsMapKey(m, KEY_REF) && !isKind(m[KEY_REF], reflect.String) {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_STRING,
+ "given": KEY_REF,
+ },
+ ))
+ }
+ if k, ok := m[KEY_REF].(string); ok {
+
+ jsonReference, err := gojsonreference.NewJsonReference(k)
+ if err != nil {
+ return err
+ }
+
+ if jsonReference.HasFullUrl {
+ currentSchema.ref = &jsonReference
+ } else {
+ inheritedReference, err := currentSchema.ref.Inherits(jsonReference)
+ if err != nil {
+ return err
+ }
+
+ currentSchema.ref = inheritedReference
+ }
+
+ if sch, ok := d.referencePool.Get(currentSchema.ref.String() + k); ok {
+ currentSchema.refSchema = sch
+
+ } else {
+ err := d.parseReference(documentNode, currentSchema, k)
+ if err != nil {
+ return err
+ }
+
+ return nil
+ }
+ }
+
+ // definitions
+ if existsMapKey(m, KEY_DEFINITIONS) {
+ if isKind(m[KEY_DEFINITIONS], reflect.Map) {
+ currentSchema.definitions = make(map[string]*subSchema)
+ for dk, dv := range m[KEY_DEFINITIONS].(map[string]interface{}) {
+ if isKind(dv, reflect.Map) {
+ newSchema := &subSchema{property: KEY_DEFINITIONS, parent: currentSchema, ref: currentSchema.ref}
+ currentSchema.definitions[dk] = newSchema
+ err := d.parseSchema(dv, newSchema)
+ if err != nil {
+ return errors.New(err.Error())
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": STRING_ARRAY_OF_SCHEMAS,
+ "given": KEY_DEFINITIONS,
+ },
+ ))
+ }
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": STRING_ARRAY_OF_SCHEMAS,
+ "given": KEY_DEFINITIONS,
+ },
+ ))
+ }
+
+ }
+
+ // id
+ if existsMapKey(m, KEY_ID) && !isKind(m[KEY_ID], reflect.String) {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_STRING,
+ "given": KEY_ID,
+ },
+ ))
+ }
+ if k, ok := m[KEY_ID].(string); ok {
+ currentSchema.id = &k
+ }
+
+ // title
+ if existsMapKey(m, KEY_TITLE) && !isKind(m[KEY_TITLE], reflect.String) {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_STRING,
+ "given": KEY_TITLE,
+ },
+ ))
+ }
+ if k, ok := m[KEY_TITLE].(string); ok {
+ currentSchema.title = &k
+ }
+
+ // description
+ if existsMapKey(m, KEY_DESCRIPTION) && !isKind(m[KEY_DESCRIPTION], reflect.String) {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_STRING,
+ "given": KEY_DESCRIPTION,
+ },
+ ))
+ }
+ if k, ok := m[KEY_DESCRIPTION].(string); ok {
+ currentSchema.description = &k
+ }
+
+ // type
+ if existsMapKey(m, KEY_TYPE) {
+ if isKind(m[KEY_TYPE], reflect.String) {
+ if k, ok := m[KEY_TYPE].(string); ok {
+ err := currentSchema.types.Add(k)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ if isKind(m[KEY_TYPE], reflect.Slice) {
+ arrayOfTypes := m[KEY_TYPE].([]interface{})
+ for _, typeInArray := range arrayOfTypes {
+ if reflect.ValueOf(typeInArray).Kind() != reflect.String {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS,
+ "given": KEY_TYPE,
+ },
+ ))
+ } else {
+ currentSchema.types.Add(typeInArray.(string))
+ }
+ }
+
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS,
+ "given": KEY_TYPE,
+ },
+ ))
+ }
+ }
+ }
+
+ // properties
+ if existsMapKey(m, KEY_PROPERTIES) {
+ err := d.parseProperties(m[KEY_PROPERTIES], currentSchema)
+ if err != nil {
+ return err
+ }
+ }
+
+ // additionalProperties
+ if existsMapKey(m, KEY_ADDITIONAL_PROPERTIES) {
+ if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Bool) {
+ currentSchema.additionalProperties = m[KEY_ADDITIONAL_PROPERTIES].(bool)
+ } else if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Map) {
+ newSchema := &subSchema{property: KEY_ADDITIONAL_PROPERTIES, parent: currentSchema, ref: currentSchema.ref}
+ currentSchema.additionalProperties = newSchema
+ err := d.parseSchema(m[KEY_ADDITIONAL_PROPERTIES], newSchema)
+ if err != nil {
+ return errors.New(err.Error())
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA,
+ "given": KEY_ADDITIONAL_PROPERTIES,
+ },
+ ))
+ }
+ }
+
+ // patternProperties
+ if existsMapKey(m, KEY_PATTERN_PROPERTIES) {
+ if isKind(m[KEY_PATTERN_PROPERTIES], reflect.Map) {
+ patternPropertiesMap := m[KEY_PATTERN_PROPERTIES].(map[string]interface{})
+ if len(patternPropertiesMap) > 0 {
+ currentSchema.patternProperties = make(map[string]*subSchema)
+ for k, v := range patternPropertiesMap {
+ _, err := regexp.MatchString(k, "")
+ if err != nil {
+ return errors.New(formatErrorDescription(
+ Locale.RegexPattern(),
+ ErrorDetails{"pattern": k},
+ ))
+ }
+ newSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref}
+ err = d.parseSchema(v, newSchema)
+ if err != nil {
+ return errors.New(err.Error())
+ }
+ currentSchema.patternProperties[k] = newSchema
+ }
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": STRING_SCHEMA,
+ "given": KEY_PATTERN_PROPERTIES,
+ },
+ ))
+ }
+ }
+
+ // dependencies
+ if existsMapKey(m, KEY_DEPENDENCIES) {
+ err := d.parseDependencies(m[KEY_DEPENDENCIES], currentSchema)
+ if err != nil {
+ return err
+ }
+ }
+
+ // items
+ if existsMapKey(m, KEY_ITEMS) {
+ if isKind(m[KEY_ITEMS], reflect.Slice) {
+ for _, itemElement := range m[KEY_ITEMS].([]interface{}) {
+ if isKind(itemElement, reflect.Map) {
+ newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS}
+ newSchema.ref = currentSchema.ref
+ currentSchema.AddItemsChild(newSchema)
+ err := d.parseSchema(itemElement, newSchema)
+ if err != nil {
+ return err
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS,
+ "given": KEY_ITEMS,
+ },
+ ))
+ }
+ currentSchema.itemsChildrenIsSingleSchema = false
+ }
+ } else if isKind(m[KEY_ITEMS], reflect.Map) {
+ newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS}
+ newSchema.ref = currentSchema.ref
+ currentSchema.AddItemsChild(newSchema)
+ err := d.parseSchema(m[KEY_ITEMS], newSchema)
+ if err != nil {
+ return err
+ }
+ currentSchema.itemsChildrenIsSingleSchema = true
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS,
+ "given": KEY_ITEMS,
+ },
+ ))
+ }
+ }
+
+ // additionalItems
+ if existsMapKey(m, KEY_ADDITIONAL_ITEMS) {
+ if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Bool) {
+ currentSchema.additionalItems = m[KEY_ADDITIONAL_ITEMS].(bool)
+ } else if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Map) {
+ newSchema := &subSchema{property: KEY_ADDITIONAL_ITEMS, parent: currentSchema, ref: currentSchema.ref}
+ currentSchema.additionalItems = newSchema
+ err := d.parseSchema(m[KEY_ADDITIONAL_ITEMS], newSchema)
+ if err != nil {
+ return errors.New(err.Error())
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA,
+ "given": KEY_ADDITIONAL_ITEMS,
+ },
+ ))
+ }
+ }
+
+ // validation : number / integer
+
+ if existsMapKey(m, KEY_MULTIPLE_OF) {
+ multipleOfValue := mustBeNumber(m[KEY_MULTIPLE_OF])
+ if multipleOfValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.InvalidType(),
+ ErrorDetails{
+ "expected": STRING_NUMBER,
+ "given": KEY_MULTIPLE_OF,
+ },
+ ))
+ }
+ if *multipleOfValue <= 0 {
+ return errors.New(formatErrorDescription(
+ Locale.GreaterThanZero(),
+ ErrorDetails{"number": KEY_MULTIPLE_OF},
+ ))
+ }
+ currentSchema.multipleOf = multipleOfValue
+ }
+
+ if existsMapKey(m, KEY_MINIMUM) {
+ minimumValue := mustBeNumber(m[KEY_MINIMUM])
+ if minimumValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfA(),
+ ErrorDetails{"x": KEY_MINIMUM, "y": STRING_NUMBER},
+ ))
+ }
+ currentSchema.minimum = minimumValue
+ }
+
+ if existsMapKey(m, KEY_EXCLUSIVE_MINIMUM) {
+ if isKind(m[KEY_EXCLUSIVE_MINIMUM], reflect.Bool) {
+ if currentSchema.minimum == nil {
+ return errors.New(formatErrorDescription(
+ Locale.CannotBeUsedWithout(),
+ ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": KEY_MINIMUM},
+ ))
+ }
+ exclusiveMinimumValue := m[KEY_EXCLUSIVE_MINIMUM].(bool)
+ currentSchema.exclusiveMinimum = exclusiveMinimumValue
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfA(),
+ ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": TYPE_BOOLEAN},
+ ))
+ }
+ }
+
+ if existsMapKey(m, KEY_MAXIMUM) {
+ maximumValue := mustBeNumber(m[KEY_MAXIMUM])
+ if maximumValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfA(),
+ ErrorDetails{"x": KEY_MAXIMUM, "y": STRING_NUMBER},
+ ))
+ }
+ currentSchema.maximum = maximumValue
+ }
+
+ if existsMapKey(m, KEY_EXCLUSIVE_MAXIMUM) {
+ if isKind(m[KEY_EXCLUSIVE_MAXIMUM], reflect.Bool) {
+ if currentSchema.maximum == nil {
+ return errors.New(formatErrorDescription(
+ Locale.CannotBeUsedWithout(),
+ ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": KEY_MAXIMUM},
+ ))
+ }
+ exclusiveMaximumValue := m[KEY_EXCLUSIVE_MAXIMUM].(bool)
+ currentSchema.exclusiveMaximum = exclusiveMaximumValue
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfA(),
+ ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": STRING_NUMBER},
+ ))
+ }
+ }
+
+ if currentSchema.minimum != nil && currentSchema.maximum != nil {
+ if *currentSchema.minimum > *currentSchema.maximum {
+ return errors.New(formatErrorDescription(
+ Locale.CannotBeGT(),
+ ErrorDetails{"x": KEY_MINIMUM, "y": KEY_MAXIMUM},
+ ))
+ }
+ }
+
+ // validation : string
+
+ if existsMapKey(m, KEY_MIN_LENGTH) {
+ minLengthIntegerValue := mustBeInteger(m[KEY_MIN_LENGTH])
+ if minLengthIntegerValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_MIN_LENGTH, "y": TYPE_INTEGER},
+ ))
+ }
+ if *minLengthIntegerValue < 0 {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeGTEZero(),
+ ErrorDetails{"key": KEY_MIN_LENGTH},
+ ))
+ }
+ currentSchema.minLength = minLengthIntegerValue
+ }
+
+ if existsMapKey(m, KEY_MAX_LENGTH) {
+ maxLengthIntegerValue := mustBeInteger(m[KEY_MAX_LENGTH])
+ if maxLengthIntegerValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_MAX_LENGTH, "y": TYPE_INTEGER},
+ ))
+ }
+ if *maxLengthIntegerValue < 0 {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeGTEZero(),
+ ErrorDetails{"key": KEY_MAX_LENGTH},
+ ))
+ }
+ currentSchema.maxLength = maxLengthIntegerValue
+ }
+
+ if currentSchema.minLength != nil && currentSchema.maxLength != nil {
+ if *currentSchema.minLength > *currentSchema.maxLength {
+ return errors.New(formatErrorDescription(
+ Locale.CannotBeGT(),
+ ErrorDetails{"x": KEY_MIN_LENGTH, "y": KEY_MAX_LENGTH},
+ ))
+ }
+ }
+
+ if existsMapKey(m, KEY_PATTERN) {
+ if isKind(m[KEY_PATTERN], reflect.String) {
+ regexpObject, err := regexp.Compile(m[KEY_PATTERN].(string))
+ if err != nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeValidRegex(),
+ ErrorDetails{"key": KEY_PATTERN},
+ ))
+ }
+ currentSchema.pattern = regexpObject
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfA(),
+ ErrorDetails{"x": KEY_PATTERN, "y": TYPE_STRING},
+ ))
+ }
+ }
+
+ if existsMapKey(m, KEY_FORMAT) {
+ formatString, ok := m[KEY_FORMAT].(string)
+ if ok && FormatCheckers.Has(formatString) {
+ currentSchema.format = formatString
+ }
+ }
+
+ // validation : object
+
+ if existsMapKey(m, KEY_MIN_PROPERTIES) {
+ minPropertiesIntegerValue := mustBeInteger(m[KEY_MIN_PROPERTIES])
+ if minPropertiesIntegerValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_MIN_PROPERTIES, "y": TYPE_INTEGER},
+ ))
+ }
+ if *minPropertiesIntegerValue < 0 {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeGTEZero(),
+ ErrorDetails{"key": KEY_MIN_PROPERTIES},
+ ))
+ }
+ currentSchema.minProperties = minPropertiesIntegerValue
+ }
+
+ if existsMapKey(m, KEY_MAX_PROPERTIES) {
+ maxPropertiesIntegerValue := mustBeInteger(m[KEY_MAX_PROPERTIES])
+ if maxPropertiesIntegerValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_MAX_PROPERTIES, "y": TYPE_INTEGER},
+ ))
+ }
+ if *maxPropertiesIntegerValue < 0 {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeGTEZero(),
+ ErrorDetails{"key": KEY_MAX_PROPERTIES},
+ ))
+ }
+ currentSchema.maxProperties = maxPropertiesIntegerValue
+ }
+
+ if currentSchema.minProperties != nil && currentSchema.maxProperties != nil {
+ if *currentSchema.minProperties > *currentSchema.maxProperties {
+ return errors.New(formatErrorDescription(
+ Locale.KeyCannotBeGreaterThan(),
+ ErrorDetails{"key": KEY_MIN_PROPERTIES, "y": KEY_MAX_PROPERTIES},
+ ))
+ }
+ }
+
+ if existsMapKey(m, KEY_REQUIRED) {
+ if isKind(m[KEY_REQUIRED], reflect.Slice) {
+ requiredValues := m[KEY_REQUIRED].([]interface{})
+ for _, requiredValue := range requiredValues {
+ if isKind(requiredValue, reflect.String) {
+ err := currentSchema.AddRequired(requiredValue.(string))
+ if err != nil {
+ return err
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.KeyItemsMustBeOfType(),
+ ErrorDetails{"key": KEY_REQUIRED, "type": TYPE_STRING},
+ ))
+ }
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_REQUIRED, "y": TYPE_ARRAY},
+ ))
+ }
+ }
+
+ // validation : array
+
+ if existsMapKey(m, KEY_MIN_ITEMS) {
+ minItemsIntegerValue := mustBeInteger(m[KEY_MIN_ITEMS])
+ if minItemsIntegerValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_MIN_ITEMS, "y": TYPE_INTEGER},
+ ))
+ }
+ if *minItemsIntegerValue < 0 {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeGTEZero(),
+ ErrorDetails{"key": KEY_MIN_ITEMS},
+ ))
+ }
+ currentSchema.minItems = minItemsIntegerValue
+ }
+
+ if existsMapKey(m, KEY_MAX_ITEMS) {
+ maxItemsIntegerValue := mustBeInteger(m[KEY_MAX_ITEMS])
+ if maxItemsIntegerValue == nil {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_MAX_ITEMS, "y": TYPE_INTEGER},
+ ))
+ }
+ if *maxItemsIntegerValue < 0 {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeGTEZero(),
+ ErrorDetails{"key": KEY_MAX_ITEMS},
+ ))
+ }
+ currentSchema.maxItems = maxItemsIntegerValue
+ }
+
+ if existsMapKey(m, KEY_UNIQUE_ITEMS) {
+ if isKind(m[KEY_UNIQUE_ITEMS], reflect.Bool) {
+ currentSchema.uniqueItems = m[KEY_UNIQUE_ITEMS].(bool)
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfA(),
+ ErrorDetails{"x": KEY_UNIQUE_ITEMS, "y": TYPE_BOOLEAN},
+ ))
+ }
+ }
+
+ // validation : all
+
+ if existsMapKey(m, KEY_ENUM) {
+ if isKind(m[KEY_ENUM], reflect.Slice) {
+ for _, v := range m[KEY_ENUM].([]interface{}) {
+ err := currentSchema.AddEnum(v)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_ENUM, "y": TYPE_ARRAY},
+ ))
+ }
+ }
+
+ // validation : subSchema
+
+ if existsMapKey(m, KEY_ONE_OF) {
+ if isKind(m[KEY_ONE_OF], reflect.Slice) {
+ for _, v := range m[KEY_ONE_OF].([]interface{}) {
+ newSchema := &subSchema{property: KEY_ONE_OF, parent: currentSchema, ref: currentSchema.ref}
+ currentSchema.AddOneOf(newSchema)
+ err := d.parseSchema(v, newSchema)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_ONE_OF, "y": TYPE_ARRAY},
+ ))
+ }
+ }
+
+ if existsMapKey(m, KEY_ANY_OF) {
+ if isKind(m[KEY_ANY_OF], reflect.Slice) {
+ for _, v := range m[KEY_ANY_OF].([]interface{}) {
+ newSchema := &subSchema{property: KEY_ANY_OF, parent: currentSchema, ref: currentSchema.ref}
+ currentSchema.AddAnyOf(newSchema)
+ err := d.parseSchema(v, newSchema)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY},
+ ))
+ }
+ }
+
+ if existsMapKey(m, KEY_ALL_OF) {
+ if isKind(m[KEY_ALL_OF], reflect.Slice) {
+ for _, v := range m[KEY_ALL_OF].([]interface{}) {
+ newSchema := &subSchema{property: KEY_ALL_OF, parent: currentSchema, ref: currentSchema.ref}
+ currentSchema.AddAllOf(newSchema)
+ err := d.parseSchema(v, newSchema)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY},
+ ))
+ }
+ }
+
+ if existsMapKey(m, KEY_NOT) {
+ if isKind(m[KEY_NOT], reflect.Map) {
+ newSchema := &subSchema{property: KEY_NOT, parent: currentSchema, ref: currentSchema.ref}
+ currentSchema.SetNot(newSchema)
+ err := d.parseSchema(m[KEY_NOT], newSchema)
+ if err != nil {
+ return err
+ }
+ } else {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfAn(),
+ ErrorDetails{"x": KEY_NOT, "y": TYPE_OBJECT},
+ ))
+ }
+ }
+
+ return nil
+}
+
+func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema, reference string) error {
+ var refdDocumentNode interface{}
+ jsonPointer := currentSchema.ref.GetPointer()
+ standaloneDocument := d.pool.GetStandaloneDocument()
+
+ if standaloneDocument != nil {
+
+ var err error
+ refdDocumentNode, _, err = jsonPointer.Get(standaloneDocument)
+ if err != nil {
+ return err
+ }
+
+ } else {
+ dsp, err := d.pool.GetDocument(*currentSchema.ref)
+ if err != nil {
+ return err
+ }
+
+ refdDocumentNode, _, err = jsonPointer.Get(dsp.Document)
+ if err != nil {
+ return err
+ }
+
+ }
+
+ if !isKind(refdDocumentNode, reflect.Map) {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfType(),
+ ErrorDetails{"key": STRING_SCHEMA, "type": TYPE_OBJECT},
+ ))
+ }
+
+ // returns the loaded referenced subSchema for the caller to update its current subSchema
+ newSchemaDocument := refdDocumentNode.(map[string]interface{})
+ newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref}
+ d.referencePool.Add(currentSchema.ref.String()+reference, newSchema)
+
+ err := d.parseSchema(newSchemaDocument, newSchema)
+ if err != nil {
+ return err
+ }
+
+ currentSchema.refSchema = newSchema
+
+ return nil
+
+}
+
+func (d *Schema) parseProperties(documentNode interface{}, currentSchema *subSchema) error {
+
+ if !isKind(documentNode, reflect.Map) {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfType(),
+ ErrorDetails{"key": STRING_PROPERTIES, "type": TYPE_OBJECT},
+ ))
+ }
+
+ m := documentNode.(map[string]interface{})
+ for k := range m {
+ schemaProperty := k
+ newSchema := &subSchema{property: schemaProperty, parent: currentSchema, ref: currentSchema.ref}
+ currentSchema.AddPropertiesChild(newSchema)
+ err := d.parseSchema(m[k], newSchema)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subSchema) error {
+
+ if !isKind(documentNode, reflect.Map) {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfType(),
+ ErrorDetails{"key": KEY_DEPENDENCIES, "type": TYPE_OBJECT},
+ ))
+ }
+
+ m := documentNode.(map[string]interface{})
+ currentSchema.dependencies = make(map[string]interface{})
+
+ for k := range m {
+ switch reflect.ValueOf(m[k]).Kind() {
+
+ case reflect.Slice:
+ values := m[k].([]interface{})
+ var valuesToRegister []string
+
+ for _, value := range values {
+ if !isKind(value, reflect.String) {
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfType(),
+ ErrorDetails{
+ "key": STRING_DEPENDENCY,
+ "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS,
+ },
+ ))
+ } else {
+ valuesToRegister = append(valuesToRegister, value.(string))
+ }
+ currentSchema.dependencies[k] = valuesToRegister
+ }
+
+ case reflect.Map:
+ depSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref}
+ err := d.parseSchema(m[k], depSchema)
+ if err != nil {
+ return err
+ }
+ currentSchema.dependencies[k] = depSchema
+
+ default:
+ return errors.New(formatErrorDescription(
+ Locale.MustBeOfType(),
+ ErrorDetails{
+ "key": STRING_DEPENDENCY,
+ "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS,
+ },
+ ))
+ }
+
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/schemaPool.go b/vendor/github.com/xeipuuv/gojsonschema/schemaPool.go
new file mode 100644
index 000000000..f2ad641af
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/schemaPool.go
@@ -0,0 +1,109 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Defines resources pooling.
+// Eases referencing and avoids downloading the same resource twice.
+//
+// created 26-02-2013
+
+package gojsonschema
+
+import (
+ "errors"
+
+ "github.com/xeipuuv/gojsonreference"
+)
+
+type schemaPoolDocument struct {
+ Document interface{}
+}
+
+type schemaPool struct {
+ schemaPoolDocuments map[string]*schemaPoolDocument
+ standaloneDocument interface{}
+ jsonLoaderFactory JSONLoaderFactory
+}
+
+func newSchemaPool(f JSONLoaderFactory) *schemaPool {
+
+ p := &schemaPool{}
+ p.schemaPoolDocuments = make(map[string]*schemaPoolDocument)
+ p.standaloneDocument = nil
+ p.jsonLoaderFactory = f
+
+ return p
+}
+
+func (p *schemaPool) SetStandaloneDocument(document interface{}) {
+ p.standaloneDocument = document
+}
+
+func (p *schemaPool) GetStandaloneDocument() (document interface{}) {
+ return p.standaloneDocument
+}
+
+func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*schemaPoolDocument, error) {
+
+ if internalLogEnabled {
+ internalLog("Get Document ( %s )", reference.String())
+ }
+
+ var err error
+
+ // It is not possible to load anything that is not canonical...
+ if !reference.IsCanonical() {
+ return nil, errors.New(formatErrorDescription(
+ Locale.ReferenceMustBeCanonical(),
+ ErrorDetails{"reference": reference},
+ ))
+ }
+
+ refToUrl := reference
+ refToUrl.GetUrl().Fragment = ""
+
+ var spd *schemaPoolDocument
+
+ // Try to find the requested document in the pool
+ for k := range p.schemaPoolDocuments {
+ if k == refToUrl.String() {
+ spd = p.schemaPoolDocuments[k]
+ }
+ }
+
+ if spd != nil {
+ if internalLogEnabled {
+ internalLog(" From pool")
+ }
+ return spd, nil
+ }
+
+ jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String())
+ document, err := jsonReferenceLoader.LoadJSON()
+ if err != nil {
+ return nil, err
+ }
+
+ spd = &schemaPoolDocument{Document: document}
+ // add the document to the pool for potential later use
+ p.schemaPoolDocuments[refToUrl.String()] = spd
+
+ return spd, nil
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go b/vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go
new file mode 100644
index 000000000..294e36a73
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go
@@ -0,0 +1,67 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Pool of referenced schemas.
+//
+// created 25-06-2013
+
+package gojsonschema
+
+import (
+ "fmt"
+)
+
+type schemaReferencePool struct {
+ documents map[string]*subSchema
+}
+
+func newSchemaReferencePool() *schemaReferencePool {
+
+ p := &schemaReferencePool{}
+ p.documents = make(map[string]*subSchema)
+
+ return p
+}
+
+func (p *schemaReferencePool) Get(ref string) (r *subSchema, o bool) {
+
+ if internalLogEnabled {
+ internalLog(fmt.Sprintf("Schema Reference ( %s )", ref))
+ }
+
+ if sch, ok := p.documents[ref]; ok {
+ if internalLogEnabled {
+ internalLog(fmt.Sprintf(" From pool"))
+ }
+ return sch, true
+ }
+
+ return nil, false
+}
+
+func (p *schemaReferencePool) Add(ref string, sch *subSchema) {
+
+ if internalLogEnabled {
+ internalLog(fmt.Sprintf("Add Schema Reference %s to pool", ref))
+ }
+
+ p.documents[ref] = sch
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/schemaType.go b/vendor/github.com/xeipuuv/gojsonschema/schemaType.go
new file mode 100644
index 000000000..36b447a29
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/schemaType.go
@@ -0,0 +1,83 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Helper structure to handle schema types, and the combination of them.
+//
+// created 28-02-2013
+
+package gojsonschema
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+type jsonSchemaType struct {
+ types []string
+}
+
+// Is the schema typed ? that is containing at least one type
+// When not typed, the schema does not need any type validation
+func (t *jsonSchemaType) IsTyped() bool {
+ return len(t.types) > 0
+}
+
+func (t *jsonSchemaType) Add(etype string) error {
+
+ if !isStringInSlice(JSON_TYPES, etype) {
+ return errors.New(formatErrorDescription(Locale.NotAValidType(), ErrorDetails{"given": "/" + etype + "/", "expected": JSON_TYPES}))
+ }
+
+ if t.Contains(etype) {
+ return errors.New(formatErrorDescription(Locale.Duplicated(), ErrorDetails{"type": etype}))
+ }
+
+ t.types = append(t.types, etype)
+
+ return nil
+}
+
+func (t *jsonSchemaType) Contains(etype string) bool {
+
+ for _, v := range t.types {
+ if v == etype {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (t *jsonSchemaType) String() string {
+
+ if len(t.types) == 0 {
+ return STRING_UNDEFINED // should never happen
+ }
+
+ // Displayed as a list [type1,type2,...]
+ if len(t.types) > 1 {
+ return fmt.Sprintf("[%s]", strings.Join(t.types, ","))
+ }
+
+ // Only one type: name only
+ return t.types[0]
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/subSchema.go b/vendor/github.com/xeipuuv/gojsonschema/subSchema.go
new file mode 100644
index 000000000..9ddbb5fc1
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/subSchema.go
@@ -0,0 +1,227 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Defines the structure of a sub-subSchema.
+// A sub-subSchema can contain other sub-schemas.
+//
+// created 27-02-2013
+
+package gojsonschema
+
+import (
+ "errors"
+ "regexp"
+ "strings"
+
+ "github.com/xeipuuv/gojsonreference"
+)
+
+const (
+ KEY_SCHEMA = "$subSchema"
+ KEY_ID = "$id"
+ KEY_REF = "$ref"
+ KEY_TITLE = "title"
+ KEY_DESCRIPTION = "description"
+ KEY_TYPE = "type"
+ KEY_ITEMS = "items"
+ KEY_ADDITIONAL_ITEMS = "additionalItems"
+ KEY_PROPERTIES = "properties"
+ KEY_PATTERN_PROPERTIES = "patternProperties"
+ KEY_ADDITIONAL_PROPERTIES = "additionalProperties"
+ KEY_DEFINITIONS = "definitions"
+ KEY_MULTIPLE_OF = "multipleOf"
+ KEY_MINIMUM = "minimum"
+ KEY_MAXIMUM = "maximum"
+ KEY_EXCLUSIVE_MINIMUM = "exclusiveMinimum"
+ KEY_EXCLUSIVE_MAXIMUM = "exclusiveMaximum"
+ KEY_MIN_LENGTH = "minLength"
+ KEY_MAX_LENGTH = "maxLength"
+ KEY_PATTERN = "pattern"
+ KEY_FORMAT = "format"
+ KEY_MIN_PROPERTIES = "minProperties"
+ KEY_MAX_PROPERTIES = "maxProperties"
+ KEY_DEPENDENCIES = "dependencies"
+ KEY_REQUIRED = "required"
+ KEY_MIN_ITEMS = "minItems"
+ KEY_MAX_ITEMS = "maxItems"
+ KEY_UNIQUE_ITEMS = "uniqueItems"
+ KEY_ENUM = "enum"
+ KEY_ONE_OF = "oneOf"
+ KEY_ANY_OF = "anyOf"
+ KEY_ALL_OF = "allOf"
+ KEY_NOT = "not"
+)
+
+type subSchema struct {
+
+ // basic subSchema meta properties
+ id *string
+ title *string
+ description *string
+
+ property string
+
+ // Types associated with the subSchema
+ types jsonSchemaType
+
+ // Reference url
+ ref *gojsonreference.JsonReference
+ // Schema referenced
+ refSchema *subSchema
+ // Json reference
+ subSchema *gojsonreference.JsonReference
+
+ // hierarchy
+ parent *subSchema
+ definitions map[string]*subSchema
+ definitionsChildren []*subSchema
+ itemsChildren []*subSchema
+ itemsChildrenIsSingleSchema bool
+ propertiesChildren []*subSchema
+
+ // validation : number / integer
+ multipleOf *float64
+ maximum *float64
+ exclusiveMaximum bool
+ minimum *float64
+ exclusiveMinimum bool
+
+ // validation : string
+ minLength *int
+ maxLength *int
+ pattern *regexp.Regexp
+ format string
+
+ // validation : object
+ minProperties *int
+ maxProperties *int
+ required []string
+
+ dependencies map[string]interface{}
+ additionalProperties interface{}
+ patternProperties map[string]*subSchema
+
+ // validation : array
+ minItems *int
+ maxItems *int
+ uniqueItems bool
+
+ additionalItems interface{}
+
+ // validation : all
+ enum []string
+
+ // validation : subSchema
+ oneOf []*subSchema
+ anyOf []*subSchema
+ allOf []*subSchema
+ not *subSchema
+}
+
+func (s *subSchema) AddEnum(i interface{}) error {
+
+ is, err := marshalToJsonString(i)
+ if err != nil {
+ return err
+ }
+
+ if isStringInSlice(s.enum, *is) {
+ return errors.New(formatErrorDescription(
+ Locale.KeyItemsMustBeUnique(),
+ ErrorDetails{"key": KEY_ENUM},
+ ))
+ }
+
+ s.enum = append(s.enum, *is)
+
+ return nil
+}
+
+func (s *subSchema) ContainsEnum(i interface{}) (bool, error) {
+
+ is, err := marshalToJsonString(i)
+ if err != nil {
+ return false, err
+ }
+
+ return isStringInSlice(s.enum, *is), nil
+}
+
+func (s *subSchema) AddOneOf(subSchema *subSchema) {
+ s.oneOf = append(s.oneOf, subSchema)
+}
+
+func (s *subSchema) AddAllOf(subSchema *subSchema) {
+ s.allOf = append(s.allOf, subSchema)
+}
+
+func (s *subSchema) AddAnyOf(subSchema *subSchema) {
+ s.anyOf = append(s.anyOf, subSchema)
+}
+
+func (s *subSchema) SetNot(subSchema *subSchema) {
+ s.not = subSchema
+}
+
+func (s *subSchema) AddRequired(value string) error {
+
+ if isStringInSlice(s.required, value) {
+ return errors.New(formatErrorDescription(
+ Locale.KeyItemsMustBeUnique(),
+ ErrorDetails{"key": KEY_REQUIRED},
+ ))
+ }
+
+ s.required = append(s.required, value)
+
+ return nil
+}
+
+func (s *subSchema) AddDefinitionChild(child *subSchema) {
+ s.definitionsChildren = append(s.definitionsChildren, child)
+}
+
+func (s *subSchema) AddItemsChild(child *subSchema) {
+ s.itemsChildren = append(s.itemsChildren, child)
+}
+
+func (s *subSchema) AddPropertiesChild(child *subSchema) {
+ s.propertiesChildren = append(s.propertiesChildren, child)
+}
+
+func (s *subSchema) PatternPropertiesString() string {
+
+ if s.patternProperties == nil || len(s.patternProperties) == 0 {
+ return STRING_UNDEFINED // should never happen
+ }
+
+ patternPropertiesKeySlice := []string{}
+ for pk := range s.patternProperties {
+ patternPropertiesKeySlice = append(patternPropertiesKeySlice, `"`+pk+`"`)
+ }
+
+ if len(patternPropertiesKeySlice) == 1 {
+ return patternPropertiesKeySlice[0]
+ }
+
+ return "[" + strings.Join(patternPropertiesKeySlice, ",") + "]"
+
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/types.go b/vendor/github.com/xeipuuv/gojsonschema/types.go
new file mode 100644
index 000000000..952d22ef6
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/types.go
@@ -0,0 +1,58 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Contains const types for schema and JSON.
+//
+// created 28-02-2013
+
+package gojsonschema
+
+const (
+ TYPE_ARRAY = `array`
+ TYPE_BOOLEAN = `boolean`
+ TYPE_INTEGER = `integer`
+ TYPE_NUMBER = `number`
+ TYPE_NULL = `null`
+ TYPE_OBJECT = `object`
+ TYPE_STRING = `string`
+)
+
+var JSON_TYPES []string
+var SCHEMA_TYPES []string
+
+func init() {
+ JSON_TYPES = []string{
+ TYPE_ARRAY,
+ TYPE_BOOLEAN,
+ TYPE_INTEGER,
+ TYPE_NUMBER,
+ TYPE_NULL,
+ TYPE_OBJECT,
+ TYPE_STRING}
+
+ SCHEMA_TYPES = []string{
+ TYPE_ARRAY,
+ TYPE_BOOLEAN,
+ TYPE_INTEGER,
+ TYPE_NUMBER,
+ TYPE_OBJECT,
+ TYPE_STRING}
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/utils.go b/vendor/github.com/xeipuuv/gojsonschema/utils.go
new file mode 100644
index 000000000..26cf75ebf
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/utils.go
@@ -0,0 +1,208 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Various utility functions.
+//
+// created 26-02-2013
+
+package gojsonschema
+
+import (
+ "encoding/json"
+ "fmt"
+ "math"
+ "reflect"
+ "strconv"
+)
+
+func isKind(what interface{}, kind reflect.Kind) bool {
+ target := what
+ if isJsonNumber(what) {
+ // JSON Numbers are strings!
+ target = *mustBeNumber(what)
+ }
+ return reflect.ValueOf(target).Kind() == kind
+}
+
+func existsMapKey(m map[string]interface{}, k string) bool {
+ _, ok := m[k]
+ return ok
+}
+
+func isStringInSlice(s []string, what string) bool {
+ for i := range s {
+ if s[i] == what {
+ return true
+ }
+ }
+ return false
+}
+
+func marshalToJsonString(value interface{}) (*string, error) {
+
+ mBytes, err := json.Marshal(value)
+ if err != nil {
+ return nil, err
+ }
+
+ sBytes := string(mBytes)
+ return &sBytes, nil
+}
+
+func isJsonNumber(what interface{}) bool {
+
+ switch what.(type) {
+
+ case json.Number:
+ return true
+ }
+
+ return false
+}
+
+func checkJsonNumber(what interface{}) (isValidFloat64 bool, isValidInt64 bool, isValidInt32 bool) {
+
+ jsonNumber := what.(json.Number)
+
+ f64, errFloat64 := jsonNumber.Float64()
+ s64 := strconv.FormatFloat(f64, 'f', -1, 64)
+ _, errInt64 := strconv.ParseInt(s64, 10, 64)
+
+ isValidFloat64 = errFloat64 == nil
+ isValidInt64 = errInt64 == nil
+
+ _, errInt32 := strconv.ParseInt(s64, 10, 32)
+ isValidInt32 = isValidInt64 && errInt32 == nil
+
+ return
+
+}
+
+// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
+const (
+ max_json_float = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
+ min_json_float = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
+)
+
+func isFloat64AnInteger(f float64) bool {
+
+ if math.IsNaN(f) || math.IsInf(f, 0) || f < min_json_float || f > max_json_float {
+ return false
+ }
+
+ return f == float64(int64(f)) || f == float64(uint64(f))
+}
+
+func mustBeInteger(what interface{}) *int {
+
+ if isJsonNumber(what) {
+
+ number := what.(json.Number)
+
+ _, _, isValidInt32 := checkJsonNumber(number)
+
+ if isValidInt32 {
+
+ int64Value, err := number.Int64()
+ if err != nil {
+ return nil
+ }
+
+ int32Value := int(int64Value)
+ return &int32Value
+
+ } else {
+ return nil
+ }
+
+ }
+
+ return nil
+}
+
+func mustBeNumber(what interface{}) *float64 {
+
+ if isJsonNumber(what) {
+
+ number := what.(json.Number)
+ float64Value, err := number.Float64()
+
+ if err == nil {
+ return &float64Value
+ } else {
+ return nil
+ }
+
+ }
+
+ return nil
+
+}
+
+// formats a number so that it is displayed as the smallest string possible
+func resultErrorFormatJsonNumber(n json.Number) string {
+
+ if int64Value, err := n.Int64(); err == nil {
+ return fmt.Sprintf("%d", int64Value)
+ }
+
+ float64Value, _ := n.Float64()
+
+ return fmt.Sprintf("%g", float64Value)
+}
+
+// formats a number so that it is displayed as the smallest string possible
+func resultErrorFormatNumber(n float64) string {
+
+ if isFloat64AnInteger(n) {
+ return fmt.Sprintf("%d", int64(n))
+ }
+
+ return fmt.Sprintf("%g", n)
+}
+
+func convertDocumentNode(val interface{}) interface{} {
+
+ if lval, ok := val.([]interface{}); ok {
+
+ res := []interface{}{}
+ for _, v := range lval {
+ res = append(res, convertDocumentNode(v))
+ }
+
+ return res
+
+ }
+
+ if mval, ok := val.(map[interface{}]interface{}); ok {
+
+ res := map[string]interface{}{}
+
+ for k, v := range mval {
+ res[k.(string)] = convertDocumentNode(v)
+ }
+
+ return res
+
+ }
+
+ return val
+}
diff --git a/vendor/github.com/xeipuuv/gojsonschema/validation.go b/vendor/github.com/xeipuuv/gojsonschema/validation.go
new file mode 100644
index 000000000..9afea2518
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonschema/validation.go
@@ -0,0 +1,844 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonschema
+// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description Extends Schema and subSchema, implements the validation phase.
+//
+// created 28-02-2013
+
+package gojsonschema
+
+import (
+ "encoding/json"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+)
+
+func Validate(ls JSONLoader, ld JSONLoader) (*Result, error) {
+
+ var err error
+
+ // load schema
+
+ schema, err := NewSchema(ls)
+ if err != nil {
+ return nil, err
+ }
+
+ // begine validation
+
+ return schema.Validate(ld)
+
+}
+
+func (v *Schema) Validate(l JSONLoader) (*Result, error) {
+
+ // load document
+
+ root, err := l.LoadJSON()
+ if err != nil {
+ return nil, err
+ }
+
+ // begin validation
+
+ result := &Result{}
+ context := newJsonContext(STRING_CONTEXT_ROOT, nil)
+ v.rootSchema.validateRecursive(v.rootSchema, root, result, context)
+
+ return result, nil
+
+}
+
+func (v *subSchema) subValidateWithContext(document interface{}, context *jsonContext) *Result {
+ result := &Result{}
+ v.validateRecursive(v, document, result, context)
+ return result
+}
+
+// Walker function to validate the json recursively against the subSchema
+func (v *subSchema) validateRecursive(currentSubSchema *subSchema, currentNode interface{}, result *Result, context *jsonContext) {
+
+ if internalLogEnabled {
+ internalLog("validateRecursive %s", context.String())
+ internalLog(" %v", currentNode)
+ }
+
+ // Handle referenced schemas, returns directly when a $ref is found
+ if currentSubSchema.refSchema != nil {
+ v.validateRecursive(currentSubSchema.refSchema, currentNode, result, context)
+ return
+ }
+
+ // Check for null value
+ if currentNode == nil {
+ if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_NULL) {
+ result.addError(
+ new(InvalidTypeError),
+ context,
+ currentNode,
+ ErrorDetails{
+ "expected": currentSubSchema.types.String(),
+ "given": TYPE_NULL,
+ },
+ )
+ return
+ }
+
+ currentSubSchema.validateSchema(currentSubSchema, currentNode, result, context)
+ v.validateCommon(currentSubSchema, currentNode, result, context)
+
+ } else { // Not a null value
+
+ if isJsonNumber(currentNode) {
+
+ value := currentNode.(json.Number)
+
+ _, isValidInt64, _ := checkJsonNumber(value)
+
+ validType := currentSubSchema.types.Contains(TYPE_NUMBER) || (isValidInt64 && currentSubSchema.types.Contains(TYPE_INTEGER))
+
+ if currentSubSchema.types.IsTyped() && !validType {
+
+ givenType := TYPE_INTEGER
+ if !isValidInt64 {
+ givenType = TYPE_NUMBER
+ }
+
+ result.addError(
+ new(InvalidTypeError),
+ context,
+ currentNode,
+ ErrorDetails{
+ "expected": currentSubSchema.types.String(),
+ "given": givenType,
+ },
+ )
+ return
+ }
+
+ currentSubSchema.validateSchema(currentSubSchema, value, result, context)
+ v.validateNumber(currentSubSchema, value, result, context)
+ v.validateCommon(currentSubSchema, value, result, context)
+ v.validateString(currentSubSchema, value, result, context)
+
+ } else {
+
+ rValue := reflect.ValueOf(currentNode)
+ rKind := rValue.Kind()
+
+ switch rKind {
+
+ // Slice => JSON array
+
+ case reflect.Slice:
+
+ if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_ARRAY) {
+ result.addError(
+ new(InvalidTypeError),
+ context,
+ currentNode,
+ ErrorDetails{
+ "expected": currentSubSchema.types.String(),
+ "given": TYPE_ARRAY,
+ },
+ )
+ return
+ }
+
+ castCurrentNode := currentNode.([]interface{})
+
+ currentSubSchema.validateSchema(currentSubSchema, castCurrentNode, result, context)
+
+ v.validateArray(currentSubSchema, castCurrentNode, result, context)
+ v.validateCommon(currentSubSchema, castCurrentNode, result, context)
+
+ // Map => JSON object
+
+ case reflect.Map:
+ if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_OBJECT) {
+ result.addError(
+ new(InvalidTypeError),
+ context,
+ currentNode,
+ ErrorDetails{
+ "expected": currentSubSchema.types.String(),
+ "given": TYPE_OBJECT,
+ },
+ )
+ return
+ }
+
+ castCurrentNode, ok := currentNode.(map[string]interface{})
+ if !ok {
+ castCurrentNode = convertDocumentNode(currentNode).(map[string]interface{})
+ }
+
+ currentSubSchema.validateSchema(currentSubSchema, castCurrentNode, result, context)
+
+ v.validateObject(currentSubSchema, castCurrentNode, result, context)
+ v.validateCommon(currentSubSchema, castCurrentNode, result, context)
+
+ for _, pSchema := range currentSubSchema.propertiesChildren {
+ nextNode, ok := castCurrentNode[pSchema.property]
+ if ok {
+ subContext := newJsonContext(pSchema.property, context)
+ v.validateRecursive(pSchema, nextNode, result, subContext)
+ }
+ }
+
+ // Simple JSON values : string, number, boolean
+
+ case reflect.Bool:
+
+ if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_BOOLEAN) {
+ result.addError(
+ new(InvalidTypeError),
+ context,
+ currentNode,
+ ErrorDetails{
+ "expected": currentSubSchema.types.String(),
+ "given": TYPE_BOOLEAN,
+ },
+ )
+ return
+ }
+
+ value := currentNode.(bool)
+
+ currentSubSchema.validateSchema(currentSubSchema, value, result, context)
+ v.validateNumber(currentSubSchema, value, result, context)
+ v.validateCommon(currentSubSchema, value, result, context)
+ v.validateString(currentSubSchema, value, result, context)
+
+ case reflect.String:
+
+ if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_STRING) {
+ result.addError(
+ new(InvalidTypeError),
+ context,
+ currentNode,
+ ErrorDetails{
+ "expected": currentSubSchema.types.String(),
+ "given": TYPE_STRING,
+ },
+ )
+ return
+ }
+
+ value := currentNode.(string)
+
+ currentSubSchema.validateSchema(currentSubSchema, value, result, context)
+ v.validateNumber(currentSubSchema, value, result, context)
+ v.validateCommon(currentSubSchema, value, result, context)
+ v.validateString(currentSubSchema, value, result, context)
+
+ }
+
+ }
+
+ }
+
+ result.incrementScore()
+}
+
+// Different kinds of validation there, subSchema / common / array / object / string...
+func (v *subSchema) validateSchema(currentSubSchema *subSchema, currentNode interface{}, result *Result, context *jsonContext) {
+
+ if internalLogEnabled {
+ internalLog("validateSchema %s", context.String())
+ internalLog(" %v", currentNode)
+ }
+
+ if len(currentSubSchema.anyOf) > 0 {
+
+ validatedAnyOf := false
+ var bestValidationResult *Result
+
+ for _, anyOfSchema := range currentSubSchema.anyOf {
+ if !validatedAnyOf {
+ validationResult := anyOfSchema.subValidateWithContext(currentNode, context)
+ validatedAnyOf = validationResult.Valid()
+
+ if !validatedAnyOf && (bestValidationResult == nil || validationResult.score > bestValidationResult.score) {
+ bestValidationResult = validationResult
+ }
+ }
+ }
+ if !validatedAnyOf {
+
+ result.addError(new(NumberAnyOfError), context, currentNode, ErrorDetails{})
+
+ if bestValidationResult != nil {
+ // add error messages of closest matching subSchema as
+ // that's probably the one the user was trying to match
+ result.mergeErrors(bestValidationResult)
+ }
+ }
+ }
+
+ if len(currentSubSchema.oneOf) > 0 {
+
+ nbValidated := 0
+ var bestValidationResult *Result
+
+ for _, oneOfSchema := range currentSubSchema.oneOf {
+ validationResult := oneOfSchema.subValidateWithContext(currentNode, context)
+ if validationResult.Valid() {
+ nbValidated++
+ } else if nbValidated == 0 && (bestValidationResult == nil || validationResult.score > bestValidationResult.score) {
+ bestValidationResult = validationResult
+ }
+ }
+
+ if nbValidated != 1 {
+
+ result.addError(new(NumberOneOfError), context, currentNode, ErrorDetails{})
+
+ if nbValidated == 0 {
+ // add error messages of closest matching subSchema as
+ // that's probably the one the user was trying to match
+ result.mergeErrors(bestValidationResult)
+ }
+ }
+
+ }
+
+ if len(currentSubSchema.allOf) > 0 {
+ nbValidated := 0
+
+ for _, allOfSchema := range currentSubSchema.allOf {
+ validationResult := allOfSchema.subValidateWithContext(currentNode, context)
+ if validationResult.Valid() {
+ nbValidated++
+ }
+ result.mergeErrors(validationResult)
+ }
+
+ if nbValidated != len(currentSubSchema.allOf) {
+ result.addError(new(NumberAllOfError), context, currentNode, ErrorDetails{})
+ }
+ }
+
+ if currentSubSchema.not != nil {
+ validationResult := currentSubSchema.not.subValidateWithContext(currentNode, context)
+ if validationResult.Valid() {
+ result.addError(new(NumberNotError), context, currentNode, ErrorDetails{})
+ }
+ }
+
+ if currentSubSchema.dependencies != nil && len(currentSubSchema.dependencies) > 0 {
+ if isKind(currentNode, reflect.Map) {
+ for elementKey := range currentNode.(map[string]interface{}) {
+ if dependency, ok := currentSubSchema.dependencies[elementKey]; ok {
+ switch dependency := dependency.(type) {
+
+ case []string:
+ for _, dependOnKey := range dependency {
+ if _, dependencyResolved := currentNode.(map[string]interface{})[dependOnKey]; !dependencyResolved {
+ result.addError(
+ new(MissingDependencyError),
+ context,
+ currentNode,
+ ErrorDetails{"dependency": dependOnKey},
+ )
+ }
+ }
+
+ case *subSchema:
+ dependency.validateRecursive(dependency, currentNode, result, context)
+
+ }
+ }
+ }
+ }
+ }
+
+ result.incrementScore()
+}
+
+func (v *subSchema) validateCommon(currentSubSchema *subSchema, value interface{}, result *Result, context *jsonContext) {
+
+ if internalLogEnabled {
+ internalLog("validateCommon %s", context.String())
+ internalLog(" %v", value)
+ }
+
+ // enum:
+ if len(currentSubSchema.enum) > 0 {
+ has, err := currentSubSchema.ContainsEnum(value)
+ if err != nil {
+ result.addError(new(InternalError), context, value, ErrorDetails{"error": err})
+ }
+ if !has {
+ result.addError(
+ new(EnumError),
+ context,
+ value,
+ ErrorDetails{
+ "allowed": strings.Join(currentSubSchema.enum, ", "),
+ },
+ )
+ }
+ }
+
+ result.incrementScore()
+}
+
+func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface{}, result *Result, context *jsonContext) {
+
+ if internalLogEnabled {
+ internalLog("validateArray %s", context.String())
+ internalLog(" %v", value)
+ }
+
+ nbValues := len(value)
+
+ // TODO explain
+ if currentSubSchema.itemsChildrenIsSingleSchema {
+ for i := range value {
+ subContext := newJsonContext(strconv.Itoa(i), context)
+ validationResult := currentSubSchema.itemsChildren[0].subValidateWithContext(value[i], subContext)
+ result.mergeErrors(validationResult)
+ }
+ } else {
+ if currentSubSchema.itemsChildren != nil && len(currentSubSchema.itemsChildren) > 0 {
+
+ nbItems := len(currentSubSchema.itemsChildren)
+
+ // while we have both schemas and values, check them against each other
+ for i := 0; i != nbItems && i != nbValues; i++ {
+ subContext := newJsonContext(strconv.Itoa(i), context)
+ validationResult := currentSubSchema.itemsChildren[i].subValidateWithContext(value[i], subContext)
+ result.mergeErrors(validationResult)
+ }
+
+ if nbItems < nbValues {
+ // we have less schemas than elements in the instance array,
+ // but that might be ok if "additionalItems" is specified.
+
+ switch currentSubSchema.additionalItems.(type) {
+ case bool:
+ if !currentSubSchema.additionalItems.(bool) {
+ result.addError(new(ArrayNoAdditionalItemsError), context, value, ErrorDetails{})
+ }
+ case *subSchema:
+ additionalItemSchema := currentSubSchema.additionalItems.(*subSchema)
+ for i := nbItems; i != nbValues; i++ {
+ subContext := newJsonContext(strconv.Itoa(i), context)
+ validationResult := additionalItemSchema.subValidateWithContext(value[i], subContext)
+ result.mergeErrors(validationResult)
+ }
+ }
+ }
+ }
+ }
+
+ // minItems & maxItems
+ if currentSubSchema.minItems != nil {
+ if nbValues < int(*currentSubSchema.minItems) {
+ result.addError(
+ new(ArrayMinItemsError),
+ context,
+ value,
+ ErrorDetails{"min": *currentSubSchema.minItems},
+ )
+ }
+ }
+ if currentSubSchema.maxItems != nil {
+ if nbValues > int(*currentSubSchema.maxItems) {
+ result.addError(
+ new(ArrayMaxItemsError),
+ context,
+ value,
+ ErrorDetails{"max": *currentSubSchema.maxItems},
+ )
+ }
+ }
+
+ // uniqueItems:
+ if currentSubSchema.uniqueItems {
+ var stringifiedItems []string
+ for _, v := range value {
+ vString, err := marshalToJsonString(v)
+ if err != nil {
+ result.addError(new(InternalError), context, value, ErrorDetails{"err": err})
+ }
+ if isStringInSlice(stringifiedItems, *vString) {
+ result.addError(
+ new(ItemsMustBeUniqueError),
+ context,
+ value,
+ ErrorDetails{"type": TYPE_ARRAY},
+ )
+ }
+ stringifiedItems = append(stringifiedItems, *vString)
+ }
+ }
+
+ result.incrementScore()
+}
+
+func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string]interface{}, result *Result, context *jsonContext) {
+
+ if internalLogEnabled {
+ internalLog("validateObject %s", context.String())
+ internalLog(" %v", value)
+ }
+
+ // minProperties & maxProperties:
+ if currentSubSchema.minProperties != nil {
+ if len(value) < int(*currentSubSchema.minProperties) {
+ result.addError(
+ new(ArrayMinPropertiesError),
+ context,
+ value,
+ ErrorDetails{"min": *currentSubSchema.minProperties},
+ )
+ }
+ }
+ if currentSubSchema.maxProperties != nil {
+ if len(value) > int(*currentSubSchema.maxProperties) {
+ result.addError(
+ new(ArrayMaxPropertiesError),
+ context,
+ value,
+ ErrorDetails{"max": *currentSubSchema.maxProperties},
+ )
+ }
+ }
+
+ // required:
+ for _, requiredProperty := range currentSubSchema.required {
+ _, ok := value[requiredProperty]
+ if ok {
+ result.incrementScore()
+ } else {
+ result.addError(
+ new(RequiredError),
+ context,
+ value,
+ ErrorDetails{"property": requiredProperty},
+ )
+ }
+ }
+
+ // additionalProperty & patternProperty:
+ if currentSubSchema.additionalProperties != nil {
+
+ switch currentSubSchema.additionalProperties.(type) {
+ case bool:
+
+ if !currentSubSchema.additionalProperties.(bool) {
+
+ for pk := range value {
+
+ found := false
+ for _, spValue := range currentSubSchema.propertiesChildren {
+ if pk == spValue.property {
+ found = true
+ }
+ }
+
+ pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context)
+
+ if found {
+
+ if pp_has && !pp_match {
+ result.addError(
+ new(AdditionalPropertyNotAllowedError),
+ context,
+ value[pk],
+ ErrorDetails{"property": pk},
+ )
+ }
+
+ } else {
+
+ if !pp_has || !pp_match {
+ result.addError(
+ new(AdditionalPropertyNotAllowedError),
+ context,
+ value[pk],
+ ErrorDetails{"property": pk},
+ )
+ }
+
+ }
+ }
+ }
+
+ case *subSchema:
+
+ additionalPropertiesSchema := currentSubSchema.additionalProperties.(*subSchema)
+ for pk := range value {
+
+ found := false
+ for _, spValue := range currentSubSchema.propertiesChildren {
+ if pk == spValue.property {
+ found = true
+ }
+ }
+
+ pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context)
+
+ if found {
+
+ if pp_has && !pp_match {
+ validationResult := additionalPropertiesSchema.subValidateWithContext(value[pk], context)
+ result.mergeErrors(validationResult)
+ }
+
+ } else {
+
+ if !pp_has || !pp_match {
+ validationResult := additionalPropertiesSchema.subValidateWithContext(value[pk], context)
+ result.mergeErrors(validationResult)
+ }
+
+ }
+
+ }
+ }
+ } else {
+
+ for pk := range value {
+
+ pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context)
+
+ if pp_has && !pp_match {
+
+ result.addError(
+ new(InvalidPropertyPatternError),
+ context,
+ value[pk],
+ ErrorDetails{
+ "property": pk,
+ "pattern": currentSubSchema.PatternPropertiesString(),
+ },
+ )
+ }
+
+ }
+ }
+
+ result.incrementScore()
+}
+
+func (v *subSchema) validatePatternProperty(currentSubSchema *subSchema, key string, value interface{}, result *Result, context *jsonContext) (has bool, matched bool) {
+
+ if internalLogEnabled {
+ internalLog("validatePatternProperty %s", context.String())
+ internalLog(" %s %v", key, value)
+ }
+
+ has = false
+
+ validatedkey := false
+
+ for pk, pv := range currentSubSchema.patternProperties {
+ if matches, _ := regexp.MatchString(pk, key); matches {
+ has = true
+ subContext := newJsonContext(key, context)
+ validationResult := pv.subValidateWithContext(value, subContext)
+ result.mergeErrors(validationResult)
+ if validationResult.Valid() {
+ validatedkey = true
+ }
+ }
+ }
+
+ if !validatedkey {
+ return has, false
+ }
+
+ result.incrementScore()
+
+ return has, true
+}
+
+func (v *subSchema) validateString(currentSubSchema *subSchema, value interface{}, result *Result, context *jsonContext) {
+
+ // Ignore JSON numbers
+ if isJsonNumber(value) {
+ return
+ }
+
+ // Ignore non strings
+ if !isKind(value, reflect.String) {
+ return
+ }
+
+ if internalLogEnabled {
+ internalLog("validateString %s", context.String())
+ internalLog(" %v", value)
+ }
+
+ stringValue := value.(string)
+
+ // minLength & maxLength:
+ if currentSubSchema.minLength != nil {
+ if utf8.RuneCount([]byte(stringValue)) < int(*currentSubSchema.minLength) {
+ result.addError(
+ new(StringLengthGTEError),
+ context,
+ value,
+ ErrorDetails{"min": *currentSubSchema.minLength},
+ )
+ }
+ }
+ if currentSubSchema.maxLength != nil {
+ if utf8.RuneCount([]byte(stringValue)) > int(*currentSubSchema.maxLength) {
+ result.addError(
+ new(StringLengthLTEError),
+ context,
+ value,
+ ErrorDetails{"max": *currentSubSchema.maxLength},
+ )
+ }
+ }
+
+ // pattern:
+ if currentSubSchema.pattern != nil {
+ if !currentSubSchema.pattern.MatchString(stringValue) {
+ result.addError(
+ new(DoesNotMatchPatternError),
+ context,
+ value,
+ ErrorDetails{"pattern": currentSubSchema.pattern},
+ )
+
+ }
+ }
+
+ // format
+ if currentSubSchema.format != "" {
+ if !FormatCheckers.IsFormat(currentSubSchema.format, stringValue) {
+ result.addError(
+ new(DoesNotMatchFormatError),
+ context,
+ value,
+ ErrorDetails{"format": currentSubSchema.format},
+ )
+ }
+ }
+
+ result.incrementScore()
+}
+
+func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{}, result *Result, context *jsonContext) {
+
+ // Ignore non numbers
+ if !isJsonNumber(value) {
+ return
+ }
+
+ if internalLogEnabled {
+ internalLog("validateNumber %s", context.String())
+ internalLog(" %v", value)
+ }
+
+ number := value.(json.Number)
+ float64Value, _ := number.Float64()
+
+ // multipleOf:
+ if currentSubSchema.multipleOf != nil {
+
+ if !isFloat64AnInteger(float64Value / *currentSubSchema.multipleOf) {
+ result.addError(
+ new(MultipleOfError),
+ context,
+ resultErrorFormatJsonNumber(number),
+ ErrorDetails{"multiple": *currentSubSchema.multipleOf},
+ )
+ }
+ }
+
+ //maximum & exclusiveMaximum:
+ if currentSubSchema.maximum != nil {
+ if currentSubSchema.exclusiveMaximum {
+ if float64Value >= *currentSubSchema.maximum {
+ result.addError(
+ new(NumberLTError),
+ context,
+ resultErrorFormatJsonNumber(number),
+ ErrorDetails{
+ "max": resultErrorFormatNumber(*currentSubSchema.maximum),
+ },
+ )
+ }
+ } else {
+ if float64Value > *currentSubSchema.maximum {
+ result.addError(
+ new(NumberLTEError),
+ context,
+ resultErrorFormatJsonNumber(number),
+ ErrorDetails{
+ "max": resultErrorFormatNumber(*currentSubSchema.maximum),
+ },
+ )
+ }
+ }
+ }
+
+ //minimum & exclusiveMinimum:
+ if currentSubSchema.minimum != nil {
+ if currentSubSchema.exclusiveMinimum {
+ if float64Value <= *currentSubSchema.minimum {
+ result.addError(
+ new(NumberGTError),
+ context,
+ resultErrorFormatJsonNumber(number),
+ ErrorDetails{
+ "min": resultErrorFormatNumber(*currentSubSchema.minimum),
+ },
+ )
+ }
+ } else {
+ if float64Value < *currentSubSchema.minimum {
+ result.addError(
+ new(NumberGTEError),
+ context,
+ resultErrorFormatJsonNumber(number),
+ ErrorDetails{
+ "min": resultErrorFormatNumber(*currentSubSchema.minimum),
+ },
+ )
+ }
+ }
+ }
+
+ // format
+ if currentSubSchema.format != "" {
+ if !FormatCheckers.IsFormat(currentSubSchema.format, float64Value) {
+ result.addError(
+ new(DoesNotMatchFormatError),
+ context,
+ value,
+ ErrorDetails{"format": currentSubSchema.format},
+ )
+ }
+ }
+
+ result.incrementScore()
+}