@@ -13,7 +13,21 @@ import (
1313 "gopkg.in/yaml.v3"
1414)
1515
16- func SaveAsYAML (data any , filename string , force bool ) error {
16+ type saver struct {
17+ nodesWithStyle map [string ]yaml.Style
18+ }
19+
20+ func NewSaver () * saver {
21+ return & saver {}
22+ }
23+
24+ func NewSaverWithStyle (nodesWithStyle map [string ]yaml.Style ) * saver {
25+ return & saver {
26+ nodesWithStyle : nodesWithStyle ,
27+ }
28+ }
29+
30+ func (s * saver ) SaveAsYAML (data any , filename string , force bool ) error {
1731 err := os .MkdirAll (filepath .Dir (filename ), 0755 )
1832 if err != nil {
1933 return err
@@ -36,15 +50,15 @@ func SaveAsYAML(data any, filename string, force bool) error {
3650 }
3751 defer file .Close ()
3852
39- err = encode (data , file )
53+ err = s . encode (data , file )
4054 if err != nil {
4155 return err
4256 }
4357 return nil
4458}
4559
46- func encode (data any , w io.Writer ) error {
47- yamlNode , err := ToYamlNode (dyn .V (data ))
60+ func ( s * saver ) encode (data any , w io.Writer ) error {
61+ yamlNode , err := s . toYamlNode (dyn .V (data ))
4862 if err != nil {
4963 return err
5064 }
@@ -53,7 +67,11 @@ func encode(data any, w io.Writer) error {
5367 return enc .Encode (yamlNode )
5468}
5569
56- func ToYamlNode (v dyn.Value ) (* yaml.Node , error ) {
70+ func (s * saver ) toYamlNode (v dyn.Value ) (* yaml.Node , error ) {
71+ return s .toYamlNodeWithStyle (v , yaml .Style (0 ))
72+ }
73+
74+ func (s * saver ) toYamlNodeWithStyle (v dyn.Value , style yaml.Style ) (* yaml.Node , error ) {
5775 switch v .Kind () {
5876 case dyn .KindMap :
5977 m , _ := v .AsMap ()
@@ -68,49 +86,60 @@ func ToYamlNode(v dyn.Value) (*yaml.Node, error) {
6886 content := make ([]* yaml.Node , 0 )
6987 for _ , k := range keys {
7088 item := m [k ]
71- node := yaml.Node {Kind : yaml .ScalarNode , Value : k }
72- c , err := ToYamlNode (item )
89+ node := yaml.Node {Kind : yaml .ScalarNode , Value : k , Style : style }
90+ var nestedNodeStyle yaml.Style
91+ if customStyle , ok := s .hasStyle (k ); ok {
92+ nestedNodeStyle = customStyle
93+ } else {
94+ nestedNodeStyle = style
95+ }
96+ c , err := s .toYamlNodeWithStyle (item , nestedNodeStyle )
7397 if err != nil {
7498 return nil , err
7599 }
76100 content = append (content , & node )
77101 content = append (content , c )
78102 }
79103
80- return & yaml.Node {Kind : yaml .MappingNode , Content : content }, nil
104+ return & yaml.Node {Kind : yaml .MappingNode , Content : content , Style : style }, nil
81105 case dyn .KindSequence :
82- s , _ := v .AsSequence ()
106+ seq , _ := v .AsSequence ()
83107 content := make ([]* yaml.Node , 0 )
84- for _ , item := range s {
85- node , err := ToYamlNode (item )
108+ for _ , item := range seq {
109+ node , err := s . toYamlNodeWithStyle (item , style )
86110 if err != nil {
87111 return nil , err
88112 }
89113 content = append (content , node )
90114 }
91- return & yaml.Node {Kind : yaml .SequenceNode , Content : content }, nil
115+ return & yaml.Node {Kind : yaml .SequenceNode , Content : content , Style : style }, nil
92116 case dyn .KindNil :
93- return & yaml.Node {Kind : yaml .ScalarNode , Value : "null" }, nil
117+ return & yaml.Node {Kind : yaml .ScalarNode , Value : "null" , Style : style }, nil
94118 case dyn .KindString :
95119 // If the string is a scalar value (bool, int, float and etc.), we want to quote it.
96120 if isScalarValueInString (v ) {
97121 return & yaml.Node {Kind : yaml .ScalarNode , Value : v .MustString (), Style : yaml .DoubleQuotedStyle }, nil
98122 }
99- return & yaml.Node {Kind : yaml .ScalarNode , Value : v .MustString ()}, nil
123+ return & yaml.Node {Kind : yaml .ScalarNode , Value : v .MustString (), Style : style }, nil
100124 case dyn .KindBool :
101- return & yaml.Node {Kind : yaml .ScalarNode , Value : fmt .Sprint (v .MustBool ())}, nil
125+ return & yaml.Node {Kind : yaml .ScalarNode , Value : fmt .Sprint (v .MustBool ()), Style : style }, nil
102126 case dyn .KindInt :
103- return & yaml.Node {Kind : yaml .ScalarNode , Value : fmt .Sprint (v .MustInt ())}, nil
127+ return & yaml.Node {Kind : yaml .ScalarNode , Value : fmt .Sprint (v .MustInt ()), Style : style }, nil
104128 case dyn .KindFloat :
105- return & yaml.Node {Kind : yaml .ScalarNode , Value : fmt .Sprint (v .MustFloat ())}, nil
129+ return & yaml.Node {Kind : yaml .ScalarNode , Value : fmt .Sprint (v .MustFloat ()), Style : style }, nil
106130 case dyn .KindTime :
107- return & yaml.Node {Kind : yaml .ScalarNode , Value : v .MustTime ().UTC ().String ()}, nil
131+ return & yaml.Node {Kind : yaml .ScalarNode , Value : v .MustTime ().UTC ().String (), Style : style }, nil
108132 default :
109133 // Panic because we only want to deal with known types.
110134 panic (fmt .Sprintf ("invalid kind: %d" , v .Kind ()))
111135 }
112136}
113137
138+ func (s * saver ) hasStyle (key string ) (yaml.Style , bool ) {
139+ style , ok := s .nodesWithStyle [key ]
140+ return style , ok
141+ }
142+
114143func isScalarValueInString (v dyn.Value ) bool {
115144 if v .Kind () != dyn .KindString {
116145 return false
0 commit comments