diff --git a/encoding/jsonschema/constraints.go b/encoding/jsonschema/constraints.go index 13816592328..6f0c8d8fbea 100644 --- a/encoding/jsonschema/constraints.go +++ b/encoding/jsonschema/constraints.go @@ -118,7 +118,20 @@ var constraints = []*constraint{ p0("$schema", func(n cue.Value, s *state) { // Identifies this as a JSON schema and specifies its version. // TODO: extract version. - s.jsonschema, _ = s.strValue(n) + + s.schemaVersion = versionDraft07 // Reasonable default version. + str, ok := s.strValue(n) + if !ok { + // If there's no $schema value, use the default. + return + } + sv, err := parseSchemaVersion(str) + if err != nil { + s.errf(n, "invalid $schema URL %q: %v", str, err) + return + } + s.schemaVersionPresent = true + s.schemaVersion = sv }), p0("$id", func(n cue.Value, s *state) { diff --git a/encoding/jsonschema/decode.go b/encoding/jsonschema/decode.go index 0582e18a2e9..3f53ecafdcf 100644 --- a/encoding/jsonschema/decode.go +++ b/encoding/jsonschema/decode.go @@ -117,8 +117,9 @@ func (d *decoder) schema(ref []ast.Label, v cue.Value) (a []ast.Decl) { expr, state := root.schemaState(v, allTypes, nil, false) tags := []string{} - if state.jsonschema != "" { - tags = append(tags, fmt.Sprintf("schema=%q", state.jsonschema)) + if state.schemaVersionPresent { + // TODO use cue/literal.String + tags = append(tags, fmt.Sprintf("schema=%q", state.schemaVersion)) } if name == nil { @@ -334,9 +335,12 @@ type state struct { deprecated bool exclusiveMin bool // For OpenAPI and legacy support. exclusiveMax bool // For OpenAPI and legacy support. - jsonschema string - id *url.URL // base URI for $ref - idPos token.Pos + + schemaVersion schemaVersion + schemaVersionPresent bool + + id *url.URL // base URI for $ref + idPos token.Pos definitions []ast.Decl diff --git a/encoding/jsonschema/decode_test.go b/encoding/jsonschema/decode_test.go index ca9d6a336ab..cfbd0b9c9e8 100644 --- a/encoding/jsonschema/decode_test.go +++ b/encoding/jsonschema/decode_test.go @@ -109,7 +109,6 @@ func TestDecode(t *testing.T) { func TestMapURL(t *testing.T) { v := cuecontext.New().CompileString(` -$schema: "xxx" type: "object" properties: x: $ref: "https://something.test/foo#/definitions/blah" `) @@ -129,7 +128,6 @@ properties: x: $ref: "https://something.test/foo#/definitions/blah" qt.Assert(t, qt.Equals(string(b), ` import "other.test/something:blah" -@jsonschema(schema="xxx") x?: blah.#blah ... `[1:])) @@ -137,7 +135,6 @@ x?: blah.#blah func TestMapURLErrors(t *testing.T) { v := cuecontext.New().CompileString(` -$schema: "xxx" type: "object" properties: { x: $ref: "https://something.test/foo#/definitions/x" @@ -151,9 +148,9 @@ properties: { }) qt.Assert(t, qt.Equals(errors.Details(err, nil), ` cannot determine import path from URL "https://something.test/foo": some error: - foo.cue:5:5 + foo.cue:4:5 cannot determine import path from URL "https://something.test/foo": some error: - foo.cue:6:5 + foo.cue:5:5 `[1:])) } diff --git a/encoding/jsonschema/schemaversion_string.go b/encoding/jsonschema/schemaversion_string.go new file mode 100644 index 00000000000..799d110c73c --- /dev/null +++ b/encoding/jsonschema/schemaversion_string.go @@ -0,0 +1,30 @@ +// Code generated by "stringer -type=schemaVersion -linecomment"; DO NOT EDIT. + +package jsonschema + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[versionUnknown-0] + _ = x[versionDraft04-1] + _ = x[versionDraft05-2] + _ = x[versionDraft06-3] + _ = x[versionDraft07-4] + _ = x[version2019_09-5] + _ = x[version2020_12-6] + _ = x[numVersions-7] +} + +const _schemaVersion_name = "unknownhttp://json-schema.org/draft-04/schema#http://json-schema.org/draft-05/schema#http://json-schema.org/draft-06/schema#http://json-schema.org/draft-07/schema#https://json-schema.org/draft/2019-09/schemahttps://json-schema.org/draft/2020-12/schemaunknown" + +var _schemaVersion_index = [...]uint16{0, 7, 46, 85, 124, 163, 207, 251, 258} + +func (i schemaVersion) String() string { + if i < 0 || i >= schemaVersion(len(_schemaVersion_index)-1) { + return "schemaVersion(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _schemaVersion_name[_schemaVersion_index[i]:_schemaVersion_index[i+1]] +} diff --git a/encoding/jsonschema/testdata/emptyobj.txtar b/encoding/jsonschema/testdata/emptyobj.txtar index c3b4a4994d2..86be8daf9b5 100644 --- a/encoding/jsonschema/testdata/emptyobj.txtar +++ b/encoding/jsonschema/testdata/emptyobj.txtar @@ -3,7 +3,7 @@ // Issue #734 -- github-workflow.json -- { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "obj1": { "oneOf": [ @@ -23,7 +23,7 @@ } } -- out/decode/cue -- -@jsonschema(schema="http://json-schema.org/draft-07/schema") +@jsonschema(schema="http://json-schema.org/draft-07/schema#") _ #obj1: null | { diff --git a/encoding/jsonschema/testdata/unsupported.txtar b/encoding/jsonschema/testdata/unsupported.txtar index 99ce39db17e..f9d6a1f34e0 100644 --- a/encoding/jsonschema/testdata/unsupported.txtar +++ b/encoding/jsonschema/testdata/unsupported.txtar @@ -1,6 +1,6 @@ -- unsupported.json -- { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "ref": { "properties": { @@ -35,7 +35,7 @@ -- out/decode/cue -- -@jsonschema(schema="http://json-schema.org/draft-07/schema") +@jsonschema(schema="http://json-schema.org/draft-07/schema#") _ #ref: null | { diff --git a/encoding/jsonschema/version.go b/encoding/jsonschema/version.go new file mode 100644 index 00000000000..8056f43c7a7 --- /dev/null +++ b/encoding/jsonschema/version.go @@ -0,0 +1,32 @@ +package jsonschema + +import ( + "fmt" +) + +//go:generate go run golang.org/x/tools/cmd/stringer -type=schemaVersion -linecomment + +type schemaVersion int + +const ( + versionUnknown schemaVersion = iota // unknown + versionDraft04 // http://json-schema.org/draft-04/schema# + versionDraft05 // http://json-schema.org/draft-05/schema# + versionDraft06 // http://json-schema.org/draft-06/schema# + versionDraft07 // http://json-schema.org/draft-07/schema# + version2019_09 // https://json-schema.org/draft/2019-09/schema + version2020_12 // https://json-schema.org/draft/2020-12/schema + + numVersions // unknown +) + +func parseSchemaVersion(sv string) (schemaVersion, error) { + // If this linear search is ever a performance issue, we could + // build a map, but it doesn't seem worthwhile for now. + for i := schemaVersion(1); i < numVersions; i++ { + if sv == i.String() { + return i, nil + } + } + return 0, fmt.Errorf("$schema URI not recognized") +}