Added StringEvaluator for evaluating string input #1266 (#1278)

This commit is contained in:
Jih-Wei, Liang 2022-08-01 00:50:56 +02:00 committed by GitHub
parent 4508bc2dc2
commit 3c222d8707
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 128 additions and 2 deletions

3
.gitignore vendored
View File

@ -57,3 +57,6 @@ debian/files
# intellij # intellij
/.idea /.idea
# vscode
.vscode

View File

@ -0,0 +1,85 @@
package yqlib
import (
"bytes"
"container/list"
"errors"
"fmt"
"io"
yaml "gopkg.in/yaml.v3"
)
type StringEvaluator interface {
Evaluate(expression string, input string, encoder Encoder, leadingContentPreProcessing bool, decoder Decoder) (string, error)
}
type stringEvaluator struct {
treeNavigator DataTreeNavigator
fileIndex int
}
func NewStringEvaluator() StringEvaluator {
return &stringEvaluator{
treeNavigator: NewDataTreeNavigator(),
}
}
func (s *stringEvaluator) Evaluate(expression string, input string, encoder Encoder, leadingContentPreProcessing bool, decoder Decoder) (string, error) {
// Use bytes.Buffer for output of string
out := new(bytes.Buffer)
printer := NewPrinter(encoder, NewSinglePrinterWriter(out))
InitExpressionParser()
node, err := ExpressionParser.ParseExpression(expression)
if err != nil {
return "", err
}
reader, leadingContent, err := readString(input, leadingContentPreProcessing)
if err != nil {
return "", err
}
var currentIndex uint
decoder.Init(reader)
for {
var dataBucket yaml.Node
errorReading := decoder.Decode(&dataBucket)
if errors.Is(errorReading, io.EOF) {
s.fileIndex = s.fileIndex + 1
return out.String(), nil
} else if errorReading != nil {
return "", fmt.Errorf("bad input '%v': %w", input, errorReading)
}
candidateNode := &CandidateNode{
Document: currentIndex,
Node: &dataBucket,
FileIndex: s.fileIndex,
}
// move document comments into candidate node
// otherwise unwrap drops them.
candidateNode.TrailingContent = dataBucket.FootComment
dataBucket.FootComment = ""
if currentIndex == 0 {
candidateNode.LeadingContent = leadingContent
}
inputList := list.New()
inputList.PushBack(candidateNode)
result, errorParsing := s.treeNavigator.GetMatchingNodes(Context{MatchingNodes: inputList}, node)
if errorParsing != nil {
return "", errorParsing
}
err = printer.PrintResults(result.MatchingNodes)
if err != nil {
return "", err
}
currentIndex = currentIndex + 1
}
}

View File

@ -0,0 +1,30 @@
package yqlib
import (
"testing"
"github.com/mikefarah/yq/v4/test"
)
func TestStringEvaluator_Evaluate_Nominal(t *testing.T) {
expected_output := `` +
`yq` + "\n" +
`---` + "\n" +
`jq` + "\n"
expression := ".[].name"
input := `` +
` - name: yq` + "\n" +
` description: yq is a portable command-line YAML, JSON and XML processor` + "\n" +
`---` + "\n" +
` - name: jq` + "\n" +
` description: Command-line JSON processor` + "\n"
encoder := NewYamlEncoder(2, true, true, true)
decoder := NewYamlDecoder()
result, err := NewStringEvaluator().Evaluate(expression, input, encoder, true, decoder)
if err != nil {
t.Error(err)
}
test.AssertResult(t, expected_output, result)
}

View File

@ -33,6 +33,14 @@ func readStream(filename string, leadingContentPreProcessing bool) (io.Reader, s
return processReadStream(reader) return processReadStream(reader)
} }
func readString(input string, leadingContentPreProcessing bool) (io.Reader, string, error) {
reader := bufio.NewReader(strings.NewReader(input))
if !leadingContentPreProcessing {
return reader, "", nil
}
return processReadStream(reader)
}
func writeString(writer io.Writer, txt string) error { func writeString(writer io.Writer, txt string) error {
_, errorWriting := writer.Write([]byte(txt)) _, errorWriting := writer.Write([]byte(txt))
return errorWriting return errorWriting