9 "github.com/hashicorp/hil"
12 // Expand takes a map and a key (prefix) and expands that value into
13 // a more complex structure. This is the reverse of the Flatten operation.
14 func Expand(m map[string]string, key string) interface{} {
15 // If the key is exactly a key in the map, just return it
16 if v, ok := m[key]; ok {
19 } else if v == "false" {
26 // Check if the key is an array, and if so, expand the array
27 if v, ok := m[key+".#"]; ok {
28 // If the count of the key is unknown, then just put the unknown
29 // value in the value itself. This will be detected by Terraform
31 if v == hil.UnknownValue {
35 return expandArray(m, key)
38 // Check if this is a prefix in the map
41 if strings.HasPrefix(k, prefix) {
42 return expandMap(m, prefix)
49 func expandArray(m map[string]string, prefix string) []interface{} {
50 num, err := strconv.ParseInt(m[prefix+".#"], 0, 0)
55 // If the number of elements in this array is 0, then return an
56 // empty slice as there is nothing to expand. Trying to expand it
57 // anyway could lead to crashes as any child maps, arrays or sets
58 // that no longer exist are still shown as empty with a count of 0.
60 return []interface{}{}
63 // The Schema "Set" type stores its values in an array format, but
64 // using numeric hash values instead of ordinal keys. Take the set
65 // of keys regardless of value, and expand them in numeric order.
66 // See GH-11042 for more details.
67 keySet := map[int]bool{}
68 computed := map[string]bool{}
70 if !strings.HasPrefix(k, prefix+".") {
74 key := k[len(prefix)+1:]
75 idx := strings.Index(key, ".")
80 // skip the count value
85 // strip the computed flag if there is one
86 if strings.HasPrefix(key, "~") {
91 k, err := strconv.Atoi(key)
98 keysList := make([]int, 0, num)
99 for key := range keySet {
100 keysList = append(keysList, key)
104 result := make([]interface{}, num)
105 for i, key := range keysList {
106 keyString := strconv.Itoa(key)
107 if computed[keyString] {
108 keyString = "~" + keyString
110 result[i] = Expand(m, fmt.Sprintf("%s.%s", prefix, keyString))
116 func expandMap(m map[string]string, prefix string) map[string]interface{} {
117 // Submaps may not have a '%' key, so we can't count on this value being
118 // here. If we don't have a count, just proceed as if we have have a map.
119 if count, ok := m[prefix+"%"]; ok && count == "0" {
120 return map[string]interface{}{}
123 result := make(map[string]interface{})
125 if !strings.HasPrefix(k, prefix) {
129 key := k[len(prefix):]
130 idx := strings.Index(key, ".")
134 if _, ok := result[key]; ok {
138 // skip the map count value
143 result[key] = Expand(m, k[:len(prefix)+len(key)])