config: Add map() interpolation function
* `map(key, value, ...)` - Returns a map consisting of the key/value pairs specified as arguments. Every odd argument must be a string key, and every even argument must have the same type as the other values specified. Duplicate keys are not allowed. Examples: * `map("hello", "world")` * `map("us-east", list("a", "b", "c"), "us-west", list("b", "c", "d"))`
This commit is contained in:
parent
3392b3a764
commit
1425b34562
|
@ -71,6 +71,7 @@ func Funcs() map[string]ast.Function {
|
||||||
"length": interpolationFuncLength(),
|
"length": interpolationFuncLength(),
|
||||||
"list": interpolationFuncList(),
|
"list": interpolationFuncList(),
|
||||||
"lower": interpolationFuncLower(),
|
"lower": interpolationFuncLower(),
|
||||||
|
"map": interpolationFuncMap(),
|
||||||
"md5": interpolationFuncMd5(),
|
"md5": interpolationFuncMd5(),
|
||||||
"uuid": interpolationFuncUUID(),
|
"uuid": interpolationFuncUUID(),
|
||||||
"replace": interpolationFuncReplace(),
|
"replace": interpolationFuncReplace(),
|
||||||
|
@ -123,6 +124,50 @@ func interpolationFuncList() ast.Function {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interpolationFuncMap creates a map from the parameters passed
|
||||||
|
// to it.
|
||||||
|
func interpolationFuncMap() ast.Function {
|
||||||
|
return ast.Function{
|
||||||
|
ArgTypes: []ast.Type{},
|
||||||
|
ReturnType: ast.TypeMap,
|
||||||
|
Variadic: true,
|
||||||
|
VariadicType: ast.TypeAny,
|
||||||
|
Callback: func(args []interface{}) (interface{}, error) {
|
||||||
|
outputMap := make(map[string]ast.Variable)
|
||||||
|
|
||||||
|
if len(args)%2 != 0 {
|
||||||
|
return nil, fmt.Errorf("requires an even number of arguments, got %d", len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstType *ast.Type
|
||||||
|
for i := 0; i < len(args); i += 2 {
|
||||||
|
key, ok := args[i].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("argument %d represents a key, so it must be a string", i+1)
|
||||||
|
}
|
||||||
|
val := args[i+1]
|
||||||
|
variable, err := hil.InterfaceToVariable(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Enforce map type homogeneity
|
||||||
|
if firstType == nil {
|
||||||
|
firstType = &variable.Type
|
||||||
|
} else if variable.Type != *firstType {
|
||||||
|
return nil, fmt.Errorf("all map values must have the same type, got %s then %s", firstType.Printable(), variable.Type.Printable())
|
||||||
|
}
|
||||||
|
// Check for duplicate keys
|
||||||
|
if _, ok := outputMap[key]; ok {
|
||||||
|
return nil, fmt.Errorf("argument %d is a duplicate key: %q", i+1, key)
|
||||||
|
}
|
||||||
|
outputMap[key] = variable
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputMap, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// interpolationFuncCompact strips a list of multi-variable values
|
// interpolationFuncCompact strips a list of multi-variable values
|
||||||
// (e.g. as returned by "split") of any empty strings.
|
// (e.g. as returned by "split") of any empty strings.
|
||||||
func interpolationFuncCompact() ast.Function {
|
func interpolationFuncCompact() ast.Function {
|
||||||
|
|
|
@ -113,6 +113,81 @@ func TestInterpolateFuncList(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInterpolateFuncMap(t *testing.T) {
|
||||||
|
testFunction(t, testFunctionConfig{
|
||||||
|
Cases: []testFunctionCase{
|
||||||
|
// empty input returns empty map
|
||||||
|
{
|
||||||
|
`${map()}`,
|
||||||
|
map[string]interface{}{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// odd args is error
|
||||||
|
{
|
||||||
|
`${map("odd")}`,
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// two args returns map w/ one k/v
|
||||||
|
{
|
||||||
|
`${map("hello", "world")}`,
|
||||||
|
map[string]interface{}{"hello": "world"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// four args get two k/v
|
||||||
|
{
|
||||||
|
`${map("hello", "world", "what's", "up?")}`,
|
||||||
|
map[string]interface{}{"hello": "world", "what's": "up?"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// map of lists is okay
|
||||||
|
{
|
||||||
|
`${map("hello", list("world"), "what's", list("up?"))}`,
|
||||||
|
map[string]interface{}{
|
||||||
|
"hello": []interface{}{"world"},
|
||||||
|
"what's": []interface{}{"up?"},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// map of maps is okay
|
||||||
|
{
|
||||||
|
`${map("hello", map("there", "world"), "what's", map("really", "up?"))}`,
|
||||||
|
map[string]interface{}{
|
||||||
|
"hello": map[string]interface{}{"there": "world"},
|
||||||
|
"what's": map[string]interface{}{"really": "up?"},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// keys have to be strings
|
||||||
|
{
|
||||||
|
`${map(list("listkey"), "val")}`,
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// types have to match
|
||||||
|
{
|
||||||
|
`${map("some", "strings", "also", list("lists"))}`,
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// duplicate keys are an error
|
||||||
|
{
|
||||||
|
`${map("key", "val", "key", "again")}`,
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestInterpolateFuncCompact(t *testing.T) {
|
func TestInterpolateFuncCompact(t *testing.T) {
|
||||||
testFunction(t, testFunctionConfig{
|
testFunction(t, testFunctionConfig{
|
||||||
Cases: []testFunctionCase{
|
Cases: []testFunctionCase{
|
||||||
|
|
|
@ -181,6 +181,13 @@ The supported built-in functions are:
|
||||||
|
|
||||||
* `lower(string)` - Returns a copy of the string with all Unicode letters mapped to their lower case.
|
* `lower(string)` - Returns a copy of the string with all Unicode letters mapped to their lower case.
|
||||||
|
|
||||||
|
* `map(key, value, ...)` - Returns a map consisting of the key/value pairs
|
||||||
|
specified as arguments. Every odd argument must be a string key, and every
|
||||||
|
even argument must have the same type as the other values specified.
|
||||||
|
Duplicate keys are not allowed. Examples:
|
||||||
|
* `map("hello", "world")`
|
||||||
|
* `map("us-east", list("a", "b", "c"), "us-west", list("b", "c", "d"))`
|
||||||
|
|
||||||
* `md5(string)` - Returns a (conventional) hexadecimal representation of the
|
* `md5(string)` - Returns a (conventional) hexadecimal representation of the
|
||||||
MD5 hash of the given string.
|
MD5 hash of the given string.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue