encode.go raw

   1  package yaml
   2  
   3  import (
   4  	"context"
   5  	"encoding"
   6  	"fmt"
   7  	"io"
   8  	"math"
   9  	"reflect"
  10  	"sort"
  11  	"strconv"
  12  	"strings"
  13  	"time"
  14  
  15  	"github.com/goccy/go-yaml/ast"
  16  	"github.com/goccy/go-yaml/internal/errors"
  17  	"github.com/goccy/go-yaml/parser"
  18  	"github.com/goccy/go-yaml/printer"
  19  	"github.com/goccy/go-yaml/token"
  20  	"golang.org/x/xerrors"
  21  )
  22  
  23  const (
  24  	// DefaultIndentSpaces default number of space for indent
  25  	DefaultIndentSpaces = 2
  26  )
  27  
  28  // Encoder writes YAML values to an output stream.
  29  type Encoder struct {
  30  	writer                     io.Writer
  31  	opts                       []EncodeOption
  32  	indent                     int
  33  	indentSequence             bool
  34  	singleQuote                bool
  35  	isFlowStyle                bool
  36  	isJSONStyle                bool
  37  	useJSONMarshaler           bool
  38  	anchorCallback             func(*ast.AnchorNode, interface{}) error
  39  	anchorPtrToNameMap         map[uintptr]string
  40  	useLiteralStyleIfMultiline bool
  41  	commentMap                 map[*Path]*Comment
  42  	written                    bool
  43  
  44  	line        int
  45  	column      int
  46  	offset      int
  47  	indentNum   int
  48  	indentLevel int
  49  }
  50  
  51  // NewEncoder returns a new encoder that writes to w.
  52  // The Encoder should be closed after use to flush all data to w.
  53  func NewEncoder(w io.Writer, opts ...EncodeOption) *Encoder {
  54  	return &Encoder{
  55  		writer:             w,
  56  		opts:               opts,
  57  		indent:             DefaultIndentSpaces,
  58  		anchorPtrToNameMap: map[uintptr]string{},
  59  		line:               1,
  60  		column:             1,
  61  		offset:             0,
  62  	}
  63  }
  64  
  65  // Close closes the encoder by writing any remaining data.
  66  // It does not write a stream terminating string "...".
  67  func (e *Encoder) Close() error {
  68  	return nil
  69  }
  70  
  71  // Encode writes the YAML encoding of v to the stream.
  72  // If multiple items are encoded to the stream,
  73  // the second and subsequent document will be preceded with a "---" document separator,
  74  // but the first will not.
  75  //
  76  // See the documentation for Marshal for details about the conversion of Go values to YAML.
  77  func (e *Encoder) Encode(v interface{}) error {
  78  	return e.EncodeContext(context.Background(), v)
  79  }
  80  
  81  // EncodeContext writes the YAML encoding of v to the stream with context.Context.
  82  func (e *Encoder) EncodeContext(ctx context.Context, v interface{}) error {
  83  	node, err := e.EncodeToNodeContext(ctx, v)
  84  	if err != nil {
  85  		return errors.Wrapf(err, "failed to encode to node")
  86  	}
  87  	if err := e.setCommentByCommentMap(node); err != nil {
  88  		return errors.Wrapf(err, "failed to set comment by comment map")
  89  	}
  90  	if !e.written {
  91  		e.written = true
  92  	} else {
  93  		// write document separator
  94  		e.writer.Write([]byte("---\n"))
  95  	}
  96  	var p printer.Printer
  97  	e.writer.Write(p.PrintNode(node))
  98  	return nil
  99  }
 100  
 101  // EncodeToNode convert v to ast.Node.
 102  func (e *Encoder) EncodeToNode(v interface{}) (ast.Node, error) {
 103  	return e.EncodeToNodeContext(context.Background(), v)
 104  }
 105  
 106  // EncodeToNodeContext convert v to ast.Node with context.Context.
 107  func (e *Encoder) EncodeToNodeContext(ctx context.Context, v interface{}) (ast.Node, error) {
 108  	for _, opt := range e.opts {
 109  		if err := opt(e); err != nil {
 110  			return nil, errors.Wrapf(err, "failed to run option for encoder")
 111  		}
 112  	}
 113  	node, err := e.encodeValue(ctx, reflect.ValueOf(v), 1)
 114  	if err != nil {
 115  		return nil, errors.Wrapf(err, "failed to encode value")
 116  	}
 117  	return node, nil
 118  }
 119  
 120  func (e *Encoder) setCommentByCommentMap(node ast.Node) error {
 121  	if e.commentMap == nil {
 122  		return nil
 123  	}
 124  	for path, comment := range e.commentMap {
 125  		n, err := path.FilterNode(node)
 126  		if err != nil {
 127  			return errors.Wrapf(err, "failed to filter node")
 128  		}
 129  		comments := []*token.Token{}
 130  		for _, text := range comment.Texts {
 131  			comments = append(comments, token.New(text, text, nil))
 132  		}
 133  		commentGroup := ast.CommentGroup(comments)
 134  		switch comment.Position {
 135  		case CommentLinePosition:
 136  			if err := n.SetComment(commentGroup); err != nil {
 137  				return errors.Wrapf(err, "failed to set comment")
 138  			}
 139  		case CommentHeadPosition:
 140  			parent := ast.Parent(node, n)
 141  			if parent == nil {
 142  				return ErrUnsupportedHeadPositionType(node)
 143  			}
 144  			switch node := parent.(type) {
 145  			case *ast.MappingValueNode:
 146  				if err := node.SetComment(commentGroup); err != nil {
 147  					return errors.Wrapf(err, "failed to set comment")
 148  				}
 149  			case *ast.MappingNode:
 150  				if err := node.SetComment(commentGroup); err != nil {
 151  					return errors.Wrapf(err, "failed to set comment")
 152  				}
 153  			default:
 154  				return ErrUnsupportedHeadPositionType(node)
 155  			}
 156  		default:
 157  			return ErrUnknownCommentPositionType
 158  		}
 159  	}
 160  	return nil
 161  }
 162  
 163  func (e *Encoder) encodeDocument(doc []byte) (ast.Node, error) {
 164  	f, err := parser.ParseBytes(doc, 0)
 165  	if err != nil {
 166  		return nil, errors.Wrapf(err, "failed to parse yaml")
 167  	}
 168  	for _, docNode := range f.Docs {
 169  		if docNode.Body != nil {
 170  			return docNode.Body, nil
 171  		}
 172  	}
 173  	return nil, nil
 174  }
 175  
 176  func (e *Encoder) isInvalidValue(v reflect.Value) bool {
 177  	if !v.IsValid() {
 178  		return true
 179  	}
 180  	kind := v.Type().Kind()
 181  	if kind == reflect.Ptr && v.IsNil() {
 182  		return true
 183  	}
 184  	if kind == reflect.Interface && v.IsNil() {
 185  		return true
 186  	}
 187  	return false
 188  }
 189  
 190  type jsonMarshaler interface {
 191  	MarshalJSON() ([]byte, error)
 192  }
 193  
 194  func (e *Encoder) canEncodeByMarshaler(v reflect.Value) bool {
 195  	if !v.CanInterface() {
 196  		return false
 197  	}
 198  	iface := v.Interface()
 199  	switch iface.(type) {
 200  	case BytesMarshalerContext:
 201  		return true
 202  	case BytesMarshaler:
 203  		return true
 204  	case InterfaceMarshalerContext:
 205  		return true
 206  	case InterfaceMarshaler:
 207  		return true
 208  	case time.Time:
 209  		return true
 210  	case time.Duration:
 211  		return true
 212  	case encoding.TextMarshaler:
 213  		return true
 214  	case jsonMarshaler:
 215  		return e.useJSONMarshaler
 216  	}
 217  	return false
 218  }
 219  
 220  func (e *Encoder) encodeByMarshaler(ctx context.Context, v reflect.Value, column int) (ast.Node, error) {
 221  	iface := v.Interface()
 222  
 223  	if marshaler, ok := iface.(BytesMarshalerContext); ok {
 224  		doc, err := marshaler.MarshalYAML(ctx)
 225  		if err != nil {
 226  			return nil, errors.Wrapf(err, "failed to MarshalYAML")
 227  		}
 228  		node, err := e.encodeDocument(doc)
 229  		if err != nil {
 230  			return nil, errors.Wrapf(err, "failed to encode document")
 231  		}
 232  		return node, nil
 233  	}
 234  
 235  	if marshaler, ok := iface.(BytesMarshaler); ok {
 236  		doc, err := marshaler.MarshalYAML()
 237  		if err != nil {
 238  			return nil, errors.Wrapf(err, "failed to MarshalYAML")
 239  		}
 240  		node, err := e.encodeDocument(doc)
 241  		if err != nil {
 242  			return nil, errors.Wrapf(err, "failed to encode document")
 243  		}
 244  		return node, nil
 245  	}
 246  
 247  	if marshaler, ok := iface.(InterfaceMarshalerContext); ok {
 248  		marshalV, err := marshaler.MarshalYAML(ctx)
 249  		if err != nil {
 250  			return nil, errors.Wrapf(err, "failed to MarshalYAML")
 251  		}
 252  		return e.encodeValue(ctx, reflect.ValueOf(marshalV), column)
 253  	}
 254  
 255  	if marshaler, ok := iface.(InterfaceMarshaler); ok {
 256  		marshalV, err := marshaler.MarshalYAML()
 257  		if err != nil {
 258  			return nil, errors.Wrapf(err, "failed to MarshalYAML")
 259  		}
 260  		return e.encodeValue(ctx, reflect.ValueOf(marshalV), column)
 261  	}
 262  
 263  	if t, ok := iface.(time.Time); ok {
 264  		return e.encodeTime(t, column), nil
 265  	}
 266  
 267  	if t, ok := iface.(time.Duration); ok {
 268  		return e.encodeDuration(t, column), nil
 269  	}
 270  
 271  	if marshaler, ok := iface.(encoding.TextMarshaler); ok {
 272  		doc, err := marshaler.MarshalText()
 273  		if err != nil {
 274  			return nil, errors.Wrapf(err, "failed to MarshalText")
 275  		}
 276  		node, err := e.encodeDocument(doc)
 277  		if err != nil {
 278  			return nil, errors.Wrapf(err, "failed to encode document")
 279  		}
 280  		return node, nil
 281  	}
 282  
 283  	if e.useJSONMarshaler {
 284  		if marshaler, ok := iface.(jsonMarshaler); ok {
 285  			jsonBytes, err := marshaler.MarshalJSON()
 286  			if err != nil {
 287  				return nil, errors.Wrapf(err, "failed to MarshalJSON")
 288  			}
 289  			doc, err := JSONToYAML(jsonBytes)
 290  			if err != nil {
 291  				return nil, errors.Wrapf(err, "failed to convert json to yaml")
 292  			}
 293  			node, err := e.encodeDocument(doc)
 294  			if err != nil {
 295  				return nil, errors.Wrapf(err, "failed to encode document")
 296  			}
 297  			return node, nil
 298  		}
 299  	}
 300  
 301  	return nil, xerrors.Errorf("does not implemented Marshaler")
 302  }
 303  
 304  func (e *Encoder) encodeValue(ctx context.Context, v reflect.Value, column int) (ast.Node, error) {
 305  	if e.isInvalidValue(v) {
 306  		return e.encodeNil(), nil
 307  	}
 308  	if e.canEncodeByMarshaler(v) {
 309  		node, err := e.encodeByMarshaler(ctx, v, column)
 310  		if err != nil {
 311  			return nil, errors.Wrapf(err, "failed to encode by marshaler")
 312  		}
 313  		return node, nil
 314  	}
 315  	switch v.Type().Kind() {
 316  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 317  		return e.encodeInt(v.Int()), nil
 318  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 319  		return e.encodeUint(v.Uint()), nil
 320  	case reflect.Float32:
 321  		return e.encodeFloat(v.Float(), 32), nil
 322  	case reflect.Float64:
 323  		return e.encodeFloat(v.Float(), 64), nil
 324  	case reflect.Ptr:
 325  		anchorName := e.anchorPtrToNameMap[v.Pointer()]
 326  		if anchorName != "" {
 327  			aliasName := anchorName
 328  			alias := ast.Alias(token.New("*", "*", e.pos(column)))
 329  			alias.Value = ast.String(token.New(aliasName, aliasName, e.pos(column)))
 330  			return alias, nil
 331  		}
 332  		return e.encodeValue(ctx, v.Elem(), column)
 333  	case reflect.Interface:
 334  		return e.encodeValue(ctx, v.Elem(), column)
 335  	case reflect.String:
 336  		return e.encodeString(v.String(), column), nil
 337  	case reflect.Bool:
 338  		return e.encodeBool(v.Bool()), nil
 339  	case reflect.Slice:
 340  		if mapSlice, ok := v.Interface().(MapSlice); ok {
 341  			return e.encodeMapSlice(ctx, mapSlice, column)
 342  		}
 343  		return e.encodeSlice(ctx, v)
 344  	case reflect.Array:
 345  		return e.encodeArray(ctx, v)
 346  	case reflect.Struct:
 347  		if v.CanInterface() {
 348  			if mapItem, ok := v.Interface().(MapItem); ok {
 349  				return e.encodeMapItem(ctx, mapItem, column)
 350  			}
 351  			if t, ok := v.Interface().(time.Time); ok {
 352  				return e.encodeTime(t, column), nil
 353  			}
 354  		}
 355  		return e.encodeStruct(ctx, v, column)
 356  	case reflect.Map:
 357  		return e.encodeMap(ctx, v, column), nil
 358  	default:
 359  		return nil, xerrors.Errorf("unknown value type %s", v.Type().String())
 360  	}
 361  }
 362  
 363  func (e *Encoder) pos(column int) *token.Position {
 364  	return &token.Position{
 365  		Line:        e.line,
 366  		Column:      column,
 367  		Offset:      e.offset,
 368  		IndentNum:   e.indentNum,
 369  		IndentLevel: e.indentLevel,
 370  	}
 371  }
 372  
 373  func (e *Encoder) encodeNil() *ast.NullNode {
 374  	value := "null"
 375  	return ast.Null(token.New(value, value, e.pos(e.column)))
 376  }
 377  
 378  func (e *Encoder) encodeInt(v int64) *ast.IntegerNode {
 379  	value := fmt.Sprint(v)
 380  	return ast.Integer(token.New(value, value, e.pos(e.column)))
 381  }
 382  
 383  func (e *Encoder) encodeUint(v uint64) *ast.IntegerNode {
 384  	value := fmt.Sprint(v)
 385  	return ast.Integer(token.New(value, value, e.pos(e.column)))
 386  }
 387  
 388  func (e *Encoder) encodeFloat(v float64, bitSize int) ast.Node {
 389  	if v == math.Inf(0) {
 390  		value := ".inf"
 391  		return ast.Infinity(token.New(value, value, e.pos(e.column)))
 392  	} else if v == math.Inf(-1) {
 393  		value := "-.inf"
 394  		return ast.Infinity(token.New(value, value, e.pos(e.column)))
 395  	} else if math.IsNaN(v) {
 396  		value := ".nan"
 397  		return ast.Nan(token.New(value, value, e.pos(e.column)))
 398  	}
 399  	value := strconv.FormatFloat(v, 'g', -1, bitSize)
 400  	if !strings.Contains(value, ".") && !strings.Contains(value, "e") {
 401  		// append x.0 suffix to keep float value context
 402  		value = fmt.Sprintf("%s.0", value)
 403  	}
 404  	return ast.Float(token.New(value, value, e.pos(e.column)))
 405  }
 406  
 407  func (e *Encoder) isNeedQuoted(v string) bool {
 408  	if e.isJSONStyle {
 409  		return true
 410  	}
 411  	if e.useLiteralStyleIfMultiline && strings.ContainsAny(v, "\n\r") {
 412  		return false
 413  	}
 414  	if e.isFlowStyle && strings.ContainsAny(v, `]},'"`) {
 415  		return true
 416  	}
 417  	if token.IsNeedQuoted(v) {
 418  		return true
 419  	}
 420  	return false
 421  }
 422  
 423  func (e *Encoder) encodeString(v string, column int) *ast.StringNode {
 424  	if e.isNeedQuoted(v) {
 425  		if e.singleQuote {
 426  			v = quoteWith(v, '\'')
 427  		} else {
 428  			v = strconv.Quote(v)
 429  		}
 430  	}
 431  	return ast.String(token.New(v, v, e.pos(column)))
 432  }
 433  
 434  func (e *Encoder) encodeBool(v bool) *ast.BoolNode {
 435  	value := fmt.Sprint(v)
 436  	return ast.Bool(token.New(value, value, e.pos(e.column)))
 437  }
 438  
 439  func (e *Encoder) encodeSlice(ctx context.Context, value reflect.Value) (*ast.SequenceNode, error) {
 440  	if e.indentSequence {
 441  		e.column += e.indent
 442  	}
 443  	column := e.column
 444  	sequence := ast.Sequence(token.New("-", "-", e.pos(column)), e.isFlowStyle)
 445  	for i := 0; i < value.Len(); i++ {
 446  		node, err := e.encodeValue(ctx, value.Index(i), column)
 447  		if err != nil {
 448  			return nil, errors.Wrapf(err, "failed to encode value for slice")
 449  		}
 450  		sequence.Values = append(sequence.Values, node)
 451  	}
 452  	if e.indentSequence {
 453  		e.column -= e.indent
 454  	}
 455  	return sequence, nil
 456  }
 457  
 458  func (e *Encoder) encodeArray(ctx context.Context, value reflect.Value) (*ast.SequenceNode, error) {
 459  	if e.indentSequence {
 460  		e.column += e.indent
 461  	}
 462  	column := e.column
 463  	sequence := ast.Sequence(token.New("-", "-", e.pos(column)), e.isFlowStyle)
 464  	for i := 0; i < value.Len(); i++ {
 465  		node, err := e.encodeValue(ctx, value.Index(i), column)
 466  		if err != nil {
 467  			return nil, errors.Wrapf(err, "failed to encode value for array")
 468  		}
 469  		sequence.Values = append(sequence.Values, node)
 470  	}
 471  	if e.indentSequence {
 472  		e.column -= e.indent
 473  	}
 474  	return sequence, nil
 475  }
 476  
 477  func (e *Encoder) encodeMapItem(ctx context.Context, item MapItem, column int) (*ast.MappingValueNode, error) {
 478  	k := reflect.ValueOf(item.Key)
 479  	v := reflect.ValueOf(item.Value)
 480  	value, err := e.encodeValue(ctx, v, column)
 481  	if err != nil {
 482  		return nil, errors.Wrapf(err, "failed to encode MapItem")
 483  	}
 484  	if e.isMapNode(value) {
 485  		value.AddColumn(e.indent)
 486  	}
 487  	return ast.MappingValue(
 488  		token.New("", "", e.pos(column)),
 489  		e.encodeString(k.Interface().(string), column),
 490  		value,
 491  	), nil
 492  }
 493  
 494  func (e *Encoder) encodeMapSlice(ctx context.Context, value MapSlice, column int) (*ast.MappingNode, error) {
 495  	node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
 496  	for _, item := range value {
 497  		value, err := e.encodeMapItem(ctx, item, column)
 498  		if err != nil {
 499  			return nil, errors.Wrapf(err, "failed to encode MapItem for MapSlice")
 500  		}
 501  		node.Values = append(node.Values, value)
 502  	}
 503  	return node, nil
 504  }
 505  
 506  func (e *Encoder) isMapNode(node ast.Node) bool {
 507  	_, ok := node.(ast.MapNode)
 508  	return ok
 509  }
 510  
 511  func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int) ast.Node {
 512  	node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
 513  	keys := make([]interface{}, len(value.MapKeys()))
 514  	for i, k := range value.MapKeys() {
 515  		keys[i] = k.Interface()
 516  	}
 517  	sort.Slice(keys, func(i, j int) bool {
 518  		return fmt.Sprint(keys[i]) < fmt.Sprint(keys[j])
 519  	})
 520  	for _, key := range keys {
 521  		k := reflect.ValueOf(key)
 522  		v := value.MapIndex(k)
 523  		value, err := e.encodeValue(ctx, v, column)
 524  		if err != nil {
 525  			return nil
 526  		}
 527  		if e.isMapNode(value) {
 528  			value.AddColumn(e.indent)
 529  		}
 530  		node.Values = append(node.Values, ast.MappingValue(
 531  			nil,
 532  			e.encodeString(fmt.Sprint(key), column),
 533  			value,
 534  		))
 535  	}
 536  	return node
 537  }
 538  
 539  // IsZeroer is used to check whether an object is zero to determine
 540  // whether it should be omitted when marshaling with the omitempty flag.
 541  // One notable implementation is time.Time.
 542  type IsZeroer interface {
 543  	IsZero() bool
 544  }
 545  
 546  func (e *Encoder) isZeroValue(v reflect.Value) bool {
 547  	kind := v.Kind()
 548  	if z, ok := v.Interface().(IsZeroer); ok {
 549  		if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
 550  			return true
 551  		}
 552  		return z.IsZero()
 553  	}
 554  	switch kind {
 555  	case reflect.String:
 556  		return len(v.String()) == 0
 557  	case reflect.Interface, reflect.Ptr:
 558  		return v.IsNil()
 559  	case reflect.Slice:
 560  		return v.Len() == 0
 561  	case reflect.Map:
 562  		return v.Len() == 0
 563  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 564  		return v.Int() == 0
 565  	case reflect.Float32, reflect.Float64:
 566  		return v.Float() == 0
 567  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 568  		return v.Uint() == 0
 569  	case reflect.Bool:
 570  		return !v.Bool()
 571  	case reflect.Struct:
 572  		vt := v.Type()
 573  		for i := v.NumField() - 1; i >= 0; i-- {
 574  			if vt.Field(i).PkgPath != "" {
 575  				continue // private field
 576  			}
 577  			if !e.isZeroValue(v.Field(i)) {
 578  				return false
 579  			}
 580  		}
 581  		return true
 582  	}
 583  	return false
 584  }
 585  
 586  func (e *Encoder) encodeTime(v time.Time, column int) *ast.StringNode {
 587  	value := v.Format(time.RFC3339Nano)
 588  	if e.isJSONStyle {
 589  		value = strconv.Quote(value)
 590  	}
 591  	return ast.String(token.New(value, value, e.pos(column)))
 592  }
 593  
 594  func (e *Encoder) encodeDuration(v time.Duration, column int) *ast.StringNode {
 595  	value := v.String()
 596  	if e.isJSONStyle {
 597  		value = strconv.Quote(value)
 598  	}
 599  	return ast.String(token.New(value, value, e.pos(column)))
 600  }
 601  
 602  func (e *Encoder) encodeAnchor(anchorName string, value ast.Node, fieldValue reflect.Value, column int) (*ast.AnchorNode, error) {
 603  	anchorNode := ast.Anchor(token.New("&", "&", e.pos(column)))
 604  	anchorNode.Name = ast.String(token.New(anchorName, anchorName, e.pos(column)))
 605  	anchorNode.Value = value
 606  	if e.anchorCallback != nil {
 607  		if err := e.anchorCallback(anchorNode, fieldValue.Interface()); err != nil {
 608  			return nil, errors.Wrapf(err, "failed to marshal anchor")
 609  		}
 610  		if snode, ok := anchorNode.Name.(*ast.StringNode); ok {
 611  			anchorName = snode.Value
 612  		}
 613  	}
 614  	if fieldValue.Kind() == reflect.Ptr {
 615  		e.anchorPtrToNameMap[fieldValue.Pointer()] = anchorName
 616  	}
 617  	return anchorNode, nil
 618  }
 619  
 620  func (e *Encoder) encodeStruct(ctx context.Context, value reflect.Value, column int) (ast.Node, error) {
 621  	node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
 622  	structType := value.Type()
 623  	structFieldMap, err := structFieldMap(structType)
 624  	if err != nil {
 625  		return nil, errors.Wrapf(err, "failed to get struct field map")
 626  	}
 627  	hasInlineAnchorField := false
 628  	var inlineAnchorValue reflect.Value
 629  	for i := 0; i < value.NumField(); i++ {
 630  		field := structType.Field(i)
 631  		if isIgnoredStructField(field) {
 632  			continue
 633  		}
 634  		fieldValue := value.FieldByName(field.Name)
 635  		structField := structFieldMap[field.Name]
 636  		if structField.IsOmitEmpty && e.isZeroValue(fieldValue) {
 637  			// omit encoding
 638  			continue
 639  		}
 640  		ve := e
 641  		if !e.isFlowStyle && structField.IsFlow {
 642  			ve = &Encoder{}
 643  			*ve = *e
 644  			ve.isFlowStyle = true
 645  		}
 646  		value, err := ve.encodeValue(ctx, fieldValue, column)
 647  		if err != nil {
 648  			return nil, errors.Wrapf(err, "failed to encode value")
 649  		}
 650  		if e.isMapNode(value) {
 651  			value.AddColumn(e.indent)
 652  		}
 653  		var key ast.MapKeyNode = e.encodeString(structField.RenderName, column)
 654  		switch {
 655  		case structField.AnchorName != "":
 656  			anchorNode, err := e.encodeAnchor(structField.AnchorName, value, fieldValue, column)
 657  			if err != nil {
 658  				return nil, errors.Wrapf(err, "failed to encode anchor")
 659  			}
 660  			value = anchorNode
 661  		case structField.IsAutoAlias:
 662  			if fieldValue.Kind() != reflect.Ptr {
 663  				return nil, xerrors.Errorf(
 664  					"%s in struct is not pointer type. but required automatically alias detection",
 665  					structField.FieldName,
 666  				)
 667  			}
 668  			anchorName := e.anchorPtrToNameMap[fieldValue.Pointer()]
 669  			if anchorName == "" {
 670  				return nil, xerrors.Errorf(
 671  					"cannot find anchor name from pointer address for automatically alias detection",
 672  				)
 673  			}
 674  			aliasName := anchorName
 675  			alias := ast.Alias(token.New("*", "*", e.pos(column)))
 676  			alias.Value = ast.String(token.New(aliasName, aliasName, e.pos(column)))
 677  			value = alias
 678  			if structField.IsInline {
 679  				// if both used alias and inline, output `<<: *alias`
 680  				key = ast.MergeKey(token.New("<<", "<<", e.pos(column)))
 681  			}
 682  		case structField.AliasName != "":
 683  			aliasName := structField.AliasName
 684  			alias := ast.Alias(token.New("*", "*", e.pos(column)))
 685  			alias.Value = ast.String(token.New(aliasName, aliasName, e.pos(column)))
 686  			value = alias
 687  			if structField.IsInline {
 688  				// if both used alias and inline, output `<<: *alias`
 689  				key = ast.MergeKey(token.New("<<", "<<", e.pos(column)))
 690  			}
 691  		case structField.IsInline:
 692  			isAutoAnchor := structField.IsAutoAnchor
 693  			if !hasInlineAnchorField {
 694  				hasInlineAnchorField = isAutoAnchor
 695  			}
 696  			if isAutoAnchor {
 697  				inlineAnchorValue = fieldValue
 698  			}
 699  			mapNode, ok := value.(ast.MapNode)
 700  			if !ok {
 701  				return nil, xerrors.Errorf("inline value is must be map or struct type")
 702  			}
 703  			mapIter := mapNode.MapRange()
 704  			for mapIter.Next() {
 705  				key := mapIter.Key()
 706  				value := mapIter.Value()
 707  				keyName := key.GetToken().Value
 708  				if structFieldMap.isIncludedRenderName(keyName) {
 709  					// if declared same key name, skip encoding this field
 710  					continue
 711  				}
 712  				key.AddColumn(-e.indent)
 713  				value.AddColumn(-e.indent)
 714  				node.Values = append(node.Values, ast.MappingValue(nil, key, value))
 715  			}
 716  			continue
 717  		case structField.IsAutoAnchor:
 718  			anchorNode, err := e.encodeAnchor(structField.RenderName, value, fieldValue, column)
 719  			if err != nil {
 720  				return nil, errors.Wrapf(err, "failed to encode anchor")
 721  			}
 722  			value = anchorNode
 723  		}
 724  		node.Values = append(node.Values, ast.MappingValue(nil, key, value))
 725  	}
 726  	if hasInlineAnchorField {
 727  		node.AddColumn(e.indent)
 728  		anchorName := "anchor"
 729  		anchorNode := ast.Anchor(token.New("&", "&", e.pos(column)))
 730  		anchorNode.Name = ast.String(token.New(anchorName, anchorName, e.pos(column)))
 731  		anchorNode.Value = node
 732  		if e.anchorCallback != nil {
 733  			if err := e.anchorCallback(anchorNode, value.Addr().Interface()); err != nil {
 734  				return nil, errors.Wrapf(err, "failed to marshal anchor")
 735  			}
 736  			if snode, ok := anchorNode.Name.(*ast.StringNode); ok {
 737  				anchorName = snode.Value
 738  			}
 739  		}
 740  		if inlineAnchorValue.Kind() == reflect.Ptr {
 741  			e.anchorPtrToNameMap[inlineAnchorValue.Pointer()] = anchorName
 742  		}
 743  		return anchorNode, nil
 744  	}
 745  	return node, nil
 746  }
 747