This commit is contained in:
Mike Farah 2023-04-11 15:33:32 +10:00
parent b4cdcfb32e
commit eb7844dd1d
13 changed files with 305 additions and 409 deletions

View File

@ -1,9 +1,12 @@
package yqlib
import (
"bufio"
"strings"
"testing"
"github.com/mikefarah/yq/v4/test"
logging "gopkg.in/op/go-logging.v1"
)
var evaluateNodesScenario = []expressionScenario{
@ -18,7 +21,7 @@ var evaluateNodesScenario = []expressionScenario{
document: `a: hello`,
expression: `.`,
expected: []string{
"D0, P[], (doc)::a: hello\n",
"D0, P[], (!!map)::a: hello\n",
},
},
{
@ -32,9 +35,19 @@ var evaluateNodesScenario = []expressionScenario{
func TestAllAtOnceEvaluateNodes(t *testing.T) {
var evaluator = NewAllAtOnceEvaluator()
logging.SetLevel(logging.DEBUG, "")
for _, tt := range evaluateNodesScenario {
node := test.ParseData(tt.document)
list, _ := evaluator.EvaluateNodes(tt.expression, &node)
decoder := NewYamlDecoder(NewDefaultYamlPreferences())
reader := bufio.NewReader(strings.NewReader(tt.document))
decoder.Init(reader)
candidateNode, errorReading := decoder.Decode()
if errorReading != nil {
t.Error(errorReading)
return
}
list, _ := evaluator.EvaluateNodes(tt.expression, candidateNode)
test.AssertResultComplex(t, tt.expected, resultsToString(t, list))
}
}

View File

@ -27,14 +27,6 @@ const (
FlowStyle
)
func createIntegerScalarNode(num int) *CandidateNode {
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!int",
Value: fmt.Sprintf("%v", num),
}
}
func createStringScalarNode(stringValue string) *CandidateNode {
var node = &CandidateNode{Kind: ScalarNode}
node.Value = stringValue
@ -94,6 +86,15 @@ type CandidateNode struct {
IsMapKey bool
}
func (n *CandidateNode) CreateChild() *CandidateNode {
return &CandidateNode{
Parent: n,
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
}
}
func (n *CandidateNode) GetKey() string {
keyPrefix := ""
if n.IsMapKey {
@ -136,7 +137,11 @@ func (n *CandidateNode) GetPath() []interface{} {
if n.Parent != nil {
return append(n.Parent.GetPath(), n.getParsedKey())
}
return []interface{}{n.getParsedKey()}
key := n.getParsedKey()
if key != nil {
return []interface{}{key}
}
return make([]interface{}, 0)
}
func (n *CandidateNode) GetNicePath() string {
@ -184,41 +189,24 @@ func (n *CandidateNode) guessTagFromCustomType() string {
return guessedTag
}
// func (n *CandidateNode) CreateChildInMap(key *CandidateNode) *CandidateNode {
// var value interface{}
// if key != nil {
// value = key.Value
// }
// return &CandidateNode{
// Path: n.createChildPath(value),
// Parent: n,
// Key: key,
// Document: n.Document,
// Filename: n.Filename,
// FileIndex: n.FileIndex,
// }
// }
func (n *CandidateNode) CreateReplacement(kind Kind, tag string, value string) *CandidateNode {
node := &CandidateNode{
Kind: kind,
Tag: tag,
Value: value,
}
n.CopyAsReplacement(node)
return node
return n.CopyAsReplacement(node)
}
func (n *CandidateNode) CopyAsReplacement(replacement *CandidateNode) *CandidateNode {
copy := replacement.Copy()
copy.Parent = n.Parent
copy.Key = n.Key
copy.IsMapKey = n.IsMapKey
copy.Document = n.Document
copy.Filename = n.Filename
copy.FileIndex = n.FileIndex
return copy
newCopy := replacement.Copy()
newCopy.Parent = n.Parent
newCopy.Key = n.Key
newCopy.IsMapKey = n.IsMapKey
newCopy.Document = n.Document
newCopy.Filename = n.Filename
newCopy.FileIndex = n.FileIndex
return newCopy
}
func (n *CandidateNode) CreateReplacementWithDocWrappers(kind Kind, tag string, style Style) *CandidateNode {
@ -230,10 +218,15 @@ func (n *CandidateNode) CreateReplacementWithDocWrappers(kind Kind, tag string,
}
func (n *CandidateNode) CopyChildren() []*CandidateNode {
log.Debug("n? %v", n)
log.Debug("n.Content %v", n.Content)
log.Debug("n.Content %v", len(n.Content))
clonedKids := make([]*CandidateNode, len(n.Content))
log.Debug("created clone")
for i, child := range n.Content {
clonedKids[i] = child.Copy()
}
log.Debug("finishing clone")
return clonedKids
}
@ -251,6 +244,11 @@ func (n *CandidateNode) doCopy(cloneContent bool) *CandidateNode {
content = n.CopyChildren()
}
var copyKey *CandidateNode
if n.Key != nil {
copyKey = n.Key.Copy()
}
return &CandidateNode{
Kind: n.Kind,
Style: n.Style,
@ -269,7 +267,7 @@ func (n *CandidateNode) doCopy(cloneContent bool) *CandidateNode {
FootComment: n.FootComment,
Parent: n.Parent,
Key: n.Key.Copy(),
Key: copyKey,
LeadingContent: n.LeadingContent,
TrailingContent: n.TrailingContent,

View File

@ -0,0 +1,205 @@
package yqlib
import (
"fmt"
yaml "gopkg.in/yaml.v3"
)
func MapYamlStyle(original yaml.Style) Style {
switch original {
case yaml.TaggedStyle:
return TaggedStyle
case yaml.DoubleQuotedStyle:
return DoubleQuotedStyle
case yaml.SingleQuotedStyle:
return SingleQuotedStyle
case yaml.LiteralStyle:
return LiteralStyle
case yaml.FoldedStyle:
return FoldedStyle
case yaml.FlowStyle:
return FlowStyle
}
return 0
}
func MapToYamlStyle(original Style) yaml.Style {
switch original {
case TaggedStyle:
return yaml.TaggedStyle
case DoubleQuotedStyle:
return yaml.DoubleQuotedStyle
case SingleQuotedStyle:
return yaml.SingleQuotedStyle
case LiteralStyle:
return yaml.LiteralStyle
case FoldedStyle:
return yaml.FoldedStyle
case FlowStyle:
return yaml.FlowStyle
}
return 0
}
func (o *CandidateNode) copyFromYamlNode(node *yaml.Node) {
o.Style = MapYamlStyle(node.Style)
o.Tag = node.Tag
o.Value = node.Value
o.Anchor = node.Anchor
// o.Alias = TODO - find Alias in our own structure
// might need to be a post process thing
o.HeadComment = node.HeadComment
o.LineComment = node.LineComment
o.FootComment = node.FootComment
o.Line = node.Line
o.Column = node.Column
}
func (o *CandidateNode) copyToYamlNode(node *yaml.Node) {
node.Style = MapToYamlStyle(o.Style)
node.Tag = o.Tag
node.Value = o.Value
node.Anchor = o.Anchor
// node.Alias = TODO - find Alias in our own structure
// might need to be a post process thing
node.HeadComment = o.HeadComment
node.LineComment = o.LineComment
node.FootComment = o.FootComment
node.Line = o.Line
node.Column = o.Column
}
func (o *CandidateNode) UnmarshalYAML(node *yaml.Node) error {
log.Debugf("unmarshalling %v", node.Tag)
switch node.Kind {
case yaml.DocumentNode:
o.Kind = DocumentNode
o.copyFromYamlNode(node)
if len(node.Content) == 0 {
return nil
}
singleChild := &CandidateNode{
Parent: o,
}
err := node.Content[0].Decode(singleChild)
if err != nil {
return err
}
o.Content = []*CandidateNode{singleChild}
return nil
case yaml.AliasNode:
log.Debug("decoding alias from yaml: %v", o.Tag)
o.Kind = AliasNode
o.copyFromYamlNode(node)
return nil
case yaml.ScalarNode:
o.Kind = ScalarNode
o.copyFromYamlNode(node)
return nil
case yaml.MappingNode:
o.Kind = MappingNode
o.copyFromYamlNode(node)
o.Content = make([]*CandidateNode, len(node.Content))
for i := 0; i < len(node.Content); i += 2 {
keyNode := o.CreateChild()
keyNode.IsMapKey = true
err := node.Content[i].Decode(keyNode)
if err != nil {
return err
}
valueNode := o.CreateChild()
valueNode.Key = keyNode
err = node.Content[i+1].Decode(valueNode)
if err != nil {
return err
}
o.Content[i] = keyNode
o.Content[i+1] = valueNode
}
return nil
case yaml.SequenceNode:
o.Kind = SequenceNode
o.copyFromYamlNode(node)
o.Content = make([]*CandidateNode, len(node.Content))
for i := 0; i < len(node.Content); i += 1 {
keyNode := o.CreateChild()
keyNode.IsMapKey = true // can't remember if we need this for sequences
keyNode.Tag = "!!int"
keyNode.Kind = ScalarNode
keyNode.Value = fmt.Sprintf("%v", i)
valueNode := o.CreateChild()
valueNode.Key = keyNode
err := node.Content[i].Decode(valueNode)
if err != nil {
return err
}
o.Content[i] = valueNode
}
return nil
case 0:
// not sure when this happens
o.copyFromYamlNode(node)
return nil
default:
return fmt.Errorf("orderedMap: invalid yaml node")
}
}
func (o *CandidateNode) MarshalYAML() (interface{}, error) {
log.Debug("encoding to yaml: %v", o.Tag)
switch o.Kind {
case DocumentNode:
target := &yaml.Node{Kind: yaml.DocumentNode}
o.copyToYamlNode(target)
singleChild := &yaml.Node{}
err := singleChild.Encode(o.Content[0])
if err != nil {
return nil, err
}
target.Content = []*yaml.Node{singleChild}
return target, nil
case AliasNode:
log.Debug("encoding alias to yaml: %v", o.Tag)
target := &yaml.Node{Kind: yaml.AliasNode}
o.copyToYamlNode(target)
return target, nil
case ScalarNode:
target := &yaml.Node{Kind: yaml.ScalarNode}
o.copyToYamlNode(target)
return target, nil
case MappingNode, SequenceNode:
targetKind := yaml.MappingNode
if o.Kind == SequenceNode {
targetKind = yaml.SequenceNode
}
target := &yaml.Node{Kind: targetKind}
o.copyToYamlNode(target)
target.Content = make([]*yaml.Node, len(o.Content))
for i := 0; i < len(o.Content); i += 1 {
child := &yaml.Node{}
err := child.Encode(o.Content[i])
if err != nil {
return nil, err
}
target.Content[i] = child
}
return target, nil
}
target := &yaml.Node{}
o.copyToYamlNode(target)
return target, nil
}

View File

@ -49,7 +49,7 @@ func (d *dataTreeNavigator) GetMatchingNodes(context Context, expressionNode *Ex
log.Debug(NodeToString(el.Value.(*CandidateNode)))
}
}
log.Debug(">>")
log.Debug("carr on>>")
handler := expressionNode.Operation.OperationType.Handler
if handler != nil {
return handler(d, context, expressionNode)

View File

@ -96,104 +96,10 @@ func (dec *yamlDecoder) Init(reader io.Reader) error {
return nil
}
func (dec *yamlDecoder) convertKind(oKind yaml.Kind) Kind {
switch oKind {
case yaml.DocumentNode:
return DocumentNode
case yaml.SequenceNode:
return SequenceNode
case yaml.MappingNode:
return MappingNode
case yaml.ScalarNode:
return ScalarNode
case yaml.AliasNode:
return AliasNode
}
return ScalarNode
}
func (dec *yamlDecoder) convertStyle(oStyle yaml.Style) Style {
switch oStyle {
case yaml.TaggedStyle:
return TaggedStyle
case yaml.DoubleQuotedStyle:
return DoubleQuotedStyle
case yaml.SingleQuotedStyle:
return SingleQuotedStyle
case yaml.LiteralStyle:
return LiteralStyle
case yaml.FoldedStyle:
return FoldedStyle
case yaml.FlowStyle:
return FlowStyle
}
return 0
}
func (dec *yamlDecoder) ConvertToCandidateNode(parent *CandidateNode, path []interface{}, yamlNode *yaml.Node) *CandidateNode {
candidateNode := &CandidateNode{
Kind: dec.convertKind(yamlNode.Kind),
Style: dec.convertStyle(yamlNode.Style),
Tag: yamlNode.Tag,
Value: yamlNode.Value,
Anchor: yamlNode.Anchor,
// not sure on this - check
Alias: dec.ConvertToCandidateNode(parent, path, yamlNode.Alias),
HeadComment: yamlNode.HeadComment,
LineComment: yamlNode.LineComment,
FootComment: yamlNode.FootComment,
Path: path,
Parent: parent,
Document: parent.Document,
Filename: parent.Filename,
Line: yamlNode.Line,
Column: yamlNode.Column,
FileIndex: parent.FileIndex,
}
kids := make([]*CandidateNode, len(yamlNode.Content))
if yamlNode.Kind == yaml.MappingNode {
// children are key, values
for i := 0; i < len(yamlNode.Content); i = i + 2 {
key := yamlNode.Content[i]
value := yamlNode.Content[i+1]
childPath := parent.createChildPath(key.Value)
keyNode := dec.ConvertToCandidateNode(parent, childPath, key)
keyNode.IsMapKey = true
valueNode := dec.ConvertToCandidateNode(parent, childPath, value)
valueNode.Key = keyNode
kids[i] = keyNode
kids[i+1] = valueNode
}
} else {
// its just an normal array
for i, v := range yamlNode.Content {
childPath := parent.createChildPath(i)
kids[i] = dec.ConvertToCandidateNode(parent, childPath, v)
}
}
candidateNode.Content = kids
return candidateNode
}
func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
var dataBucket yaml.Node
err := dec.decoder.Decode(&dataBucket)
var candidateNode CandidateNode
err := dec.decoder.Decode(&candidateNode)
log.Debugf("decoded the yaml")
if errors.Is(err, io.EOF) && dec.leadingContent != "" && !dec.readAnything {
// force returning an empty node with a comment.
dec.readAnything = true
@ -211,8 +117,6 @@ func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
return nil, err
}
candidateNode := dec.ConvertToCandidateNode(&CandidateNode{}, make([]interface{}, 0), &dataBucket)
if dec.leadingContent != "" {
candidateNode.LeadingContent = dec.leadingContent
dec.leadingContent = ""
@ -220,9 +124,9 @@ func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
dec.readAnything = true
// move document comments into candidate node
// otherwise unwrap drops them.
candidateNode.TrailingContent = dataBucket.FootComment
dataBucket.FootComment = ""
return candidateNode, nil
candidateNode.TrailingContent = candidateNode.FootComment
candidateNode.FootComment = ""
return &candidateNode, nil
}
func (dec *yamlDecoder) blankNodeWithComment() *CandidateNode {

View File

@ -16,213 +16,3 @@ These are most commonly used with the `select` operator to filter particular nod
- comparison (`>=`, `<` etc) operators [here](https://mikefarah.gitbook.io/yq/operators/compare)
- select operator [here](https://mikefarah.gitbook.io/yq/operators/select)
## `or` example
Running
```bash
yq --null-input 'true or false'
```
will output
```yaml
true
```
## `and` example
Running
```bash
yq --null-input 'true and false'
```
will output
```yaml
false
```
## Matching nodes with select, equals and or
Given a sample.yml file of:
```yaml
- a: bird
b: dog
- a: frog
b: bird
- a: cat
b: fly
```
then
```bash
yq '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
```
will output
```yaml
- a: bird
b: dog
- a: cat
b: fly
```
## `any` returns true if any boolean in a given array is true
Given a sample.yml file of:
```yaml
- false
- true
```
then
```bash
yq 'any' sample.yml
```
will output
```yaml
true
```
## `any` returns false for an empty array
Given a sample.yml file of:
```yaml
[]
```
then
```bash
yq 'any' sample.yml
```
will output
```yaml
false
```
## `any_c` returns true if any element in the array is true for the given condition.
Given a sample.yml file of:
```yaml
a:
- rad
- awesome
b:
- meh
- whatever
```
then
```bash
yq '.[] |= any_c(. == "awesome")' sample.yml
```
will output
```yaml
a: true
b: false
```
## `all` returns true if all booleans in a given array are true
Given a sample.yml file of:
```yaml
- true
- true
```
then
```bash
yq 'all' sample.yml
```
will output
```yaml
true
```
## `all` returns true for an empty array
Given a sample.yml file of:
```yaml
[]
```
then
```bash
yq 'all' sample.yml
```
will output
```yaml
true
```
## `all_c` returns true if all elements in the array are true for the given condition.
Given a sample.yml file of:
```yaml
a:
- rad
- awesome
b:
- meh
- 12
```
then
```bash
yq '.[] |= all_c(tag == "!!str")' sample.yml
```
will output
```yaml
a: true
b: false
```
## Not true is false
Running
```bash
yq --null-input 'true | not'
```
will output
```yaml
false
```
## Not false is true
Running
```bash
yq --null-input 'false | not'
```
will output
```yaml
true
```
## String values considered to be true
Running
```bash
yq --null-input '"cat" | not'
```
will output
```yaml
false
```
## Empty string value considered to be true
Running
```bash
yq --null-input '"" | not'
```
will output
```yaml
false
```
## Numbers are considered to be true
Running
```bash
yq --null-input '1 | not'
```
will output
```yaml
false
```
## Zero is considered to be true
Running
```bash
yq --null-input '0 | not'
```
will output
```yaml
false
```
## Null is considered to be false
Running
```bash
yq --null-input '~ | not'
```
will output
```yaml
true
```

View File

@ -56,11 +56,11 @@ func (je *jsonEncoder) Encode(writer io.Writer, node *CandidateNode) error {
var dataBucket orderedMap
// firstly, convert all map keys to strings
mapKeysToStrings(node)
errorDecoding := node.Decode(&dataBucket)
// errorDecoding := node.Decode(&dataBucket)
if errorDecoding != nil {
return errorDecoding
}
// if errorDecoding != nil {
// return errorDecoding
// }
err := encoder.Encode(dataBucket)
if err != nil {
return err

View File

@ -18,7 +18,7 @@ func yamlToProps(sampleYaml string, unwrapScalar bool) string {
if err != nil {
panic(err)
}
node := inputs.Front().Value.(*CandidateNode).Node
node := inputs.Front().Value.(*CandidateNode)
err = propsEncoder.Encode(writer, node)
if err != nil {
panic(err)

View File

@ -20,7 +20,7 @@ func yamlToJSON(sampleYaml string, indent int) string {
if err != nil {
panic(err)
}
node := inputs.Front().Value.(*CandidateNode).Node
node := inputs.Front().Value.(*CandidateNode)
err = jsonEncoder.Encode(writer, node)
if err != nil {
panic(err)

View File

@ -5,7 +5,6 @@ import (
"github.com/alecthomas/repr"
"github.com/mikefarah/yq/v4/test"
yaml "gopkg.in/yaml.v3"
)
type participleLexerScenario struct {
@ -41,11 +40,9 @@ var participleLexerScenarios = []participleLexerScenario{
Value: 0,
StringValue: "0",
CandidateNode: &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!int",
Value: "0",
},
Kind: ScalarNode,
Tag: "!!int",
Value: "0",
},
},
},
@ -64,11 +61,9 @@ var participleLexerScenarios = []participleLexerScenario{
Value: int64(3),
StringValue: "3",
CandidateNode: &CandidateNode{
Node: &yaml.Node{
Kind: yaml.Kind(8),
Tag: "!!int",
Value: "3",
},
Kind: ScalarNode,
Tag: "!!int",
Value: "3",
},
},
},
@ -106,11 +101,9 @@ var participleLexerScenarios = []participleLexerScenario{
Value: int64(-2),
StringValue: "-2",
CandidateNode: &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!int",
Value: "-2",
},
Kind: ScalarNode,
Tag: "!!int",
Value: "-2",
},
},
},
@ -631,11 +624,9 @@ var participleLexerScenarios = []participleLexerScenario{
StringValue: "string with a\n",
Preferences: nil,
CandidateNode: &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: "string with a\n",
},
Kind: ScalarNode,
Tag: "!!str",
Value: "string with a\n",
},
},
},
@ -652,11 +643,9 @@ var participleLexerScenarios = []participleLexerScenario{
StringValue: `string with a "`,
Preferences: nil,
CandidateNode: &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: `string with a "`,
},
Kind: ScalarNode,
Tag: "!!str",
Value: `string with a "`,
},
},
},

View File

@ -2,7 +2,6 @@
package yqlib
import (
"bytes"
"container/list"
"fmt"
"math"
@ -446,23 +445,23 @@ func NodeToString(node *CandidateNode) string {
if node == nil {
return "-- nil --"
}
buf := new(bytes.Buffer)
encoder := yaml.NewEncoder(buf)
errorEncoding := encoder.Encode(node)
if errorEncoding != nil {
log.Error("Error debugging node, %v", errorEncoding.Error())
}
errorClosingEncoder := encoder.Close()
if errorClosingEncoder != nil {
log.Error("Error closing encoder: ", errorClosingEncoder.Error())
}
// buf := new(bytes.Buffer)
// encoder := yaml.NewEncoder(buf)
// errorEncoding := encoder.Encode(node)
// if errorEncoding != nil {
// log.Error("Error debugging node, %v", errorEncoding.Error())
// }
// errorClosingEncoder := encoder.Close()
// if errorClosingEncoder != nil {
// log.Error("Error closing encoder: ", errorClosingEncoder.Error())
// }
tag := node.Tag
if node.Kind == DocumentNode {
tag = "doc"
} else if node.Kind == AliasNode {
tag = "alias"
}
return fmt.Sprintf(`D%v, P%v, (%v)::%v`, node.Document, node.GetNicePath(), tag, buf.String())
return fmt.Sprintf(`D%v, P%v, (%v)::%v`, node.Document, node.GetNicePath(), tag, node.Value)
}
func KindString(kind yaml.Kind) string {

View File

@ -14,7 +14,6 @@ import (
"github.com/mikefarah/yq/v4/test"
logging "gopkg.in/op/go-logging.v1"
yaml "gopkg.in/yaml.v3"
)
type expressionScenario struct {
@ -82,7 +81,8 @@ func testScenario(t *testing.T, s *expressionScenario) {
candidateNode := &CandidateNode{
Document: 0,
Filename: "",
Node: &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode},
Tag: "!!null",
Kind: ScalarNode,
FileIndex: 0,
}
inputs.PushBack(candidateNode)
@ -138,13 +138,13 @@ func resultToString(t *testing.T, n *CandidateNode) string {
return ""
}
tag := n.Node.Tag
if n.Node.Kind == yaml.DocumentNode {
tag := n.Tag
if n.Kind == DocumentNode {
tag = "doc"
} else if n.Node.Kind == yaml.AliasNode {
} else if n.Kind == AliasNode {
tag = "alias"
}
return fmt.Sprintf(`D%v, P%v, (%v)::%v`, n.Document, n.Path, tag, valueBuffer.String())
return fmt.Sprintf(`D%v, P%v, (%v)::%v`, n.Document, n.GetPath(), tag, valueBuffer.String())
}
func resultsToString(t *testing.T, results *list.List) []string {
@ -352,7 +352,8 @@ func documentOutput(t *testing.T, w *bufio.Writer, s expressionScenario, formatt
candidateNode := &CandidateNode{
Document: 0,
Filename: "",
Node: &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode},
Tag: "!!null",
Kind: ScalarNode,
FileIndex: 0,
}
inputs.PushBack(candidateNode)

View File

@ -6,8 +6,6 @@ import (
"io"
"os"
"regexp"
"gopkg.in/yaml.v3"
)
type PrinterWriter interface {
@ -56,17 +54,16 @@ func NewMultiPrinterWriter(expression *ExpressionNode, format PrinterOutputForma
func (sp *multiPrintWriter) GetWriter(node *CandidateNode) (*bufio.Writer, error) {
name := ""
indexVariableNode := yaml.Node{Kind: yaml.ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%v", sp.index)}
indexVariableCandidate := CandidateNode{Node: &indexVariableNode}
indexVariableNode := CandidateNode{Kind: ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%v", sp.index)}
context := Context{MatchingNodes: node.AsList()}
context.SetVariable("index", indexVariableCandidate.AsList())
context.SetVariable("index", indexVariableNode.AsList())
result, err := sp.treeNavigator.GetMatchingNodes(context, sp.nameExpression)
if err != nil {
return nil, err
}
if result.MatchingNodes.Len() > 0 {
name = result.MatchingNodes.Front().Value.(*CandidateNode).Node.Value
name = result.MatchingNodes.Front().Value.(*CandidateNode).Value
}
var extensionRegexp = regexp.MustCompile(`\.[a-zA-Z0-9]+$`)
if !extensionRegexp.MatchString(name) {