2019-10-18 00:00:58 +09:00
|
|
|
package yaml
|
|
|
|
|
|
|
|
|
|
import (
|
2019-12-29 02:04:39 +09:00
|
|
|
"bytes"
|
2020-11-11 19:27:58 +09:00
|
|
|
"context"
|
2020-01-12 02:50:51 +09:00
|
|
|
"encoding"
|
2019-10-18 00:00:58 +09:00
|
|
|
"encoding/base64"
|
2019-10-18 15:20:09 +09:00
|
|
|
"fmt"
|
2019-10-18 00:00:58 +09:00
|
|
|
"io"
|
2019-10-29 19:46:55 +09:00
|
|
|
"math"
|
2019-10-18 15:20:09 +09:00
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
2019-10-18 00:00:58 +09:00
|
|
|
"reflect"
|
2023-03-01 16:59:07 +09:00
|
|
|
"sort"
|
2019-10-31 17:38:53 +09:00
|
|
|
"strconv"
|
2024-11-13 00:40:31 +09:00
|
|
|
"strings"
|
2019-11-01 14:09:33 +09:00
|
|
|
"time"
|
2019-10-18 00:00:58 +09:00
|
|
|
|
|
|
|
|
"github.com/goccy/go-yaml/ast"
|
2019-10-24 11:07:40 +09:00
|
|
|
"github.com/goccy/go-yaml/internal/errors"
|
2019-10-18 00:00:58 +09:00
|
|
|
"github.com/goccy/go-yaml/parser"
|
|
|
|
|
"github.com/goccy/go-yaml/token"
|
|
|
|
|
)
|
|
|
|
|
|
2019-10-21 12:53:30 +09:00
|
|
|
// Decoder reads and decodes YAML values from an input stream.
|
2019-10-18 00:00:58 +09:00
|
|
|
type Decoder struct {
|
2019-12-10 18:41:23 +09:00
|
|
|
reader io.Reader
|
|
|
|
|
referenceReaders []io.Reader
|
2020-01-09 21:49:52 +09:00
|
|
|
anchorNodeMap map[string]ast.Node
|
2024-10-30 19:25:18 +09:00
|
|
|
aliasValueMap map[*ast.AliasNode]any
|
2020-01-09 21:49:52 +09:00
|
|
|
anchorValueMap map[string]reflect.Value
|
2023-04-02 10:50:03 +09:00
|
|
|
customUnmarshalerMap map[reflect.Type]func(interface{}, []byte) error
|
2021-09-07 19:49:15 +09:00
|
|
|
toCommentMap CommentMap
|
2019-12-10 18:41:23 +09:00
|
|
|
opts []DecodeOption
|
|
|
|
|
referenceFiles []string
|
|
|
|
|
referenceDirs []string
|
|
|
|
|
isRecursiveDir bool
|
|
|
|
|
isResolvedReference bool
|
|
|
|
|
validator StructValidator
|
|
|
|
|
disallowUnknownField bool
|
2024-11-13 18:29:20 +09:00
|
|
|
allowDuplicateMapKey bool
|
2020-05-29 19:47:47 +09:00
|
|
|
useOrderedMap bool
|
2020-10-26 19:00:49 +09:00
|
|
|
useJSONUnmarshaler bool
|
2020-06-01 16:14:20 +09:00
|
|
|
parsedFile *ast.File
|
|
|
|
|
streamIndex int
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-21 12:53:30 +09:00
|
|
|
// NewDecoder returns a new decoder that reads from r.
|
2019-10-18 15:20:09 +09:00
|
|
|
func NewDecoder(r io.Reader, opts ...DecodeOption) *Decoder {
|
2019-10-18 14:27:49 +09:00
|
|
|
return &Decoder{
|
2019-12-10 18:41:23 +09:00
|
|
|
reader: r,
|
2020-01-09 21:49:52 +09:00
|
|
|
anchorNodeMap: map[string]ast.Node{},
|
2024-10-30 19:25:18 +09:00
|
|
|
aliasValueMap: make(map[*ast.AliasNode]any),
|
2020-01-09 21:49:52 +09:00
|
|
|
anchorValueMap: map[string]reflect.Value{},
|
2023-04-02 10:50:03 +09:00
|
|
|
customUnmarshalerMap: map[reflect.Type]func(interface{}, []byte) error{},
|
2019-12-10 18:41:23 +09:00
|
|
|
opts: opts,
|
|
|
|
|
referenceReaders: []io.Reader{},
|
|
|
|
|
referenceFiles: []string{},
|
|
|
|
|
referenceDirs: []string{},
|
|
|
|
|
isRecursiveDir: false,
|
|
|
|
|
isResolvedReference: false,
|
|
|
|
|
disallowUnknownField: false,
|
2024-11-13 18:29:20 +09:00
|
|
|
allowDuplicateMapKey: false,
|
2020-05-29 19:47:47 +09:00
|
|
|
useOrderedMap: false,
|
2019-10-18 14:27:49 +09:00
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-31 17:38:53 +09:00
|
|
|
func (d *Decoder) castToFloat(v interface{}) interface{} {
|
|
|
|
|
switch vv := v.(type) {
|
|
|
|
|
case int:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case int8:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case int16:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case int32:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case int64:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case uint:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case uint8:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case uint16:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case uint32:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case uint64:
|
|
|
|
|
return float64(vv)
|
2019-11-01 11:26:36 +09:00
|
|
|
case float32:
|
|
|
|
|
return float64(vv)
|
|
|
|
|
case float64:
|
|
|
|
|
return vv
|
2019-10-31 17:38:53 +09:00
|
|
|
case string:
|
2019-11-01 11:26:36 +09:00
|
|
|
// if error occurred, return zero value
|
2019-10-31 17:38:53 +09:00
|
|
|
f, _ := strconv.ParseFloat(vv, 64)
|
|
|
|
|
return f
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-15 12:14:02 +09:00
|
|
|
func (d *Decoder) mergeValueNode(value ast.Node) ast.Node {
|
|
|
|
|
if value.Type() == ast.AliasType {
|
2024-10-28 11:31:15 +09:00
|
|
|
aliasNode, _ := value.(*ast.AliasNode)
|
2020-06-15 12:14:02 +09:00
|
|
|
aliasName := aliasNode.Value.GetToken().Value
|
|
|
|
|
return d.anchorNodeMap[aliasName]
|
|
|
|
|
}
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 17:40:43 +09:00
|
|
|
func (d *Decoder) mapKeyNodeToString(node ast.MapKeyNode) (string, error) {
|
|
|
|
|
key, err := d.nodeToValue(node)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
2020-07-02 17:26:35 +09:00
|
|
|
if key == nil {
|
2024-11-02 17:40:43 +09:00
|
|
|
return "null", nil
|
2020-07-02 17:26:35 +09:00
|
|
|
}
|
|
|
|
|
if k, ok := key.(string); ok {
|
2024-11-02 17:40:43 +09:00
|
|
|
return k, nil
|
2020-07-02 17:26:35 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
return fmt.Sprint(key), nil
|
2020-07-02 17:26:35 +09:00
|
|
|
}
|
|
|
|
|
|
2024-11-02 17:40:43 +09:00
|
|
|
func (d *Decoder) setToMapValue(node ast.Node, m map[string]interface{}) error {
|
2021-09-07 19:49:15 +09:00
|
|
|
d.setPathToCommentMap(node)
|
2019-12-29 00:06:46 +09:00
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.MappingValueNode:
|
2020-06-11 20:58:37 +09:00
|
|
|
if n.Key.Type() == ast.MergeKeyType {
|
2024-11-02 17:40:43 +09:00
|
|
|
if err := d.setToMapValue(d.mergeValueNode(n.Value), m); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2019-12-29 00:06:46 +09:00
|
|
|
} else {
|
2024-11-02 17:40:43 +09:00
|
|
|
key, err := d.mapKeyNodeToString(n.Key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
v, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
m[key] = v
|
2019-12-29 00:06:46 +09:00
|
|
|
}
|
|
|
|
|
case *ast.MappingNode:
|
|
|
|
|
for _, value := range n.Values {
|
2024-11-02 17:40:43 +09:00
|
|
|
if err := d.setToMapValue(value, m); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2019-12-29 00:06:46 +09:00
|
|
|
}
|
2021-03-02 12:24:12 +09:00
|
|
|
case *ast.AnchorNode:
|
|
|
|
|
anchorName := n.Name.GetToken().Value
|
|
|
|
|
d.anchorNodeMap[anchorName] = n.Value
|
2019-12-29 00:06:46 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
return nil
|
2019-12-29 00:06:46 +09:00
|
|
|
}
|
|
|
|
|
|
2024-11-02 17:40:43 +09:00
|
|
|
func (d *Decoder) setToOrderedMapValue(node ast.Node, m *MapSlice) error {
|
2024-11-06 18:21:28 +09:00
|
|
|
d.setPathToCommentMap(node)
|
2020-05-29 19:47:47 +09:00
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.MappingValueNode:
|
2020-06-11 20:58:37 +09:00
|
|
|
if n.Key.Type() == ast.MergeKeyType {
|
2024-11-02 17:40:43 +09:00
|
|
|
if err := d.setToOrderedMapValue(d.mergeValueNode(n.Value), m); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-05-29 19:47:47 +09:00
|
|
|
} else {
|
2024-11-02 17:40:43 +09:00
|
|
|
key, err := d.mapKeyNodeToString(n.Key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
value, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
*m = append(*m, MapItem{Key: key, Value: value})
|
2020-05-29 19:47:47 +09:00
|
|
|
}
|
|
|
|
|
case *ast.MappingNode:
|
|
|
|
|
for _, value := range n.Values {
|
2024-11-02 17:40:43 +09:00
|
|
|
if err := d.setToOrderedMapValue(value, m); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-05-29 19:47:47 +09:00
|
|
|
}
|
|
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
return nil
|
2020-05-29 19:47:47 +09:00
|
|
|
}
|
|
|
|
|
|
2021-09-07 19:49:15 +09:00
|
|
|
func (d *Decoder) setPathToCommentMap(node ast.Node) {
|
|
|
|
|
if d.toCommentMap == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-03-01 16:59:07 +09:00
|
|
|
d.addHeadOrLineCommentToMap(node)
|
|
|
|
|
d.addFootCommentToMap(node)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) addHeadOrLineCommentToMap(node ast.Node) {
|
|
|
|
|
sequence, ok := node.(*ast.SequenceNode)
|
|
|
|
|
if ok {
|
|
|
|
|
d.addSequenceNodeCommentToMap(sequence)
|
|
|
|
|
return
|
|
|
|
|
}
|
2021-09-07 19:49:15 +09:00
|
|
|
commentGroup := node.GetComment()
|
|
|
|
|
if commentGroup == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
texts := []string{}
|
2023-03-01 16:59:07 +09:00
|
|
|
targetLine := node.GetToken().Position.Line
|
2023-03-28 17:49:13 +09:00
|
|
|
minCommentLine := math.MaxInt
|
2021-09-07 19:49:15 +09:00
|
|
|
for _, comment := range commentGroup.Comments {
|
2023-03-01 16:59:07 +09:00
|
|
|
if minCommentLine > comment.Token.Position.Line {
|
|
|
|
|
minCommentLine = comment.Token.Position.Line
|
|
|
|
|
}
|
2021-09-07 19:49:15 +09:00
|
|
|
texts = append(texts, comment.Token.Value)
|
|
|
|
|
}
|
|
|
|
|
if len(texts) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-03-01 16:59:07 +09:00
|
|
|
commentPath := node.GetPath()
|
|
|
|
|
if minCommentLine < targetLine {
|
2024-11-26 11:05:45 +09:00
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.MappingNode:
|
|
|
|
|
if len(n.Values) != 0 {
|
|
|
|
|
commentPath = n.Values[0].Key.GetPath()
|
|
|
|
|
}
|
|
|
|
|
case *ast.MappingValueNode:
|
|
|
|
|
commentPath = n.Key.GetPath()
|
|
|
|
|
}
|
2023-03-01 16:59:07 +09:00
|
|
|
d.addCommentToMap(commentPath, HeadComment(texts...))
|
2021-09-07 19:49:15 +09:00
|
|
|
} else {
|
2023-03-01 16:59:07 +09:00
|
|
|
d.addCommentToMap(commentPath, LineComment(texts[0]))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) addSequenceNodeCommentToMap(node *ast.SequenceNode) {
|
|
|
|
|
if len(node.ValueHeadComments) != 0 {
|
|
|
|
|
for idx, headComment := range node.ValueHeadComments {
|
|
|
|
|
if headComment == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
texts := make([]string, 0, len(headComment.Comments))
|
|
|
|
|
for _, comment := range headComment.Comments {
|
|
|
|
|
texts = append(texts, comment.Token.Value)
|
|
|
|
|
}
|
|
|
|
|
if len(texts) != 0 {
|
|
|
|
|
d.addCommentToMap(node.Values[idx].GetPath(), HeadComment(texts...))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
firstElemHeadComment := node.GetComment()
|
|
|
|
|
if firstElemHeadComment != nil {
|
|
|
|
|
texts := make([]string, 0, len(firstElemHeadComment.Comments))
|
|
|
|
|
for _, comment := range firstElemHeadComment.Comments {
|
|
|
|
|
texts = append(texts, comment.Token.Value)
|
|
|
|
|
}
|
|
|
|
|
if len(texts) != 0 {
|
|
|
|
|
d.addCommentToMap(node.Values[0].GetPath(), HeadComment(texts...))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) addFootCommentToMap(node ast.Node) {
|
|
|
|
|
var (
|
|
|
|
|
footComment *ast.CommentGroupNode
|
|
|
|
|
footCommentPath string = node.GetPath()
|
|
|
|
|
)
|
|
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.SequenceNode:
|
|
|
|
|
footComment = n.FootComment
|
2024-11-26 11:05:45 +09:00
|
|
|
if n.FootComment != nil {
|
|
|
|
|
footCommentPath = n.FootComment.GetPath()
|
|
|
|
|
}
|
2023-03-01 16:59:07 +09:00
|
|
|
case *ast.MappingNode:
|
|
|
|
|
footComment = n.FootComment
|
2024-11-26 11:05:45 +09:00
|
|
|
if n.FootComment != nil {
|
|
|
|
|
footCommentPath = n.FootComment.GetPath()
|
|
|
|
|
}
|
2023-03-01 16:59:07 +09:00
|
|
|
case *ast.MappingValueNode:
|
|
|
|
|
footComment = n.FootComment
|
2024-11-26 11:05:45 +09:00
|
|
|
if n.FootComment != nil {
|
|
|
|
|
footCommentPath = n.FootComment.GetPath()
|
|
|
|
|
}
|
2023-03-01 16:59:07 +09:00
|
|
|
}
|
|
|
|
|
if footComment == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var texts []string
|
|
|
|
|
for _, comment := range footComment.Comments {
|
|
|
|
|
texts = append(texts, comment.Token.Value)
|
|
|
|
|
}
|
|
|
|
|
if len(texts) != 0 {
|
|
|
|
|
d.addCommentToMap(footCommentPath, FootComment(texts...))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) addCommentToMap(path string, comment *Comment) {
|
|
|
|
|
for _, c := range d.toCommentMap[path] {
|
|
|
|
|
if c.Position == comment.Position {
|
|
|
|
|
// already added same comment
|
|
|
|
|
return
|
|
|
|
|
}
|
2021-09-07 19:49:15 +09:00
|
|
|
}
|
2023-03-01 16:59:07 +09:00
|
|
|
d.toCommentMap[path] = append(d.toCommentMap[path], comment)
|
|
|
|
|
sort.Slice(d.toCommentMap[path], func(i, j int) bool {
|
|
|
|
|
return d.toCommentMap[path][i].Position < d.toCommentMap[path][j].Position
|
|
|
|
|
})
|
2021-09-07 19:49:15 +09:00
|
|
|
}
|
|
|
|
|
|
2024-11-02 17:40:43 +09:00
|
|
|
func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
|
2021-09-07 19:49:15 +09:00
|
|
|
d.setPathToCommentMap(node)
|
2019-10-18 00:00:58 +09:00
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.NullNode:
|
2024-11-02 17:40:43 +09:00
|
|
|
return nil, nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.StringNode:
|
2024-11-02 17:40:43 +09:00
|
|
|
return n.GetValue(), nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.IntegerNode:
|
2024-11-02 17:40:43 +09:00
|
|
|
return n.GetValue(), nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.FloatNode:
|
2024-11-02 17:40:43 +09:00
|
|
|
return n.GetValue(), nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.BoolNode:
|
2024-11-02 17:40:43 +09:00
|
|
|
return n.GetValue(), nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.InfinityNode:
|
2024-11-02 17:40:43 +09:00
|
|
|
return n.GetValue(), nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.NanNode:
|
2024-11-02 17:40:43 +09:00
|
|
|
return n.GetValue(), nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.TagNode:
|
2020-07-02 17:26:35 +09:00
|
|
|
switch token.ReservedTagKeyword(n.Start.Value) {
|
2019-11-01 14:22:06 +09:00
|
|
|
case token.TimestampTag:
|
|
|
|
|
t, _ := d.castToTime(n.Value)
|
2024-11-02 17:40:43 +09:00
|
|
|
return t, nil
|
2020-07-02 17:26:35 +09:00
|
|
|
case token.IntegerTag:
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
i, _ := strconv.Atoi(fmt.Sprint(v))
|
|
|
|
|
return i, nil
|
2019-10-31 17:38:53 +09:00
|
|
|
case token.FloatTag:
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return d.castToFloat(v), nil
|
2019-10-31 17:38:53 +09:00
|
|
|
case token.NullTag:
|
2024-11-02 17:40:43 +09:00
|
|
|
return nil, nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case token.BinaryTag:
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
b, _ := base64.StdEncoding.DecodeString(v.(string))
|
|
|
|
|
return b, nil
|
2024-11-13 00:40:31 +09:00
|
|
|
case token.BooleanTag:
|
|
|
|
|
v, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
str := strings.ToLower(fmt.Sprint(v))
|
|
|
|
|
b, err := strconv.ParseBool(str)
|
|
|
|
|
if err == nil {
|
|
|
|
|
return b, nil
|
|
|
|
|
}
|
|
|
|
|
switch str {
|
|
|
|
|
case "yes":
|
|
|
|
|
return true, nil
|
|
|
|
|
case "no":
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
return nil, errors.ErrSyntax(fmt.Sprintf("cannot convert %q to boolean", fmt.Sprint(v)), n.Value.GetToken())
|
2020-07-02 17:26:35 +09:00
|
|
|
case token.StringTag:
|
|
|
|
|
return d.nodeToValue(n.Value)
|
|
|
|
|
case token.MappingTag:
|
|
|
|
|
return d.nodeToValue(n.Value)
|
2024-11-13 00:40:31 +09:00
|
|
|
default:
|
|
|
|
|
return d.nodeToValue(n.Value)
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-18 14:27:49 +09:00
|
|
|
case *ast.AnchorNode:
|
|
|
|
|
anchorName := n.Name.GetToken().Value
|
2024-11-02 17:40:43 +09:00
|
|
|
|
|
|
|
|
// To handle the case where alias is processed recursively, the result of alias can be set to nil in advance.
|
|
|
|
|
d.anchorNodeMap[anchorName] = nil
|
|
|
|
|
anchorValue, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
delete(d.anchorNodeMap, anchorName)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-01-09 21:49:52 +09:00
|
|
|
d.anchorNodeMap[anchorName] = n.Value
|
2024-11-02 17:40:43 +09:00
|
|
|
return anchorValue, nil
|
2019-10-18 14:27:49 +09:00
|
|
|
case *ast.AliasNode:
|
2024-10-30 19:25:18 +09:00
|
|
|
if v, exists := d.aliasValueMap[n]; exists {
|
2024-11-02 17:40:43 +09:00
|
|
|
return v, nil
|
2024-10-30 19:25:18 +09:00
|
|
|
}
|
|
|
|
|
// To handle the case where alias is processed recursively, the result of alias can be set to nil in advance.
|
|
|
|
|
d.aliasValueMap[n] = nil
|
|
|
|
|
|
2019-10-18 14:27:49 +09:00
|
|
|
aliasName := n.Value.GetToken().Value
|
2024-11-02 17:40:43 +09:00
|
|
|
node, exists := d.anchorNodeMap[aliasName]
|
|
|
|
|
if !exists {
|
|
|
|
|
return nil, errors.ErrSyntax(fmt.Sprintf("could not find alias %q", aliasName), n.Value.GetToken())
|
|
|
|
|
}
|
|
|
|
|
aliasValue, err := d.nodeToValue(node)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-10-30 19:25:18 +09:00
|
|
|
|
|
|
|
|
// once the correct alias value is obtained, overwrite with that value.
|
|
|
|
|
d.aliasValueMap[n] = aliasValue
|
2024-11-02 17:40:43 +09:00
|
|
|
return aliasValue, nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.LiteralNode:
|
2024-11-02 17:40:43 +09:00
|
|
|
return n.Value.GetValue(), nil
|
2020-07-02 17:26:35 +09:00
|
|
|
case *ast.MappingKeyNode:
|
|
|
|
|
return d.nodeToValue(n.Value)
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.MappingValueNode:
|
2020-06-15 12:14:02 +09:00
|
|
|
if n.Key.Type() == ast.MergeKeyType {
|
|
|
|
|
value := d.mergeValueNode(n.Value)
|
2020-05-29 19:47:47 +09:00
|
|
|
if d.useOrderedMap {
|
|
|
|
|
m := MapSlice{}
|
2024-11-02 17:40:43 +09:00
|
|
|
if err := d.setToOrderedMapValue(value, &m); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return m, nil
|
2020-05-29 19:47:47 +09:00
|
|
|
}
|
2019-12-29 00:06:46 +09:00
|
|
|
m := map[string]interface{}{}
|
2024-11-02 17:40:43 +09:00
|
|
|
if err := d.setToMapValue(value, m); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
key, err := d.mapKeyNodeToString(n.Key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2019-12-29 00:06:46 +09:00
|
|
|
}
|
2020-05-29 19:47:47 +09:00
|
|
|
if d.useOrderedMap {
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return MapSlice{{Key: key, Value: v}}, nil
|
2020-05-29 19:47:47 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2019-10-21 14:54:26 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
return map[string]interface{}{key: v}, nil
|
2019-10-31 12:14:39 +09:00
|
|
|
case *ast.MappingNode:
|
2020-05-29 19:47:47 +09:00
|
|
|
if d.useOrderedMap {
|
|
|
|
|
m := make(MapSlice, 0, len(n.Values))
|
|
|
|
|
for _, value := range n.Values {
|
2024-11-02 17:40:43 +09:00
|
|
|
if err := d.setToOrderedMapValue(value, &m); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-05-29 19:47:47 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
return m, nil
|
2020-05-29 19:47:47 +09:00
|
|
|
}
|
2019-12-29 00:06:46 +09:00
|
|
|
m := make(map[string]interface{}, len(n.Values))
|
2019-10-18 00:00:58 +09:00
|
|
|
for _, value := range n.Values {
|
2024-11-02 17:40:43 +09:00
|
|
|
if err := d.setToMapValue(value, m); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
return m, nil
|
2019-10-18 00:00:58 +09:00
|
|
|
case *ast.SequenceNode:
|
2019-12-29 00:06:46 +09:00
|
|
|
v := make([]interface{}, 0, len(n.Values))
|
2019-10-18 00:00:58 +09:00
|
|
|
for _, value := range n.Values {
|
2024-11-02 17:40:43 +09:00
|
|
|
vv, err := d.nodeToValue(value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
v = append(v, vv)
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
return v, nil
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
return nil, nil
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2022-09-16 12:52:14 +02:00
|
|
|
func (d *Decoder) resolveAlias(node ast.Node) (ast.Node, error) {
|
2020-06-11 19:42:23 +09:00
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.MappingNode:
|
2022-09-16 12:52:14 +02:00
|
|
|
for idx, v := range n.Values {
|
|
|
|
|
value, err := d.resolveAlias(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-10-28 11:31:15 +09:00
|
|
|
n.Values[idx], _ = value.(*ast.MappingValueNode)
|
2020-06-11 19:42:23 +09:00
|
|
|
}
|
2020-07-02 17:26:35 +09:00
|
|
|
case *ast.TagNode:
|
2022-09-16 12:52:14 +02:00
|
|
|
value, err := d.resolveAlias(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
n.Value = value
|
2020-07-02 17:26:35 +09:00
|
|
|
case *ast.MappingKeyNode:
|
2022-09-16 12:52:14 +02:00
|
|
|
value, err := d.resolveAlias(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
n.Value = value
|
2020-06-11 19:42:23 +09:00
|
|
|
case *ast.MappingValueNode:
|
2020-06-11 20:40:27 +09:00
|
|
|
if n.Key.Type() == ast.MergeKeyType && n.Value.Type() == ast.AliasType {
|
2022-09-16 12:52:14 +02:00
|
|
|
value, err := d.resolveAlias(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-06-11 20:40:27 +09:00
|
|
|
keyColumn := n.Key.GetToken().Position.Column
|
|
|
|
|
requiredColumn := keyColumn + 2
|
2020-06-11 20:58:37 +09:00
|
|
|
value.AddColumn(requiredColumn)
|
2020-06-11 20:40:27 +09:00
|
|
|
n.Value = value
|
|
|
|
|
} else {
|
2022-09-16 12:52:14 +02:00
|
|
|
key, err := d.resolveAlias(n.Key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-10-28 11:31:15 +09:00
|
|
|
n.Key, _ = key.(ast.MapKeyNode)
|
2022-09-16 12:52:14 +02:00
|
|
|
value, err := d.resolveAlias(n.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
n.Value = value
|
2020-06-11 20:40:27 +09:00
|
|
|
}
|
2020-06-11 19:42:23 +09:00
|
|
|
case *ast.SequenceNode:
|
2022-09-16 12:52:14 +02:00
|
|
|
for idx, v := range n.Values {
|
|
|
|
|
value, err := d.resolveAlias(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
n.Values[idx] = value
|
2020-06-11 19:42:23 +09:00
|
|
|
}
|
|
|
|
|
case *ast.AliasNode:
|
|
|
|
|
aliasName := n.Value.GetToken().Value
|
2022-09-16 12:52:14 +02:00
|
|
|
node := d.anchorNodeMap[aliasName]
|
|
|
|
|
if node == nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, fmt.Errorf("cannot find anchor by alias name %s", aliasName)
|
2022-09-16 12:52:14 +02:00
|
|
|
}
|
|
|
|
|
return d.resolveAlias(node)
|
2020-06-11 19:42:23 +09:00
|
|
|
}
|
2022-09-16 12:52:14 +02:00
|
|
|
return node, nil
|
2020-06-11 19:42:23 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-24 23:54:17 +09:00
|
|
|
func (d *Decoder) getMapNode(node ast.Node) (ast.MapNode, error) {
|
2019-11-01 12:42:41 +09:00
|
|
|
if _, ok := node.(*ast.NullNode); ok {
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
if anchor, ok := node.(*ast.AnchorNode); ok {
|
|
|
|
|
mapNode, ok := anchor.Value.(ast.MapNode)
|
|
|
|
|
if ok {
|
|
|
|
|
return mapNode, nil
|
|
|
|
|
}
|
2024-11-14 16:01:08 +09:00
|
|
|
return nil, errors.ErrUnexpectedNodeType(anchor.Value.Type(), ast.MappingType, node.GetToken())
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
if alias, ok := node.(*ast.AliasNode); ok {
|
|
|
|
|
aliasName := alias.Value.GetToken().Value
|
2020-01-09 21:49:52 +09:00
|
|
|
node := d.anchorNodeMap[aliasName]
|
|
|
|
|
if node == nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, fmt.Errorf("cannot find anchor by alias name %s", aliasName)
|
2020-01-09 21:49:52 +09:00
|
|
|
}
|
|
|
|
|
mapNode, ok := node.(ast.MapNode)
|
2019-10-24 23:54:17 +09:00
|
|
|
if ok {
|
|
|
|
|
return mapNode, nil
|
|
|
|
|
}
|
2024-11-14 16:01:08 +09:00
|
|
|
return nil, errors.ErrUnexpectedNodeType(node.Type(), ast.MappingType, node.GetToken())
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
mapNode, ok := node.(ast.MapNode)
|
|
|
|
|
if !ok {
|
2024-11-14 16:01:08 +09:00
|
|
|
return nil, errors.ErrUnexpectedNodeType(node.Type(), ast.MappingType, node.GetToken())
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
return mapNode, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) getArrayNode(node ast.Node) (ast.ArrayNode, error) {
|
2019-11-01 12:42:41 +09:00
|
|
|
if _, ok := node.(*ast.NullNode); ok {
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
if anchor, ok := node.(*ast.AnchorNode); ok {
|
|
|
|
|
arrayNode, ok := anchor.Value.(ast.ArrayNode)
|
|
|
|
|
if ok {
|
|
|
|
|
return arrayNode, nil
|
|
|
|
|
}
|
2021-06-25 12:34:27 -04:00
|
|
|
|
2024-11-14 16:01:08 +09:00
|
|
|
return nil, errors.ErrUnexpectedNodeType(anchor.Value.Type(), ast.SequenceType, node.GetToken())
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
if alias, ok := node.(*ast.AliasNode); ok {
|
|
|
|
|
aliasName := alias.Value.GetToken().Value
|
2020-01-09 21:49:52 +09:00
|
|
|
node := d.anchorNodeMap[aliasName]
|
|
|
|
|
if node == nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, fmt.Errorf("cannot find anchor by alias name %s", aliasName)
|
2020-01-09 21:49:52 +09:00
|
|
|
}
|
|
|
|
|
arrayNode, ok := node.(ast.ArrayNode)
|
2019-10-24 23:54:17 +09:00
|
|
|
if ok {
|
|
|
|
|
return arrayNode, nil
|
|
|
|
|
}
|
2024-11-14 16:01:08 +09:00
|
|
|
return nil, errors.ErrUnexpectedNodeType(node.Type(), ast.SequenceType, node.GetToken())
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
arrayNode, ok := node.(ast.ArrayNode)
|
|
|
|
|
if !ok {
|
2024-11-14 16:01:08 +09:00
|
|
|
return nil, errors.ErrUnexpectedNodeType(node.Type(), ast.SequenceType, node.GetToken())
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
return arrayNode, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-09 23:06:32 +00:00
|
|
|
func (d *Decoder) convertValue(v reflect.Value, typ reflect.Type, src ast.Node) (reflect.Value, error) {
|
2019-10-29 16:23:26 +09:00
|
|
|
if typ.Kind() != reflect.String {
|
2019-12-10 14:33:08 +09:00
|
|
|
if !v.Type().ConvertibleTo(typ) {
|
2024-07-16 11:38:06 +01:00
|
|
|
|
|
|
|
|
// Special case for "strings -> floats" aka scientific notation
|
|
|
|
|
// If the destination type is a float and the source type is a string, check if we can
|
|
|
|
|
// use strconv.ParseFloat to convert the string to a float.
|
|
|
|
|
if (typ.Kind() == reflect.Float32 || typ.Kind() == reflect.Float64) &&
|
|
|
|
|
v.Type().Kind() == reflect.String {
|
|
|
|
|
if f, err := strconv.ParseFloat(v.String(), 64); err == nil {
|
|
|
|
|
if typ.Kind() == reflect.Float32 {
|
|
|
|
|
return reflect.ValueOf(float32(f)), nil
|
|
|
|
|
} else if typ.Kind() == reflect.Float64 {
|
|
|
|
|
return reflect.ValueOf(f), nil
|
|
|
|
|
}
|
|
|
|
|
// else, fall through to the error below
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-14 16:01:08 +09:00
|
|
|
return reflect.Zero(typ), errors.ErrTypeMismatch(typ, v.Type(), src.GetToken())
|
2019-12-10 14:33:08 +09:00
|
|
|
}
|
|
|
|
|
return v.Convert(typ), nil
|
2019-10-29 16:23:26 +09:00
|
|
|
}
|
|
|
|
|
// cast value to string
|
|
|
|
|
switch v.Type().Kind() {
|
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
2019-12-10 14:33:08 +09:00
|
|
|
return reflect.ValueOf(fmt.Sprint(v.Int())), nil
|
2019-10-29 16:23:26 +09:00
|
|
|
case reflect.Float32, reflect.Float64:
|
2019-12-10 14:33:08 +09:00
|
|
|
return reflect.ValueOf(fmt.Sprint(v.Float())), nil
|
2019-10-29 16:23:26 +09:00
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
2019-12-10 14:33:08 +09:00
|
|
|
return reflect.ValueOf(fmt.Sprint(v.Uint())), nil
|
2019-10-29 16:23:26 +09:00
|
|
|
case reflect.Bool:
|
2019-12-10 14:33:08 +09:00
|
|
|
return reflect.ValueOf(fmt.Sprint(v.Bool())), nil
|
|
|
|
|
}
|
|
|
|
|
if !v.Type().ConvertibleTo(typ) {
|
2024-11-14 16:01:08 +09:00
|
|
|
return reflect.Zero(typ), errors.ErrTypeMismatch(typ, v.Type(), src.GetToken())
|
2019-10-29 16:23:26 +09:00
|
|
|
}
|
2019-12-10 14:33:08 +09:00
|
|
|
return v.Convert(typ), nil
|
2019-10-29 16:23:26 +09:00
|
|
|
}
|
|
|
|
|
|
2020-06-09 10:36:35 +09:00
|
|
|
func (d *Decoder) deleteStructKeys(structType reflect.Type, unknownFields map[string]ast.Node) error {
|
2020-06-08 23:06:16 +09:00
|
|
|
if structType.Kind() == reflect.Ptr {
|
|
|
|
|
structType = structType.Elem()
|
|
|
|
|
}
|
|
|
|
|
structFieldMap, err := structFieldMap(structType)
|
2019-12-13 15:00:04 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-12-13 15:00:04 +09:00
|
|
|
}
|
|
|
|
|
|
2020-06-08 23:06:16 +09:00
|
|
|
for j := 0; j < structType.NumField(); j++ {
|
|
|
|
|
field := structType.Field(j)
|
2019-12-13 15:00:04 +09:00
|
|
|
if isIgnoredStructField(field) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-03 13:26:05 +03:00
|
|
|
structField, exists := structFieldMap[field.Name]
|
|
|
|
|
if !exists {
|
2019-12-16 23:30:53 +09:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if structField.IsInline {
|
2024-10-28 11:31:15 +09:00
|
|
|
_ = d.deleteStructKeys(field.Type, unknownFields)
|
2019-12-16 23:30:53 +09:00
|
|
|
} else {
|
2019-12-13 15:00:04 +09:00
|
|
|
delete(unknownFields, structField.RenderName)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-16 22:37:59 +09:00
|
|
|
func (d *Decoder) lastNode(node ast.Node) ast.Node {
|
|
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.MappingNode:
|
|
|
|
|
if len(n.Values) > 0 {
|
|
|
|
|
return d.lastNode(n.Values[len(n.Values)-1])
|
|
|
|
|
}
|
|
|
|
|
case *ast.MappingValueNode:
|
|
|
|
|
return d.lastNode(n.Value)
|
|
|
|
|
case *ast.SequenceNode:
|
|
|
|
|
if len(n.Values) > 0 {
|
|
|
|
|
return d.lastNode(n.Values[len(n.Values)-1])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return node
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-16 12:52:14 +02:00
|
|
|
func (d *Decoder) unmarshalableDocument(node ast.Node) ([]byte, error) {
|
|
|
|
|
var err error
|
|
|
|
|
node, err = d.resolveAlias(node)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-06-23 12:39:50 +09:00
|
|
|
doc := node.String()
|
|
|
|
|
last := d.lastNode(node)
|
|
|
|
|
if last != nil && last.Type() == ast.LiteralType {
|
|
|
|
|
doc += "\n"
|
|
|
|
|
}
|
2022-09-16 12:52:14 +02:00
|
|
|
return []byte(doc), nil
|
2020-06-23 12:39:50 +09:00
|
|
|
}
|
|
|
|
|
|
2022-09-16 12:52:14 +02:00
|
|
|
func (d *Decoder) unmarshalableText(node ast.Node) ([]byte, bool, error) {
|
|
|
|
|
var err error
|
|
|
|
|
node, err = d.resolveAlias(node)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, false, err
|
|
|
|
|
}
|
2020-06-23 12:39:50 +09:00
|
|
|
if node.Type() == ast.AnchorType {
|
|
|
|
|
node = node.(*ast.AnchorNode).Value
|
|
|
|
|
}
|
|
|
|
|
switch n := node.(type) {
|
|
|
|
|
case *ast.StringNode:
|
2022-09-16 12:52:14 +02:00
|
|
|
return []byte(n.Value), true, nil
|
2020-06-23 12:39:50 +09:00
|
|
|
case *ast.LiteralNode:
|
2022-09-16 12:52:14 +02:00
|
|
|
return []byte(n.Value.GetToken().Value), true, nil
|
2020-06-23 12:39:50 +09:00
|
|
|
default:
|
|
|
|
|
scalar, ok := n.(ast.ScalarNode)
|
|
|
|
|
if ok {
|
2022-09-16 12:52:14 +02:00
|
|
|
return []byte(fmt.Sprint(scalar.GetValue())), true, nil
|
2020-06-23 12:39:50 +09:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 12:52:14 +02:00
|
|
|
return nil, false, nil
|
2020-06-23 12:39:50 +09:00
|
|
|
}
|
|
|
|
|
|
2020-10-26 19:00:49 +09:00
|
|
|
type jsonUnmarshaler interface {
|
|
|
|
|
UnmarshalJSON([]byte) error
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-02 10:50:03 +09:00
|
|
|
func (d *Decoder) existsTypeInCustomUnmarshalerMap(t reflect.Type) bool {
|
|
|
|
|
if _, exists := d.customUnmarshalerMap[t]; exists {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
globalCustomUnmarshalerMu.Lock()
|
|
|
|
|
defer globalCustomUnmarshalerMu.Unlock()
|
|
|
|
|
if _, exists := globalCustomUnmarshalerMap[t]; exists {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) unmarshalerFromCustomUnmarshalerMap(t reflect.Type) (func(interface{}, []byte) error, bool) {
|
|
|
|
|
if unmarshaler, exists := d.customUnmarshalerMap[t]; exists {
|
|
|
|
|
return unmarshaler, exists
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
globalCustomUnmarshalerMu.Lock()
|
|
|
|
|
defer globalCustomUnmarshalerMu.Unlock()
|
|
|
|
|
if unmarshaler, exists := globalCustomUnmarshalerMap[t]; exists {
|
|
|
|
|
return unmarshaler, exists
|
|
|
|
|
}
|
|
|
|
|
return nil, false
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) canDecodeByUnmarshaler(dst reflect.Value) bool {
|
2023-04-02 10:50:03 +09:00
|
|
|
ptrValue := dst.Addr()
|
|
|
|
|
if d.existsTypeInCustomUnmarshalerMap(ptrValue.Type()) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
iface := ptrValue.Interface()
|
2020-11-11 19:27:58 +09:00
|
|
|
switch iface.(type) {
|
|
|
|
|
case BytesUnmarshalerContext:
|
|
|
|
|
return true
|
|
|
|
|
case BytesUnmarshaler:
|
|
|
|
|
return true
|
|
|
|
|
case InterfaceUnmarshalerContext:
|
|
|
|
|
return true
|
|
|
|
|
case InterfaceUnmarshaler:
|
|
|
|
|
return true
|
|
|
|
|
case *time.Time:
|
|
|
|
|
return true
|
2021-08-11 15:02:20 -04:00
|
|
|
case *time.Duration:
|
|
|
|
|
return true
|
2020-11-11 19:27:58 +09:00
|
|
|
case encoding.TextUnmarshaler:
|
|
|
|
|
return true
|
|
|
|
|
case jsonUnmarshaler:
|
|
|
|
|
return d.useJSONUnmarshaler
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) decodeByUnmarshaler(ctx context.Context, dst reflect.Value, src ast.Node) error {
|
2023-04-02 10:50:03 +09:00
|
|
|
ptrValue := dst.Addr()
|
|
|
|
|
if unmarshaler, exists := d.unmarshalerFromCustomUnmarshalerMap(ptrValue.Type()); exists {
|
|
|
|
|
b, err := d.unmarshalableDocument(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2023-04-02 10:50:03 +09:00
|
|
|
}
|
|
|
|
|
if err := unmarshaler(ptrValue.Interface(), b); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2023-04-02 10:50:03 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
iface := ptrValue.Interface()
|
2020-11-11 19:27:58 +09:00
|
|
|
|
|
|
|
|
if unmarshaler, ok := iface.(BytesUnmarshalerContext); ok {
|
2022-09-16 12:52:14 +02:00
|
|
|
b, err := d.unmarshalableDocument(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2022-09-16 12:52:14 +02:00
|
|
|
}
|
|
|
|
|
if err := unmarshaler.UnmarshalYAML(ctx, b); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-03-02 22:51:53 +09:00
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
return nil
|
2020-01-09 21:49:52 +09:00
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
|
|
|
|
|
if unmarshaler, ok := iface.(BytesUnmarshaler); ok {
|
2022-09-16 12:52:14 +02:00
|
|
|
b, err := d.unmarshalableDocument(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2022-09-16 12:52:14 +02:00
|
|
|
}
|
|
|
|
|
if err := unmarshaler.UnmarshalYAML(b); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
2020-11-11 19:27:58 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if unmarshaler, ok := iface.(InterfaceUnmarshalerContext); ok {
|
|
|
|
|
if err := unmarshaler.UnmarshalYAML(ctx, func(v interface{}) error {
|
|
|
|
|
rv := reflect.ValueOf(v)
|
|
|
|
|
if rv.Type().Kind() != reflect.Ptr {
|
2024-10-28 21:24:15 +09:00
|
|
|
return ErrDecodeRequiredPointerType
|
2020-11-11 19:27:58 +09:00
|
|
|
}
|
|
|
|
|
if err := d.decodeValue(ctx, rv.Elem(), src); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-11-11 19:27:58 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-11-11 19:27:58 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if unmarshaler, ok := iface.(InterfaceUnmarshaler); ok {
|
2019-10-24 17:18:03 +09:00
|
|
|
if err := unmarshaler.UnmarshalYAML(func(v interface{}) error {
|
|
|
|
|
rv := reflect.ValueOf(v)
|
|
|
|
|
if rv.Type().Kind() != reflect.Ptr {
|
2024-10-28 21:24:15 +09:00
|
|
|
return ErrDecodeRequiredPointerType
|
2019-10-24 17:18:03 +09:00
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
if err := d.decodeValue(ctx, rv.Elem(), src); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-24 17:18:03 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-24 17:18:03 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
2020-11-11 19:27:58 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, ok := iface.(*time.Time); ok {
|
|
|
|
|
return d.decodeTime(ctx, dst, src)
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-11 15:02:20 -04:00
|
|
|
if _, ok := iface.(*time.Duration); ok {
|
|
|
|
|
return d.decodeDuration(ctx, dst, src)
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
if unmarshaler, isText := iface.(encoding.TextUnmarshaler); isText {
|
2022-09-16 12:52:14 +02:00
|
|
|
b, ok, err := d.unmarshalableText(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2022-09-16 12:52:14 +02:00
|
|
|
}
|
2020-06-23 12:39:50 +09:00
|
|
|
if ok {
|
|
|
|
|
if err := unmarshaler.UnmarshalText(b); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-06-23 12:39:50 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
2020-01-12 02:50:51 +09:00
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if d.useJSONUnmarshaler {
|
|
|
|
|
if unmarshaler, ok := iface.(jsonUnmarshaler); ok {
|
2022-09-16 12:52:14 +02:00
|
|
|
b, err := d.unmarshalableDocument(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2022-09-16 12:52:14 +02:00
|
|
|
}
|
|
|
|
|
jsonBytes, err := YAMLToJSON(b)
|
2020-10-26 19:00:49 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-10-26 19:00:49 +09:00
|
|
|
}
|
|
|
|
|
jsonBytes = bytes.TrimRight(jsonBytes, "\n")
|
|
|
|
|
if err := unmarshaler.UnmarshalJSON(jsonBytes); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-10-26 19:00:49 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
|
2024-10-28 21:24:15 +09:00
|
|
|
return fmt.Errorf("does not implemented Unmarshaler")
|
2020-11-11 19:27:58 +09:00
|
|
|
}
|
|
|
|
|
|
2021-03-01 13:47:31 +09:00
|
|
|
var (
|
|
|
|
|
astNodeType = reflect.TypeOf((*ast.Node)(nil)).Elem()
|
|
|
|
|
)
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.Node) error {
|
|
|
|
|
if src.Type() == ast.AnchorType {
|
|
|
|
|
anchorName := src.(*ast.AnchorNode).Name.GetToken().Value
|
|
|
|
|
if _, exists := d.anchorValueMap[anchorName]; !exists {
|
|
|
|
|
d.anchorValueMap[anchorName] = dst
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if d.canDecodeByUnmarshaler(dst) {
|
|
|
|
|
if err := d.decodeByUnmarshaler(ctx, dst, src); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-11-11 19:27:58 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
valueType := dst.Type()
|
2019-10-18 00:00:58 +09:00
|
|
|
switch valueType.Kind() {
|
|
|
|
|
case reflect.Ptr:
|
2019-10-24 17:18:03 +09:00
|
|
|
if dst.IsNil() {
|
|
|
|
|
return nil
|
2019-10-21 14:54:26 +09:00
|
|
|
}
|
2019-10-30 16:57:59 +09:00
|
|
|
if src.Type() == ast.NullType {
|
|
|
|
|
// set nil value to pointer
|
|
|
|
|
dst.Set(reflect.Zero(valueType))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
v := d.createDecodableValue(dst.Type())
|
2020-11-11 19:27:58 +09:00
|
|
|
if err := d.decodeValue(ctx, v, src); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-24 17:18:03 +09:00
|
|
|
}
|
|
|
|
|
dst.Set(d.castToAssignableValue(v, dst.Type()))
|
2019-10-18 00:00:58 +09:00
|
|
|
case reflect.Interface:
|
2021-03-01 13:47:31 +09:00
|
|
|
if dst.Type() == astNodeType {
|
|
|
|
|
dst.Set(reflect.ValueOf(src))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
srcVal, err := d.nodeToValue(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
v := reflect.ValueOf(srcVal)
|
2019-10-24 17:18:03 +09:00
|
|
|
if v.IsValid() {
|
|
|
|
|
dst.Set(v)
|
|
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
case reflect.Map:
|
2020-11-11 19:27:58 +09:00
|
|
|
return d.decodeMap(ctx, dst, src)
|
2019-11-01 12:43:57 +09:00
|
|
|
case reflect.Array:
|
2020-11-11 19:27:58 +09:00
|
|
|
return d.decodeArray(ctx, dst, src)
|
2019-11-01 12:43:57 +09:00
|
|
|
case reflect.Slice:
|
2020-05-28 17:30:19 +09:00
|
|
|
if mapSlice, ok := dst.Addr().Interface().(*MapSlice); ok {
|
2020-11-11 19:27:58 +09:00
|
|
|
return d.decodeMapSlice(ctx, mapSlice, src)
|
2020-05-28 17:30:19 +09:00
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
return d.decodeSlice(ctx, dst, src)
|
2019-10-18 00:00:58 +09:00
|
|
|
case reflect.Struct:
|
2020-05-28 17:30:19 +09:00
|
|
|
if mapItem, ok := dst.Addr().Interface().(*MapItem); ok {
|
2020-11-11 19:27:58 +09:00
|
|
|
return d.decodeMapItem(ctx, mapItem, src)
|
2020-05-28 17:30:19 +09:00
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
return d.decodeStruct(ctx, dst, src)
|
2019-10-29 19:46:55 +09:00
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2019-10-29 19:46:55 +09:00
|
|
|
switch vv := v.(type) {
|
|
|
|
|
case int64:
|
|
|
|
|
if !dst.OverflowInt(vv) {
|
|
|
|
|
dst.SetInt(vv)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-29 20:15:27 +09:00
|
|
|
case uint64:
|
|
|
|
|
if vv <= math.MaxInt64 && !dst.OverflowInt(int64(vv)) {
|
|
|
|
|
dst.SetInt(int64(vv))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-29 19:46:55 +09:00
|
|
|
case float64:
|
|
|
|
|
if vv <= math.MaxInt64 && !dst.OverflowInt(int64(vv)) {
|
|
|
|
|
dst.SetInt(int64(vv))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2024-07-16 11:38:06 +01:00
|
|
|
case string: // handle scientific notation
|
|
|
|
|
if i, err := strconv.ParseFloat(vv, 64); err == nil {
|
|
|
|
|
if 0 <= i && i <= math.MaxUint64 && !dst.OverflowInt(int64(i)) {
|
|
|
|
|
dst.SetInt(int64(i))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
} else { // couldn't be parsed as float
|
2024-11-14 16:01:08 +09:00
|
|
|
return errors.ErrTypeMismatch(valueType, reflect.TypeOf(v), src.GetToken())
|
2024-07-16 11:38:06 +01:00
|
|
|
}
|
2019-11-01 12:43:36 +09:00
|
|
|
default:
|
2024-11-14 16:01:08 +09:00
|
|
|
return errors.ErrTypeMismatch(valueType, reflect.TypeOf(v), src.GetToken())
|
2019-10-29 19:46:55 +09:00
|
|
|
}
|
2024-10-28 07:04:03 +00:00
|
|
|
return errors.ErrOverflow(valueType, fmt.Sprint(v), src.GetToken())
|
2019-10-29 19:46:55 +09:00
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2019-10-29 19:46:55 +09:00
|
|
|
switch vv := v.(type) {
|
|
|
|
|
case int64:
|
2019-10-29 20:15:27 +09:00
|
|
|
if 0 <= vv && !dst.OverflowUint(uint64(vv)) {
|
2019-10-29 19:46:55 +09:00
|
|
|
dst.SetUint(uint64(vv))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-29 20:15:27 +09:00
|
|
|
case uint64:
|
|
|
|
|
if !dst.OverflowUint(vv) {
|
|
|
|
|
dst.SetUint(vv)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-29 19:46:55 +09:00
|
|
|
case float64:
|
|
|
|
|
if 0 <= vv && vv <= math.MaxUint64 && !dst.OverflowUint(uint64(vv)) {
|
|
|
|
|
dst.SetUint(uint64(vv))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2024-07-16 11:38:06 +01:00
|
|
|
case string: // handle scientific notation
|
|
|
|
|
if i, err := strconv.ParseFloat(vv, 64); err == nil {
|
|
|
|
|
if 0 <= i && i <= math.MaxUint64 && !dst.OverflowUint(uint64(i)) {
|
|
|
|
|
dst.SetUint(uint64(i))
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
} else { // couldn't be parsed as float
|
2024-11-14 16:01:08 +09:00
|
|
|
return errors.ErrTypeMismatch(valueType, reflect.TypeOf(v), src.GetToken())
|
2024-07-16 11:38:06 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-01 12:43:36 +09:00
|
|
|
default:
|
2024-11-14 16:01:08 +09:00
|
|
|
return errors.ErrTypeMismatch(valueType, reflect.TypeOf(v), src.GetToken())
|
2019-10-29 19:46:55 +09:00
|
|
|
}
|
2024-10-28 07:04:03 +00:00
|
|
|
return errors.ErrOverflow(valueType, fmt.Sprint(v), src.GetToken())
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
srcVal, err := d.nodeToValue(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
v := reflect.ValueOf(srcVal)
|
2019-10-24 17:18:03 +09:00
|
|
|
if v.IsValid() {
|
2022-02-09 23:06:32 +00:00
|
|
|
convertedValue, err := d.convertValue(v, dst.Type(), src)
|
2019-12-10 14:33:08 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-12-10 14:33:08 +09:00
|
|
|
}
|
|
|
|
|
dst.Set(convertedValue)
|
2019-10-24 17:18:03 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-24 17:18:03 +09:00
|
|
|
func (d *Decoder) createDecodableValue(typ reflect.Type) reflect.Value {
|
|
|
|
|
for {
|
|
|
|
|
if typ.Kind() == reflect.Ptr {
|
|
|
|
|
typ = typ.Elem()
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
return reflect.New(typ).Elem()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) castToAssignableValue(value reflect.Value, target reflect.Type) reflect.Value {
|
|
|
|
|
if target.Kind() != reflect.Ptr {
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
maxTryCount := 5
|
|
|
|
|
tryCount := 0
|
|
|
|
|
for {
|
|
|
|
|
if tryCount > maxTryCount {
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
if value.Type().AssignableTo(target) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
value = value.Addr()
|
|
|
|
|
tryCount++
|
|
|
|
|
}
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-15 15:11:46 +02:00
|
|
|
func (d *Decoder) createDecodedNewValue(
|
|
|
|
|
ctx context.Context, typ reflect.Type, defaultVal reflect.Value, node ast.Node,
|
|
|
|
|
) (reflect.Value, error) {
|
2020-01-09 21:49:52 +09:00
|
|
|
if node.Type() == ast.AliasType {
|
|
|
|
|
aliasName := node.(*ast.AliasNode).Value.GetToken().Value
|
|
|
|
|
newValue := d.anchorValueMap[aliasName]
|
|
|
|
|
if newValue.IsValid() {
|
|
|
|
|
return newValue, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-30 10:06:24 +02:00
|
|
|
var newValue reflect.Value
|
2020-02-22 11:43:45 +09:00
|
|
|
if node.Type() == ast.NullType {
|
2024-07-30 10:06:24 +02:00
|
|
|
newValue = reflect.New(typ).Elem()
|
|
|
|
|
} else {
|
|
|
|
|
newValue = d.createDecodableValue(typ)
|
2020-02-22 11:43:45 +09:00
|
|
|
}
|
2021-10-15 15:11:46 +02:00
|
|
|
for defaultVal.Kind() == reflect.Ptr {
|
|
|
|
|
defaultVal = defaultVal.Elem()
|
|
|
|
|
}
|
|
|
|
|
if defaultVal.IsValid() && defaultVal.Type().AssignableTo(newValue.Type()) {
|
|
|
|
|
newValue.Set(defaultVal)
|
|
|
|
|
}
|
2024-07-30 10:06:24 +02:00
|
|
|
if node.Type() != ast.NullType {
|
|
|
|
|
if err := d.decodeValue(ctx, newValue, node); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return newValue, err
|
2024-07-30 10:06:24 +02:00
|
|
|
}
|
2020-01-09 21:49:52 +09:00
|
|
|
}
|
|
|
|
|
return newValue, nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-02 22:53:33 +09:00
|
|
|
func (d *Decoder) keyToNodeMap(node ast.Node, ignoreMergeKey bool, getKeyOrValueNode func(*ast.MapNodeIter) ast.Node) (map[string]ast.Node, error) {
|
2019-10-24 23:54:17 +09:00
|
|
|
mapNode, err := d.getMapNode(node)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
2020-06-08 23:34:34 +09:00
|
|
|
keyMap := map[string]struct{}{}
|
2019-10-24 23:54:17 +09:00
|
|
|
keyToNodeMap := map[string]ast.Node{}
|
2019-11-01 12:42:41 +09:00
|
|
|
if mapNode == nil {
|
|
|
|
|
return keyToNodeMap, nil
|
|
|
|
|
}
|
|
|
|
|
mapIter := mapNode.MapRange()
|
2019-10-24 23:54:17 +09:00
|
|
|
for mapIter.Next() {
|
|
|
|
|
keyNode := mapIter.Key()
|
|
|
|
|
if keyNode.Type() == ast.MergeKeyType {
|
2020-03-02 22:53:33 +09:00
|
|
|
if ignoreMergeKey {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
mergeMap, err := d.keyToNodeMap(mapIter.Value(), ignoreMergeKey, getKeyOrValueNode)
|
2019-10-24 23:54:17 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
for k, v := range mergeMap {
|
2020-06-08 23:34:34 +09:00
|
|
|
if err := d.validateDuplicateKey(keyMap, k, v); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2020-06-08 23:34:34 +09:00
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
keyToNodeMap[k] = v
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2024-11-02 17:40:43 +09:00
|
|
|
keyVal, err := d.nodeToValue(keyNode)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
key, ok := keyVal.(string)
|
2019-10-24 23:54:17 +09:00
|
|
|
if !ok {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
2020-06-08 23:34:34 +09:00
|
|
|
if err := d.validateDuplicateKey(keyMap, key, keyNode); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2020-06-08 23:34:34 +09:00
|
|
|
}
|
2019-12-11 15:42:22 +09:00
|
|
|
keyToNodeMap[key] = getKeyOrValueNode(mapIter)
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return keyToNodeMap, nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-02 22:53:33 +09:00
|
|
|
func (d *Decoder) keyToKeyNodeMap(node ast.Node, ignoreMergeKey bool) (map[string]ast.Node, error) {
|
|
|
|
|
m, err := d.keyToNodeMap(node, ignoreMergeKey, func(nodeMap *ast.MapNodeIter) ast.Node { return nodeMap.Key() })
|
2019-12-11 11:27:43 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-12-11 11:27:43 +09:00
|
|
|
}
|
|
|
|
|
return m, nil
|
2019-12-11 10:38:21 +09:00
|
|
|
}
|
|
|
|
|
|
2020-03-02 22:53:33 +09:00
|
|
|
func (d *Decoder) keyToValueNodeMap(node ast.Node, ignoreMergeKey bool) (map[string]ast.Node, error) {
|
|
|
|
|
m, err := d.keyToNodeMap(node, ignoreMergeKey, func(nodeMap *ast.MapNodeIter) ast.Node { return nodeMap.Value() })
|
2019-12-11 11:27:43 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-12-11 11:27:43 +09:00
|
|
|
}
|
|
|
|
|
return m, nil
|
2019-12-11 10:38:21 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-28 22:44:21 +09:00
|
|
|
func (d *Decoder) setDefaultValueIfConflicted(v reflect.Value, fieldMap StructFieldMap) error {
|
|
|
|
|
typ := v.Type()
|
|
|
|
|
if typ.Kind() != reflect.Struct {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
embeddedStructFieldMap, err := structFieldMap(typ)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-28 22:44:21 +09:00
|
|
|
}
|
|
|
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
|
|
|
field := typ.Field(i)
|
2019-11-06 19:44:18 +09:00
|
|
|
if isIgnoredStructField(field) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2019-10-28 22:44:21 +09:00
|
|
|
structField := embeddedStructFieldMap[field.Name]
|
|
|
|
|
if !fieldMap.isIncludedRenderName(structField.RenderName) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// if declared same key name, set default value
|
|
|
|
|
fieldValue := v.Field(i)
|
|
|
|
|
if fieldValue.CanSet() {
|
|
|
|
|
fieldValue.Set(reflect.Zero(fieldValue.Type()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-01 14:09:33 +09:00
|
|
|
// This is a subset of the formats allowed by the regular expression
|
|
|
|
|
// defined at http://yaml.org/type/timestamp.html.
|
|
|
|
|
var allowedTimestampFormats = []string{
|
|
|
|
|
"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
|
|
|
|
|
"2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
|
|
|
|
|
"2006-1-2 15:4:5.999999999", // space separated with no time zone
|
|
|
|
|
"2006-1-2", // date only
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-01 14:22:06 +09:00
|
|
|
func (d *Decoder) castToTime(src ast.Node) (time.Time, error) {
|
2019-11-01 14:09:33 +09:00
|
|
|
if src == nil {
|
2019-11-01 14:22:06 +09:00
|
|
|
return time.Time{}, nil
|
2019-11-01 14:09:33 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return time.Time{}, err
|
|
|
|
|
}
|
2019-11-01 14:22:06 +09:00
|
|
|
if t, ok := v.(time.Time); ok {
|
|
|
|
|
return t, nil
|
|
|
|
|
}
|
2019-11-01 14:09:33 +09:00
|
|
|
s, ok := v.(string)
|
|
|
|
|
if !ok {
|
2024-11-14 16:01:08 +09:00
|
|
|
return time.Time{}, errors.ErrTypeMismatch(reflect.TypeOf(time.Time{}), reflect.TypeOf(v), src.GetToken())
|
2019-11-01 14:09:33 +09:00
|
|
|
}
|
|
|
|
|
for _, format := range allowedTimestampFormats {
|
|
|
|
|
t, err := time.Parse(format, s)
|
|
|
|
|
if err != nil {
|
|
|
|
|
// invalid format
|
|
|
|
|
continue
|
|
|
|
|
}
|
2019-11-01 14:22:06 +09:00
|
|
|
return t, nil
|
|
|
|
|
}
|
|
|
|
|
return time.Time{}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decodeTime(ctx context.Context, dst reflect.Value, src ast.Node) error {
|
2019-11-01 14:22:06 +09:00
|
|
|
t, err := d.castToTime(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-11-01 14:09:33 +09:00
|
|
|
}
|
2019-11-01 14:22:06 +09:00
|
|
|
dst.Set(reflect.ValueOf(t))
|
2021-08-11 15:02:20 -04:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) castToDuration(src ast.Node) (time.Duration, error) {
|
|
|
|
|
if src == nil {
|
|
|
|
|
return 0, nil
|
|
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
2021-08-11 15:02:20 -04:00
|
|
|
if t, ok := v.(time.Duration); ok {
|
|
|
|
|
return t, nil
|
|
|
|
|
}
|
|
|
|
|
s, ok := v.(string)
|
|
|
|
|
if !ok {
|
2024-11-14 16:01:08 +09:00
|
|
|
return 0, errors.ErrTypeMismatch(reflect.TypeOf(time.Duration(0)), reflect.TypeOf(v), src.GetToken())
|
2021-08-11 15:02:20 -04:00
|
|
|
}
|
|
|
|
|
t, err := time.ParseDuration(s)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return 0, err
|
2021-08-11 15:02:20 -04:00
|
|
|
}
|
|
|
|
|
return t, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) decodeDuration(ctx context.Context, dst reflect.Value, src ast.Node) error {
|
|
|
|
|
t, err := d.castToDuration(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2021-08-11 15:02:20 -04:00
|
|
|
}
|
|
|
|
|
dst.Set(reflect.ValueOf(t))
|
2019-11-01 14:09:33 +09:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-02 22:55:57 +09:00
|
|
|
// getMergeAliasName support single alias only
|
|
|
|
|
func (d *Decoder) getMergeAliasName(src ast.Node) string {
|
|
|
|
|
mapNode, err := d.getMapNode(src)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
if mapNode == nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
mapIter := mapNode.MapRange()
|
|
|
|
|
for mapIter.Next() {
|
|
|
|
|
key := mapIter.Key()
|
|
|
|
|
value := mapIter.Value()
|
|
|
|
|
if key.Type() == ast.MergeKeyType && value.Type() == ast.AliasType {
|
|
|
|
|
return value.(*ast.AliasNode).Value.GetToken().Value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.Node) error {
|
2019-10-24 17:18:03 +09:00
|
|
|
if src == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
structType := dst.Type()
|
2021-03-01 13:47:31 +09:00
|
|
|
srcValue := reflect.ValueOf(src)
|
|
|
|
|
srcType := srcValue.Type()
|
|
|
|
|
if srcType.Kind() == reflect.Ptr {
|
|
|
|
|
srcType = srcType.Elem()
|
|
|
|
|
srcValue = srcValue.Elem()
|
|
|
|
|
}
|
|
|
|
|
if structType == srcType {
|
|
|
|
|
// dst value implements ast.Node
|
|
|
|
|
dst.Set(srcValue)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-12-13 15:00:04 +09:00
|
|
|
structFieldMap, err := structFieldMap(structType)
|
2019-10-18 12:55:38 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2020-03-02 22:53:33 +09:00
|
|
|
ignoreMergeKey := structFieldMap.hasMergeProperty()
|
|
|
|
|
keyToNodeMap, err := d.keyToValueNodeMap(src, ignoreMergeKey)
|
2019-10-24 23:54:17 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-12-11 13:07:34 +09:00
|
|
|
var unknownFields map[string]ast.Node
|
2019-12-10 18:41:23 +09:00
|
|
|
if d.disallowUnknownField {
|
2020-03-02 22:53:33 +09:00
|
|
|
unknownFields, err = d.keyToKeyNodeMap(src, ignoreMergeKey)
|
2019-12-10 18:41:23 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-12-10 18:41:23 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-02 22:55:57 +09:00
|
|
|
aliasName := d.getMergeAliasName(src)
|
2019-12-10 14:33:08 +09:00
|
|
|
var foundErr error
|
|
|
|
|
|
2019-10-18 12:55:38 +09:00
|
|
|
for i := 0; i < structType.NumField(); i++ {
|
|
|
|
|
field := structType.Field(i)
|
2019-10-19 18:28:36 +09:00
|
|
|
if isIgnoredStructField(field) {
|
2019-10-18 12:55:38 +09:00
|
|
|
continue
|
|
|
|
|
}
|
2019-12-13 15:00:04 +09:00
|
|
|
structField := structFieldMap[field.Name]
|
2019-10-28 22:12:23 +09:00
|
|
|
if structField.IsInline {
|
2019-12-14 11:55:23 +09:00
|
|
|
fieldValue := dst.FieldByName(field.Name)
|
2020-03-02 22:55:57 +09:00
|
|
|
if structField.IsAutoAlias {
|
|
|
|
|
if aliasName != "" {
|
|
|
|
|
newFieldValue := d.anchorValueMap[aliasName]
|
|
|
|
|
if newFieldValue.IsValid() {
|
|
|
|
|
fieldValue.Set(d.castToAssignableValue(newFieldValue, fieldValue.Type()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2019-10-28 22:12:23 +09:00
|
|
|
if !fieldValue.CanSet() {
|
2024-10-28 21:24:15 +09:00
|
|
|
return fmt.Errorf("cannot set embedded type as unexported field %s.%s", field.PkgPath, field.Name)
|
2019-10-28 22:12:23 +09:00
|
|
|
}
|
2019-10-30 16:57:59 +09:00
|
|
|
if fieldValue.Type().Kind() == reflect.Ptr && src.Type() == ast.NullType {
|
|
|
|
|
// set nil value to pointer
|
|
|
|
|
fieldValue.Set(reflect.Zero(fieldValue.Type()))
|
|
|
|
|
continue
|
|
|
|
|
}
|
2020-03-02 22:55:57 +09:00
|
|
|
mapNode := ast.Mapping(nil, false)
|
|
|
|
|
for k, v := range keyToNodeMap {
|
2020-06-21 16:22:04 +09:00
|
|
|
key := &ast.StringNode{BaseNode: &ast.BaseNode{}, Value: k}
|
|
|
|
|
mapNode.Values = append(mapNode.Values, ast.MappingValue(nil, key, v))
|
2020-03-02 22:55:57 +09:00
|
|
|
}
|
2021-10-15 15:11:46 +02:00
|
|
|
newFieldValue, err := d.createDecodedNewValue(ctx, fieldValue.Type(), fieldValue, mapNode)
|
2019-12-18 13:26:59 +09:00
|
|
|
if d.disallowUnknownField {
|
2021-08-10 00:33:19 -04:00
|
|
|
if err := d.deleteStructKeys(fieldValue.Type(), unknownFields); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-12-18 13:26:59 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
2019-12-10 14:33:08 +09:00
|
|
|
if foundErr != nil {
|
2019-10-29 19:46:55 +09:00
|
|
|
continue
|
|
|
|
|
}
|
2022-05-02 18:00:24 +00:00
|
|
|
var te *errors.TypeError
|
2024-10-28 21:24:15 +09:00
|
|
|
if errors.As(err, &te) {
|
2022-05-02 18:00:24 +00:00
|
|
|
if te.StructFieldName != nil {
|
|
|
|
|
fieldName := fmt.Sprintf("%s.%s", structType.Name(), *te.StructFieldName)
|
|
|
|
|
te.StructFieldName = &fieldName
|
2019-12-11 00:41:05 +09:00
|
|
|
} else {
|
|
|
|
|
fieldName := fmt.Sprintf("%s.%s", structType.Name(), field.Name)
|
2022-05-02 18:00:24 +00:00
|
|
|
te.StructFieldName = &fieldName
|
2019-12-11 00:41:05 +09:00
|
|
|
}
|
2019-12-10 14:33:08 +09:00
|
|
|
foundErr = te
|
2019-12-13 13:33:56 +09:00
|
|
|
continue
|
2019-12-16 23:30:53 +09:00
|
|
|
} else {
|
2019-12-18 13:26:59 +09:00
|
|
|
foundErr = err
|
2019-12-13 15:00:04 +09:00
|
|
|
}
|
2019-12-18 13:26:59 +09:00
|
|
|
continue
|
2019-10-28 22:12:23 +09:00
|
|
|
}
|
2024-10-28 11:31:15 +09:00
|
|
|
_ = d.setDefaultValueIfConflicted(newFieldValue, structFieldMap)
|
2019-10-28 22:12:23 +09:00
|
|
|
fieldValue.Set(d.castToAssignableValue(newFieldValue, fieldValue.Type()))
|
|
|
|
|
continue
|
|
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
v, exists := keyToNodeMap[structField.RenderName]
|
2019-10-18 12:55:38 +09:00
|
|
|
if !exists {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2019-12-11 13:07:34 +09:00
|
|
|
delete(unknownFields, structField.RenderName)
|
2019-12-14 11:55:23 +09:00
|
|
|
fieldValue := dst.FieldByName(field.Name)
|
2019-10-30 16:57:59 +09:00
|
|
|
if fieldValue.Type().Kind() == reflect.Ptr && src.Type() == ast.NullType {
|
|
|
|
|
// set nil value to pointer
|
|
|
|
|
fieldValue.Set(reflect.Zero(fieldValue.Type()))
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-10-15 15:11:46 +02:00
|
|
|
newFieldValue, err := d.createDecodedNewValue(ctx, fieldValue.Type(), fieldValue, v)
|
2020-01-09 21:49:52 +09:00
|
|
|
if err != nil {
|
2019-12-10 14:33:08 +09:00
|
|
|
if foundErr != nil {
|
2019-10-29 19:46:55 +09:00
|
|
|
continue
|
|
|
|
|
}
|
2022-05-02 18:00:24 +00:00
|
|
|
var te *errors.TypeError
|
2024-10-28 21:24:15 +09:00
|
|
|
if errors.As(err, &te) {
|
2019-12-10 14:33:08 +09:00
|
|
|
fieldName := fmt.Sprintf("%s.%s", structType.Name(), field.Name)
|
2022-05-02 18:00:24 +00:00
|
|
|
te.StructFieldName = &fieldName
|
2019-12-10 14:33:08 +09:00
|
|
|
foundErr = te
|
|
|
|
|
} else {
|
|
|
|
|
foundErr = err
|
|
|
|
|
}
|
|
|
|
|
continue
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
fieldValue.Set(d.castToAssignableValue(newFieldValue, fieldValue.Type()))
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2020-07-12 19:02:23 +03:00
|
|
|
if foundErr != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return foundErr
|
2020-07-12 19:02:23 +03:00
|
|
|
}
|
|
|
|
|
|
2021-08-11 00:04:14 -04:00
|
|
|
// Ignore unknown fields when parsing an inline struct (recognized by a nil token).
|
|
|
|
|
// Unknown fields are expected (they could be fields from the parent struct).
|
2021-08-10 03:38:16 -04:00
|
|
|
if len(unknownFields) != 0 && d.disallowUnknownField && src.GetToken() != nil {
|
2020-07-12 19:02:23 +03:00
|
|
|
for key, node := range unknownFields {
|
2024-11-14 16:01:08 +09:00
|
|
|
return errors.ErrUnknownField(fmt.Sprintf(`unknown field "%s"`, key), node.GetToken())
|
2020-07-12 19:02:23 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-26 10:08:44 +09:00
|
|
|
if d.validator != nil {
|
2019-12-14 11:55:23 +09:00
|
|
|
if err := d.validator.Struct(dst.Interface()); err != nil {
|
2019-10-26 10:08:44 +09:00
|
|
|
ev := reflect.ValueOf(err)
|
|
|
|
|
if ev.Type().Kind() == reflect.Slice {
|
|
|
|
|
for i := 0; i < ev.Len(); i++ {
|
|
|
|
|
fieldErr, ok := ev.Index(i).Interface().(FieldError)
|
|
|
|
|
if !ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fieldName := fieldErr.StructField()
|
2020-07-03 13:28:59 +03:00
|
|
|
structField, exists := structFieldMap[fieldName]
|
|
|
|
|
if !exists {
|
2020-06-28 22:16:03 +03:00
|
|
|
continue
|
|
|
|
|
}
|
2019-10-26 10:08:44 +09:00
|
|
|
node, exists := keyToNodeMap[structField.RenderName]
|
|
|
|
|
if exists {
|
|
|
|
|
// TODO: to make FieldError message cutomizable
|
|
|
|
|
return errors.ErrSyntax(fmt.Sprintf("%s", err), node.GetToken())
|
2021-04-24 17:06:35 -04:00
|
|
|
} else if t := src.GetToken(); t != nil && t.Prev != nil && t.Prev.Prev != nil {
|
|
|
|
|
// A missing required field will not be in the keyToNodeMap
|
|
|
|
|
// the error needs to be associated with the parent of the source node
|
|
|
|
|
return errors.ErrSyntax(fmt.Sprintf("%s", err), t.Prev.Prev)
|
2019-10-26 10:08:44 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-10 03:38:16 -04:00
|
|
|
return err
|
2019-10-26 10:08:44 +09:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
return nil
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decodeArray(ctx context.Context, dst reflect.Value, src ast.Node) error {
|
2019-11-01 12:43:57 +09:00
|
|
|
arrayNode, err := d.getArrayNode(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-11-01 12:43:57 +09:00
|
|
|
}
|
|
|
|
|
if arrayNode == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
iter := arrayNode.ArrayRange()
|
|
|
|
|
arrayValue := reflect.New(dst.Type()).Elem()
|
|
|
|
|
arrayType := dst.Type()
|
|
|
|
|
elemType := arrayType.Elem()
|
|
|
|
|
idx := 0
|
2019-12-10 14:33:08 +09:00
|
|
|
|
|
|
|
|
var foundErr error
|
2019-11-01 12:43:57 +09:00
|
|
|
for iter.Next() {
|
|
|
|
|
v := iter.Value()
|
|
|
|
|
if elemType.Kind() == reflect.Ptr && v.Type() == ast.NullType {
|
|
|
|
|
// set nil value to pointer
|
|
|
|
|
arrayValue.Index(idx).Set(reflect.Zero(elemType))
|
|
|
|
|
} else {
|
2021-10-15 15:11:46 +02:00
|
|
|
dstValue, err := d.createDecodedNewValue(ctx, elemType, reflect.Value{}, v)
|
2020-01-09 21:49:52 +09:00
|
|
|
if err != nil {
|
2019-12-10 14:33:08 +09:00
|
|
|
if foundErr == nil {
|
|
|
|
|
foundErr = err
|
2019-11-01 12:43:57 +09:00
|
|
|
}
|
2019-12-10 14:33:08 +09:00
|
|
|
continue
|
2019-11-01 12:43:57 +09:00
|
|
|
} else {
|
|
|
|
|
arrayValue.Index(idx).Set(d.castToAssignableValue(dstValue, elemType))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
idx++
|
|
|
|
|
}
|
|
|
|
|
dst.Set(arrayValue)
|
2019-12-10 14:33:08 +09:00
|
|
|
if foundErr != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return foundErr
|
2019-12-10 14:33:08 +09:00
|
|
|
}
|
2019-11-01 12:43:57 +09:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decodeSlice(ctx context.Context, dst reflect.Value, src ast.Node) error {
|
2019-10-24 23:54:17 +09:00
|
|
|
arrayNode, err := d.getArrayNode(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
2019-11-01 12:42:41 +09:00
|
|
|
if arrayNode == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-24 23:54:17 +09:00
|
|
|
iter := arrayNode.ArrayRange()
|
2019-10-24 17:18:03 +09:00
|
|
|
sliceType := dst.Type()
|
2019-10-24 23:54:17 +09:00
|
|
|
sliceValue := reflect.MakeSlice(sliceType, 0, iter.Len())
|
2019-10-24 17:18:03 +09:00
|
|
|
elemType := sliceType.Elem()
|
2019-12-10 14:33:08 +09:00
|
|
|
|
|
|
|
|
var foundErr error
|
2019-10-24 23:54:17 +09:00
|
|
|
for iter.Next() {
|
|
|
|
|
v := iter.Value()
|
2019-10-30 16:57:59 +09:00
|
|
|
if elemType.Kind() == reflect.Ptr && v.Type() == ast.NullType {
|
|
|
|
|
// set nil value to pointer
|
|
|
|
|
sliceValue = reflect.Append(sliceValue, reflect.Zero(elemType))
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-10-15 15:11:46 +02:00
|
|
|
dstValue, err := d.createDecodedNewValue(ctx, elemType, reflect.Value{}, v)
|
2020-01-09 21:49:52 +09:00
|
|
|
if err != nil {
|
2019-12-10 14:33:08 +09:00
|
|
|
if foundErr == nil {
|
|
|
|
|
foundErr = err
|
2019-10-31 17:56:04 +09:00
|
|
|
}
|
2019-12-10 14:33:08 +09:00
|
|
|
continue
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
sliceValue = reflect.Append(sliceValue, d.castToAssignableValue(dstValue, elemType))
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
dst.Set(sliceValue)
|
2019-12-10 14:33:08 +09:00
|
|
|
if foundErr != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return foundErr
|
2019-12-10 14:33:08 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
return nil
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decodeMapItem(ctx context.Context, dst *MapItem, src ast.Node) error {
|
2020-05-28 17:30:19 +09:00
|
|
|
mapNode, err := d.getMapNode(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-05-28 17:30:19 +09:00
|
|
|
}
|
|
|
|
|
if mapNode == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
mapIter := mapNode.MapRange()
|
|
|
|
|
if !mapIter.Next() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
key := mapIter.Key()
|
|
|
|
|
value := mapIter.Value()
|
|
|
|
|
if key.Type() == ast.MergeKeyType {
|
2020-11-11 19:27:58 +09:00
|
|
|
if err := d.decodeMapItem(ctx, dst, value); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-05-28 17:30:19 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
k, err := d.nodeToValue(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
v, err := d.nodeToValue(value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2020-05-28 17:30:19 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
*dst = MapItem{Key: k, Value: v}
|
2020-05-28 17:30:19 +09:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-08 23:34:34 +09:00
|
|
|
func (d *Decoder) validateDuplicateKey(keyMap map[string]struct{}, key interface{}, keyNode ast.Node) error {
|
2020-06-01 17:26:27 +09:00
|
|
|
k, ok := key.(string)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2024-11-13 18:29:20 +09:00
|
|
|
if !d.allowDuplicateMapKey {
|
2020-06-01 17:26:27 +09:00
|
|
|
if _, exists := keyMap[k]; exists {
|
2024-11-14 16:01:08 +09:00
|
|
|
return errors.ErrDuplicateKey(fmt.Sprintf(`duplicate key "%s"`, k), keyNode.GetToken())
|
2020-06-01 17:26:27 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
keyMap[k] = struct{}{}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decodeMapSlice(ctx context.Context, dst *MapSlice, src ast.Node) error {
|
2020-05-28 17:30:19 +09:00
|
|
|
mapNode, err := d.getMapNode(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-05-28 17:30:19 +09:00
|
|
|
}
|
|
|
|
|
if mapNode == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
mapSlice := MapSlice{}
|
|
|
|
|
mapIter := mapNode.MapRange()
|
2020-06-01 17:26:27 +09:00
|
|
|
keyMap := map[string]struct{}{}
|
2020-05-28 17:30:19 +09:00
|
|
|
for mapIter.Next() {
|
|
|
|
|
key := mapIter.Key()
|
|
|
|
|
value := mapIter.Value()
|
|
|
|
|
if key.Type() == ast.MergeKeyType {
|
|
|
|
|
var m MapSlice
|
2020-11-11 19:27:58 +09:00
|
|
|
if err := d.decodeMapSlice(ctx, &m, value); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-05-28 17:30:19 +09:00
|
|
|
}
|
|
|
|
|
for _, v := range m {
|
2020-06-08 23:34:34 +09:00
|
|
|
if err := d.validateDuplicateKey(keyMap, v.Key, value); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-06-01 17:26:27 +09:00
|
|
|
}
|
2020-05-28 17:30:19 +09:00
|
|
|
mapSlice = append(mapSlice, v)
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
k, err := d.nodeToValue(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2020-06-08 23:34:34 +09:00
|
|
|
if err := d.validateDuplicateKey(keyMap, k, key); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-06-01 17:26:27 +09:00
|
|
|
}
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
mapSlice = append(mapSlice, MapItem{Key: k, Value: v})
|
2020-05-28 17:30:19 +09:00
|
|
|
}
|
|
|
|
|
*dst = mapSlice
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decodeMap(ctx context.Context, dst reflect.Value, src ast.Node) error {
|
2019-10-24 23:54:17 +09:00
|
|
|
mapNode, err := d.getMapNode(src)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-24 23:54:17 +09:00
|
|
|
}
|
2019-11-01 12:42:41 +09:00
|
|
|
if mapNode == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
mapType := dst.Type()
|
2019-10-18 00:00:58 +09:00
|
|
|
mapValue := reflect.MakeMap(mapType)
|
|
|
|
|
keyType := mapValue.Type().Key()
|
|
|
|
|
valueType := mapValue.Type().Elem()
|
2019-10-24 23:54:17 +09:00
|
|
|
mapIter := mapNode.MapRange()
|
2020-06-01 17:26:27 +09:00
|
|
|
keyMap := map[string]struct{}{}
|
2019-12-10 14:33:08 +09:00
|
|
|
var foundErr error
|
2019-10-24 23:54:17 +09:00
|
|
|
for mapIter.Next() {
|
|
|
|
|
key := mapIter.Key()
|
|
|
|
|
value := mapIter.Value()
|
2020-03-02 16:18:13 +09:00
|
|
|
if key.Type() == ast.MergeKeyType {
|
2020-11-11 19:27:58 +09:00
|
|
|
if err := d.decodeMap(ctx, dst, value); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-03-02 16:18:13 +09:00
|
|
|
}
|
|
|
|
|
iter := dst.MapRange()
|
|
|
|
|
for iter.Next() {
|
2020-06-08 23:34:34 +09:00
|
|
|
if err := d.validateDuplicateKey(keyMap, iter.Key(), value); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-06-01 17:26:27 +09:00
|
|
|
}
|
2020-03-02 16:18:13 +09:00
|
|
|
mapValue.SetMapIndex(iter.Key(), iter.Value())
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2024-06-19 11:51:44 +03:00
|
|
|
|
|
|
|
|
k := d.createDecodableValue(keyType)
|
|
|
|
|
if d.canDecodeByUnmarshaler(k) {
|
|
|
|
|
if err := d.decodeByUnmarshaler(ctx, k, key); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2024-06-19 11:51:44 +03:00
|
|
|
}
|
|
|
|
|
} else {
|
2024-11-02 17:40:43 +09:00
|
|
|
keyVal, err := d.nodeToValue(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
k = reflect.ValueOf(keyVal)
|
2024-06-19 11:51:44 +03:00
|
|
|
if k.IsValid() && k.Type().ConvertibleTo(keyType) {
|
|
|
|
|
k = k.Convert(keyType)
|
|
|
|
|
}
|
2019-10-30 16:57:59 +09:00
|
|
|
}
|
2024-06-19 11:51:44 +03:00
|
|
|
|
2020-06-01 17:31:07 +09:00
|
|
|
if k.IsValid() {
|
2020-06-08 23:34:34 +09:00
|
|
|
if err := d.validateDuplicateKey(keyMap, k.Interface(), key); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-06-01 17:31:07 +09:00
|
|
|
}
|
2020-06-01 17:26:27 +09:00
|
|
|
}
|
2019-10-30 16:57:59 +09:00
|
|
|
if valueType.Kind() == reflect.Ptr && value.Type() == ast.NullType {
|
|
|
|
|
// set nil value to pointer
|
|
|
|
|
mapValue.SetMapIndex(k, reflect.Zero(valueType))
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-10-15 15:11:46 +02:00
|
|
|
dstValue, err := d.createDecodedNewValue(ctx, valueType, reflect.Value{}, value)
|
2020-01-09 21:49:52 +09:00
|
|
|
if err != nil {
|
2019-12-10 14:33:08 +09:00
|
|
|
if foundErr == nil {
|
|
|
|
|
foundErr = err
|
2019-10-29 19:46:55 +09:00
|
|
|
}
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-30 16:57:59 +09:00
|
|
|
if !k.IsValid() {
|
|
|
|
|
// expect nil key
|
|
|
|
|
mapValue.SetMapIndex(d.createDecodableValue(keyType), d.castToAssignableValue(dstValue, valueType))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
mapValue.SetMapIndex(k, d.castToAssignableValue(dstValue, valueType))
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
dst.Set(mapValue)
|
2019-12-10 14:33:08 +09:00
|
|
|
if foundErr != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return foundErr
|
2019-12-10 14:33:08 +09:00
|
|
|
}
|
2019-10-24 17:18:03 +09:00
|
|
|
return nil
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-18 15:20:09 +09:00
|
|
|
func (d *Decoder) fileToReader(file string) (io.Reader, error) {
|
|
|
|
|
reader, err := os.Open(file)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-18 15:20:09 +09:00
|
|
|
return reader, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) isYAMLFile(file string) bool {
|
|
|
|
|
ext := filepath.Ext(file)
|
|
|
|
|
if ext == ".yml" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if ext == ".yaml" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) readersUnderDir(dir string) ([]io.Reader, error) {
|
|
|
|
|
pattern := fmt.Sprintf("%s/*", dir)
|
|
|
|
|
matches, err := filepath.Glob(pattern)
|
2019-10-18 00:00:58 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
readers := []io.Reader{}
|
|
|
|
|
for _, match := range matches {
|
|
|
|
|
if !d.isYAMLFile(match) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
reader, err := d.fileToReader(match)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
readers = append(readers, reader)
|
|
|
|
|
}
|
|
|
|
|
return readers, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) readersUnderDirRecursive(dir string) ([]io.Reader, error) {
|
|
|
|
|
readers := []io.Reader{}
|
2024-10-28 11:31:15 +09:00
|
|
|
if err := filepath.Walk(dir, func(path string, info os.FileInfo, _ error) error {
|
2019-10-18 15:20:09 +09:00
|
|
|
if !d.isYAMLFile(path) {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2024-10-28 11:31:15 +09:00
|
|
|
reader, readerErr := d.fileToReader(path)
|
|
|
|
|
if readerErr != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return readerErr
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
readers = append(readers, reader)
|
|
|
|
|
return nil
|
|
|
|
|
}); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
return readers, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) resolveReference() error {
|
|
|
|
|
for _, opt := range d.opts {
|
|
|
|
|
if err := opt(d); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, file := range d.referenceFiles {
|
|
|
|
|
reader, err := d.fileToReader(file)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
d.referenceReaders = append(d.referenceReaders, reader)
|
|
|
|
|
}
|
|
|
|
|
for _, dir := range d.referenceDirs {
|
|
|
|
|
if !d.isRecursiveDir {
|
|
|
|
|
readers, err := d.readersUnderDir(dir)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
d.referenceReaders = append(d.referenceReaders, readers...)
|
|
|
|
|
} else {
|
|
|
|
|
readers, err := d.readersUnderDirRecursive(dir)
|
|
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
d.referenceReaders = append(d.referenceReaders, readers...)
|
|
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2019-10-18 15:20:09 +09:00
|
|
|
for _, reader := range d.referenceReaders {
|
2024-02-26 01:11:21 -05:00
|
|
|
bytes, err := io.ReadAll(reader)
|
2019-10-18 15:20:09 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assign new anchor definition to anchorMap
|
2020-06-01 16:14:20 +09:00
|
|
|
if _, err := d.parse(bytes); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
d.isResolvedReference = true
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-01 16:14:20 +09:00
|
|
|
func (d *Decoder) parse(bytes []byte) (*ast.File, error) {
|
2021-09-07 19:49:15 +09:00
|
|
|
var parseMode parser.Mode
|
|
|
|
|
if d.toCommentMap != nil {
|
|
|
|
|
parseMode = parser.ParseComments
|
|
|
|
|
}
|
2024-11-13 18:29:20 +09:00
|
|
|
var opts []parser.Option
|
|
|
|
|
if d.allowDuplicateMapKey {
|
|
|
|
|
opts = append(opts, parser.AllowDuplicateMapKey())
|
|
|
|
|
}
|
|
|
|
|
f, err := parser.ParseBytes(bytes, parseMode, opts...)
|
2019-10-18 00:00:58 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return nil, err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
2020-06-01 16:14:20 +09:00
|
|
|
normalizedFile := &ast.File{}
|
|
|
|
|
for _, doc := range f.Docs {
|
|
|
|
|
// try to decode ast.Node to value and map anchor value to anchorMap
|
2024-11-02 17:40:43 +09:00
|
|
|
v, err := d.nodeToValue(doc.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if v != nil {
|
2020-06-01 16:14:20 +09:00
|
|
|
normalizedFile.Docs = append(normalizedFile.Docs, doc)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return normalizedFile, nil
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
|
2020-06-01 16:14:20 +09:00
|
|
|
func (d *Decoder) isInitialized() bool {
|
|
|
|
|
return d.parsedFile != nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Decoder) decodeInit() error {
|
2019-10-18 15:20:09 +09:00
|
|
|
if !d.isResolvedReference {
|
|
|
|
|
if err := d.resolveReference(); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
|
|
|
|
}
|
2019-12-29 02:04:39 +09:00
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if _, err := io.Copy(&buf, d.reader); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 15:20:09 +09:00
|
|
|
}
|
2020-06-01 16:14:20 +09:00
|
|
|
file, err := d.parse(buf.Bytes())
|
2019-10-18 15:20:09 +09:00
|
|
|
if err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
2020-06-01 16:14:20 +09:00
|
|
|
d.parsedFile = file
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 19:27:58 +09:00
|
|
|
func (d *Decoder) decode(ctx context.Context, v reflect.Value) error {
|
2020-06-01 16:14:20 +09:00
|
|
|
if len(d.parsedFile.Docs) <= d.streamIndex {
|
|
|
|
|
return io.EOF
|
|
|
|
|
}
|
|
|
|
|
body := d.parsedFile.Docs[d.streamIndex].Body
|
|
|
|
|
if body == nil {
|
2019-10-18 00:00:58 +09:00
|
|
|
return nil
|
|
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
if err := d.decodeValue(ctx, v.Elem(), body); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2020-06-01 16:14:20 +09:00
|
|
|
d.streamIndex++
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decode reads the next YAML-encoded value from its input
|
|
|
|
|
// and stores it in the value pointed to by v.
|
|
|
|
|
//
|
|
|
|
|
// See the documentation for Unmarshal for details about the
|
|
|
|
|
// conversion of YAML into a Go value.
|
|
|
|
|
func (d *Decoder) Decode(v interface{}) error {
|
2020-11-11 19:27:58 +09:00
|
|
|
return d.DecodeContext(context.Background(), v)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DecodeContext reads the next YAML-encoded value from its input
|
|
|
|
|
// and stores it in the value pointed to by v with context.Context.
|
|
|
|
|
func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
|
2020-06-01 16:14:20 +09:00
|
|
|
rv := reflect.ValueOf(v)
|
|
|
|
|
if rv.Type().Kind() != reflect.Ptr {
|
2024-10-28 21:24:15 +09:00
|
|
|
return ErrDecodeRequiredPointerType
|
2020-06-01 16:14:20 +09:00
|
|
|
}
|
|
|
|
|
if d.isInitialized() {
|
2020-11-11 19:27:58 +09:00
|
|
|
if err := d.decode(ctx, rv); err != nil {
|
2020-06-01 16:14:20 +09:00
|
|
|
if err == io.EOF {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-06-01 16:14:20 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if err := d.decodeInit(); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-06-01 16:14:20 +09:00
|
|
|
}
|
2020-11-11 19:27:58 +09:00
|
|
|
if err := d.decode(ctx, rv); err != nil {
|
2020-06-01 16:14:20 +09:00
|
|
|
if err == io.EOF {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2020-06-01 16:14:20 +09:00
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
return nil
|
|
|
|
|
}
|
2021-07-19 20:49:54 +09:00
|
|
|
|
|
|
|
|
// 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 {
|
2024-10-28 21:24:15 +09:00
|
|
|
return ErrDecodeRequiredPointerType
|
2021-07-19 20:49:54 +09:00
|
|
|
}
|
|
|
|
|
if !d.isInitialized() {
|
|
|
|
|
if err := d.decodeInit(); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2021-07-19 20:49:54 +09:00
|
|
|
}
|
|
|
|
|
}
|
2021-07-20 02:13:35 +09:00
|
|
|
// resolve references to the anchor on the same file
|
2024-11-02 17:40:43 +09:00
|
|
|
if _, err := d.nodeToValue(node); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2021-07-19 20:49:54 +09:00
|
|
|
if err := d.decodeValue(ctx, rv.Elem(), node); err != nil {
|
2024-10-28 21:24:15 +09:00
|
|
|
return err
|
2021-07-19 20:49:54 +09:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|