forked from TomWright/dasel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathselector.go
159 lines (142 loc) · 3.04 KB
/
selector.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package dasel
import (
"errors"
"strings"
)
// ErrDynamicSelectorBracketMismatch is returned when the number of opening brackets doesn't equal that
// of the closing brackets.
var ErrDynamicSelectorBracketMismatch = errors.New("dynamic selector bracket mismatch")
// ExtractNextSelector returns the next selector from the given input.
func ExtractNextSelector(input string) (string, int) {
escapedIndex := -1
res := ""
i := 0
read := 0
for k, v := range input {
curRuneStr := string(v)
curRuneLength := len(curRuneStr)
if escapedIndex == k-1 && k != 0 {
// last character was escape character
res += curRuneStr
read += curRuneLength
continue
}
if v == '(' || v == '[' {
i++
} else if v == ')' || v == ']' {
i--
}
if v == '\\' {
escapedIndex = k
read += curRuneLength
continue
}
if i == 0 && v == '.' && k != 0 {
break
}
res += curRuneStr
read += curRuneLength
}
return res, read
}
// DynamicSelectorToGroups takes a dynamic selector and splits it into groups.
func DynamicSelectorToGroups(selector string) ([]string, error) {
i := 0
tmp := ""
res := make([]string, 0)
for k, v := range selector {
if v == '(' {
if i > 0 {
tmp += string(v)
} else {
tmp = ""
}
i++
} else if v == ')' {
i--
if i == 0 {
res = append(res, tmp)
tmp = ""
} else {
tmp += string(v)
}
} else if v == '.' && i == 0 && k != 0 {
return res, nil
} else {
tmp += string(v)
}
}
if i != 0 {
return nil, ErrDynamicSelectorBracketMismatch
}
return res, nil
}
// DynamicSelectorParts contains the parts for a dynamic selector.
type DynamicSelectorParts struct {
Key string
Comparison string
Value string
}
var comparisons = []string{
"=",
"!=",
"<",
"<=",
">",
">=",
}
func isBuildingComparison(comparison string) bool {
for _, c := range comparisons {
if strings.HasPrefix(c, comparison) {
return true
}
}
return false
}
func isValidComparison(comparison string) bool {
for _, c := range comparisons {
if comparison == c {
return true
}
}
return false
}
// FindDynamicSelectorParts extracts the parts from the dynamic selector given.
func FindDynamicSelectorParts(selector string) DynamicSelectorParts {
i := 0
parts := DynamicSelectorParts{}
for _, v := range selector {
switch {
// Start of a group
case v == '(':
if parts.Comparison == "" {
parts.Key += string(v)
} else {
parts.Value += string(v)
}
i++
// End of a group
case v == ')':
i--
if parts.Comparison == "" {
parts.Key += string(v)
} else {
parts.Value += string(v)
}
// Matches a comparison operator
case i == 0 && isValidComparison(parts.Comparison+string(v)):
parts.Comparison += string(v)
// Is building a comparison character
case i == 0 && isBuildingComparison(parts.Comparison+string(v)):
parts.Comparison += string(v)
// Add to key or value based on comparison existence
default:
if parts.Comparison == "" {
parts.Key += string(v)
} else {
parts.Value += string(v)
}
}
}
return parts
}