Merge branch 'glasser/jsonencode-list-map' of https://github.com/meteor/terraform into meteor-glasser/jsonencode-list-map
This commit is contained in:
commit
48b8b86580
|
@ -409,16 +409,54 @@ func interpolationFuncJoin() ast.Function {
|
||||||
}
|
}
|
||||||
|
|
||||||
// interpolationFuncJSONEncode implements the "jsonencode" function that encodes
|
// interpolationFuncJSONEncode implements the "jsonencode" function that encodes
|
||||||
// a string as its JSON representation.
|
// a string, list, or map as its JSON representation. For now, values in the
|
||||||
|
// list or map may only be strings.
|
||||||
func interpolationFuncJSONEncode() ast.Function {
|
func interpolationFuncJSONEncode() ast.Function {
|
||||||
return ast.Function{
|
return ast.Function{
|
||||||
ArgTypes: []ast.Type{ast.TypeString},
|
ArgTypes: []ast.Type{ast.TypeAny},
|
||||||
ReturnType: ast.TypeString,
|
ReturnType: ast.TypeString,
|
||||||
Callback: func(args []interface{}) (interface{}, error) {
|
Callback: func(args []interface{}) (interface{}, error) {
|
||||||
s := args[0].(string)
|
var toEncode interface{}
|
||||||
jEnc, err := json.Marshal(s)
|
|
||||||
|
switch typedArg := args[0].(type) {
|
||||||
|
case string:
|
||||||
|
toEncode = typedArg
|
||||||
|
|
||||||
|
case []ast.Variable:
|
||||||
|
// We preallocate the list here. Note that it's important that in
|
||||||
|
// the length 0 case, we have an empty list rather than nil, as
|
||||||
|
// they encode differently.
|
||||||
|
// XXX It would be nice to support arbitrarily nested data here. Is
|
||||||
|
// there an inverse of hil.InterfaceToVariable?
|
||||||
|
strings := make([]string, len(typedArg))
|
||||||
|
|
||||||
|
for i, v := range typedArg {
|
||||||
|
if v.Type != ast.TypeString {
|
||||||
|
return "", fmt.Errorf("list elements must be strings")
|
||||||
|
}
|
||||||
|
strings[i] = v.Value.(string)
|
||||||
|
}
|
||||||
|
toEncode = strings
|
||||||
|
|
||||||
|
case map[string]ast.Variable:
|
||||||
|
// XXX It would be nice to support arbitrarily nested data here. Is
|
||||||
|
// there an inverse of hil.InterfaceToVariable?
|
||||||
|
stringMap := make(map[string]string)
|
||||||
|
for k, v := range typedArg {
|
||||||
|
if v.Type != ast.TypeString {
|
||||||
|
return "", fmt.Errorf("map values must be strings")
|
||||||
|
}
|
||||||
|
stringMap[k] = v.Value.(string)
|
||||||
|
}
|
||||||
|
toEncode = stringMap
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("unknown type for JSON encoding: %T", args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
jEnc, err := json.Marshal(toEncode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to encode JSON data '%s'", s)
|
return "", fmt.Errorf("failed to encode JSON data '%s'", toEncode)
|
||||||
}
|
}
|
||||||
return string(jEnc), nil
|
return string(jEnc), nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -419,6 +419,22 @@ func TestInterpolateFuncJSONEncode(t *testing.T) {
|
||||||
Value: " foo \\ \n \t \" bar ",
|
Value: " foo \\ \n \t \" bar ",
|
||||||
Type: ast.TypeString,
|
Type: ast.TypeString,
|
||||||
},
|
},
|
||||||
|
"list": interfaceToVariableSwallowError([]string{"foo", "bar\tbaz"}),
|
||||||
|
// XXX can't use InterfaceToVariable as it converts empty slice into empty
|
||||||
|
// map.
|
||||||
|
"emptylist": ast.Variable{
|
||||||
|
Value: []ast.Variable{},
|
||||||
|
Type: ast.TypeList,
|
||||||
|
},
|
||||||
|
"map": interfaceToVariableSwallowError(map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"ba \n z": "q\\x",
|
||||||
|
}),
|
||||||
|
"emptymap": interfaceToVariableSwallowError(map[string]string{}),
|
||||||
|
|
||||||
|
// Not yet supported (but it would be nice)
|
||||||
|
"nestedlist": interfaceToVariableSwallowError([][]string{{"foo"}}),
|
||||||
|
"nestedmap": interfaceToVariableSwallowError(map[string][]string{"foo": {"bar"}}),
|
||||||
},
|
},
|
||||||
Cases: []testFunctionCase{
|
Cases: []testFunctionCase{
|
||||||
{
|
{
|
||||||
|
@ -446,6 +462,36 @@ func TestInterpolateFuncJSONEncode(t *testing.T) {
|
||||||
nil,
|
nil,
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
`${jsonencode(list)}`,
|
||||||
|
`["foo","bar\tbaz"]`,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`${jsonencode(emptylist)}`,
|
||||||
|
`[]`,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`${jsonencode(map)}`,
|
||||||
|
`{"ba \n z":"q\\x","foo":"bar"}`,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`${jsonencode(emptymap)}`,
|
||||||
|
`{}`,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`${jsonencode(nestedlist)}`,
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`${jsonencode(nestedmap)}`,
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,8 +150,10 @@ The supported built-in functions are:
|
||||||
only possible with splat variables from resources with a count
|
only possible with splat variables from resources with a count
|
||||||
greater than one. Example: `join(",", aws_instance.foo.*.id)`
|
greater than one. Example: `join(",", aws_instance.foo.*.id)`
|
||||||
|
|
||||||
* `jsonencode(string)` - Returns a JSON-encoded representation of the given
|
* `jsonencode(item)` - Returns a JSON-encoded representation of the given
|
||||||
string (including double quotes).
|
item, which may be a string, list of strings, or map from string to string.
|
||||||
|
Note that if the item is a string, the return value includes the double
|
||||||
|
quotes.
|
||||||
|
|
||||||
* `length(list)` - Returns a number of members in a given list
|
* `length(list)` - Returns a number of members in a given list
|
||||||
or a number of characters in a given string.
|
or a number of characters in a given string.
|
||||||
|
|
Loading…
Reference in New Issue