@@ -34,8 +34,10 @@ type Encoder struct {
34
34
isFlowStyle bool
35
35
isJSONStyle bool
36
36
useJSONMarshaler bool
37
+ useAutoAnchor bool
37
38
anchorCallback func (* ast.AnchorNode , interface {}) error
38
39
anchorPtrToNameMap map [uintptr ]string
40
+ anchorNameRefMap map [string ]struct {}
39
41
customMarshalerMap map [reflect.Type ]func (interface {}) ([]byte , error )
40
42
useLiteralStyleIfMultiline bool
41
43
commentMap map [* Path ][]* Comment
@@ -56,6 +58,7 @@ func NewEncoder(w io.Writer, opts ...EncodeOption) *Encoder {
56
58
opts : opts ,
57
59
indent : DefaultIndentSpaces ,
58
60
anchorPtrToNameMap : map [uintptr ]string {},
61
+ anchorNameRefMap : make (map [string ]struct {}),
59
62
customMarshalerMap : map [reflect.Type ]func (interface {}) ([]byte , error ){},
60
63
line : 1 ,
61
64
column : 1 ,
@@ -111,6 +114,10 @@ func (e *Encoder) EncodeToNodeContext(ctx context.Context, v interface{}) (ast.N
111
114
return nil , err
112
115
}
113
116
}
117
+ if _ , err := e .encodeValue (ctx , reflect .ValueOf (v ), 1 ); err != nil {
118
+ return nil , err
119
+ }
120
+ e .anchorPtrToNameMap = make (map [uintptr ]string )
114
121
node , err := e .encodeValue (ctx , reflect .ValueOf (v ), 1 )
115
122
if err != nil {
116
123
return nil , err
@@ -448,6 +455,7 @@ func (e *Encoder) encodeValue(ctx context.Context, v reflect.Value, column int)
448
455
case reflect .Ptr :
449
456
anchorName := e .anchorPtrToNameMap [v .Pointer ()]
450
457
if anchorName != "" {
458
+ e .anchorNameRefMap [anchorName ] = struct {}{}
451
459
aliasName := anchorName
452
460
alias := ast .Alias (token .New ("*" , "*" , e .pos (column )))
453
461
alias .Value = ast .String (token .New (aliasName , aliasName , e .pos (column )))
@@ -464,6 +472,14 @@ func (e *Encoder) encodeValue(ctx context.Context, v reflect.Value, column int)
464
472
if mapSlice , ok := v .Interface ().(MapSlice ); ok {
465
473
return e .encodeMapSlice (ctx , mapSlice , column )
466
474
}
475
+ anchorName := e .anchorPtrToNameMap [v .Pointer ()]
476
+ if anchorName != "" {
477
+ e .anchorNameRefMap [anchorName ] = struct {}{}
478
+ aliasName := anchorName
479
+ alias := ast .Alias (token .New ("*" , "*" , e .pos (column )))
480
+ alias .Value = ast .String (token .New (aliasName , aliasName , e .pos (column )))
481
+ return alias , nil
482
+ }
467
483
return e .encodeSlice (ctx , v )
468
484
case reflect .Array :
469
485
return e .encodeArray (ctx , v )
@@ -478,6 +494,13 @@ func (e *Encoder) encodeValue(ctx context.Context, v reflect.Value, column int)
478
494
}
479
495
return e .encodeStruct (ctx , v , column )
480
496
case reflect .Map :
497
+ anchorName := e .anchorPtrToNameMap [v .Pointer ()]
498
+ if anchorName != "" {
499
+ aliasName := anchorName
500
+ alias := ast .Alias (token .New ("*" , "*" , e .pos (column )))
501
+ alias .Value = ast .String (token .New (aliasName , aliasName , e .pos (column )))
502
+ return alias , nil
503
+ }
481
504
return e .encodeMap (ctx , v , column ), nil
482
505
default :
483
506
return nil , fmt .Errorf ("unknown value type %s" , v .Type ().String ())
@@ -662,11 +685,21 @@ func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int
662
685
if e .isMapNode (value ) {
663
686
value .AddColumn (e .indent )
664
687
}
688
+ if _ , exists := e .anchorNameRefMap [fmt .Sprint (key )]; exists {
689
+ anchorName := fmt .Sprint (key )
690
+ anchorNode := ast .Anchor (token .New ("&" , "&" , e .pos (column )))
691
+ anchorNode .Name = ast .String (token .New (anchorName , anchorName , e .pos (column )))
692
+ anchorNode .Value = value
693
+ value = anchorNode
694
+ }
665
695
node .Values = append (node .Values , ast .MappingValue (
666
696
nil ,
667
697
e .encodeString (fmt .Sprint (key ), column ),
668
698
value ,
669
699
))
700
+ if ptr := e .toPointer (v ); ptr != 0 {
701
+ e .anchorPtrToNameMap [ptr ] = fmt .Sprint (key )
702
+ }
670
703
}
671
704
return node
672
705
}
@@ -868,3 +901,23 @@ func (e *Encoder) encodeStruct(ctx context.Context, value reflect.Value, column
868
901
}
869
902
return node , nil
870
903
}
904
+
905
+ func (e * Encoder ) toPointer (v reflect.Value ) uintptr {
906
+ if e .isInvalidValue (v ) {
907
+ return 0
908
+ }
909
+
910
+ switch v .Type ().Kind () {
911
+ case reflect .Ptr :
912
+ return v .Pointer ()
913
+ case reflect .Interface :
914
+ return e .toPointer (v .Elem ())
915
+ case reflect .Slice :
916
+ return v .Pointer ()
917
+ case reflect .Array :
918
+ return v .Pointer ()
919
+ case reflect .Map :
920
+ return v .Pointer ()
921
+ }
922
+ return 0
923
+ }
0 commit comments