forked from LaconicNetwork/kompose
add github.com/pkg/errors to glide and vendor
This adds github.com/pkg/errors to glide.yaml followed by glide and glide-vc commands. The github.com/pkg/errors package is currently required mainly for the errors.Wrap() and errors.New() methods, since this lets us to annotate the errors while passing the error message up the call stack.
This commit is contained in:
+8
-40
@@ -1,20 +1,10 @@
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
"text/template"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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 {
|
||||
@@ -240,35 +230,13 @@ func newError(err ResultError, context *jsonContext, value interface{}, locale l
|
||||
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.
|
||||
// formatErrorDescription takes a string in this format: %field% is required
|
||||
// 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)
|
||||
|
||||
tpl, err = tpl.Parse(s)
|
||||
errorTemplates.Unlock()
|
||||
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
for name, val := range details {
|
||||
s = strings.Replace(s, "%"+strings.ToLower(name)+"%", fmt.Sprintf("%v", val), -1)
|
||||
}
|
||||
|
||||
err = tpl.Execute(&descrAsBuffer, details)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return descrAsBuffer.String()
|
||||
return s
|
||||
}
|
||||
|
||||
+4
-21
@@ -5,7 +5,6 @@ import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -60,9 +59,6 @@ type (
|
||||
|
||||
// UUIDFormatChecker validates a UUID is in the correct format
|
||||
UUIDFormatChecker struct{}
|
||||
|
||||
// RegexFormatChecker validates a regex is in the correct format
|
||||
RegexFormatChecker struct{}
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -77,7 +73,6 @@ var (
|
||||
"ipv6": IPV6FormatChecker{},
|
||||
"uri": URIFormatChecker{},
|
||||
"uuid": UUIDFormatChecker{},
|
||||
"regex": RegexFormatChecker{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -85,7 +80,7 @@ var (
|
||||
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]))*$`)
|
||||
rxHostname = regexp.MustCompile(`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[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}$")
|
||||
)
|
||||
@@ -137,13 +132,13 @@ func (f EmailFormatChecker) IsFormat(input string) bool {
|
||||
// Credit: https://github.com/asaskevich/govalidator
|
||||
func (f IPV4FormatChecker) IsFormat(input string) bool {
|
||||
ip := net.ParseIP(input)
|
||||
return ip != nil && strings.Contains(input, ".")
|
||||
return ip != nil && ip.To4() != nil
|
||||
}
|
||||
|
||||
// Credit: https://github.com/asaskevich/govalidator
|
||||
func (f IPV6FormatChecker) IsFormat(input string) bool {
|
||||
ip := net.ParseIP(input)
|
||||
return ip != nil && strings.Contains(input, ":")
|
||||
return ip != nil && ip.To4() == nil
|
||||
}
|
||||
|
||||
func (f DateTimeFormatChecker) IsFormat(input string) bool {
|
||||
@@ -174,21 +169,9 @@ func (f URIFormatChecker) IsFormat(input string) bool {
|
||||
}
|
||||
|
||||
func (f HostnameFormatChecker) IsFormat(input string) bool {
|
||||
return rxHostname.MatchString(input) && len(input) < 256
|
||||
return rxHostname.MatchString(input)
|
||||
}
|
||||
|
||||
func (f UUIDFormatChecker) IsFormat(input string) bool {
|
||||
return rxUUID.MatchString(input)
|
||||
}
|
||||
|
||||
// IsFormat implements FormatChecker interface.
|
||||
func (f RegexFormatChecker) IsFormat(input string) bool {
|
||||
if input == "" {
|
||||
return true
|
||||
}
|
||||
_, err := regexp.Compile(input)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
+82
-136
@@ -33,7 +33,6 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -41,92 +40,34 @@ import (
|
||||
"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)
|
||||
jsonSource() interface{}
|
||||
loadJSON() (interface{}, error)
|
||||
loadSchema() (*Schema, error)
|
||||
}
|
||||
|
||||
// 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{} {
|
||||
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,
|
||||
}
|
||||
return &jsonReferenceLoader{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) {
|
||||
func (l *jsonReferenceLoader) loadJSON() (interface{}, error) {
|
||||
|
||||
var err error
|
||||
|
||||
reference, err := gojsonreference.NewJsonReference(l.JsonSource().(string))
|
||||
reference, err := gojsonreference.NewJsonReference(l.jsonSource().(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -138,7 +79,7 @@ func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
|
||||
|
||||
if reference.HasFileScheme {
|
||||
|
||||
filename := strings.Replace(refToUrl.GetUrl().Path, "file://", "", -1)
|
||||
filename := strings.Replace(refToUrl.String(), "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
|
||||
@@ -146,6 +87,7 @@ func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
|
||||
filename = filename[1:]
|
||||
}
|
||||
filename = filepath.FromSlash(filename)
|
||||
filename = strings.Replace(filename, "%20", " ", -1)
|
||||
}
|
||||
|
||||
document, err = l.loadFromFile(filename)
|
||||
@@ -166,6 +108,33 @@ func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
|
||||
|
||||
}
|
||||
|
||||
func (l *jsonReferenceLoader) loadSchema() (*Schema, error) {
|
||||
|
||||
var err error
|
||||
|
||||
d := Schema{}
|
||||
d.pool = newSchemaPool()
|
||||
d.referencePool = newSchemaReferencePool()
|
||||
|
||||
d.documentReference, err = gojsonreference.NewJsonReference(l.jsonSource().(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spd, err := d.pool.GetDocument(d.documentReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.parse(spd.Document)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d, nil
|
||||
|
||||
}
|
||||
|
||||
func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) {
|
||||
|
||||
resp, err := http.Get(address)
|
||||
@@ -175,7 +144,7 @@ func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error)
|
||||
|
||||
// must return HTTP Status 200 OK
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(formatErrorDescription(Locale.HttpBadStatus(), ErrorDetails{"status": resp.Status}))
|
||||
return nil, errors.New(formatErrorDescription(Locale.httpBadStatus(), ErrorDetails{"status": resp.Status}))
|
||||
}
|
||||
|
||||
bodyBuff, err := ioutil.ReadAll(resp.Body)
|
||||
@@ -188,13 +157,8 @@ func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error)
|
||||
}
|
||||
|
||||
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)
|
||||
bodyBuff, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -209,52 +173,45 @@ type jsonStringLoader struct {
|
||||
source string
|
||||
}
|
||||
|
||||
func (l *jsonStringLoader) JsonSource() interface{} {
|
||||
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) {
|
||||
func (l *jsonStringLoader) loadJSON() (interface{}, error) {
|
||||
|
||||
return decodeJsonUsingNumber(strings.NewReader(l.JsonSource().(string)))
|
||||
return decodeJsonUsingNumber(strings.NewReader(l.jsonSource().(string)))
|
||||
|
||||
}
|
||||
|
||||
// JSON bytes loader
|
||||
func (l *jsonStringLoader) loadSchema() (*Schema, error) {
|
||||
|
||||
type jsonBytesLoader struct {
|
||||
source []byte
|
||||
}
|
||||
var err error
|
||||
|
||||
func (l *jsonBytesLoader) JsonSource() interface{} {
|
||||
return l.source
|
||||
}
|
||||
document, err := l.loadJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (l *jsonBytesLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
||||
return gojsonreference.NewJsonReference("#")
|
||||
}
|
||||
d := Schema{}
|
||||
d.pool = newSchemaPool()
|
||||
d.referencePool = newSchemaReferencePool()
|
||||
d.documentReference, err = gojsonreference.NewJsonReference("#")
|
||||
d.pool.SetStandaloneDocument(document)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (l *jsonBytesLoader) LoaderFactory() JSONLoaderFactory {
|
||||
return &DefaultJSONLoaderFactory{}
|
||||
}
|
||||
err = d.parse(document)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func NewBytesLoader(source []byte) *jsonBytesLoader {
|
||||
return &jsonBytesLoader{source: source}
|
||||
}
|
||||
return &d, nil
|
||||
|
||||
func (l *jsonBytesLoader) LoadJSON() (interface{}, error) {
|
||||
return decodeJsonUsingNumber(bytes.NewReader(l.JsonSource().([]byte)))
|
||||
}
|
||||
|
||||
// JSON Go (types) loader
|
||||
@@ -264,27 +221,19 @@ type jsonGoLoader struct {
|
||||
source interface{}
|
||||
}
|
||||
|
||||
func (l *jsonGoLoader) JsonSource() 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) {
|
||||
func (l *jsonGoLoader) loadJSON() (interface{}, error) {
|
||||
|
||||
// convert it to a compliant JSON first to avoid types "mismatches"
|
||||
|
||||
jsonBytes, err := json.Marshal(l.JsonSource())
|
||||
jsonBytes, err := json.Marshal(l.jsonSource())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -293,34 +242,31 @@ func (l *jsonGoLoader) LoadJSON() (interface{}, error) {
|
||||
|
||||
}
|
||||
|
||||
type jsonIOLoader struct {
|
||||
buf *bytes.Buffer
|
||||
}
|
||||
func (l *jsonGoLoader) loadSchema() (*Schema, error) {
|
||||
|
||||
func NewReaderLoader(source io.Reader) (*jsonIOLoader, io.Reader) {
|
||||
buf := &bytes.Buffer{}
|
||||
return &jsonIOLoader{buf: buf}, io.TeeReader(source, buf)
|
||||
}
|
||||
var err error
|
||||
|
||||
func NewWriterLoader(source io.Writer) (*jsonIOLoader, io.Writer) {
|
||||
buf := &bytes.Buffer{}
|
||||
return &jsonIOLoader{buf: buf}, io.MultiWriter(source, buf)
|
||||
}
|
||||
document, err := l.loadJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (l *jsonIOLoader) JsonSource() interface{} {
|
||||
return l.buf.String()
|
||||
}
|
||||
d := Schema{}
|
||||
d.pool = newSchemaPool()
|
||||
d.referencePool = newSchemaReferencePool()
|
||||
d.documentReference, err = gojsonreference.NewJsonReference("#")
|
||||
d.pool.SetStandaloneDocument(document)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (l *jsonIOLoader) LoadJSON() (interface{}, error) {
|
||||
return decodeJsonUsingNumber(l.buf)
|
||||
}
|
||||
err = d.parse(document)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (l *jsonIOLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
||||
return gojsonreference.NewJsonReference("#")
|
||||
}
|
||||
return &d, nil
|
||||
|
||||
func (l *jsonIOLoader) LoaderFactory() JSONLoaderFactory {
|
||||
return &DefaultJSONLoaderFactory{}
|
||||
}
|
||||
|
||||
func decodeJsonUsingNumber(r io.Reader) (interface{}, error) {
|
||||
|
||||
+42
-47
@@ -26,7 +26,7 @@
|
||||
package gojsonschema
|
||||
|
||||
type (
|
||||
// locale is an interface for defining custom error strings
|
||||
// locale is an interface for definining custom error strings
|
||||
locale interface {
|
||||
Required() string
|
||||
InvalidType() string
|
||||
@@ -37,7 +37,6 @@ type (
|
||||
MissingDependency() string
|
||||
Internal() string
|
||||
Enum() string
|
||||
ArrayNotEnoughItems() string
|
||||
ArrayNoAdditionalItems() string
|
||||
ArrayMinItems() string
|
||||
ArrayMaxItems() string
|
||||
@@ -73,7 +72,7 @@ type (
|
||||
ReferenceMustBeCanonical() string
|
||||
NotAValidType() string
|
||||
Duplicated() string
|
||||
HttpBadStatus() string
|
||||
httpBadStatus() string
|
||||
|
||||
// ErrorFormat
|
||||
ErrorFormat() string
|
||||
@@ -84,11 +83,11 @@ type (
|
||||
)
|
||||
|
||||
func (l DefaultLocale) Required() string {
|
||||
return `{{.property}} is required`
|
||||
return `%property% is required`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) InvalidType() string {
|
||||
return `Invalid type. Expected: {{.expected}}, given: {{.given}}`
|
||||
return `Invalid type. Expected: %expected%, given: %given%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) NumberAnyOf() string {
|
||||
@@ -108,161 +107,157 @@ func (l DefaultLocale) NumberNot() string {
|
||||
}
|
||||
|
||||
func (l DefaultLocale) MissingDependency() string {
|
||||
return `Has a dependency on {{.dependency}}`
|
||||
return `Has a dependency on %dependency%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) Internal() string {
|
||||
return `Internal Error {{.error}}`
|
||||
return `Internal Error %error%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) Enum() string {
|
||||
return `{{.field}} must be one of the following: {{.allowed}}`
|
||||
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`
|
||||
return `Array must have at least %min% items`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) ArrayMaxItems() string {
|
||||
return `Array must have at most {{.max}} items`
|
||||
return `Array must have at most %max% items`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) Unique() string {
|
||||
return `{{.type}} items must be unique`
|
||||
return `%type% items must be unique`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) ArrayMinProperties() string {
|
||||
return `Must have at least {{.min}} properties`
|
||||
return `Must have at least %min% properties`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) ArrayMaxProperties() string {
|
||||
return `Must have at most {{.max}} properties`
|
||||
return `Must have at most %max% properties`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) AdditionalPropertyNotAllowed() string {
|
||||
return `Additional property {{.property}} is not allowed`
|
||||
return `Additional property %property% is not allowed`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) InvalidPropertyPattern() string {
|
||||
return `Property "{{.property}}" does not match pattern {{.pattern}}`
|
||||
return `Property "%property%" does not match pattern %pattern%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) StringGTE() string {
|
||||
return `String length must be greater than or equal to {{.min}}`
|
||||
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}}`
|
||||
return `String length must be less than or equal to %max%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) DoesNotMatchPattern() string {
|
||||
return `Does not match pattern '{{.pattern}}'`
|
||||
return `Does not match pattern '%pattern%'`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) DoesNotMatchFormat() string {
|
||||
return `Does not match format '{{.format}}'`
|
||||
return `Does not match format '%format%'`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) MultipleOf() string {
|
||||
return `Must be a multiple of {{.multiple}}`
|
||||
return `Must be a multiple of %multiple%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) NumberGTE() string {
|
||||
return `Must be greater than or equal to {{.min}}`
|
||||
return `Must be greater than or equal to %min%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) NumberGT() string {
|
||||
return `Must be greater than {{.min}}`
|
||||
return `Must be greater than %min%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) NumberLTE() string {
|
||||
return `Must be less than or equal to {{.max}}`
|
||||
return `Must be less than or equal to %max%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) NumberLT() string {
|
||||
return `Must be less than {{.max}}`
|
||||
return `Must be less than %max%`
|
||||
}
|
||||
|
||||
// Schema validators
|
||||
func (l DefaultLocale) RegexPattern() string {
|
||||
return `Invalid regex pattern '{{.pattern}}'`
|
||||
return `Invalid regex pattern '%pattern%'`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) GreaterThanZero() string {
|
||||
return `{{.number}} must be strictly greater than 0`
|
||||
return `%number% must be strictly greater than 0`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) MustBeOfA() string {
|
||||
return `{{.x}} must be of a {{.y}}`
|
||||
return `%x% must be of a %y%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) MustBeOfAn() string {
|
||||
return `{{.x}} must be of an {{.y}}`
|
||||
return `%x% must be of an %y%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) CannotBeUsedWithout() string {
|
||||
return `{{.x}} cannot be used without {{.y}}`
|
||||
return `%x% cannot be used without %y%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) CannotBeGT() string {
|
||||
return `{{.x}} cannot be greater than {{.y}}`
|
||||
return `%x% cannot be greater than %y%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) MustBeOfType() string {
|
||||
return `{{.key}} must be of type {{.type}}`
|
||||
return `%key% must be of type %type%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) MustBeValidRegex() string {
|
||||
return `{{.key}} must be a valid regex`
|
||||
return `%key% must be a valid regex`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) MustBeValidFormat() string {
|
||||
return `{{.key}} must be a valid format {{.given}}`
|
||||
return `%key% must be a valid format %given%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) MustBeGTEZero() string {
|
||||
return `{{.key}} must be greater than or equal to 0`
|
||||
return `%key% must be greater than or equal to 0`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) KeyCannotBeGreaterThan() string {
|
||||
return `{{.key}} cannot be greater than {{.y}}`
|
||||
return `%key% cannot be greater than %y%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) KeyItemsMustBeOfType() string {
|
||||
return `{{.key}} items must be {{.type}}`
|
||||
return `%key% items must be %type%`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) KeyItemsMustBeUnique() string {
|
||||
return `{{.key}} items must be unique`
|
||||
return `%key% items must be unique`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) ReferenceMustBeCanonical() string {
|
||||
return `Reference {{.reference}} must be canonical`
|
||||
return `Reference %reference% must be canonical`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) NotAValidType() string {
|
||||
return `{{.type}} is not a valid type -- `
|
||||
return `%type% is not a valid type -- `
|
||||
}
|
||||
|
||||
func (l DefaultLocale) Duplicated() string {
|
||||
return `{{.type}} type is duplicated`
|
||||
return `%type% type is duplicated`
|
||||
}
|
||||
|
||||
func (l DefaultLocale) HttpBadStatus() string {
|
||||
return `Could not read schema from HTTP, response status is {{.status}}`
|
||||
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}}`
|
||||
return `%field%: %description%`
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
+1
-2
@@ -48,7 +48,6 @@ type (
|
||||
Value() interface{}
|
||||
SetDetails(ErrorDetails)
|
||||
Details() ErrorDetails
|
||||
String() string
|
||||
}
|
||||
|
||||
// ResultErrorFields holds the fields for each ResultError implementation.
|
||||
@@ -127,7 +126,7 @@ func (v ResultErrorFields) String() string {
|
||||
valueString := fmt.Sprintf("%v", v.value)
|
||||
|
||||
// marshal the go value value to json
|
||||
if v.value == nil {
|
||||
if v.Value == nil {
|
||||
valueString = TYPE_NULL
|
||||
} else {
|
||||
if vs, err := marshalToJsonString(v.value); err == nil {
|
||||
|
||||
+32
-54
@@ -42,39 +42,7 @@ var (
|
||||
)
|
||||
|
||||
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
|
||||
return l.loadSchema()
|
||||
}
|
||||
|
||||
type Schema struct {
|
||||
@@ -148,27 +116,14 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
|
||||
}
|
||||
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)
|
||||
|
||||
var err error
|
||||
err = d.parseReference(documentNode, currentSchema, k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -800,11 +755,31 @@ func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema, reference string) error {
|
||||
var refdDocumentNode interface{}
|
||||
jsonPointer := currentSchema.ref.GetPointer()
|
||||
func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema, reference string) (e error) {
|
||||
|
||||
var err error
|
||||
|
||||
jsonReference, err := gojsonreference.NewJsonReference(reference)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
standaloneDocument := d.pool.GetStandaloneDocument()
|
||||
|
||||
if jsonReference.HasFullUrl {
|
||||
currentSchema.ref = &jsonReference
|
||||
} else {
|
||||
inheritedReference, err := currentSchema.ref.Inherits(jsonReference)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentSchema.ref = inheritedReference
|
||||
}
|
||||
|
||||
jsonPointer := currentSchema.ref.GetPointer()
|
||||
|
||||
var refdDocumentNode interface{}
|
||||
|
||||
if standaloneDocument != nil {
|
||||
|
||||
var err error
|
||||
@@ -814,6 +789,8 @@ func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSche
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
var err error
|
||||
dsp, err := d.pool.GetDocument(*currentSchema.ref)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -835,10 +812,11 @@ func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSche
|
||||
|
||||
// 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)
|
||||
err = d.parseSchema(newSchemaDocument, newSchema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+3
-5
@@ -39,15 +39,13 @@ type schemaPoolDocument struct {
|
||||
type schemaPool struct {
|
||||
schemaPoolDocuments map[string]*schemaPoolDocument
|
||||
standaloneDocument interface{}
|
||||
jsonLoaderFactory JSONLoaderFactory
|
||||
}
|
||||
|
||||
func newSchemaPool(f JSONLoaderFactory) *schemaPool {
|
||||
func newSchemaPool() *schemaPool {
|
||||
|
||||
p := &schemaPool{}
|
||||
p.schemaPoolDocuments = make(map[string]*schemaPoolDocument)
|
||||
p.standaloneDocument = nil
|
||||
p.jsonLoaderFactory = f
|
||||
|
||||
return p
|
||||
}
|
||||
@@ -95,8 +93,8 @@ func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*sche
|
||||
return spd, nil
|
||||
}
|
||||
|
||||
jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String())
|
||||
document, err := jsonReferenceLoader.LoadJSON()
|
||||
jsonReferenceLoader := NewReferenceLoader(reference.String())
|
||||
document, err := jsonReferenceLoader.loadJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ func (s *subSchema) PatternPropertiesString() string {
|
||||
}
|
||||
|
||||
patternPropertiesKeySlice := []string{}
|
||||
for pk := range s.patternProperties {
|
||||
for pk, _ := range s.patternProperties {
|
||||
patternPropertiesKeySlice = append(patternPropertiesKeySlice, `"`+pk+`"`)
|
||||
}
|
||||
|
||||
|
||||
+4
-10
@@ -34,12 +34,7 @@ import (
|
||||
)
|
||||
|
||||
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
|
||||
return reflect.ValueOf(what).Kind() == kind
|
||||
}
|
||||
|
||||
func existsMapKey(m map[string]interface{}, k string) bool {
|
||||
@@ -82,14 +77,13 @@ func checkJsonNumber(what interface{}) (isValidFloat64 bool, isValidInt64 bool,
|
||||
|
||||
jsonNumber := what.(json.Number)
|
||||
|
||||
f64, errFloat64 := jsonNumber.Float64()
|
||||
s64 := strconv.FormatFloat(f64, 'f', -1, 64)
|
||||
_, errInt64 := strconv.ParseInt(s64, 10, 64)
|
||||
_, errFloat64 := jsonNumber.Float64()
|
||||
_, errInt64 := jsonNumber.Int64()
|
||||
|
||||
isValidFloat64 = errFloat64 == nil
|
||||
isValidInt64 = errInt64 == nil
|
||||
|
||||
_, errInt32 := strconv.ParseInt(s64, 10, 32)
|
||||
_, errInt32 := strconv.ParseInt(jsonNumber.String(), 10, 32)
|
||||
isValidInt32 = isValidInt64 && errInt32 == nil
|
||||
|
||||
return
|
||||
|
||||
+20
-23
@@ -55,7 +55,7 @@ func (v *Schema) Validate(l JSONLoader) (*Result, error) {
|
||||
|
||||
// load document
|
||||
|
||||
root, err := l.LoadJSON()
|
||||
root, err := l.loadJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -412,7 +412,7 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
|
||||
internalLog(" %v", value)
|
||||
}
|
||||
|
||||
nbValues := len(value)
|
||||
nbItems := len(value)
|
||||
|
||||
// TODO explain
|
||||
if currentSubSchema.itemsChildrenIsSingleSchema {
|
||||
@@ -425,18 +425,15 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
|
||||
if currentSubSchema.itemsChildren != nil && len(currentSubSchema.itemsChildren) > 0 {
|
||||
|
||||
nbItems := len(currentSubSchema.itemsChildren)
|
||||
nbValues := len(value)
|
||||
|
||||
// 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.
|
||||
|
||||
if nbItems == nbValues {
|
||||
for i := 0; i != nbItems; i++ {
|
||||
subContext := newJsonContext(strconv.Itoa(i), context)
|
||||
validationResult := currentSubSchema.itemsChildren[i].subValidateWithContext(value[i], subContext)
|
||||
result.mergeErrors(validationResult)
|
||||
}
|
||||
} else if nbItems < nbValues {
|
||||
switch currentSubSchema.additionalItems.(type) {
|
||||
case bool:
|
||||
if !currentSubSchema.additionalItems.(bool) {
|
||||
@@ -456,7 +453,7 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
|
||||
|
||||
// minItems & maxItems
|
||||
if currentSubSchema.minItems != nil {
|
||||
if nbValues < int(*currentSubSchema.minItems) {
|
||||
if nbItems < int(*currentSubSchema.minItems) {
|
||||
result.addError(
|
||||
new(ArrayMinItemsError),
|
||||
context,
|
||||
@@ -466,7 +463,7 @@ func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface
|
||||
}
|
||||
}
|
||||
if currentSubSchema.maxItems != nil {
|
||||
if nbValues > int(*currentSubSchema.maxItems) {
|
||||
if nbItems > int(*currentSubSchema.maxItems) {
|
||||
result.addError(
|
||||
new(ArrayMaxItemsError),
|
||||
context,
|
||||
@@ -779,22 +776,22 @@ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{
|
||||
if currentSubSchema.exclusiveMaximum {
|
||||
if float64Value >= *currentSubSchema.maximum {
|
||||
result.addError(
|
||||
new(NumberLTError),
|
||||
new(NumberLTEError),
|
||||
context,
|
||||
resultErrorFormatJsonNumber(number),
|
||||
ErrorDetails{
|
||||
"max": resultErrorFormatNumber(*currentSubSchema.maximum),
|
||||
"min": resultErrorFormatNumber(*currentSubSchema.maximum),
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if float64Value > *currentSubSchema.maximum {
|
||||
result.addError(
|
||||
new(NumberLTEError),
|
||||
new(NumberLTError),
|
||||
context,
|
||||
resultErrorFormatJsonNumber(number),
|
||||
ErrorDetails{
|
||||
"max": resultErrorFormatNumber(*currentSubSchema.maximum),
|
||||
"min": resultErrorFormatNumber(*currentSubSchema.maximum),
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -806,22 +803,22 @@ func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{
|
||||
if currentSubSchema.exclusiveMinimum {
|
||||
if float64Value <= *currentSubSchema.minimum {
|
||||
result.addError(
|
||||
new(NumberGTError),
|
||||
new(NumberGTEError),
|
||||
context,
|
||||
resultErrorFormatJsonNumber(number),
|
||||
ErrorDetails{
|
||||
"min": resultErrorFormatNumber(*currentSubSchema.minimum),
|
||||
"max": resultErrorFormatNumber(*currentSubSchema.minimum),
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if float64Value < *currentSubSchema.minimum {
|
||||
result.addError(
|
||||
new(NumberGTEError),
|
||||
new(NumberGTError),
|
||||
context,
|
||||
resultErrorFormatJsonNumber(number),
|
||||
ErrorDetails{
|
||||
"min": resultErrorFormatNumber(*currentSubSchema.minimum),
|
||||
"max": resultErrorFormatNumber(*currentSubSchema.minimum),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user