Skip to content

Commit

Permalink
encoding/jsonschema: add Config.AllowNonExistentRoot
Browse files Browse the repository at this point in the history
`AllowNonExistentRoot` prevents an error when there is no value at the
above Root path. Such an error can be useful to signal that the data may
not be a JSON Schema, but is not always a good idea.

When extracting CUE from OpenAPI documents, they are not required to
contain a .components.schemas member but in the usual case of using
the command line, it's probably an error if there is no such member
(because it might mean that we're not using the right kind of file at
all, and we're probably expecting some schemas to be present otherwise
we wouldn't be invoking the cue command to extract schemas).

However, in some cases, we don't want to consider it an error, so add
an option to cause us to ignore a missing root.

Another possibility might be to change jsonschema.Extract to return a
custom error type/value, but this means that it would be harder to
change the cue command to import openapi files even as CUE even when
there are no definitions.

Also in passing fix an error message that was not including the error
that it was about.

Signed-off-by: Roger Peppe <[email protected]>
Change-Id: Ib9d6ef9be834a869000762bff9bc9cd4bc9bd115
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1207007
Reviewed-by: Daniel Martí <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
Unity-Result: CUE porcuepine <[email protected]>
  • Loading branch information
rogpeppe committed Jan 12, 2025
1 parent dfe3ae0 commit 15f243b
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 2 deletions.
6 changes: 4 additions & 2 deletions encoding/jsonschema/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ func (d *decoder) decode(v cue.Value) *ast.File {
return nil
}
defsRoot = v.LookupPath(defsPath)
if kind := defsRoot.Kind(); kind != cue.StructKind {
if !defsRoot.Exists() && d.cfg.AllowNonExistentRoot {
defsRoot = v.Context().CompileString("{}")
} else if defsRoot.Kind() != cue.StructKind {
d.errf(defsRoot, "value at path %v must be struct containing definitions but is actually %v", d.cfg.Root, defsRoot)
return nil
}
Expand Down Expand Up @@ -904,7 +906,7 @@ func (s *state) addDefinition(n cue.Value) *definedSchema {
loc.Path = relPath(n, s.root)
importPath, path, err := s.cfg.MapRef(loc)
if err != nil {
s.errf(n, "cannot get reference for %v", loc)
s.errf(n, "cannot get reference for %v: %v", loc, err)
return nil
}
def = &definedSchema{
Expand Down
1 change: 1 addition & 0 deletions encoding/jsonschema/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func TestDecode(t *testing.T) {
}
cfg.Strict = t.HasTag("strict")
cfg.StrictKeywords = cfg.StrictKeywords || t.HasTag("strictKeywords")
cfg.AllowNonExistentRoot = t.HasTag("allowNonExistentRoot")
cfg.StrictFeatures = t.HasTag("strictFeatures")
cfg.PkgName, _ = t.Value("pkgName")

Expand Down
6 changes: 6 additions & 0 deletions encoding/jsonschema/jsonschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ type Config struct {
// only. Just `#` is preferred.
Root string

// AllowNonExistentRoot holds whether it's an error when there
// is no value at the above Root path. For example, when extracting
// an OpenAPI schema, the #/components/schemas path might not
// exist, but that could be considered OK even so.
AllowNonExistentRoot bool

// Map maps the locations of schemas and definitions to a new location.
// References are updated accordingly. A returned label must be
// an identifier or string literal.
Expand Down
9 changes: 9 additions & 0 deletions encoding/jsonschema/testdata/txtar/openapi_nonexistent.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Test what happens when there's an OpenAPI schema that has no
/components/schemas entry but AllowNonExistentRoot is true

#allowNonExistentRoot
#version: openapi

-- schema.yaml --
-- out/decode/extract --

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Test what happens when there's an OpenAPI schema that has no
/components/schemas entry and AllowNonExistentRoot is false

#version: openapi

-- schema.yaml --
-- out/decode/extract --
ERROR:
value at path #/components/schemas/ must be struct containing definitions but is actually _|_ // field not found: components

0 comments on commit 15f243b

Please sign in to comment.