go-yaml/option.go

278 lines
7.2 KiB
Go
Raw Normal View History

package yaml
import (
"io"
"reflect"
"github.com/goccy/go-yaml/ast"
)
2019-10-21 01:29:32 +09:00
// DecodeOption functional option type for Decoder
type DecodeOption func(d *Decoder) error
2019-10-21 01:29:32 +09:00
// ReferenceReaders pass to Decoder that reference to anchor defined by passed readers
func ReferenceReaders(readers ...io.Reader) DecodeOption {
return func(d *Decoder) error {
d.referenceReaders = append(d.referenceReaders, readers...)
return nil
}
}
2019-10-21 01:29:32 +09:00
// ReferenceFiles pass to Decoder that reference to anchor defined by passed files
func ReferenceFiles(files ...string) DecodeOption {
return func(d *Decoder) error {
d.referenceFiles = files
return nil
}
}
2019-10-21 01:29:32 +09:00
// ReferenceDirs pass to Decoder that reference to anchor defined by files under the passed dirs
func ReferenceDirs(dirs ...string) DecodeOption {
return func(d *Decoder) error {
d.referenceDirs = dirs
return nil
}
}
2019-10-21 01:29:32 +09:00
// RecursiveDir search yaml file recursively from passed dirs by ReferenceDirs option
func RecursiveDir(isRecursive bool) DecodeOption {
return func(d *Decoder) error {
d.isRecursiveDir = isRecursive
return nil
}
}
2019-10-19 18:28:36 +09:00
// Validator set StructValidator instance to Decoder
func Validator(v StructValidator) DecodeOption {
return func(d *Decoder) error {
d.validator = v
return nil
}
}
// Strict enable DisallowUnknownField
func Strict() DecodeOption {
return func(d *Decoder) error {
d.disallowUnknownField = true
return nil
}
}
2019-12-10 18:41:23 +09:00
// DisallowUnknownField causes the Decoder to return an error when the destination
// is a struct and the input contains object keys which do not match any
// non-ignored, exported fields in the destination.
func DisallowUnknownField() DecodeOption {
return func(d *Decoder) error {
d.disallowUnknownField = true
return nil
}
}
// AllowDuplicateMapKey ignore syntax error when mapping keys that are duplicates.
func AllowDuplicateMapKey() DecodeOption {
return func(d *Decoder) error {
d.allowDuplicateMapKey = true
return nil
}
}
2020-05-29 19:47:47 +09:00
// UseOrderedMap can be interpreted as a map,
// and uses MapSlice ( ordered map ) aggressively if there is no type specification
func UseOrderedMap() DecodeOption {
return func(d *Decoder) error {
d.useOrderedMap = true
return nil
}
}
// UseJSONUnmarshaler if neither `BytesUnmarshaler` nor `InterfaceUnmarshaler` is implemented
// and `UnmashalJSON([]byte)error` is implemented, convert the argument from `YAML` to `JSON` and then call it.
func UseJSONUnmarshaler() DecodeOption {
return func(d *Decoder) error {
d.useJSONUnmarshaler = true
return nil
}
}
// CustomUnmarshaler overrides any decoding process for the type specified in generics.
//
// NOTE: If RegisterCustomUnmarshaler and CustomUnmarshaler of DecodeOption are specified for the same type,
// the CustomUnmarshaler specified in DecodeOption takes precedence.
func CustomUnmarshaler[T any](unmarshaler func(*T, []byte) error) DecodeOption {
return func(d *Decoder) error {
var typ *T
d.customUnmarshalerMap[reflect.TypeOf(typ)] = func(v interface{}, b []byte) error {
return unmarshaler(v.(*T), b)
}
return nil
}
}
2019-10-21 01:29:32 +09:00
// EncodeOption functional option type for Encoder
2019-10-19 18:28:36 +09:00
type EncodeOption func(e *Encoder) error
2019-10-21 01:29:32 +09:00
// Indent change indent number
2019-10-19 18:28:36 +09:00
func Indent(spaces int) EncodeOption {
return func(e *Encoder) error {
e.indentNum = spaces
2019-10-19 18:28:36 +09:00
return nil
}
}
2019-10-31 13:29:43 +09:00
2021-06-29 16:35:54 +02:00
// IndentSequence causes sequence values to be indented the same value as Indent
func IndentSequence(indent bool) EncodeOption {
return func(e *Encoder) error {
e.indentSequence = indent
return nil
}
}
2021-08-09 14:54:53 +00:00
// UseSingleQuote determines if single or double quotes should be preferred for strings.
func UseSingleQuote(sq bool) EncodeOption {
return func(e *Encoder) error {
e.singleQuote = sq
return nil
}
}
2019-10-31 13:29:43 +09:00
// Flow encoding by flow style
func Flow(isFlowStyle bool) EncodeOption {
return func(e *Encoder) error {
e.isFlowStyle = isFlowStyle
return nil
}
}
// UseLiteralStyleIfMultiline causes encoding multiline strings with a literal syntax,
2020-10-05 06:18:09 +03:00
// no matter what characters they include
func UseLiteralStyleIfMultiline(useLiteralStyleIfMultiline bool) EncodeOption {
2020-10-05 06:18:09 +03:00
return func(e *Encoder) error {
e.useLiteralStyleIfMultiline = useLiteralStyleIfMultiline
2020-10-05 06:18:09 +03:00
return nil
}
}
2020-06-02 19:56:02 +09:00
// JSON encode in JSON format
func JSON() EncodeOption {
return func(e *Encoder) error {
e.isJSONStyle = true
e.isFlowStyle = true
return nil
}
}
// MarshalAnchor call back if encoder find an anchor during encoding
func MarshalAnchor(callback func(*ast.AnchorNode, interface{}) error) EncodeOption {
return func(e *Encoder) error {
e.anchorCallback = callback
return nil
}
}
// UseJSONMarshaler if neither `BytesMarshaler` nor `InterfaceMarshaler`
// nor `encoding.TextMarshaler` is implemented and `MarshalJSON()([]byte, error)` is implemented,
// call `MarshalJSON` to convert the returned `JSON` to `YAML` for processing.
func UseJSONMarshaler() EncodeOption {
return func(e *Encoder) error {
e.useJSONMarshaler = true
return nil
}
}
2021-07-20 14:26:02 +09:00
// CustomMarshaler overrides any encoding process for the type specified in generics.
//
// NOTE: If type T implements MarshalYAML for pointer receiver, the type specified in CustomMarshaler must be *T.
// If RegisterCustomMarshaler and CustomMarshaler of EncodeOption are specified for the same type,
// the CustomMarshaler specified in EncodeOption takes precedence.
func CustomMarshaler[T any](marshaler func(T) ([]byte, error)) EncodeOption {
return func(e *Encoder) error {
var typ T
e.customMarshalerMap[reflect.TypeOf(typ)] = func(v interface{}) ([]byte, error) {
return marshaler(v.(T))
}
return nil
}
}
2021-07-20 14:26:02 +09:00
// CommentPosition type of the position for comment.
type CommentPosition int
const (
2023-03-01 16:59:07 +09:00
CommentHeadPosition CommentPosition = CommentPosition(iota)
CommentLinePosition
CommentFootPosition
2021-07-20 14:26:02 +09:00
)
func (p CommentPosition) String() string {
switch p {
case CommentHeadPosition:
return "Head"
2023-03-01 16:59:07 +09:00
case CommentLinePosition:
return "Line"
case CommentFootPosition:
return "Foot"
2021-07-20 14:26:02 +09:00
default:
return ""
}
}
// LineComment create a one-line comment for CommentMap.
func LineComment(text string) *Comment {
return &Comment{
Texts: []string{text},
Position: CommentLinePosition,
}
}
// HeadComment create a multiline comment for CommentMap.
func HeadComment(texts ...string) *Comment {
return &Comment{
Texts: texts,
Position: CommentHeadPosition,
}
}
2023-03-01 16:59:07 +09:00
// FootComment create a multiline comment for CommentMap.
func FootComment(texts ...string) *Comment {
return &Comment{
Texts: texts,
Position: CommentFootPosition,
}
}
2021-07-20 14:26:02 +09:00
// Comment raw data for comment.
type Comment struct {
Texts []string
Position CommentPosition
}
// CommentMap map of the position of the comment and the comment information.
2023-03-01 16:59:07 +09:00
type CommentMap map[string][]*Comment
2021-07-20 14:26:02 +09:00
// WithComment add a comment using the location and text information given in the CommentMap.
func WithComment(cm CommentMap) EncodeOption {
return func(e *Encoder) error {
2023-03-01 16:59:07 +09:00
commentMap := map[*Path][]*Comment{}
2021-07-20 14:26:02 +09:00
for k, v := range cm {
path, err := PathString(k)
if err != nil {
return err
}
commentMap[path] = v
}
e.commentMap = commentMap
return nil
}
}
2021-09-07 19:49:15 +09:00
// CommentToMap apply the position and content of comments in a YAML document to a CommentMap.
func CommentToMap(cm CommentMap) DecodeOption {
return func(d *Decoder) error {
if cm == nil {
return ErrInvalidCommentMapValue
}
d.toCommentMap = cm
return nil
}
}