-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvalue.go
104 lines (96 loc) · 1.86 KB
/
value.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
package brief
import "strings"
// ValueSpec states
const (
NoKey = "noKey"
NoVal = "noVal"
NoCTX = "noCTX"
NoName = "noName"
)
// ValueSpec <elem>.<key> or <elem>.Name
type ValueSpec struct {
Elem, Name string
HasKey bool
}
// NewValueSpec spec for a value Name or Key-value
// <elem>.<key> or <elem>.Name
func NewValueSpec(spec string) *ValueSpec {
elem, name, hasKey := ParseValueSpec(spec)
return &ValueSpec{
Elem: elem,
Name: name,
HasKey: hasKey,
}
}
// Value from node if matching elem and has key
func (val *ValueSpec) Value(node *Node) (string, bool) {
if val.Elem != node.Type {
return "", false
}
if val.HasKey {
val, ok := node.Keys[val.Name]
return val, ok
}
if len(node.Name) == 0 {
return "", false
}
return node.Name, true
}
// ParseValueSpec type.key or type.Name
// return type, value and hasKey
func ParseValueSpec(spec string) (string, string, bool) {
values := strings.Split(spec, ".")
hasKey := len(values) > 1
elem := spec
name := NoKey
if hasKey {
elem = values[0]
name = values[1]
}
return elem, name, hasKey
}
// Lookup value spec in parents
func (val *ValueSpec) Lookup(node *Node) string {
ctx := node.Context(val.Elem)
if ctx == nil {
return NoCTX
}
if val.HasKey {
kval, ok := ctx.Keys[val.Name]
if !ok {
return NoKey
}
if len(kval) == 0 {
return NoVal
}
return kval
}
if len(ctx.Name) == 0 {
return NoName
}
return ctx.Name
}
// Collect value specs up the hierarchy into a Slice
func (node *Node) Collect(names ...string) []string {
at := node
specs := make([]*ValueSpec, len(names))
for i, name := range names {
specs[i] = NewValueSpec(name)
}
result := make([]string, 0)
for {
if at == nil {
break
}
for _, spec := range specs {
val, ok := spec.Value(at)
if !ok {
continue
}
result = append(result, val)
break
}
at = at.Parent
}
return result
}