Skip to content

Commit

Permalink
support recursive anchor (#489)
Browse files Browse the repository at this point in the history
  • Loading branch information
goccy authored Oct 30, 2024
1 parent c9f75fe commit 950afad
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 3 deletions.
14 changes: 13 additions & 1 deletion decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Decoder struct {
reader io.Reader
referenceReaders []io.Reader
anchorNodeMap map[string]ast.Node
aliasValueMap map[*ast.AliasNode]any
anchorValueMap map[string]reflect.Value
customUnmarshalerMap map[reflect.Type]func(interface{}, []byte) error
toCommentMap CommentMap
Expand All @@ -48,6 +49,7 @@ func NewDecoder(r io.Reader, opts ...DecodeOption) *Decoder {
return &Decoder{
reader: r,
anchorNodeMap: map[string]ast.Node{},
aliasValueMap: make(map[*ast.AliasNode]any),
anchorValueMap: map[string]reflect.Value{},
customUnmarshalerMap: map[reflect.Type]func(interface{}, []byte) error{},
opts: opts,
Expand Down Expand Up @@ -301,9 +303,19 @@ func (d *Decoder) nodeToValue(node ast.Node) interface{} {
d.anchorNodeMap[anchorName] = n.Value
return anchorValue
case *ast.AliasNode:
if v, exists := d.aliasValueMap[n]; exists {
return v
}
// To handle the case where alias is processed recursively, the result of alias can be set to nil in advance.
d.aliasValueMap[n] = nil

aliasName := n.Value.GetToken().Value
node := d.anchorNodeMap[aliasName]
return d.nodeToValue(node)
aliasValue := d.nodeToValue(node)

// once the correct alias value is obtained, overwrite with that value.
d.aliasValueMap[n] = aliasValue
return aliasValue
case *ast.LiteralNode:
return n.Value.GetValue()
case *ast.MappingKeyNode:
Expand Down
16 changes: 15 additions & 1 deletion decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,21 @@ func TestDecoder(t *testing.T) {
"a: &a [1, 2]\nb: *a\n",
struct{ B []int }{[]int{1, 2}},
},

{
"&0: *0\n*0:\n*0:",
map[string]any{"null": nil},
},
{
"key1: &anchor\n subkey: *anchor\nkey2: *anchor\n",
map[string]any{
"key1": map[string]any{
"subkey": nil,
},
"key2": map[string]any{
"subkey": nil,
},
},
},
{
"tags:\n- hello-world\na: foo",
struct {
Expand Down
2 changes: 1 addition & 1 deletion lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2400,7 +2400,7 @@ func TestInvalid(t *testing.T) {
src string
}{
{
name: "literal opt",
name: "literal opt with content",
src: `
a: |invalid
foo`,
Expand Down

0 comments on commit 950afad

Please sign in to comment.