1package jsonschema
2
3import (
4 "errors"
5 "fmt"
6 "net/url"
7 "strings"
8)
9
10// ID represents a Schema ID type which should always be a URI.
11// See draft-bhutton-json-schema-00 section 8.2.1
12type ID string
13
14// EmptyID is used to explicitly define an ID with no value.
15const EmptyID ID = ""
16
17// Validate is used to check if the ID looks like a proper schema.
18// This is done by parsing the ID as a URL and checking it has all the
19// relevant parts.
20func (id ID) Validate() error {
21 u, err := url.Parse(id.String())
22 if err != nil {
23 return fmt.Errorf("invalid URL: %w", err)
24 }
25 if u.Hostname() == "" {
26 return errors.New("missing hostname")
27 }
28 if !strings.Contains(u.Hostname(), ".") {
29 return errors.New("hostname does not look valid")
30 }
31 if u.Path == "" {
32 return errors.New("path is expected")
33 }
34 if u.Scheme != "https" && u.Scheme != "http" {
35 return errors.New("unexpected schema")
36 }
37 return nil
38}
39
40// Anchor sets the anchor part of the schema URI.
41func (id ID) Anchor(name string) ID {
42 b := id.Base()
43 return ID(b.String() + "#" + name)
44}
45
46// Def adds or replaces a definition identifier.
47func (id ID) Def(name string) ID {
48 b := id.Base()
49 return ID(b.String() + "#/$defs/" + name)
50}
51
52// Add appends the provided path to the id, and removes any
53// anchor data that might be there.
54func (id ID) Add(path string) ID {
55 b := id.Base()
56 if !strings.HasPrefix(path, "/") {
57 path = "/" + path
58 }
59 return ID(b.String() + path)
60}
61
62// Base removes any anchor information from the schema
63func (id ID) Base() ID {
64 s := id.String()
65 i := strings.LastIndex(s, "#")
66 if i != -1 {
67 s = s[0:i]
68 }
69 s = strings.TrimRight(s, "/")
70 return ID(s)
71}
72
73// String provides string version of ID
74func (id ID) String() string {
75 return string(id)
76}