1
1
package yqutil
2
2
3
3
import (
4
- "bufio"
5
4
"bytes"
6
5
"fmt"
7
6
"os"
8
7
"strings"
9
8
9
+ "github.com/google/yamlfmt"
10
10
"github.com/google/yamlfmt/formatters/basic"
11
11
"github.com/mikefarah/yq/v4/pkg/yqlib"
12
12
"github.com/sirupsen/logrus"
@@ -16,7 +16,16 @@ import (
16
16
// EvaluateExpression evaluates the yq expression, and returns the modified yaml.
17
17
func EvaluateExpression (expression string , content []byte ) ([]byte , error ) {
18
18
logrus .Debugf ("Evaluating yq expression: %q" , expression )
19
- contentModified , err := replaceLineBreaksWithMagicString (content )
19
+ formatter , err := yamlfmtBasicFormatter ()
20
+ if err != nil {
21
+ return nil , err
22
+ }
23
+ // `ApplyFeatures()` is being called directly before passing content to `yqlib`.
24
+ // This results in `ApplyFeatures()` being called twice with `FeatureApplyBefore`:
25
+ // once here and once inside `formatter.Format`.
26
+ // Currently, calling `ApplyFeatures()` with `FeatureApplyBefore` twice is not an issue,
27
+ // but future changes to `yamlfmt` might cause problems if it is called twice.
28
+ contentModified , err := formatter .Features .ApplyFeatures (content , yamlfmt .FeatureApplyBefore )
20
29
if err != nil {
21
30
return nil , err
22
31
}
@@ -75,7 +84,7 @@ func EvaluateExpression(expression string, content []byte) ([]byte, error) {
75
84
return nil , err
76
85
}
77
86
78
- return yamlfmt (out .Bytes ())
87
+ return formatter . Format (out .Bytes ())
79
88
}
80
89
81
90
func Join (yqExprs []string ) string {
@@ -85,55 +94,23 @@ func Join(yqExprs []string) string {
85
94
return strings .Join (yqExprs , " | " )
86
95
}
87
96
88
- func yamlfmt ( content [] byte ) ([] byte , error ) {
97
+ func yamlfmtBasicFormatter ( ) (* basic. BasicFormatter , error ) {
89
98
factory := basic.BasicFormatterFactory {}
90
99
config := map [string ]interface {}{
91
- "indentless_arrays" : true ,
92
- "line_ending" : "lf" , // prefer LF even on Windows
93
- "pad_line_comments" : 2 ,
94
- "retain_line_breaks" : true , // does not affect to the output because yq removes empty lines before formatting
100
+ "indentless_arrays" : true ,
101
+ "line_ending" : "lf" , // prefer LF even on Windows
102
+ "pad_line_comments" : 2 ,
103
+ "retain_line_breaks" : true ,
104
+ "retain_line_breaks_single" : false ,
95
105
}
106
+
96
107
formatter , err := factory .NewFormatter (config )
97
108
if err != nil {
98
109
return nil , err
99
110
}
100
- return formatter .Format (content )
101
- }
102
-
103
- const yamlfmtLineBreakPlaceholder = "#magic___^_^___line"
104
-
105
- type paddinger struct {
106
- strings.Builder
107
- }
108
-
109
- func (p * paddinger ) adjust (txt string ) {
110
- var indentSize int
111
- for i := 0 ; i < len (txt ) && txt [i ] == ' ' ; i ++ { // yaml only allows space to indent.
112
- indentSize ++
113
- }
114
- // Grows if the given size is larger than us and always return the max padding.
115
- for diff := indentSize - p .Len (); diff > 0 ; diff -- {
116
- p .WriteByte (' ' )
117
- }
118
- }
119
-
120
- func replaceLineBreaksWithMagicString (content []byte ) ([]byte , error ) {
121
- // hotfix: yq does not support line breaks in the middle of a string.
122
- var buf bytes.Buffer
123
- reader := bytes .NewReader (content )
124
- scanner := bufio .NewScanner (reader )
125
- var padding paddinger
126
- for scanner .Scan () {
127
- txt := scanner .Text ()
128
- padding .adjust (txt )
129
- if strings .TrimSpace (txt ) == "" { // line break or empty space line.
130
- buf .WriteString (padding .String ()) // prepend some padding incase literal multiline strings.
131
- buf .WriteString (yamlfmtLineBreakPlaceholder )
132
- buf .WriteString ("\n " )
133
- } else {
134
- buf .WriteString (txt )
135
- buf .WriteString ("\n " )
136
- }
111
+ basicFormatter , ok := formatter .(* basic.BasicFormatter )
112
+ if ! ok {
113
+ return nil , fmt .Errorf ("unexpected formatter type: %T" , formatter )
137
114
}
138
- return buf . Bytes (), scanner . Err ()
115
+ return basicFormatter , nil
139
116
}
0 commit comments