blob: 6961a2e521652da1e0f878b0674c5a102a3d6753 [file] [log] [blame]
Marcel van Lohuizen671b9562020-03-10 12:42:45 +01001// Copyright 2020 CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package jsonschema
16
17import (
18 "net/url"
19 "path"
20 "strings"
21
22 "cuelang.org/go/cue/errors"
23 "cuelang.org/go/cue/token"
24)
25
26func (d *decoder) parseRef(p token.Pos, str string) []string {
27 u, err := url.Parse(str)
28 if err != nil {
29 d.addErr(errors.Newf(p, "invalid JSON reference: %s", err))
30 return nil
31 }
32
33 if u.Host != "" || u.Path != "" {
34 d.addErr(errors.Newf(p, "external references (%s) not supported", str))
35 // TODO: handle
36 // host:
37 // If the host corresponds to a package known to cue,
38 // load it from there. It would prefer schema converted to
39 // CUE, although we could consider loading raw JSON schema
40 // if present.
41 // If not present, advise the user to run cue get.
42 // path:
43 // Look up on file system or relatively to authority location.
44 return nil
45 }
46
47 if !path.IsAbs(u.Fragment) {
48 d.addErr(errors.Newf(p, "anchors (%s) not supported", u.Fragment))
49 // TODO: support anchors
50 return nil
51 }
52
53 // NOTE: Go bug?: url.URL has no raw representation of the fragment. This
54 // means that %2F gets translated to `/` before it can be split. This, in
55 // turn, means that field names cannot have a `/` as name.
56
57 s := strings.TrimRight(u.Fragment[1:], "/")
58 return strings.Split(s, "/")
59}
60
61func (d *decoder) mapRef(p token.Pos, str string, ref []string) []string {
62 fn := d.cfg.Map
63 if fn == nil {
64 fn = jsonSchemaRef
65 }
66 a, err := fn(p, ref)
67 if err != nil {
68 if str == "" {
69 str = "#/" + strings.Join(ref, "/")
70 }
71 d.addErr(errors.Newf(p, "invalid reference %q: %v", str, err))
72 return nil
73 }
74 if len(a) == 0 {
75 // TODO: should we allow inserting at root level?
76 if str == "" {
77 str = "#/" + strings.Join(ref, "/")
78 }
79 d.addErr(errors.Newf(p,
80 "invalid empty reference returned by map for %q", str))
81 return nil
82 }
83 return a
84}
85
86func jsonSchemaRef(p token.Pos, a []string) ([]string, error) {
87 // TODO: technically, references could reference a
88 // non-definition. We disallow this case for the standard
89 // JSON Schema interpretation. We could detect cases that
90 // are not definitions and then resolve those as literal
91 // values.
92 if len(a) != 2 || (a[0] != "definitions" && a[0] != "$defs") {
93 return nil, errors.Newf(p,
94 // Don't mention the ability to use $defs, as this definition seems
95 // to already have been withdrawn from the JSON Schema spec.
96 "$ref must be of the form #/definitions/...")
97 }
98 return append([]string{rootDefs}, a[1:]...), nil
99}