Skip to content

Commit 3c222d8

Browse files
authored
Added StringEvaluator for evaluating string input #1266 (#1278)
1 parent 4508bc2 commit 3c222d8

File tree

5 files changed

+128
-2
lines changed

5 files changed

+128
-2
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,7 @@ _build
5656
debian/files
5757

5858
# intellij
59-
/.idea
59+
/.idea
60+
61+
# vscode
62+
.vscode

pkg/yqlib/stream_evaluator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (s *streamEvaluator) Evaluate(filename string, reader io.Reader, node *Expr
110110
Node: &dataBucket,
111111
FileIndex: s.fileIndex,
112112
}
113-
//move document comments into candidate node
113+
// move document comments into candidate node
114114
// otherwise unwrap drops them.
115115
candidateNode.TrailingContent = dataBucket.FootComment
116116
dataBucket.FootComment = ""

pkg/yqlib/string_evaluator.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package yqlib
2+
3+
import (
4+
"bytes"
5+
"container/list"
6+
"errors"
7+
"fmt"
8+
"io"
9+
10+
yaml "gopkg.in/yaml.v3"
11+
)
12+
13+
type StringEvaluator interface {
14+
Evaluate(expression string, input string, encoder Encoder, leadingContentPreProcessing bool, decoder Decoder) (string, error)
15+
}
16+
17+
type stringEvaluator struct {
18+
treeNavigator DataTreeNavigator
19+
fileIndex int
20+
}
21+
22+
func NewStringEvaluator() StringEvaluator {
23+
return &stringEvaluator{
24+
treeNavigator: NewDataTreeNavigator(),
25+
}
26+
}
27+
28+
func (s *stringEvaluator) Evaluate(expression string, input string, encoder Encoder, leadingContentPreProcessing bool, decoder Decoder) (string, error) {
29+
30+
// Use bytes.Buffer for output of string
31+
out := new(bytes.Buffer)
32+
printer := NewPrinter(encoder, NewSinglePrinterWriter(out))
33+
34+
InitExpressionParser()
35+
node, err := ExpressionParser.ParseExpression(expression)
36+
if err != nil {
37+
return "", err
38+
}
39+
40+
reader, leadingContent, err := readString(input, leadingContentPreProcessing)
41+
if err != nil {
42+
return "", err
43+
}
44+
45+
var currentIndex uint
46+
decoder.Init(reader)
47+
for {
48+
var dataBucket yaml.Node
49+
errorReading := decoder.Decode(&dataBucket)
50+
51+
if errors.Is(errorReading, io.EOF) {
52+
s.fileIndex = s.fileIndex + 1
53+
return out.String(), nil
54+
} else if errorReading != nil {
55+
return "", fmt.Errorf("bad input '%v': %w", input, errorReading)
56+
}
57+
58+
candidateNode := &CandidateNode{
59+
Document: currentIndex,
60+
Node: &dataBucket,
61+
FileIndex: s.fileIndex,
62+
}
63+
// move document comments into candidate node
64+
// otherwise unwrap drops them.
65+
candidateNode.TrailingContent = dataBucket.FootComment
66+
dataBucket.FootComment = ""
67+
68+
if currentIndex == 0 {
69+
candidateNode.LeadingContent = leadingContent
70+
}
71+
inputList := list.New()
72+
inputList.PushBack(candidateNode)
73+
74+
result, errorParsing := s.treeNavigator.GetMatchingNodes(Context{MatchingNodes: inputList}, node)
75+
if errorParsing != nil {
76+
return "", errorParsing
77+
}
78+
err = printer.PrintResults(result.MatchingNodes)
79+
80+
if err != nil {
81+
return "", err
82+
}
83+
currentIndex = currentIndex + 1
84+
}
85+
}

pkg/yqlib/string_evaluator_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package yqlib
2+
3+
import (
4+
"testing"
5+
6+
"github.com/mikefarah/yq/v4/test"
7+
)
8+
9+
func TestStringEvaluator_Evaluate_Nominal(t *testing.T) {
10+
expected_output := `` +
11+
`yq` + "\n" +
12+
`---` + "\n" +
13+
`jq` + "\n"
14+
expression := ".[].name"
15+
input := `` +
16+
` - name: yq` + "\n" +
17+
` description: yq is a portable command-line YAML, JSON and XML processor` + "\n" +
18+
`---` + "\n" +
19+
` - name: jq` + "\n" +
20+
` description: Command-line JSON processor` + "\n"
21+
encoder := NewYamlEncoder(2, true, true, true)
22+
decoder := NewYamlDecoder()
23+
24+
result, err := NewStringEvaluator().Evaluate(expression, input, encoder, true, decoder)
25+
if err != nil {
26+
t.Error(err)
27+
}
28+
29+
test.AssertResult(t, expected_output, result)
30+
}

pkg/yqlib/utils.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ func readStream(filename string, leadingContentPreProcessing bool) (io.Reader, s
3333
return processReadStream(reader)
3434
}
3535

36+
func readString(input string, leadingContentPreProcessing bool) (io.Reader, string, error) {
37+
reader := bufio.NewReader(strings.NewReader(input))
38+
if !leadingContentPreProcessing {
39+
return reader, "", nil
40+
}
41+
return processReadStream(reader)
42+
}
43+
3644
func writeString(writer io.Writer, txt string) error {
3745
_, errorWriting := writer.Write([]byte(txt))
3846
return errorWriting

0 commit comments

Comments
 (0)