Skip to content
This repository was archived by the owner on Mar 20, 2024. It is now read-only.

Commit cd6ee75

Browse files
flosellrodaine
authored andcommitted
Add support for multiple keys (#8)
* Add support for multiple keys * Rename variable to avoid shadowing previous variable
1 parent 8731714 commit cd6ee75

File tree

5 files changed

+63
-19
lines changed

5 files changed

+63
-19
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Foo "bar" "baz" {
2+
Fizz = "buzz"
3+
}

example_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,17 @@ func Example() {
2424
Sound string `hcl:"says" hcle:"omitempty"`
2525
}
2626

27+
type Pet struct {
28+
Species string `hcl:",key"`
29+
Name string `hcl:",key"`
30+
Sound string `hcl:"says" hcle:"omitempty"`
31+
}
32+
2733
type Config struct {
2834
Farm `hcl:",squash"`
2935
Farmer Farmer `hcl:"farmer"`
3036
Animals []Animal `hcl:"animal"`
37+
Pets []Pet `hcl:"pet"`
3138
Buildings map[string]string `hcl:"buildings"`
3239
}
3340

@@ -55,6 +62,13 @@ func Example() {
5562
Name: "rock",
5663
},
5764
},
65+
Pets: []Pet{
66+
{
67+
Species: "cat",
68+
Name: "whiskers",
69+
Sound: "meow",
70+
},
71+
},
5872
Buildings: map[string]string{
5973
"House": "123 Numbers Lane",
6074
"Barn": "456 Digits Drive",
@@ -93,6 +107,10 @@ func Example() {
93107
//
94108
// animal "rock" {}
95109
//
110+
// pet "cat" "whiskers" {
111+
// says = "meow"
112+
// }
113+
//
96114
// buildings {
97115
// Barn = "456 Digits Drive"
98116
// House = "123 Numbers Lane"

hclencoder_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,27 @@ func TestEncoder(t *testing.T) {
9090
},
9191
Output: "keyed-nested-structs",
9292
},
93+
{
94+
ID: "multiple keys nested structs",
95+
Input: struct {
96+
Foo struct {
97+
Key string `hcl:",key"`
98+
OtherKey string `hcl:",key"`
99+
Fizz string
100+
}
101+
}{
102+
struct {
103+
Key string `hcl:",key"`
104+
OtherKey string `hcl:",key"`
105+
Fizz string
106+
}{
107+
"bar",
108+
"baz",
109+
"buzz",
110+
},
111+
},
112+
Output: "multiple-keys-nested-structs",
113+
},
93114
{
94115
ID: "nested struct slice",
95116
Input: struct {

nodes.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ type fieldMeta struct {
6262
}
6363

6464
// encode converts a reflected valued into an HCL ast.Node in a depth-first manner.
65-
func encode(in reflect.Value) (node ast.Node, key *ast.ObjectKey, err error) {
65+
func encode(in reflect.Value) (node ast.Node, key []*ast.ObjectKey, err error) {
6666
in, isNil := deref(in)
6767
if isNil {
6868
return nil, nil, nil
@@ -92,7 +92,7 @@ func encode(in reflect.Value) (node ast.Node, key *ast.ObjectKey, err error) {
9292

9393
// encodePrimitive converts a primitive value into an ast.LiteralType. An
9494
// ast.ObjectKey is never returned.
95-
func encodePrimitive(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
95+
func encodePrimitive(in reflect.Value) (ast.Node, []*ast.ObjectKey, error) {
9696
tkn, err := tokenize(in, false)
9797
if err != nil {
9898
return nil, nil, err
@@ -103,7 +103,7 @@ func encodePrimitive(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
103103

104104
// encodeList converts a slice to an appropriate ast.Node type depending on its
105105
// element value type. An ast.ObjectKey is never returned.
106-
func encodeList(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
106+
func encodeList(in reflect.Value) (ast.Node, []*ast.ObjectKey, error) {
107107
childType := in.Type().Elem()
108108

109109
childLoop:
@@ -126,7 +126,7 @@ childLoop:
126126

127127
// encodePrimitiveList converts a slice of primitive values to an ast.ListType. An
128128
// ast.ObjectKey is never returned.
129-
func encodePrimitiveList(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
129+
func encodePrimitiveList(in reflect.Value) (ast.Node, []*ast.ObjectKey, error) {
130130
l := in.Len()
131131
n := &ast.ListType{List: make([]ast.Node, 0, l)}
132132

@@ -145,7 +145,7 @@ func encodePrimitiveList(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
145145

146146
// encodeBlockList converts a slice of non-primitive types to an ast.ObjectList. An
147147
// ast.ObjectKey is never returned.
148-
func encodeBlockList(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
148+
func encodeBlockList(in reflect.Value) (ast.Node, []*ast.ObjectKey, error) {
149149
l := in.Len()
150150
n := &ast.ObjectList{Items: make([]*ast.ObjectItem, 0, l)}
151151

@@ -162,7 +162,7 @@ func encodeBlockList(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
162162
}
163163

164164
item := &ast.ObjectItem{Val: child}
165-
item.Keys = []*ast.ObjectKey{childKey}
165+
item.Keys = childKey
166166
n.Add(item)
167167
}
168168

@@ -171,7 +171,7 @@ func encodeBlockList(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
171171

172172
// encodeMap converts a map type into an ast.ObjectType. Maps must have string
173173
// key values to be encoded. An ast.ObjectKey is never returned.
174-
func encodeMap(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
174+
func encodeMap(in reflect.Value) (ast.Node, []*ast.ObjectKey, error) {
175175
if keyType := in.Type().Key().Kind(); keyType != reflect.String {
176176
return nil, nil, fmt.Errorf("map keys must be strings, %s given", keyType)
177177
}
@@ -207,7 +207,7 @@ func encodeMap(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
207207
Val: val,
208208
}
209209
if childKey != nil {
210-
item.Keys = append(item.Keys, childKey)
210+
item.Keys = append(item.Keys, childKey...)
211211
}
212212
l = append(l, item)
213213

@@ -222,10 +222,10 @@ func encodeMap(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
222222
// encodeStruct converts a struct type into an ast.ObjectType. An ast.ObjectKey
223223
// may be returned if a KeyTag is present that should be used by a parent
224224
// ast.ObjectItem if this node is nested.
225-
func encodeStruct(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
225+
func encodeStruct(in reflect.Value) (ast.Node, []*ast.ObjectKey, error) {
226226
l := in.NumField()
227227
list := &ast.ObjectList{Items: make([]*ast.ObjectItem, 0, l)}
228-
var key *ast.ObjectKey
228+
keys := make([]*ast.ObjectKey, 0)
229229

230230
for i := 0; i < l; i++ {
231231
field := in.Type().Field(i)
@@ -259,7 +259,7 @@ func encodeStruct(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
259259
// this field is a key and should be bubbled up to the parent node
260260
if meta.key {
261261
if lit, ok := val.(*ast.LiteralType); ok && lit.Token.Type == token.STRING {
262-
key = &ast.ObjectKey{Token: lit.Token}
262+
keys = append(keys, &ast.ObjectKey{Token: lit.Token})
263263
continue
264264
}
265265
return nil, nil, errors.New("struct key fields must be string literals")
@@ -279,9 +279,9 @@ func encodeStruct(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
279279
// if the item is an object list, we need to flatten out the items
280280
if val, ok := val.(*ast.ObjectList); ok {
281281
for _, obj := range val.Items {
282-
keys := append([]*ast.ObjectKey{itemKey}, obj.Keys...)
282+
objectKeys := append([]*ast.ObjectKey{itemKey}, obj.Keys...)
283283
list.Add(&ast.ObjectItem{
284-
Keys: keys,
284+
Keys: objectKeys,
285285
Val: obj.Val,
286286
})
287287
}
@@ -293,12 +293,14 @@ func encodeStruct(in reflect.Value) (ast.Node, *ast.ObjectKey, error) {
293293
Val: val,
294294
}
295295
if childKey != nil {
296-
item.Keys = append(item.Keys, childKey)
296+
item.Keys = append(item.Keys, childKey...)
297297
}
298298
list.Add(item)
299299
}
300-
301-
return &ast.ObjectType{List: list}, key, nil
300+
if len(keys) == 0 {
301+
return &ast.ObjectType{List: list}, nil, nil
302+
}
303+
return &ast.ObjectType{List: list}, keys, nil
302304
}
303305

304306
// tokenize converts a primitive type into an token.Token. IDENT tokens (unquoted strings)

nodes_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@ import (
1010
"github.com/stretchr/testify/assert"
1111
)
1212

13-
type encodeFunc func(reflect.Value) (ast.Node, *ast.ObjectKey, error)
13+
type encodeFunc func(reflect.Value) (ast.Node, []*ast.ObjectKey, error)
1414

1515
type encodeTest struct {
1616
ID string
1717
Input reflect.Value
1818
Expected ast.Node
19-
Key *ast.ObjectKey
19+
Key []*ast.ObjectKey
2020
Error bool
2121
}
2222

23-
func (test encodeTest) Test(f encodeFunc, t *testing.T) (node ast.Node, key *ast.ObjectKey, err error) {
23+
func (test encodeTest) Test(f encodeFunc, t *testing.T) (node ast.Node, key []*ast.ObjectKey, err error) {
2424
node, key, err = f(test.Input)
2525

2626
if test.Error {

0 commit comments

Comments
 (0)