Skip to content

Commit

Permalink
separate $schema load from root
Browse files Browse the repository at this point in the history
  • Loading branch information
santhosh-tekuri committed Apr 24, 2024
1 parent b682da7 commit df415dd
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 51 deletions.
34 changes: 34 additions & 0 deletions draft.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package jsonschema

import (
"fmt"
"slices"
"strings"
)

Expand Down Expand Up @@ -222,6 +223,39 @@ func (d *Draft) getID(obj map[string]any) string {
return id
}

func (d *Draft) getVocabs(url url, doc any) ([]string, error) {
if d.version < 2019 {
return nil, nil
}
obj, ok := doc.(map[string]any)
if !ok {
return nil, nil
}
v, ok := obj["$vocabulary"]
if !ok {
return nil, nil
}
obj, ok = v.(map[string]any)
if !ok {
return nil, nil
}

var vocabs []string
for vocab, reqd := range obj {
if reqd, ok := reqd.(bool); !ok || !reqd {
continue
}
name, ok := strings.CutPrefix(vocab, d.vocabPrefix)
if !ok {
return nil, &UnsupportedVocabularyError{url.String(), vocab}
}
if !slices.Contains(vocabs, name) {
vocabs = append(vocabs, name)
}
}
return vocabs, nil
}

func (d *Draft) validate(up urlPtr, v any, regexpEngine RegexpEngine) error {
err := d.sch.validate(v, regexpEngine)
if err != nil {
Expand Down
55 changes: 55 additions & 0 deletions loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,61 @@ func (l *defaultLoader) load(url url) (any, error) {
return doc, nil
}

func (l *defaultLoader) getDraft(up urlPtr, doc any, defaultDraft *Draft, cycle map[url]struct{}) (*Draft, error) {
obj, ok := doc.(map[string]any)
if !ok {
return defaultDraft, nil
}
sch, ok := strVal(obj, "$schema")
if !ok {
return defaultDraft, nil
}
if draft := draftFromURL(sch); draft != nil {
return draft, nil
}
sch, _ = split(sch)
if _, err := gourl.Parse(sch); err != nil {
return nil, &InvalidMetaSchemaURLError{up.String(), err}
}
schUrl := url(sch)
if up.ptr.isEmpty() && schUrl == up.url {
return nil, &UnsupportedDraftError{schUrl.String()}
}
if _, ok := cycle[schUrl]; ok {
return nil, &MetaSchemaCycleError{schUrl.String()}
}
cycle[schUrl] = struct{}{}
doc, err := l.load(schUrl)
if err != nil {
return nil, err
}
return l.getDraft(urlPtr{schUrl, ""}, doc, defaultDraft, cycle)
}

func (l *defaultLoader) getMetaVocabs(doc any, draft *Draft) ([]string, error) {
obj, ok := doc.(map[string]any)
if !ok {
return nil, nil
}
sch, ok := strVal(obj, "$schema")
if !ok {
return nil, nil
}
if draft := draftFromURL(sch); draft != nil {
return nil, nil
}
sch, _ = split(sch)
if _, err := gourl.Parse(sch); err != nil {
return nil, &ParseURLError{sch, err}
}
schUrl := url(sch)
doc, err := l.load(schUrl)
if err != nil {
return nil, err
}
return draft.getVocabs(schUrl, doc)
}

// --

type LoadURLError struct {
Expand Down
7 changes: 0 additions & 7 deletions root.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,6 @@ func newResource(ptr jsonPointer, id url) *resource {

//--

type meta struct {
draft *Draft
vocabs []string
}

// --

type UnsupportedVocabularyError struct {
URL string
Vocabulary string
Expand Down
51 changes: 7 additions & 44 deletions roots.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package jsonschema

import (
"fmt"
gourl "net/url"
"strings"
)

Expand Down Expand Up @@ -35,60 +34,24 @@ func (rr *roots) orLoad(u url) (*root, error) {
if err != nil {
return nil, err
}
return rr.addRoot(u, doc, make(map[url]struct{}))
return rr.addRoot(u, doc)
}

func (rr *roots) getMeta(up urlPtr, doc any, cycle map[url]struct{}) (meta, error) {
obj, ok := doc.(map[string]any)
if !ok {
return meta{rr.defaultDraft, nil}, nil
}
sch, ok := strVal(obj, "$schema")
if !ok {
return meta{rr.defaultDraft, nil}, nil
}
if draft := draftFromURL(sch); draft != nil {
return meta{draft, nil}, nil
}
sch, _ = split(sch)
if _, err := gourl.Parse(sch); err != nil {
return meta{}, &InvalidMetaSchemaURLError{up.String(), err}
}
schUrl := url(sch)
if r, ok := rr.roots[schUrl]; ok {
vocabs, err := r.getReqdVocabs()
return meta{r.draft, vocabs}, err
}
if schUrl == up.url {
return meta{}, &UnsupportedDraftError{schUrl.String()}
}
if _, ok := cycle[schUrl]; ok {
return meta{}, &MetaSchemaCycleError{schUrl.String()}
}
cycle[schUrl] = struct{}{}
doc, err := rr.loader.load(schUrl)
if err != nil {
return meta{}, err
}
r, err := rr.addRoot(schUrl, doc, cycle)
func (rr *roots) addRoot(u url, doc any) (*root, error) {
draft, err := rr.loader.getDraft(urlPtr{u, ""}, doc, rr.defaultDraft, map[url]struct{}{})
if err != nil {
return meta{}, err
return nil, err
}
vocabs, err := r.getReqdVocabs()
return meta{r.draft, vocabs}, err
}

func (rr *roots) addRoot(u url, doc any, cycle map[url]struct{}) (*root, error) {
meta, err := rr.getMeta(urlPtr{u, ""}, doc, cycle)
vocabs, err := rr.loader.getMetaVocabs(doc, draft)
if err != nil {
return nil, err
}
r := &root{
url: u,
doc: doc,
draft: meta.draft,
draft: draft,
resources: map[jsonPointer]*resource{},
metaVocabs: meta.vocabs,
metaVocabs: vocabs,
subschemasProcessed: map[jsonPointer]struct{}{},
}
if err := r.collectResources(doc, u, ""); err != nil {
Expand Down

0 comments on commit df415dd

Please sign in to comment.