-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreference_path.go
119 lines (96 loc) · 3.67 KB
/
reference_path.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package chaff
import (
"fmt"
"regexp"
"strconv"
"strings"
)
// Based on a reference path and a schema node, resolve the schema node at the reference path
func resolveReferencePath(node schemaNode, refPath string) (schemaNode, error) {
if refPath == "" {
return node, nil
}
return resolveSubReferencePath(node, refPath, "")
}
// Recursively resolve a reference path based on a schema node (Internally used by resolveReferencePath)
func resolveSubReferencePath(node schemaNode, refPath string, resolvedPath string) (schemaNode, error) {
pathPart, path := getReferencePathToken(refPath)
resolvedPath = resolvedPath + "/" + pathPart
if path == "" {
return node, nil
}
switch pathPart {
// Object
case "properties":
return resolveReferenceProperty(node.Properties, path, resolvedPath)
case "patternProperties":
return resolveReferenceProperty(node.PatternProperties, path, resolvedPath)
case "additionalProperties":
if node.AdditionalProperties.DisallowAdditional {
return schemaNode{}, fmt.Errorf("[%s] No schema node for additional properties", resolvedPath)
}
return resolveSubReferencePath(*node.AdditionalProperties.Schema, path, resolvedPath)
// Array
case "items":
part, _ := getReferencePathToken(path)
match, err := regexp.MatchString(`^\d+$`, part)
if !match || err != nil {
return resolveSubReferencePath(*node.Items.Node, path, resolvedPath)
}
return resolveReferenceSlice(node.Items.Nodes, path, resolvedPath)
case "prefixItems":
return resolveReferenceSlice(node.PrefixItems, path, resolvedPath)
case "additionalItems":
return resolveSubReferencePath(*node.AdditionalItems, path, resolvedPath)
// Combinations
case "allOf":
return resolveReferenceSlice(node.AllOf, path, resolvedPath)
case "anyOf":
return resolveReferenceSlice(node.AnyOf, path, resolvedPath)
case "oneOf":
return resolveReferenceSlice(node.OneOf, path, resolvedPath)
// Definitions
case "definitions":
return resolveReferenceProperty(node.Definitions, path, resolvedPath)
case "$defs":
return resolveReferenceProperty(node.Defs, path, resolvedPath)
// Root
case "#":
return resolveSubReferencePath(node, path, resolvedPath)
default:
return schemaNode{}, fmt.Errorf("[%s] Invalid reference path", resolvedPath)
}
}
// Resolve a reference property based on a map of schema nodes
func resolveReferenceProperty(nodes map[string]schemaNode, path string, resolvedPath string) (schemaNode, error) {
propertyName, path := getReferencePathToken(path)
resolvedPath = resolvedPath + "/" + propertyName
node, ok := nodes[propertyName]
if !ok {
return schemaNode{}, fmt.Errorf("[%s] Property %s not found", resolvedPath, propertyName)
}
return resolveSubReferencePath(node, path, resolvedPath)
}
// Resolve a reference based on a slice of schema nodes and a path
func resolveReferenceSlice(nodes []schemaNode, path string, resolvedPath string)(schemaNode, error){
part, itemPath := getReferencePathToken(path)
resolvedPath = resolvedPath + "/" + part
partInt, err := strconv.Atoi(part)
if err != nil {
return schemaNode{}, fmt.Errorf("[%s] Invalid array index (Must be a number) %s", resolvedPath, part)
}
if len(nodes) > partInt || partInt < 0 {
return schemaNode{}, fmt.Errorf("[%s] Array index out of bounds %d", resolvedPath, partInt)
}
node := nodes[partInt]
return resolveSubReferencePath(node, itemPath, resolvedPath)
}
var pathDeliminator = regexp.MustCompile(`\/`)
// Get the first token of a reference path and the rest of the path
func getReferencePathToken(pathRef string) (string, string){
if !strings.Contains(pathRef, "/"){
return pathRef, ""
}
refPathParts := pathDeliminator.Split(pathRef, 2)
return refPathParts[0], refPathParts[1]
}