configs/configupgrade: Replace calls to list() and map()

We now have native language features for declaring tuples and objects,
which are the idiomatic way to construct sequence and mapping values that
can then be converted to list, set, and map types as needed.
This commit is contained in:
Martin Atkins 2018-11-30 18:23:09 -08:00
parent 8cf024d45a
commit 4927a4105b
4 changed files with 119 additions and 4 deletions

View File

@ -0,0 +1,13 @@
locals {
list = "${list("a", "b", "c")}"
list_concat = "${concat(list("a", "b"), list("c"))}"
list_empty = "${list()}"
map = "${map("a", "b", "c", "d")}"
map_merge = "${merge(map("a", "b"), map("c", "d"))}"
map_empty = "${map()}"
map_invalid = "${map("a", "b", "c")}"
list_of_map = "${list(map("a", "b"))}"
map_of_list = "${map("a", list("b"))}"
}

View File

@ -0,0 +1,29 @@
locals {
list = ["a", "b", "c"]
list_concat = concat(["a", "b"], ["c"])
list_empty = []
map = {
"a" = "b"
"c" = "d"
}
map_merge = merge(
{
"a" = "b"
},
{
"c" = "d"
},
)
map_empty = {}
map_invalid = map("a", "b", "c")
list_of_map = [
{
"a" = "b"
},
]
map_of_list = {
"a" = ["b"]
}
}

View File

@ -0,0 +1,3 @@
terraform {
required_version = ">= 0.12"
}

View File

@ -172,16 +172,86 @@ func upgradeExpr(val interface{}, filename string, interp bool, an *analysis) ([
name := tv.Func name := tv.Func
args := tv.Args args := tv.Args
buf.WriteString(name) argExprs := make([][]byte, len(args))
buf.WriteByte('(') multiline := false
totalLen := 0
for i, arg := range args { for i, arg := range args {
if i > 0 { if i > 0 {
buf.WriteString(", ") totalLen += 2
} }
exprSrc, exprDiags := upgradeExpr(arg, filename, true, an) exprSrc, exprDiags := upgradeExpr(arg, filename, true, an)
diags = diags.Append(exprDiags) diags = diags.Append(exprDiags)
argExprs[i] = exprSrc
if bytes.Contains(exprSrc, []byte{'\n'}) {
// If any of our arguments are multi-line then we'll also be multiline
multiline = true
}
totalLen += len(exprSrc)
}
if totalLen > 60 { // heuristic, since we don't know here how indented we are already
multiline = true
}
// Some functions are now better expressed as native language constructs.
// These cases will return early if they emit anything, or otherwise
// fall through to the default emitter.
switch name {
case "list":
// Should now use tuple constructor syntax
buf.WriteByte('[')
if multiline {
buf.WriteByte('\n')
}
for i, exprSrc := range argExprs {
buf.Write(exprSrc)
if multiline {
buf.WriteString(",\n")
} else {
if i < len(args)-1 {
buf.WriteString(", ")
}
}
}
buf.WriteByte(']')
return buf.Bytes(), diags
case "map":
// Should now use object constructor syntax, but we can only
// achieve that if the call is valid, which requires an even
// number of arguments.
if len(argExprs) == 0 {
buf.WriteString("{}")
return buf.Bytes(), diags
} else if len(argExprs)%2 == 0 {
buf.WriteString("{\n")
for i := 0; i < len(argExprs); i += 2 {
k := argExprs[i]
v := argExprs[i+1]
buf.Write(k)
buf.WriteString(" = ")
buf.Write(v)
buf.WriteByte('\n')
}
buf.WriteByte('}')
return buf.Bytes(), diags
}
}
buf.WriteString(name)
buf.WriteByte('(')
if multiline {
buf.WriteByte('\n')
}
for i, exprSrc := range argExprs {
buf.Write(exprSrc) buf.Write(exprSrc)
if multiline {
buf.WriteString(",\n")
} else {
if i < len(args)-1 {
buf.WriteString(", ")
}
}
} }
buf.WriteByte(')') buf.WriteByte(')')