2017-04-17 18:08:24 -04:00
|
|
|
// 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"
|
2019-04-12 20:56:09 -04:00
|
|
|
"math/big"
|
2017-04-17 18:08:24 -04:00
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/xeipuuv/gojsonreference"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-04-12 20:56:09 -04:00
|
|
|
KEY_SCHEMA = "$schema"
|
|
|
|
KEY_ID = "id"
|
|
|
|
KEY_ID_NEW = "$id"
|
2017-04-17 18:08:24 -04:00
|
|
|
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"
|
2019-04-12 20:56:09 -04:00
|
|
|
KEY_PROPERTY_NAMES = "propertyNames"
|
2017-04-17 18:08:24 -04:00
|
|
|
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"
|
2019-04-12 20:56:09 -04:00
|
|
|
KEY_CONTAINS = "contains"
|
|
|
|
KEY_CONST = "const"
|
2017-04-17 18:08:24 -04:00
|
|
|
KEY_ENUM = "enum"
|
|
|
|
KEY_ONE_OF = "oneOf"
|
|
|
|
KEY_ANY_OF = "anyOf"
|
|
|
|
KEY_ALL_OF = "allOf"
|
|
|
|
KEY_NOT = "not"
|
2019-04-12 20:56:09 -04:00
|
|
|
KEY_IF = "if"
|
|
|
|
KEY_THEN = "then"
|
|
|
|
KEY_ELSE = "else"
|
2017-04-17 18:08:24 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type subSchema struct {
|
2019-04-12 20:56:09 -04:00
|
|
|
draft *Draft
|
2017-04-17 18:08:24 -04:00
|
|
|
|
|
|
|
// basic subSchema meta properties
|
2019-04-12 20:56:09 -04:00
|
|
|
id *gojsonreference.JsonReference
|
2017-04-17 18:08:24 -04:00
|
|
|
title *string
|
|
|
|
description *string
|
|
|
|
|
|
|
|
property string
|
|
|
|
|
|
|
|
// Types associated with the subSchema
|
|
|
|
types jsonSchemaType
|
|
|
|
|
|
|
|
// Reference url
|
|
|
|
ref *gojsonreference.JsonReference
|
|
|
|
// Schema referenced
|
|
|
|
refSchema *subSchema
|
|
|
|
|
|
|
|
// hierarchy
|
|
|
|
parent *subSchema
|
|
|
|
itemsChildren []*subSchema
|
|
|
|
itemsChildrenIsSingleSchema bool
|
|
|
|
propertiesChildren []*subSchema
|
|
|
|
|
|
|
|
// validation : number / integer
|
2019-04-12 20:56:09 -04:00
|
|
|
multipleOf *big.Rat
|
|
|
|
maximum *big.Rat
|
|
|
|
exclusiveMaximum *big.Rat
|
|
|
|
minimum *big.Rat
|
|
|
|
exclusiveMinimum *big.Rat
|
2017-04-17 18:08:24 -04:00
|
|
|
|
|
|
|
// 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
|
2019-04-12 20:56:09 -04:00
|
|
|
propertyNames *subSchema
|
2017-04-17 18:08:24 -04:00
|
|
|
|
|
|
|
// validation : array
|
|
|
|
minItems *int
|
|
|
|
maxItems *int
|
|
|
|
uniqueItems bool
|
2019-04-12 20:56:09 -04:00
|
|
|
contains *subSchema
|
2017-04-17 18:08:24 -04:00
|
|
|
|
|
|
|
additionalItems interface{}
|
|
|
|
|
|
|
|
// validation : all
|
2019-04-12 20:56:09 -04:00
|
|
|
_const *string //const is a golang keyword
|
|
|
|
enum []string
|
2017-04-17 18:08:24 -04:00
|
|
|
|
|
|
|
// validation : subSchema
|
|
|
|
oneOf []*subSchema
|
|
|
|
anyOf []*subSchema
|
|
|
|
allOf []*subSchema
|
|
|
|
not *subSchema
|
2019-04-12 20:56:09 -04:00
|
|
|
_if *subSchema // if/else are golang keywords
|
|
|
|
_then *subSchema
|
|
|
|
_else *subSchema
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *subSchema) AddConst(i interface{}) error {
|
|
|
|
|
|
|
|
is, err := marshalWithoutNumber(i)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
s._const = is
|
|
|
|
return nil
|
2017-04-17 18:08:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *subSchema) AddEnum(i interface{}) error {
|
|
|
|
|
2019-04-12 20:56:09 -04:00
|
|
|
is, err := marshalWithoutNumber(i)
|
2017-04-17 18:08:24 -04:00
|
|
|
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) {
|
|
|
|
|
2019-04-12 20:56:09 -04:00
|
|
|
is, err := marshalWithoutNumber(i)
|
2017-04-17 18:08:24 -04:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-04-12 20:56:09 -04:00
|
|
|
func (s *subSchema) SetIf(subSchema *subSchema) {
|
|
|
|
s._if = subSchema
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *subSchema) SetThen(subSchema *subSchema) {
|
|
|
|
s._then = subSchema
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *subSchema) SetElse(subSchema *subSchema) {
|
|
|
|
s._else = subSchema
|
|
|
|
}
|
|
|
|
|
2017-04-17 18:08:24 -04:00
|
|
|
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) 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{}
|
2019-04-12 20:56:09 -04:00
|
|
|
for pk := range s.patternProperties {
|
2017-04-17 18:08:24 -04:00
|
|
|
patternPropertiesKeySlice = append(patternPropertiesKeySlice, `"`+pk+`"`)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(patternPropertiesKeySlice) == 1 {
|
|
|
|
return patternPropertiesKeySlice[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
return "[" + strings.Join(patternPropertiesKeySlice, ",") + "]"
|
|
|
|
|
|
|
|
}
|