2019-10-18 00:00:58 +09:00
|
|
|
package yaml
|
|
|
|
|
|
2019-10-18 12:55:38 +09:00
|
|
|
import (
|
|
|
|
|
"bytes"
|
2020-06-01 16:14:20 +09:00
|
|
|
"io"
|
2019-10-18 12:55:38 +09:00
|
|
|
|
2019-10-24 11:07:40 +09:00
|
|
|
"github.com/goccy/go-yaml/internal/errors"
|
|
|
|
|
"golang.org/x/xerrors"
|
2019-10-18 12:55:38 +09:00
|
|
|
)
|
|
|
|
|
|
2019-10-26 07:19:18 +09:00
|
|
|
// BytesMarshaler interface may be implemented by types to customize their
|
2019-10-21 12:53:30 +09:00
|
|
|
// behavior when being marshaled into a YAML document. The returned value
|
|
|
|
|
// is marshaled in place of the original value implementing Marshaler.
|
|
|
|
|
//
|
|
|
|
|
// If an error is returned by MarshalYAML, the marshaling procedure stops
|
|
|
|
|
// and returns with the provided error.
|
2019-10-26 07:19:18 +09:00
|
|
|
type BytesMarshaler interface {
|
2019-10-25 02:38:32 +09:00
|
|
|
MarshalYAML() ([]byte, error)
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-26 07:19:18 +09:00
|
|
|
// InterfaceMarshaler interface has MarshalYAML compatible with github.com/go-yaml/yaml package.
|
|
|
|
|
type InterfaceMarshaler interface {
|
2019-10-24 17:14:07 +09:00
|
|
|
MarshalYAML() (interface{}, error)
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-26 07:19:18 +09:00
|
|
|
// BytesUnmarshaler interface may be implemented by types to customize their
|
2019-10-21 12:53:30 +09:00
|
|
|
// behavior when being unmarshaled from a YAML document.
|
2019-10-26 07:19:18 +09:00
|
|
|
type BytesUnmarshaler interface {
|
2019-10-24 23:54:17 +09:00
|
|
|
UnmarshalYAML([]byte) error
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-26 07:19:18 +09:00
|
|
|
// InterfaceUnmarshaler interface has UnmarshalYAML compatible with github.com/go-yaml/yaml package.
|
|
|
|
|
type InterfaceUnmarshaler interface {
|
2019-10-24 17:14:07 +09:00
|
|
|
UnmarshalYAML(func(interface{}) error) error
|
2019-10-18 00:00:58 +09:00
|
|
|
}
|
|
|
|
|
|
2019-10-24 17:14:07 +09:00
|
|
|
// MapItem is an item in a MapSlice.
|
|
|
|
|
type MapItem struct {
|
|
|
|
|
Key, Value interface{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MapSlice encodes and decodes as a YAML map.
|
|
|
|
|
// The order of keys is preserved when encoding and decoding.
|
|
|
|
|
type MapSlice []MapItem
|
|
|
|
|
|
2020-06-21 16:20:46 +09:00
|
|
|
// ToMap convert to map[interface{}]interface{}.
|
|
|
|
|
func (s MapSlice) ToMap() map[interface{}]interface{} {
|
|
|
|
|
v := map[interface{}]interface{}{}
|
|
|
|
|
for _, item := range s {
|
|
|
|
|
v[item.Key] = item.Value
|
|
|
|
|
}
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 12:53:30 +09:00
|
|
|
// Marshal serializes the value provided into a YAML document. The structure
|
|
|
|
|
// of the generated document will reflect the structure of the value itself.
|
|
|
|
|
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
|
|
|
|
|
//
|
|
|
|
|
// Struct fields are only marshalled if they are exported (have an upper case
|
|
|
|
|
// first letter), and are marshalled using the field name lowercased as the
|
|
|
|
|
// default key. Custom keys may be defined via the "yaml" name in the field
|
|
|
|
|
// tag: the content preceding the first comma is used as the key, and the
|
|
|
|
|
// following comma-separated options are used to tweak the marshalling process.
|
|
|
|
|
// Conflicting names result in a runtime error.
|
|
|
|
|
//
|
|
|
|
|
// The field tag format accepted is:
|
|
|
|
|
//
|
|
|
|
|
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
|
|
|
|
//
|
|
|
|
|
// The following flags are currently supported:
|
|
|
|
|
//
|
|
|
|
|
// omitempty Only include the field if it's not set to the zero
|
|
|
|
|
// value for the type or to empty slices or maps.
|
|
|
|
|
// Zero valued structs will be omitted if all their public
|
|
|
|
|
// fields are zero, unless they implement an IsZero
|
|
|
|
|
// method (see the IsZeroer interface type), in which
|
|
|
|
|
// case the field will be included if that method returns true.
|
|
|
|
|
//
|
|
|
|
|
// flow Marshal using a flow style (useful for structs,
|
|
|
|
|
// sequences and maps).
|
|
|
|
|
//
|
|
|
|
|
// inline Inline the field, which must be a struct or a map,
|
|
|
|
|
// causing all of its fields or keys to be processed as if
|
|
|
|
|
// they were part of the outer struct. For maps, keys must
|
|
|
|
|
// not conflict with the yaml keys of other struct fields.
|
|
|
|
|
//
|
|
|
|
|
// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style.
|
|
|
|
|
// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name
|
|
|
|
|
//
|
|
|
|
|
// alias Marshal with alias. If want to define alias name explicitly, use alias=name style.
|
|
|
|
|
// Otherwise, If omitted alias name and the field type is pointer type,
|
|
|
|
|
// assigned anchor name automatically from same pointer address.
|
|
|
|
|
//
|
|
|
|
|
// In addition, if the key is "-", the field is ignored.
|
|
|
|
|
//
|
|
|
|
|
// For example:
|
|
|
|
|
//
|
|
|
|
|
// type T struct {
|
|
|
|
|
// F int `yaml:"a,omitempty"`
|
|
|
|
|
// B int
|
|
|
|
|
// }
|
|
|
|
|
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
2020-06-27 14:54:14 -07:00
|
|
|
// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n"
|
2019-10-21 12:53:30 +09:00
|
|
|
//
|
2019-10-19 18:28:36 +09:00
|
|
|
func Marshal(v interface{}) ([]byte, error) {
|
2020-06-21 16:21:19 +09:00
|
|
|
return MarshalWithOptions(v)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MarshalWithOptions serializes the value provided into a YAML document with EncodeOptions.
|
|
|
|
|
func MarshalWithOptions(v interface{}, opts ...EncodeOption) ([]byte, error) {
|
2019-10-19 18:28:36 +09:00
|
|
|
var buf bytes.Buffer
|
2020-06-21 16:21:19 +09:00
|
|
|
enc := NewEncoder(&buf, opts...)
|
2019-10-19 18:28:36 +09:00
|
|
|
if err := enc.Encode(v); err != nil {
|
2019-10-25 15:06:56 +09:00
|
|
|
return nil, errors.Wrapf(err, "failed to marshal")
|
2019-10-19 18:28:36 +09:00
|
|
|
}
|
|
|
|
|
return buf.Bytes(), nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 12:53:30 +09:00
|
|
|
// Unmarshal decodes the first document found within the in byte slice
|
|
|
|
|
// and assigns decoded values into the out value.
|
|
|
|
|
//
|
|
|
|
|
// Struct fields are only unmarshalled if they are exported (have an
|
|
|
|
|
// upper case first letter), and are unmarshalled using the field name
|
|
|
|
|
// lowercased as the default key. Custom keys may be defined via the
|
|
|
|
|
// "yaml" name in the field tag: the content preceding the first comma
|
|
|
|
|
// is used as the key, and the following comma-separated options are
|
|
|
|
|
// used to tweak the marshalling process (see Marshal).
|
|
|
|
|
// Conflicting names result in a runtime error.
|
|
|
|
|
//
|
|
|
|
|
// For example:
|
|
|
|
|
//
|
|
|
|
|
// type T struct {
|
|
|
|
|
// F int `yaml:"a,omitempty"`
|
|
|
|
|
// B int
|
|
|
|
|
// }
|
|
|
|
|
// var t T
|
|
|
|
|
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
|
|
|
|
//
|
|
|
|
|
// See the documentation of Marshal for the format of tags and a list of
|
|
|
|
|
// supported tag options.
|
|
|
|
|
//
|
2019-10-18 00:00:58 +09:00
|
|
|
func Unmarshal(data []byte, v interface{}) error {
|
2020-06-21 16:21:19 +09:00
|
|
|
return UnmarshalWithOptions(data, v)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnmarshalWithOptions decodes with DecodeOptions the first document found within the in byte slice
|
|
|
|
|
// and assigns decoded values into the out value.
|
|
|
|
|
func UnmarshalWithOptions(data []byte, v interface{}, opts ...DecodeOption) error {
|
|
|
|
|
dec := NewDecoder(bytes.NewBuffer(data), opts...)
|
2019-10-18 12:55:38 +09:00
|
|
|
if err := dec.Decode(v); err != nil {
|
2020-06-01 16:14:20 +09:00
|
|
|
if err == io.EOF {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-23 16:40:26 +09:00
|
|
|
return errors.Wrapf(err, "failed to unmarshal")
|
2019-10-18 12:55:38 +09:00
|
|
|
}
|
2019-10-18 00:00:58 +09:00
|
|
|
return nil
|
|
|
|
|
}
|
2019-10-24 11:07:40 +09:00
|
|
|
|
2019-10-24 15:28:41 +09:00
|
|
|
// FormatError is a utility function that takes advantage of the metadata
|
|
|
|
|
// stored in the errors returned by this package's parser.
|
|
|
|
|
//
|
|
|
|
|
// If the second argument `colored` is true, the error message is colorized.
|
|
|
|
|
// If the third argument `inclSource` is true, the error message will
|
|
|
|
|
// contain snippets of the YAML source that was used.
|
2019-10-24 11:07:40 +09:00
|
|
|
func FormatError(e error, colored, inclSource bool) string {
|
|
|
|
|
var pp errors.PrettyPrinter
|
|
|
|
|
if xerrors.As(e, &pp) {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
pp.PrettyPrint(&errors.Sink{&buf}, colored, inclSource)
|
|
|
|
|
return buf.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return e.Error()
|
|
|
|
|
}
|