helpers.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // 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. package compiler
  15. import (
  16. "fmt"
  17. "gopkg.in/yaml.v2"
  18. "regexp"
  19. "sort"
  20. "strconv"
  21. )
  22. // compiler helper functions, usually called from generated code
  23. // UnpackMap gets a yaml.MapSlice if possible.
  24. func UnpackMap(in interface{}) (yaml.MapSlice, bool) {
  25. m, ok := in.(yaml.MapSlice)
  26. if ok {
  27. return m, true
  28. }
  29. // do we have an empty array?
  30. a, ok := in.([]interface{})
  31. if ok && len(a) == 0 {
  32. // if so, return an empty map
  33. return yaml.MapSlice{}, true
  34. }
  35. return nil, false
  36. }
  37. // SortedKeysForMap returns the sorted keys of a yaml.MapSlice.
  38. func SortedKeysForMap(m yaml.MapSlice) []string {
  39. keys := make([]string, 0)
  40. for _, item := range m {
  41. keys = append(keys, item.Key.(string))
  42. }
  43. sort.Strings(keys)
  44. return keys
  45. }
  46. // MapHasKey returns true if a yaml.MapSlice contains a specified key.
  47. func MapHasKey(m yaml.MapSlice, key string) bool {
  48. for _, item := range m {
  49. itemKey, ok := item.Key.(string)
  50. if ok && key == itemKey {
  51. return true
  52. }
  53. }
  54. return false
  55. }
  56. // MapValueForKey gets the value of a map value for a specified key.
  57. func MapValueForKey(m yaml.MapSlice, key string) interface{} {
  58. for _, item := range m {
  59. itemKey, ok := item.Key.(string)
  60. if ok && key == itemKey {
  61. return item.Value
  62. }
  63. }
  64. return nil
  65. }
  66. // ConvertInterfaceArrayToStringArray converts an array of interfaces to an array of strings, if possible.
  67. func ConvertInterfaceArrayToStringArray(interfaceArray []interface{}) []string {
  68. stringArray := make([]string, 0)
  69. for _, item := range interfaceArray {
  70. v, ok := item.(string)
  71. if ok {
  72. stringArray = append(stringArray, v)
  73. }
  74. }
  75. return stringArray
  76. }
  77. // MissingKeysInMap identifies which keys from a list of required keys are not in a map.
  78. func MissingKeysInMap(m yaml.MapSlice, requiredKeys []string) []string {
  79. missingKeys := make([]string, 0)
  80. for _, k := range requiredKeys {
  81. if !MapHasKey(m, k) {
  82. missingKeys = append(missingKeys, k)
  83. }
  84. }
  85. return missingKeys
  86. }
  87. // InvalidKeysInMap returns keys in a map that don't match a list of allowed keys and patterns.
  88. func InvalidKeysInMap(m yaml.MapSlice, allowedKeys []string, allowedPatterns []*regexp.Regexp) []string {
  89. invalidKeys := make([]string, 0)
  90. for _, item := range m {
  91. itemKey, ok := item.Key.(string)
  92. if ok {
  93. key := itemKey
  94. found := false
  95. // does the key match an allowed key?
  96. for _, allowedKey := range allowedKeys {
  97. if key == allowedKey {
  98. found = true
  99. break
  100. }
  101. }
  102. if !found {
  103. // does the key match an allowed pattern?
  104. for _, allowedPattern := range allowedPatterns {
  105. if allowedPattern.MatchString(key) {
  106. found = true
  107. break
  108. }
  109. }
  110. if !found {
  111. invalidKeys = append(invalidKeys, key)
  112. }
  113. }
  114. }
  115. }
  116. return invalidKeys
  117. }
  118. // DescribeMap describes a map (for debugging purposes).
  119. func DescribeMap(in interface{}, indent string) string {
  120. description := ""
  121. m, ok := in.(map[string]interface{})
  122. if ok {
  123. keys := make([]string, 0)
  124. for k := range m {
  125. keys = append(keys, k)
  126. }
  127. sort.Strings(keys)
  128. for _, k := range keys {
  129. v := m[k]
  130. description += fmt.Sprintf("%s%s:\n", indent, k)
  131. description += DescribeMap(v, indent+" ")
  132. }
  133. return description
  134. }
  135. a, ok := in.([]interface{})
  136. if ok {
  137. for i, v := range a {
  138. description += fmt.Sprintf("%s%d:\n", indent, i)
  139. description += DescribeMap(v, indent+" ")
  140. }
  141. return description
  142. }
  143. description += fmt.Sprintf("%s%+v\n", indent, in)
  144. return description
  145. }
  146. // PluralProperties returns the string "properties" pluralized.
  147. func PluralProperties(count int) string {
  148. if count == 1 {
  149. return "property"
  150. }
  151. return "properties"
  152. }
  153. // StringArrayContainsValue returns true if a string array contains a specified value.
  154. func StringArrayContainsValue(array []string, value string) bool {
  155. for _, item := range array {
  156. if item == value {
  157. return true
  158. }
  159. }
  160. return false
  161. }
  162. // StringArrayContainsValues returns true if a string array contains all of a list of specified values.
  163. func StringArrayContainsValues(array []string, values []string) bool {
  164. for _, value := range values {
  165. if !StringArrayContainsValue(array, value) {
  166. return false
  167. }
  168. }
  169. return true
  170. }
  171. // StringValue returns the string value of an item.
  172. func StringValue(item interface{}) (value string, ok bool) {
  173. value, ok = item.(string)
  174. if ok {
  175. return value, ok
  176. }
  177. intValue, ok := item.(int)
  178. if ok {
  179. return strconv.Itoa(intValue), true
  180. }
  181. return "", false
  182. }