option.go raw

   1  package yaml
   2  
   3  import (
   4  	"io"
   5  
   6  	"github.com/goccy/go-yaml/ast"
   7  )
   8  
   9  // DecodeOption functional option type for Decoder
  10  type DecodeOption func(d *Decoder) error
  11  
  12  // ReferenceReaders pass to Decoder that reference to anchor defined by passed readers
  13  func ReferenceReaders(readers ...io.Reader) DecodeOption {
  14  	return func(d *Decoder) error {
  15  		d.referenceReaders = append(d.referenceReaders, readers...)
  16  		return nil
  17  	}
  18  }
  19  
  20  // ReferenceFiles pass to Decoder that reference to anchor defined by passed files
  21  func ReferenceFiles(files ...string) DecodeOption {
  22  	return func(d *Decoder) error {
  23  		d.referenceFiles = files
  24  		return nil
  25  	}
  26  }
  27  
  28  // ReferenceDirs pass to Decoder that reference to anchor defined by files under the passed dirs
  29  func ReferenceDirs(dirs ...string) DecodeOption {
  30  	return func(d *Decoder) error {
  31  		d.referenceDirs = dirs
  32  		return nil
  33  	}
  34  }
  35  
  36  // RecursiveDir search yaml file recursively from passed dirs by ReferenceDirs option
  37  func RecursiveDir(isRecursive bool) DecodeOption {
  38  	return func(d *Decoder) error {
  39  		d.isRecursiveDir = isRecursive
  40  		return nil
  41  	}
  42  }
  43  
  44  // Validator set StructValidator instance to Decoder
  45  func Validator(v StructValidator) DecodeOption {
  46  	return func(d *Decoder) error {
  47  		d.validator = v
  48  		return nil
  49  	}
  50  }
  51  
  52  // Strict enable DisallowUnknownField and DisallowDuplicateKey
  53  func Strict() DecodeOption {
  54  	return func(d *Decoder) error {
  55  		d.disallowUnknownField = true
  56  		d.disallowDuplicateKey = true
  57  		return nil
  58  	}
  59  }
  60  
  61  // DisallowUnknownField causes the Decoder to return an error when the destination
  62  // is a struct and the input contains object keys which do not match any
  63  // non-ignored, exported fields in the destination.
  64  func DisallowUnknownField() DecodeOption {
  65  	return func(d *Decoder) error {
  66  		d.disallowUnknownField = true
  67  		return nil
  68  	}
  69  }
  70  
  71  // DisallowDuplicateKey causes an error when mapping keys that are duplicates
  72  func DisallowDuplicateKey() DecodeOption {
  73  	return func(d *Decoder) error {
  74  		d.disallowDuplicateKey = true
  75  		return nil
  76  	}
  77  }
  78  
  79  // UseOrderedMap can be interpreted as a map,
  80  // and uses MapSlice ( ordered map ) aggressively if there is no type specification
  81  func UseOrderedMap() DecodeOption {
  82  	return func(d *Decoder) error {
  83  		d.useOrderedMap = true
  84  		return nil
  85  	}
  86  }
  87  
  88  // UseJSONUnmarshaler if neither `BytesUnmarshaler` nor `InterfaceUnmarshaler` is implemented
  89  // and `UnmashalJSON([]byte)error` is implemented, convert the argument from `YAML` to `JSON` and then call it.
  90  func UseJSONUnmarshaler() DecodeOption {
  91  	return func(d *Decoder) error {
  92  		d.useJSONUnmarshaler = true
  93  		return nil
  94  	}
  95  }
  96  
  97  // EncodeOption functional option type for Encoder
  98  type EncodeOption func(e *Encoder) error
  99  
 100  // Indent change indent number
 101  func Indent(spaces int) EncodeOption {
 102  	return func(e *Encoder) error {
 103  		e.indent = spaces
 104  		return nil
 105  	}
 106  }
 107  
 108  // IndentSequence causes sequence values to be indented the same value as Indent
 109  func IndentSequence(indent bool) EncodeOption {
 110  	return func(e *Encoder) error {
 111  		e.indentSequence = indent
 112  		return nil
 113  	}
 114  }
 115  
 116  // UseSingleQuote determines if single or double quotes should be preferred for strings.
 117  func UseSingleQuote(sq bool) EncodeOption {
 118  	return func(e *Encoder) error {
 119  		e.singleQuote = sq
 120  		return nil
 121  	}
 122  }
 123  
 124  // Flow encoding by flow style
 125  func Flow(isFlowStyle bool) EncodeOption {
 126  	return func(e *Encoder) error {
 127  		e.isFlowStyle = isFlowStyle
 128  		return nil
 129  	}
 130  }
 131  
 132  // UseLiteralStyleIfMultiline causes encoding multiline strings with a literal syntax,
 133  // no matter what characters they include
 134  func UseLiteralStyleIfMultiline(useLiteralStyleIfMultiline bool) EncodeOption {
 135  	return func(e *Encoder) error {
 136  		e.useLiteralStyleIfMultiline = useLiteralStyleIfMultiline
 137  		return nil
 138  	}
 139  }
 140  
 141  // JSON encode in JSON format
 142  func JSON() EncodeOption {
 143  	return func(e *Encoder) error {
 144  		e.isJSONStyle = true
 145  		e.isFlowStyle = true
 146  		return nil
 147  	}
 148  }
 149  
 150  // MarshalAnchor call back if encoder find an anchor during encoding
 151  func MarshalAnchor(callback func(*ast.AnchorNode, interface{}) error) EncodeOption {
 152  	return func(e *Encoder) error {
 153  		e.anchorCallback = callback
 154  		return nil
 155  	}
 156  }
 157  
 158  // UseJSONMarshaler if neither `BytesMarshaler` nor `InterfaceMarshaler`
 159  // nor `encoding.TextMarshaler` is implemented and `MarshalJSON()([]byte, error)` is implemented,
 160  // call `MarshalJSON` to convert the returned `JSON` to `YAML` for processing.
 161  func UseJSONMarshaler() EncodeOption {
 162  	return func(e *Encoder) error {
 163  		e.useJSONMarshaler = true
 164  		return nil
 165  	}
 166  }
 167  
 168  // CommentPosition type of the position for comment.
 169  type CommentPosition int
 170  
 171  const (
 172  	CommentLinePosition CommentPosition = iota
 173  	CommentHeadPosition
 174  )
 175  
 176  func (p CommentPosition) String() string {
 177  	switch p {
 178  	case CommentLinePosition:
 179  		return "Line"
 180  	case CommentHeadPosition:
 181  		return "Head"
 182  	default:
 183  		return ""
 184  	}
 185  }
 186  
 187  // LineComment create a one-line comment for CommentMap.
 188  func LineComment(text string) *Comment {
 189  	return &Comment{
 190  		Texts:    []string{text},
 191  		Position: CommentLinePosition,
 192  	}
 193  }
 194  
 195  // HeadComment create a multiline comment for CommentMap.
 196  func HeadComment(texts ...string) *Comment {
 197  	return &Comment{
 198  		Texts:    texts,
 199  		Position: CommentHeadPosition,
 200  	}
 201  }
 202  
 203  // Comment raw data for comment.
 204  type Comment struct {
 205  	Texts    []string
 206  	Position CommentPosition
 207  }
 208  
 209  // CommentMap map of the position of the comment and the comment information.
 210  type CommentMap map[string]*Comment
 211  
 212  // WithComment add a comment using the location and text information given in the CommentMap.
 213  func WithComment(cm CommentMap) EncodeOption {
 214  	return func(e *Encoder) error {
 215  		commentMap := map[*Path]*Comment{}
 216  		for k, v := range cm {
 217  			path, err := PathString(k)
 218  			if err != nil {
 219  				return err
 220  			}
 221  			commentMap[path] = v
 222  		}
 223  		e.commentMap = commentMap
 224  		return nil
 225  	}
 226  }
 227  
 228  // CommentToMap apply the position and content of comments in a YAML document to a CommentMap.
 229  func CommentToMap(cm CommentMap) DecodeOption {
 230  	return func(d *Decoder) error {
 231  		if cm == nil {
 232  			return ErrInvalidCommentMapValue
 233  		}
 234  		d.toCommentMap = cm
 235  		return nil
 236  	}
 237  }
 238