blob: 76df635ff9bf860f82bd5818d2346247be27d524 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001// Copyright 2017 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package compiler
16
17import (
18 "fmt"
19 "gopkg.in/yaml.v2"
20 "regexp"
21 "sort"
22 "strconv"
23)
24
25// compiler helper functions, usually called from generated code
26
27// UnpackMap gets a yaml.MapSlice if possible.
28func UnpackMap(in interface{}) (yaml.MapSlice, bool) {
29 m, ok := in.(yaml.MapSlice)
30 if ok {
31 return m, true
32 }
33 // do we have an empty array?
34 a, ok := in.([]interface{})
35 if ok && len(a) == 0 {
36 // if so, return an empty map
37 return yaml.MapSlice{}, true
38 }
39 return nil, false
40}
41
42// SortedKeysForMap returns the sorted keys of a yaml.MapSlice.
43func SortedKeysForMap(m yaml.MapSlice) []string {
44 keys := make([]string, 0)
45 for _, item := range m {
46 keys = append(keys, item.Key.(string))
47 }
48 sort.Strings(keys)
49 return keys
50}
51
52// MapHasKey returns true if a yaml.MapSlice contains a specified key.
53func MapHasKey(m yaml.MapSlice, key string) bool {
54 for _, item := range m {
55 itemKey, ok := item.Key.(string)
56 if ok && key == itemKey {
57 return true
58 }
59 }
60 return false
61}
62
63// MapValueForKey gets the value of a map value for a specified key.
64func MapValueForKey(m yaml.MapSlice, key string) interface{} {
65 for _, item := range m {
66 itemKey, ok := item.Key.(string)
67 if ok && key == itemKey {
68 return item.Value
69 }
70 }
71 return nil
72}
73
74// ConvertInterfaceArrayToStringArray converts an array of interfaces to an array of strings, if possible.
75func ConvertInterfaceArrayToStringArray(interfaceArray []interface{}) []string {
76 stringArray := make([]string, 0)
77 for _, item := range interfaceArray {
78 v, ok := item.(string)
79 if ok {
80 stringArray = append(stringArray, v)
81 }
82 }
83 return stringArray
84}
85
86// MissingKeysInMap identifies which keys from a list of required keys are not in a map.
87func MissingKeysInMap(m yaml.MapSlice, requiredKeys []string) []string {
88 missingKeys := make([]string, 0)
89 for _, k := range requiredKeys {
90 if !MapHasKey(m, k) {
91 missingKeys = append(missingKeys, k)
92 }
93 }
94 return missingKeys
95}
96
97// InvalidKeysInMap returns keys in a map that don't match a list of allowed keys and patterns.
98func InvalidKeysInMap(m yaml.MapSlice, allowedKeys []string, allowedPatterns []*regexp.Regexp) []string {
99 invalidKeys := make([]string, 0)
100 for _, item := range m {
101 itemKey, ok := item.Key.(string)
102 if ok {
103 key := itemKey
104 found := false
105 // does the key match an allowed key?
106 for _, allowedKey := range allowedKeys {
107 if key == allowedKey {
108 found = true
109 break
110 }
111 }
112 if !found {
113 // does the key match an allowed pattern?
114 for _, allowedPattern := range allowedPatterns {
115 if allowedPattern.MatchString(key) {
116 found = true
117 break
118 }
119 }
120 if !found {
121 invalidKeys = append(invalidKeys, key)
122 }
123 }
124 }
125 }
126 return invalidKeys
127}
128
129// DescribeMap describes a map (for debugging purposes).
130func DescribeMap(in interface{}, indent string) string {
131 description := ""
132 m, ok := in.(map[string]interface{})
133 if ok {
134 keys := make([]string, 0)
135 for k := range m {
136 keys = append(keys, k)
137 }
138 sort.Strings(keys)
139 for _, k := range keys {
140 v := m[k]
141 description += fmt.Sprintf("%s%s:\n", indent, k)
142 description += DescribeMap(v, indent+" ")
143 }
144 return description
145 }
146 a, ok := in.([]interface{})
147 if ok {
148 for i, v := range a {
149 description += fmt.Sprintf("%s%d:\n", indent, i)
150 description += DescribeMap(v, indent+" ")
151 }
152 return description
153 }
154 description += fmt.Sprintf("%s%+v\n", indent, in)
155 return description
156}
157
158// PluralProperties returns the string "properties" pluralized.
159func PluralProperties(count int) string {
160 if count == 1 {
161 return "property"
162 }
163 return "properties"
164}
165
166// StringArrayContainsValue returns true if a string array contains a specified value.
167func StringArrayContainsValue(array []string, value string) bool {
168 for _, item := range array {
169 if item == value {
170 return true
171 }
172 }
173 return false
174}
175
176// StringArrayContainsValues returns true if a string array contains all of a list of specified values.
177func StringArrayContainsValues(array []string, values []string) bool {
178 for _, value := range values {
179 if !StringArrayContainsValue(array, value) {
180 return false
181 }
182 }
183 return true
184}
185
186// StringValue returns the string value of an item.
187func StringValue(item interface{}) (value string, ok bool) {
188 value, ok = item.(string)
189 if ok {
190 return value, ok
191 }
192 intValue, ok := item.(int)
193 if ok {
194 return strconv.Itoa(intValue), true
195 }
196 return "", false
197}