Skip to content

Commit

Permalink
feat: support more keywords and improve conversion results for comple…
Browse files Browse the repository at this point in the history
…x json schema (#216)

* feat: improve generated schema for $ref keyword

Signed-off-by: jakezhu9 <[email protected]>

* feat: support oneOf keyword for schema generation

Signed-off-by: jakezhu9 <[email protected]>

* feat: support allOf keyword for schema generation

Signed-off-by: jakezhu9 <[email protected]>

* feat: support patternProperties keyword for schema generation

Signed-off-by: jakezhu9 <[email protected]>

* feat: support import complex json schema

Signed-off-by: jakezhu9 <[email protected]>

* fix: format for default values

Signed-off-by: jakezhu9 <[email protected]>

* fix: generate more then one schema for PatternProperties keyword

Signed-off-by: jakezhu9 <[email protected]>

* fix: use a fixed order in PatternProperties

Signed-off-by: jakezhu9 <[email protected]>

---------

Signed-off-by: jakezhu9 <[email protected]>
  • Loading branch information
jakezhu9 authored Jan 15, 2024
1 parent d5a2ade commit b5f04ee
Show file tree
Hide file tree
Showing 19 changed files with 4,107 additions and 113 deletions.
2 changes: 2 additions & 0 deletions pkg/3rdparty/jsonschema/draft2019_09_keywords.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ func LoadDraft2019_09() {
RegisterKeyword("oneOf", NewOneOf)
RegisterKeyword("not", NewNot)

SetKeywordOrder("allOf", -1)

// object Keywords
RegisterKeyword("properties", NewProperties)
RegisterKeyword("patternProperties", NewPatternProperties)
Expand Down
8 changes: 8 additions & 0 deletions pkg/3rdparty/jsonschema/keywords_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ func NewRef() Keyword {
return new(Ref)
}

// ResolveRef attempts to resolve the reference and return the resolved schema
func (r *Ref) ResolveRef(rootSchema *Schema) *Schema {
if r.resolved == nil {
r._resolveRef(context.Background(), NewValidationState(rootSchema))
}
return r.resolved
}

// ValidateKeyword implements the Keyword interface for Ref
func (r *Ref) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
schemaDebug("[Ref] Validating")
Expand Down
37 changes: 21 additions & 16 deletions pkg/3rdparty/jsonschema/keywords_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"context"
"encoding/json"
"fmt"
orderedmap "github.com/wk8/go-ordered-map/v2"
"regexp"
"sort"
"strconv"

orderedmap "github.com/wk8/go-ordered-map/v2"

jptr "github.com/qri-io/jsonpointer"
)

Expand Down Expand Up @@ -214,15 +216,15 @@ func NewPatternProperties() Keyword {
}

type patternSchema struct {
key string
re *regexp.Regexp
schema *Schema
Key string
Re *regexp.Regexp
Schema *Schema
}

// Register implements the Keyword interface for PatternProperties
func (p *PatternProperties) Register(uri string, registry *SchemaRegistry) {
for _, v := range *p {
v.schema.Register(uri, registry)
v.Schema.Register(uri, registry)
}
}

Expand All @@ -239,13 +241,13 @@ func (p *PatternProperties) Resolve(pointer jptr.Pointer, uri string) *Schema {
patProp := &patternSchema{}

for _, v := range *p {
if v.key == *current {
if v.Key == *current {
patProp = &v
break
}
}

return patProp.schema.Resolve(pointer.Tail(), uri)
return patProp.Schema.Resolve(pointer.Tail(), uri)
}

// ValidateKeyword implements the Keyword interface for PatternProperties
Expand All @@ -254,15 +256,15 @@ func (p PatternProperties) ValidateKeyword(ctx context.Context, currentState *Va
if obj, ok := data.(map[string]interface{}); ok {
for key, val := range obj {
for _, ptn := range p {
if ptn.re.Match([]byte(key)) {
if ptn.Re.Match([]byte(key)) {
currentState.SetEvaluatedKey(key)
subState := currentState.NewSubState()
subState.DescendBase("patternProperties", key)
subState.DescendRelative("patternProperties", key)
subState.DescendInstance(key)

subState.Errs = &[]KeyError{}
ptn.schema.ValidateKeyword(ctx, subState, val)
ptn.Schema.ValidateKeyword(ctx, subState, val)
currentState.AddSubErrors(*subState.Errs...)

if subState.IsValid() {
Expand All @@ -277,8 +279,8 @@ func (p PatternProperties) ValidateKeyword(ctx context.Context, currentState *Va
// JSONProp implements the JSONPather for PatternProperties
func (p PatternProperties) JSONProp(name string) interface{} {
for _, pp := range p {
if pp.key == name {
return pp.schema
if pp.Key == name {
return pp.Schema
}
}
return nil
Expand All @@ -288,7 +290,7 @@ func (p PatternProperties) JSONProp(name string) interface{} {
func (p PatternProperties) JSONChildren() (res map[string]JSONPather) {
res = map[string]JSONPather{}
for i, pp := range p {
res[strconv.Itoa(i)] = pp.schema
res[strconv.Itoa(i)] = pp.Schema
}
return
}
Expand All @@ -308,13 +310,16 @@ func (p *PatternProperties) UnmarshalJSON(data []byte) error {
return fmt.Errorf("invalid pattern: %s: %s", key, err.Error())
}
ptn[i] = patternSchema{
key: key,
re: re,
schema: sch,
Key: key,
Re: re,
Schema: sch,
}
i++
}

sort.Slice(ptn, func(i, j int) bool {
return ptn[i].Key < ptn[j].Key
})
*p = ptn
return nil
}
Expand All @@ -323,7 +328,7 @@ func (p *PatternProperties) UnmarshalJSON(data []byte) error {
func (p PatternProperties) MarshalJSON() ([]byte, error) {
obj := map[string]interface{}{}
for _, prop := range p {
obj[prop.key] = prop.schema
obj[prop.Key] = prop.Schema
}
return json.Marshal(obj)
}
Expand Down
Loading

0 comments on commit b5f04ee

Please sign in to comment.