1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package compiler
16
17 import (
18 "fmt"
19 "regexp"
20 "sort"
21 "strconv"
22
23 "gopkg.in/yaml.v3"
24
25 "github.com/google/gnostic-models/jsonschema"
26 )
27
28
29
30
31 func UnpackMap(in *yaml.Node) (*yaml.Node, bool) {
32 if in == nil {
33 return nil, false
34 }
35 return in, true
36 }
37
38
39 func SortedKeysForMap(m *yaml.Node) []string {
40 keys := make([]string, 0)
41 if m.Kind == yaml.MappingNode {
42 for i := 0; i < len(m.Content); i += 2 {
43 keys = append(keys, m.Content[i].Value)
44 }
45 }
46 sort.Strings(keys)
47 return keys
48 }
49
50
51 func MapHasKey(m *yaml.Node, key string) bool {
52 if m == nil {
53 return false
54 }
55 if m.Kind == yaml.MappingNode {
56 for i := 0; i < len(m.Content); i += 2 {
57 itemKey := m.Content[i].Value
58 if key == itemKey {
59 return true
60 }
61 }
62 }
63 return false
64 }
65
66
67 func MapValueForKey(m *yaml.Node, key string) *yaml.Node {
68 if m == nil {
69 return nil
70 }
71 if m.Kind == yaml.MappingNode {
72 for i := 0; i < len(m.Content); i += 2 {
73 itemKey := m.Content[i].Value
74 if key == itemKey {
75 return m.Content[i+1]
76 }
77 }
78 }
79 return nil
80 }
81
82
83 func ConvertInterfaceArrayToStringArray(interfaceArray []interface{}) []string {
84 stringArray := make([]string, 0)
85 for _, item := range interfaceArray {
86 v, ok := item.(string)
87 if ok {
88 stringArray = append(stringArray, v)
89 }
90 }
91 return stringArray
92 }
93
94
95 func SequenceNodeForNode(node *yaml.Node) (*yaml.Node, bool) {
96 if node.Kind != yaml.SequenceNode {
97 return nil, false
98 }
99 return node, true
100 }
101
102
103 func BoolForScalarNode(node *yaml.Node) (bool, bool) {
104 if node == nil {
105 return false, false
106 }
107 if node.Kind == yaml.DocumentNode {
108 return BoolForScalarNode(node.Content[0])
109 }
110 if node.Kind != yaml.ScalarNode {
111 return false, false
112 }
113 if node.Tag != "!!bool" {
114 return false, false
115 }
116 v, err := strconv.ParseBool(node.Value)
117 if err != nil {
118 return false, false
119 }
120 return v, true
121 }
122
123
124 func IntForScalarNode(node *yaml.Node) (int64, bool) {
125 if node == nil {
126 return 0, false
127 }
128 if node.Kind == yaml.DocumentNode {
129 return IntForScalarNode(node.Content[0])
130 }
131 if node.Kind != yaml.ScalarNode {
132 return 0, false
133 }
134 if node.Tag != "!!int" {
135 return 0, false
136 }
137 v, err := strconv.ParseInt(node.Value, 10, 64)
138 if err != nil {
139 return 0, false
140 }
141 return v, true
142 }
143
144
145 func FloatForScalarNode(node *yaml.Node) (float64, bool) {
146 if node == nil {
147 return 0.0, false
148 }
149 if node.Kind == yaml.DocumentNode {
150 return FloatForScalarNode(node.Content[0])
151 }
152 if node.Kind != yaml.ScalarNode {
153 return 0.0, false
154 }
155 if (node.Tag != "!!int") && (node.Tag != "!!float") {
156 return 0.0, false
157 }
158 v, err := strconv.ParseFloat(node.Value, 64)
159 if err != nil {
160 return 0.0, false
161 }
162 return v, true
163 }
164
165
166 func StringForScalarNode(node *yaml.Node) (string, bool) {
167 if node == nil {
168 return "", false
169 }
170 if node.Kind == yaml.DocumentNode {
171 return StringForScalarNode(node.Content[0])
172 }
173 switch node.Kind {
174 case yaml.ScalarNode:
175 switch node.Tag {
176 case "!!int":
177 return node.Value, true
178 case "!!str":
179 return node.Value, true
180 case "!!timestamp":
181 return node.Value, true
182 case "!!null":
183 return "", true
184 default:
185 return "", false
186 }
187 default:
188 return "", false
189 }
190 }
191
192
193 func StringArrayForSequenceNode(node *yaml.Node) []string {
194 stringArray := make([]string, 0)
195 for _, item := range node.Content {
196 v, ok := StringForScalarNode(item)
197 if ok {
198 stringArray = append(stringArray, v)
199 }
200 }
201 return stringArray
202 }
203
204
205 func MissingKeysInMap(m *yaml.Node, requiredKeys []string) []string {
206 missingKeys := make([]string, 0)
207 for _, k := range requiredKeys {
208 if !MapHasKey(m, k) {
209 missingKeys = append(missingKeys, k)
210 }
211 }
212 return missingKeys
213 }
214
215
216 func InvalidKeysInMap(m *yaml.Node, allowedKeys []string, allowedPatterns []*regexp.Regexp) []string {
217 invalidKeys := make([]string, 0)
218 if m == nil || m.Kind != yaml.MappingNode {
219 return invalidKeys
220 }
221 for i := 0; i < len(m.Content); i += 2 {
222 key := m.Content[i].Value
223 found := false
224
225 for _, allowedKey := range allowedKeys {
226 if key == allowedKey {
227 found = true
228 break
229 }
230 }
231 if !found {
232
233 for _, allowedPattern := range allowedPatterns {
234 if allowedPattern.MatchString(key) {
235 found = true
236 break
237 }
238 }
239 if !found {
240 invalidKeys = append(invalidKeys, key)
241 }
242 }
243 }
244 return invalidKeys
245 }
246
247
248 func NewNullNode() *yaml.Node {
249 node := &yaml.Node{
250 Kind: yaml.ScalarNode,
251 Tag: "!!null",
252 }
253 return node
254 }
255
256
257 func NewMappingNode() *yaml.Node {
258 return &yaml.Node{
259 Kind: yaml.MappingNode,
260 Content: make([]*yaml.Node, 0),
261 }
262 }
263
264
265 func NewSequenceNode() *yaml.Node {
266 node := &yaml.Node{
267 Kind: yaml.SequenceNode,
268 Content: make([]*yaml.Node, 0),
269 }
270 return node
271 }
272
273
274 func NewScalarNodeForString(s string) *yaml.Node {
275 return &yaml.Node{
276 Kind: yaml.ScalarNode,
277 Tag: "!!str",
278 Value: s,
279 }
280 }
281
282
283 func NewSequenceNodeForStringArray(strings []string) *yaml.Node {
284 node := &yaml.Node{
285 Kind: yaml.SequenceNode,
286 Content: make([]*yaml.Node, 0),
287 }
288 for _, s := range strings {
289 node.Content = append(node.Content, NewScalarNodeForString(s))
290 }
291 return node
292 }
293
294
295 func NewScalarNodeForBool(b bool) *yaml.Node {
296 return &yaml.Node{
297 Kind: yaml.ScalarNode,
298 Tag: "!!bool",
299 Value: fmt.Sprintf("%t", b),
300 }
301 }
302
303
304 func NewScalarNodeForFloat(f float64) *yaml.Node {
305 return &yaml.Node{
306 Kind: yaml.ScalarNode,
307 Tag: "!!float",
308 Value: fmt.Sprintf("%g", f),
309 }
310 }
311
312
313 func NewScalarNodeForInt(i int64) *yaml.Node {
314 return &yaml.Node{
315 Kind: yaml.ScalarNode,
316 Tag: "!!int",
317 Value: fmt.Sprintf("%d", i),
318 }
319 }
320
321
322 func PluralProperties(count int) string {
323 if count == 1 {
324 return "property"
325 }
326 return "properties"
327 }
328
329
330 func StringArrayContainsValue(array []string, value string) bool {
331 for _, item := range array {
332 if item == value {
333 return true
334 }
335 }
336 return false
337 }
338
339
340 func StringArrayContainsValues(array []string, values []string) bool {
341 for _, value := range values {
342 if !StringArrayContainsValue(array, value) {
343 return false
344 }
345 }
346 return true
347 }
348
349
350 func StringValue(item interface{}) (value string, ok bool) {
351 value, ok = item.(string)
352 if ok {
353 return value, ok
354 }
355 intValue, ok := item.(int)
356 if ok {
357 return strconv.Itoa(intValue), true
358 }
359 return "", false
360 }
361
362
363 func Description(item interface{}) string {
364 value, ok := item.(*yaml.Node)
365 if ok {
366 return jsonschema.Render(value)
367 }
368 return fmt.Sprintf("%+v", item)
369 }
370
371
372 func Display(node *yaml.Node) string {
373 switch node.Kind {
374 case yaml.ScalarNode:
375 switch node.Tag {
376 case "!!str":
377 return fmt.Sprintf("%s (string)", node.Value)
378 }
379 }
380 return fmt.Sprintf("%+v (%T)", node, node)
381 }
382
383
384 func Marshal(in *yaml.Node) []byte {
385 clearStyle(in)
386
387 bytes, _ := yaml.Marshal(in)
388
389 return bytes
390 }
391
392 func clearStyle(node *yaml.Node) {
393 node.Style = 0
394 for _, c := range node.Content {
395 clearStyle(c)
396 }
397 }
398
View as plain text