Skip to content

Commit

Permalink
Add yaml.NodeToValue(ast.Node, interface{}, ...DecodeOption) error
Browse files Browse the repository at this point in the history
  • Loading branch information
zoncoen committed Jul 19, 2021
1 parent 88ebfa0 commit f6a3c23
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
22 changes: 22 additions & 0 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -1489,3 +1489,25 @@ func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
}
return nil
}

// DecodeFromNode decodes node into the value pointed to by v.
func (d *Decoder) DecodeFromNode(node ast.Node, v interface{}) error {
return d.DecodeFromNodeContext(context.Background(), node, v)
}

// DecodeFromNodeContext decodes node into the value pointed to by v with context.Context.
func (d *Decoder) DecodeFromNodeContext(ctx context.Context, node ast.Node, v interface{}) error {
rv := reflect.ValueOf(v)
if rv.Type().Kind() != reflect.Ptr {
return errors.ErrDecodeRequiredPointerType
}
if !d.isInitialized() {
if err := d.decodeInit(); err != nil {
return errors.Wrapf(err, "failed to decodInit")
}
}
if err := d.decodeValue(ctx, rv.Elem(), node); err != nil {
return errors.Wrapf(err, "failed to decode value")
}
return nil
}
51 changes: 51 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/goccy/go-yaml"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/internal/errors"
"github.com/goccy/go-yaml/parser"
"golang.org/x/xerrors"
)
Expand Down Expand Up @@ -1716,6 +1717,40 @@ func Test_UnmarshalerWithContext(t *testing.T) {
}
}

func TestDecoder_DecodeFromNode(t *testing.T) {
t.Run("with reference", func(t *testing.T) {
anchor := strings.NewReader(`
map: &map
text: hello`)
var buf bytes.Buffer
dec := yaml.NewDecoder(&buf, yaml.ReferenceReaders(anchor))
f, err := parser.ParseBytes([]byte("map: *map"), 0)
if err != nil {
t.Fatalf("failed to parse: %s", err)
}
type T struct {
Map map[string]string
}
var v T
if err := dec.DecodeFromNode(f.Docs[0].Body, &v); err != nil {
t.Fatalf("failed to decode: %s", err)
}
actual := fmt.Sprintf("%+v", v)
expect := fmt.Sprintf("%+v", T{map[string]string{"text": "hello"}})
if actual != expect {
t.Fatalf("actual=[%s], expect=[%s]", actual, expect)
}
})
t.Run("value is not pointer", func(t *testing.T) {
var buf bytes.Buffer
var v bool
err := yaml.NewDecoder(&buf).DecodeFromNode(nil, v)
if !xerrors.Is(err, errors.ErrDecodeRequiredPointerType) {
t.Fatalf("unexpected error: %s", err)
}
})
}

func Example_JSONTags() {
yml := `---
foo: 1
Expand Down Expand Up @@ -1756,6 +1791,22 @@ complecated: string
// ^
}

func Example_Unmarshal_Node() {
f, err := parser.ParseBytes([]byte("text: node example"), 0)
if err != nil {
panic(err)
}
var v struct {
Text string `yaml:"text"`
}
if err := yaml.NodeToValue(f.Docs[0].Body, &v); err != nil {
panic(err)
}
fmt.Println(v.Text)
// OUTPUT:
// node example
}

type unmarshalableYAMLStringValue string

func (v *unmarshalableYAMLStringValue) UnmarshalYAML(b []byte) error {
Expand Down
9 changes: 9 additions & 0 deletions yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,15 @@ func UnmarshalWithContext(ctx context.Context, data []byte, v interface{}, opts
return nil
}

// NodeToValue converts node to the value pointed to by v.
func NodeToValue(node ast.Node, v interface{}, opts ...DecodeOption) error {
var buf bytes.Buffer
if err := NewDecoder(&buf, opts...).DecodeFromNode(node, v); err != nil {
return errors.Wrapf(err, "failed to convert node to value")
}
return nil
}

// FormatError is a utility function that takes advantage of the metadata
// stored in the errors returned by this package's parser.
//
Expand Down

0 comments on commit f6a3c23

Please sign in to comment.