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