This commit is contained in:
Mike Farah 2023-04-03 17:27:41 +10:00
parent 6a891e5239
commit 8fef31b417
10 changed files with 225 additions and 228 deletions

View File

@ -35,6 +35,13 @@ func createIntegerScalarNode(num int) *CandidateNode {
}
}
func createStringScalarNode(stringValue string) *CandidateNode {
var node = &CandidateNode{Kind: ScalarNode}
node.Value = stringValue
node.Tag = "!!str"
return node
}
func createScalarNode(value interface{}, stringValue string) *CandidateNode {
var node = &CandidateNode{Kind: ScalarNode}
node.Value = stringValue
@ -137,36 +144,37 @@ func (n *CandidateNode) guessTagFromCustomType() string {
log.Debug("guessTagFromCustomType: could not guess underlying tag type %v", errorReading)
return n.Tag
}
guessedTag := unwrapDoc(dataBucket).Tag
guessedTag := dataBucket.unwrapDocument().Tag
log.Info("im guessing the tag %v is a %v", n.Tag, guessedTag)
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) CreateChildInMap(key *CandidateNode) *CandidateNode {
// var value interface{}
// if key != nil {
// value = key.Value
// }
// return &CandidateNode{
// Path: n.createChildPath(value),
// Parent: n,
// Key: key,
func (n *CandidateNode) CreateChildInArray(index int) *CandidateNode {
return &CandidateNode{
Path: n.createChildPath(index),
Parent: n,
Key: createIntegerScalarNode(index),
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
}
}
// Document: n.Document,
// Filename: n.Filename,
// FileIndex: n.FileIndex,
// }
// }
// func (n *CandidateNode) CreateChildInArray(index int) *CandidateNode {
// return &CandidateNode{
// Path: n.createChildPath(index),
// Parent: n,
// Key: createIntegerScalarNode(index),
// Document: n.Document,
// Filename: n.Filename,
// FileIndex: n.FileIndex,
// }
// }
func (n *CandidateNode) CreateReplacement() *CandidateNode {
return &CandidateNode{

View File

@ -4,7 +4,6 @@ import (
"fmt"
logging "gopkg.in/op/go-logging.v1"
yaml "gopkg.in/yaml.v3"
)
type DataTreeNavigator interface {
@ -13,7 +12,7 @@ type DataTreeNavigator interface {
// a new context of matching candidates
GetMatchingNodes(context Context, expressionNode *ExpressionNode) (Context, error)
DeeplyAssign(context Context, path []interface{}, rhsNode *yaml.Node) error
DeeplyAssign(context Context, rhsNode *CandidateNode) error
}
type dataTreeNavigator struct {
@ -23,12 +22,7 @@ func NewDataTreeNavigator() DataTreeNavigator {
return &dataTreeNavigator{}
}
func (d *dataTreeNavigator) DeeplyAssign(context Context, path []interface{}, rhsNode *yaml.Node) error {
rhsCandidateNode := &CandidateNode{
Path: path,
Node: rhsNode,
}
func (d *dataTreeNavigator) DeeplyAssign(context Context, rhsCandidateNode *CandidateNode) error {
assignmentOp := &Operation{OperationType: assignOpType, Preferences: assignPreferences{}}
@ -36,7 +30,7 @@ func (d *dataTreeNavigator) DeeplyAssign(context Context, path []interface{}, rh
assignmentOpNode := &ExpressionNode{
Operation: assignmentOp,
LHS: createTraversalTree(path, traversePreferences{}, false),
LHS: createTraversalTree(rhsCandidateNode.Path, traversePreferences{}, false),
RHS: &ExpressionNode{Operation: rhsOp},
}

View File

@ -5,8 +5,6 @@ import (
"encoding/base64"
"io"
"strings"
yaml "gopkg.in/yaml.v3"
)
type base64Padder struct {
@ -70,11 +68,5 @@ func (dec *base64Decoder) Decode() (*CandidateNode, error) {
}
}
dec.readAnything = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: buf.String(),
},
}, nil
return createStringScalarNode(buf.String()), nil
}

View File

@ -6,7 +6,6 @@ import (
"io"
"github.com/dimchansky/utfbom"
yaml "gopkg.in/yaml.v3"
)
type csvObjectDecoder struct {
@ -28,7 +27,7 @@ func (dec *csvObjectDecoder) Init(reader io.Reader) error {
return nil
}
func (dec *csvObjectDecoder) convertToYamlNode(content string) *yaml.Node {
func (dec *csvObjectDecoder) convertToNode(content string) *CandidateNode {
node, err := parseSnippet(content)
if err != nil {
return createScalarNode(content, content)
@ -36,14 +35,14 @@ func (dec *csvObjectDecoder) convertToYamlNode(content string) *yaml.Node {
return node
}
func (dec *csvObjectDecoder) createObject(headerRow []string, contentRow []string) *yaml.Node {
objectNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
func (dec *csvObjectDecoder) createObject(headerRow []string, contentRow []string) *CandidateNode {
objectNode := &CandidateNode{Kind: MappingNode, Tag: "!!map"}
for i, header := range headerRow {
objectNode.Content = append(
objectNode.Content,
createScalarNode(header, header),
dec.convertToYamlNode(contentRow[i]))
dec.convertToNode(contentRow[i]))
}
return objectNode
}
@ -58,7 +57,7 @@ func (dec *csvObjectDecoder) Decode() (*CandidateNode, error) {
return nil, err
}
rootArray := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
rootArray := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"}
contentRow, err := dec.reader.Read()
@ -73,9 +72,7 @@ func (dec *csvObjectDecoder) Decode() (*CandidateNode, error) {
}
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{rootArray},
},
Kind: DocumentNode,
Content: []*CandidateNode{rootArray},
}, nil
}

View File

@ -8,7 +8,6 @@ import (
"strings"
"github.com/magiconair/properties"
"gopkg.in/yaml.v3"
)
type propertiesDecoder struct {
@ -52,16 +51,14 @@ func (dec *propertiesDecoder) applyPropertyComments(context Context, path []inte
assignmentOp := &Operation{OperationType: assignOpType, Preferences: assignPreferences{}}
rhsCandidateNode := &CandidateNode{
Path: path,
Node: &yaml.Node{
Tag: "!!str",
Value: fmt.Sprintf("%v", path[len(path)-1]),
HeadComment: dec.processComment(strings.Join(comments, "\n")),
Kind: yaml.ScalarNode,
},
Path: path,
Tag: "!!str",
Value: fmt.Sprintf("%v", path[len(path)-1]),
HeadComment: dec.processComment(strings.Join(comments, "\n")),
Kind: ScalarNode,
}
rhsCandidateNode.Node.Tag = guessTagFromCustomType(rhsCandidateNode.Node)
rhsCandidateNode.Tag = rhsCandidateNode.guessTagFromCustomType()
rhsOp := &Operation{OperationType: referenceOpType, CandidateNode: rhsCandidateNode}
@ -87,15 +84,11 @@ func (dec *propertiesDecoder) applyProperty(context Context, properties *propert
}
}
rhsNode := &yaml.Node{
Value: value,
Tag: "!!str",
Kind: yaml.ScalarNode,
}
rhsNode := createStringScalarNode(value)
rhsNode.Tag = rhsNode.guessTagFromCustomType()
rhsNode.Path = path
rhsNode.Tag = guessTagFromCustomType(rhsNode)
return dec.d.DeeplyAssign(context, path, rhsNode)
return dec.d.DeeplyAssign(context, rhsNode)
}
func (dec *propertiesDecoder) Decode() (*CandidateNode, error) {
@ -118,10 +111,8 @@ func (dec *propertiesDecoder) Decode() (*CandidateNode, error) {
properties.DisableExpansion = true
rootMap := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
Kind: MappingNode,
Tag: "!!map",
}
context := Context{}
@ -136,10 +127,8 @@ func (dec *propertiesDecoder) Decode() (*CandidateNode, error) {
dec.finished = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{rootMap.Node},
},
Kind: DocumentNode,
Content: []*CandidateNode{rootMap},
}, nil
}

View File

@ -11,7 +11,6 @@ import (
"time"
toml "github.com/pelletier/go-toml/v2/unstable"
yaml "gopkg.in/yaml.v3"
)
type tomlDecoder struct {
@ -37,10 +36,9 @@ func (dec *tomlDecoder) Init(reader io.Reader) error {
}
dec.parser.Reset(buf.Bytes())
dec.rootMap = &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
}}
Kind: MappingNode,
Tag: "!!map",
}
return nil
}
@ -64,10 +62,12 @@ func (dec *tomlDecoder) processKeyValueIntoMap(rootMap *CandidateNode, tomlNode
if err != nil {
return err
}
valueNode.Path = path
context := Context{}
context = context.SingleChildContext(rootMap)
return dec.d.DeeplyAssign(context, path, valueNode)
return dec.d.DeeplyAssign(context, valueNode)
}
func (dec *tomlDecoder) decodeKeyValuesIntoMap(rootMap *CandidateNode, tomlNode *toml.Node) (bool, error) {
@ -95,8 +95,8 @@ func (dec *tomlDecoder) decodeKeyValuesIntoMap(rootMap *CandidateNode, tomlNode
return false, nil
}
func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*yaml.Node, error) {
content := make([]*yaml.Node, 0)
func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*CandidateNode, error) {
content := make([]*CandidateNode, 0)
log.Debug("!! createInlineTableMap")
iterator := tomlNode.Children()
@ -107,28 +107,26 @@ func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*yaml.Node, e
}
keyValues := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
Kind: MappingNode,
Tag: "!!map",
}
if err := dec.processKeyValueIntoMap(keyValues, child); err != nil {
return nil, err
}
content = append(content, keyValues.Node.Content...)
content = append(content, keyValues.Content...)
}
return &yaml.Node{
Kind: yaml.MappingNode,
return &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: content,
}, nil
}
func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*yaml.Node, error) {
content := make([]*yaml.Node, 0)
func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*CandidateNode, error) {
content := make([]*CandidateNode, 0)
iterator := tomlNode.Children()
for iterator.Next() {
child := iterator.Node()
@ -139,43 +137,43 @@ func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*yaml.Node, error) {
content = append(content, yamlNode)
}
return &yaml.Node{
Kind: yaml.SequenceNode,
return &CandidateNode{
Kind: SequenceNode,
Tag: "!!seq",
Content: content,
}, nil
}
func (dec *tomlDecoder) createStringScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createStringScalar(tomlNode *toml.Node) (*CandidateNode, error) {
content := string(tomlNode.Data)
return createScalarNode(content, content), nil
}
func (dec *tomlDecoder) createBoolScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createBoolScalar(tomlNode *toml.Node) (*CandidateNode, error) {
content := string(tomlNode.Data)
return createScalarNode(content == "true", content), nil
}
func (dec *tomlDecoder) createIntegerScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createIntegerScalar(tomlNode *toml.Node) (*CandidateNode, error) {
content := string(tomlNode.Data)
_, num, err := parseInt64(content)
return createScalarNode(num, content), err
}
func (dec *tomlDecoder) createDateTimeScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createDateTimeScalar(tomlNode *toml.Node) (*CandidateNode, error) {
content := string(tomlNode.Data)
val, err := parseDateTime(time.RFC3339, content)
return createScalarNode(val, content), err
}
func (dec *tomlDecoder) createFloatScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createFloatScalar(tomlNode *toml.Node) (*CandidateNode, error) {
content := string(tomlNode.Data)
num, err := strconv.ParseFloat(content, 64)
return createScalarNode(num, content), err
}
func (dec *tomlDecoder) decodeNode(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) decodeNode(tomlNode *toml.Node) (*CandidateNode, error) {
switch tomlNode.Kind {
case toml.Key, toml.String:
return dec.createStringScalar(tomlNode)
@ -241,15 +239,13 @@ func (dec *tomlDecoder) Decode() (*CandidateNode, error) {
// must have finished
dec.finished = true
if len(dec.rootMap.Node.Content) == 0 {
if len(dec.rootMap.Content) == 0 {
return nil, io.EOF
}
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{dec.rootMap.Node},
},
Kind: DocumentNode,
Content: []*CandidateNode{dec.rootMap},
}, deferredError
}
@ -259,9 +255,9 @@ func (dec *tomlDecoder) processTopLevelNode(currentNode *toml.Node) (bool, error
var err error
log.Debug("!!!!!!!!!!!!Going to process %v state is current %v", currentNode.Kind, NodeToString(dec.rootMap))
if currentNode.Kind == toml.Table {
runAgainstCurrentExp, err = dec.processTable((currentNode))
runAgainstCurrentExp, err = dec.processTable(currentNode)
} else if currentNode.Kind == toml.ArrayTable {
runAgainstCurrentExp, err = dec.processArrayTable((currentNode))
runAgainstCurrentExp, err = dec.processArrayTable(currentNode)
} else {
runAgainstCurrentExp, err = dec.decodeKeyValuesIntoMap(dec.rootMap, currentNode)
}
@ -281,10 +277,9 @@ func (dec *tomlDecoder) processTable(currentNode *toml.Node) (bool, error) {
}
tableNodeValue := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
Kind: MappingNode,
Tag: "!!map",
Path: fullPath,
}
tableValue := dec.parser.Expression()
@ -301,21 +296,19 @@ func (dec *tomlDecoder) processTable(currentNode *toml.Node) (bool, error) {
c := Context{}
c = c.SingleChildContext(dec.rootMap)
err = dec.d.DeeplyAssign(c, fullPath, tableNodeValue.Node)
err = dec.d.DeeplyAssign(c, tableNodeValue)
if err != nil {
return false, err
}
return runAgainstCurrentExp, nil
}
func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode *yaml.Node) error {
func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode *CandidateNode) error {
rhsCandidateNode := &CandidateNode{
Path: path,
Node: &yaml.Node{
Kind: yaml.SequenceNode,
Tag: "!!seq",
Content: []*yaml.Node{rhsNode},
},
Path: path,
Kind: SequenceNode,
Tag: "!!seq",
Content: []*CandidateNode{rhsNode},
}
assignmentOp := &Operation{OperationType: addAssignOpType}
@ -346,10 +339,9 @@ func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error)
}
tableNodeValue := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
Kind: MappingNode,
Tag: "!!map",
Path: fullPath,
}
tableValue := dec.parser.Expression()
@ -363,7 +355,7 @@ func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error)
c = c.SingleChildContext(dec.rootMap)
// += function
err = dec.arrayAppend(c, fullPath, tableNodeValue.Node)
err = dec.arrayAppend(c, fullPath, tableNodeValue)
return runAgainstCurrentExp, err
}

View File

@ -130,44 +130,65 @@ func (dec *yamlDecoder) convertStyle(oStyle yaml.Style) Style {
return 0
}
func (dec *yamlDecoder) ConvertToCandidateNode(yamlNode *yaml.Node) *CandidateNode {
kids := make([]*CandidateNode, len(yamlNode.Content))
for i, v := range yamlNode.Content {
kids[i] = dec.ConvertToCandidateNode(v)
}
func (dec *yamlDecoder) ConvertToCandidateNode(parent *CandidateNode, path []interface{}, yamlNode *yaml.Node) *CandidateNode {
return &CandidateNode{
candidateNode := &CandidateNode{
Kind: dec.convertKind(yamlNode.Kind),
Style: dec.convertStyle(yamlNode.Style),
Tag: yamlNode.Tag,
Value: yamlNode.Value,
Anchor: yamlNode.Anchor,
Alias: dec.ConvertToCandidateNode(yamlNode.Alias),
Content: kids,
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: yamlNode.Parent,
// Key: yamlNode.Key,
Parent: parent,
// LeadingContent: yamlNode.LeadingContent,
// TrailingContent: yamlNode.TrailingContent,
// Path: yamlNode.Path,
// Document: yamlNode.Document,
// Filename: yamlNode.Filename,
Document: parent.Document,
Filename: parent.Filename,
Line: yamlNode.Line,
Column: yamlNode.Column,
// FileIndex: yamlNode.FileIndex,
// EvaluateTogether: yamlNode.EvaluateTogether,
// IsMapKey: yamlNode.IsMapKey,
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) {
@ -190,7 +211,7 @@ func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
return nil, err
}
candidateNode := dec.ConvertToCandidateNode(&dataBucket)
candidateNode := dec.ConvertToCandidateNode(&CandidateNode{}, make([]interface{}, 0), &dataBucket)
if dec.leadingContent != "" {
candidateNode.LeadingContent = dec.leadingContent

View File

@ -258,10 +258,10 @@ func guessTagFromCustomType(node *yaml.Node) string {
return guessedTag
}
func parseSnippet(value string) (*yaml.Node, error) {
func parseSnippet(value string) (*CandidateNode, error) {
if value == "" {
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!null",
}, nil
}
@ -274,10 +274,10 @@ func parseSnippet(value string) (*yaml.Node, error) {
if err != nil {
return nil, err
}
if len(parsedNode.Node.Content) == 0 {
if len(parsedNode.Content) == 0 {
return nil, fmt.Errorf("bad data")
}
result := unwrapDoc(parsedNode.Node)
result := parsedNode.unwrapDocument()
result.Line = 0
result.Column = 0
return result, err
@ -382,13 +382,6 @@ func parseInt(numberString string) (int, error) {
return int(parsed), err
}
func createStringScalarNode(stringValue string) *yaml.Node {
var node = &yaml.Node{Kind: yaml.ScalarNode}
node.Value = stringValue
node.Tag = "!!str"
return node
}
func headAndLineComment(node *yaml.Node) string {
return headComment(node) + lineComment(node)
}

View File

@ -5,7 +5,6 @@ import (
"fmt"
"github.com/elliotchance/orderedmap"
yaml "gopkg.in/yaml.v3"
)
type traversePreferences struct {
@ -17,7 +16,7 @@ type traversePreferences struct {
}
func splat(context Context, prefs traversePreferences) (Context, error) {
return traverseNodesWithArrayIndices(context, make([]*yaml.Node, 0), prefs)
return traverseNodesWithArrayIndices(context, make([]*CandidateNode, 0), prefs)
}
func traversePathOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
@ -37,39 +36,38 @@ func traversePathOperator(d *dataTreeNavigator, context Context, expressionNode
func traverse(context Context, matchingNode *CandidateNode, operation *Operation) (*list.List, error) {
log.Debug("Traversing %v", NodeToString(matchingNode))
value := matchingNode.Node
if value.Tag == "!!null" && operation.Value != "[]" && !context.DontAutoCreate {
if matchingNode.Tag == "!!null" && operation.Value != "[]" && !context.DontAutoCreate {
log.Debugf("Guessing kind")
// we must have added this automatically, lets guess what it should be now
switch operation.Value.(type) {
case int, int64:
log.Debugf("probably an array")
value.Kind = yaml.SequenceNode
matchingNode.Kind = SequenceNode
default:
log.Debugf("probably a map")
value.Kind = yaml.MappingNode
matchingNode.Kind = MappingNode
}
value.Tag = ""
matchingNode.Tag = ""
}
switch value.Kind {
case yaml.MappingNode:
log.Debug("its a map with %v entries", len(value.Content)/2)
switch matchingNode.Kind {
case MappingNode:
log.Debug("its a map with %v entries", len(matchingNode.Content)/2)
return traverseMap(context, matchingNode, createStringScalarNode(operation.StringValue), operation.Preferences.(traversePreferences), false)
case yaml.SequenceNode:
log.Debug("its a sequence of %v things!", len(value.Content))
case SequenceNode:
log.Debug("its a sequence of %v things!", len(matchingNode.Content))
return traverseArray(matchingNode, operation, operation.Preferences.(traversePreferences))
case yaml.AliasNode:
case AliasNode:
log.Debug("its an alias!")
matchingNode.Node = matchingNode.Node.Alias
matchingNode = matchingNode.Alias
return traverse(context, matchingNode, operation)
case yaml.DocumentNode:
case DocumentNode:
log.Debug("digging into doc node")
return traverse(context, matchingNode.CreateChildInMap(nil, matchingNode.Node.Content[0]), operation)
return traverse(context, matchingNode.Content[0], operation)
default:
return list.New(), nil
}
@ -103,7 +101,7 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode
if expressionNode.Operation.Preferences != nil {
prefs = expressionNode.Operation.Preferences.(traversePreferences)
}
var indicesToTraverse = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Content
var indicesToTraverse = rhs.MatchingNodes.Front().Value.(*CandidateNode).Content
log.Debugf("indicesToTraverse %v", len(indicesToTraverse))
@ -115,7 +113,7 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode
return context.ChildContext(result.MatchingNodes), nil
}
func traverseNodesWithArrayIndices(context Context, indicesToTraverse []*yaml.Node, prefs traversePreferences) (Context, error) {
func traverseNodesWithArrayIndices(context Context, indicesToTraverse []*CandidateNode, prefs traversePreferences) (Context, error) {
var matchingNodeMap = list.New()
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
@ -129,34 +127,33 @@ func traverseNodesWithArrayIndices(context Context, indicesToTraverse []*yaml.No
return context.ChildContext(matchingNodeMap), nil
}
func traverseArrayIndices(context Context, matchingNode *CandidateNode, indicesToTraverse []*yaml.Node, prefs traversePreferences) (*list.List, error) { // call this if doc / alias like the other traverse
node := matchingNode.Node
if node.Tag == "!!null" {
func traverseArrayIndices(context Context, matchingNode *CandidateNode, indicesToTraverse []*CandidateNode, prefs traversePreferences) (*list.List, error) { // call this if doc / alias like the other traverse
if matchingNode.Tag == "!!null" {
log.Debugf("OperatorArrayTraverse got a null - turning it into an empty array")
// auto vivification
node.Tag = ""
node.Kind = yaml.SequenceNode
matchingNode.Tag = ""
matchingNode.Kind = SequenceNode
//check that the indices are numeric, if not, then we should create an object
if len(indicesToTraverse) != 0 && indicesToTraverse[0].Tag != "!!int" {
node.Kind = yaml.MappingNode
matchingNode.Kind = MappingNode
}
}
if node.Kind == yaml.AliasNode {
matchingNode.Node = node.Alias
if matchingNode.Kind == AliasNode {
matchingNode = matchingNode.Alias
return traverseArrayIndices(context, matchingNode, indicesToTraverse, prefs)
} else if node.Kind == yaml.SequenceNode {
} else if matchingNode.Kind == SequenceNode {
return traverseArrayWithIndices(matchingNode, indicesToTraverse, prefs)
} else if node.Kind == yaml.MappingNode {
} else if matchingNode.Kind == MappingNode {
return traverseMapWithIndices(context, matchingNode, indicesToTraverse, prefs)
} else if node.Kind == yaml.DocumentNode {
return traverseArrayIndices(context, matchingNode.CreateChildInMap(nil, matchingNode.Node.Content[0]), indicesToTraverse, prefs)
} else if matchingNode.Kind == DocumentNode {
return traverseArrayIndices(context, matchingNode.Content[0], indicesToTraverse, prefs)
}
log.Debugf("OperatorArrayTraverse skipping %v as its a %v", matchingNode, node.Tag)
log.Debugf("OperatorArrayTraverse skipping %v as its a %v", matchingNode, matchingNode.Tag)
return list.New(), nil
}
func traverseMapWithIndices(context Context, candidate *CandidateNode, indices []*yaml.Node, prefs traversePreferences) (*list.List, error) {
func traverseMapWithIndices(context Context, candidate *CandidateNode, indices []*CandidateNode, prefs traversePreferences) (*list.List, error) {
if len(indices) == 0 {
return traverseMap(context, candidate, createStringScalarNode(""), prefs, true)
}
@ -175,15 +172,15 @@ func traverseMapWithIndices(context Context, candidate *CandidateNode, indices [
return matchingNodeMap, nil
}
func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node, prefs traversePreferences) (*list.List, error) {
func traverseArrayWithIndices(candidate *CandidateNode, indices []*CandidateNode, prefs traversePreferences) (*list.List, error) {
log.Debug("traverseArrayWithIndices")
var newMatches = list.New()
node := unwrapDoc(candidate.Node)
node := candidate.unwrapDocument()
if len(indices) == 0 {
log.Debug("splatting")
var index int
for index = 0; index < len(node.Content); index = index + 1 {
newMatches.PushBack(candidate.CreateChildInArray(index, node.Content[index]))
newMatches.PushBack(node.Content[index])
}
return newMatches, nil
@ -206,7 +203,7 @@ func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node, pr
node.Style = 0
}
node.Content = append(node.Content, &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"})
node.Content = append(node.Content, &CandidateNode{Tag: "!!null", Kind: ScalarNode, Value: "null"})
contentLength = len(node.Content)
}
@ -218,16 +215,16 @@ func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node, pr
return nil, fmt.Errorf("index [%v] out of range, array size is %v", index, contentLength)
}
newMatches.PushBack(candidate.CreateChildInArray(index, node.Content[indexToUse]))
newMatches.PushBack(node.Content[indexToUse])
}
return newMatches, nil
}
func keyMatches(key *yaml.Node, wantedKey string) bool {
func keyMatches(key *CandidateNode, wantedKey string) bool {
return matchKey(key.Value, wantedKey)
}
func traverseMap(context Context, matchingNode *CandidateNode, keyNode *yaml.Node, prefs traversePreferences, splat bool) (*list.List, error) {
func traverseMap(context Context, matchingNode *CandidateNode, keyNode *CandidateNode, prefs traversePreferences, splat bool) (*list.List, error) {
var newMatches = orderedmap.NewOrderedMap()
err := doTraverseMap(newMatches, matchingNode, keyNode.Value, prefs, splat)
@ -238,26 +235,21 @@ func traverseMap(context Context, matchingNode *CandidateNode, keyNode *yaml.Nod
if !splat && !prefs.DontAutoCreate && !context.DontAutoCreate && newMatches.Len() == 0 {
log.Debugf("no matches, creating one")
//no matches, create one automagically
valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"}
valueNode := &CandidateNode{Tag: "!!null", Kind: ScalarNode, Value: "null"}
node := matchingNode.Node
if len(node.Content) == 0 {
node.Style = 0
if len(matchingNode.Content) == 0 {
matchingNode.Style = 0
}
node.Content = append(node.Content, keyNode, valueNode)
matchingNode.Content = append(matchingNode.Content, keyNode, valueNode)
if prefs.IncludeMapKeys {
log.Debug("including key")
candidateNode := matchingNode.CreateChildInMap(keyNode, keyNode)
candidateNode.IsMapKey = true
newMatches.Set(fmt.Sprintf("keyOf-%v", candidateNode.GetKey()), candidateNode)
newMatches.Set(keyNode.GetKey(), keyNode)
}
if !prefs.DontIncludeMapValues {
log.Debug("including value")
candidateNode := matchingNode.CreateChildInMap(keyNode, valueNode)
newMatches.Set(candidateNode.GetKey(), candidateNode)
newMatches.Set(valueNode.GetKey(), valueNode)
}
}
@ -270,14 +262,12 @@ func traverseMap(context Context, matchingNode *CandidateNode, keyNode *yaml.Nod
return results, nil
}
func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, wantedKey string, prefs traversePreferences, splat bool) error {
func doTraverseMap(newMatches *orderedmap.OrderedMap, node *CandidateNode, wantedKey string, prefs traversePreferences, splat bool) error {
// value.Content is a concatenated array of key, value,
// so keys are in the even indices, values in odd.
// merge aliases are defined first, but we only want to traverse them
// if we don't find a match directly on this node first.
node := candidate.Node
var contents = node.Content
for index := 0; index < len(contents); index = index + 2 {
key := contents[index]
@ -287,7 +277,7 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode,
//skip the 'merge' tag, find a direct match first
if key.Tag == "!!merge" && !prefs.DontFollowAlias {
log.Debug("Merge anchor")
err := traverseMergeAnchor(newMatches, candidate, value, wantedKey, prefs, splat)
err := traverseMergeAnchor(newMatches, node, value, wantedKey, prefs, splat)
if err != nil {
return err
}
@ -295,14 +285,11 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode,
log.Debug("MATCHED")
if prefs.IncludeMapKeys {
log.Debug("including key")
candidateNode := candidate.CreateChildInMap(key, key)
candidateNode.IsMapKey = true
newMatches.Set(fmt.Sprintf("keyOf-%v", candidateNode.GetKey()), candidateNode)
newMatches.Set(key.GetKey(), key)
}
if !prefs.DontIncludeMapValues {
log.Debug("including value")
candidateNode := candidate.CreateChildInMap(key, value)
newMatches.Set(candidateNode.GetKey(), candidateNode)
newMatches.Set(value.GetKey(), value)
}
}
}
@ -310,15 +297,15 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode,
return nil
}
func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *CandidateNode, value *yaml.Node, wantedKey string, prefs traversePreferences, splat bool) error {
func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *CandidateNode, value *CandidateNode, wantedKey string, prefs traversePreferences, splat bool) error {
switch value.Kind {
case yaml.AliasNode:
if value.Alias.Kind != yaml.MappingNode {
case AliasNode:
if value.Alias.Kind != MappingNode {
return fmt.Errorf("can only use merge anchors with maps (!!map), but got %v", value.Alias.Tag)
}
candidateNode := originalCandidate.CreateReplacement(value.Alias)
return doTraverseMap(newMatches, candidateNode, wantedKey, prefs, splat)
case yaml.SequenceNode:
// candidateNode := originalCandidate.CreateReplacement(value.Alias)
return doTraverseMap(newMatches, value.Alias, wantedKey, prefs, splat)
case SequenceNode:
for _, childValue := range value.Content {
err := traverseMergeAnchor(newMatches, originalCandidate, childValue, wantedKey, prefs, splat)
if err != nil {
@ -331,6 +318,6 @@ func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *C
func traverseArray(candidate *CandidateNode, operation *Operation, prefs traversePreferences) (*list.List, error) {
log.Debug("operation Value %v", operation.Value)
indices := []*yaml.Node{{Value: operation.StringValue}}
indices := []*CandidateNode{{Value: operation.StringValue}}
return traverseArrayWithIndices(candidate, indices, prefs)
}

View File

@ -94,6 +94,30 @@ var tomlScenarios = []formatScenario{
expected: "person:\n name: hello\n address: 12 cat st\n",
scenarioType: "decode",
},
{
skipDoc: true,
description: "Parse: include key information",
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",
expression: ".person.name | key",
expected: "name\n",
scenarioType: "roundtrip",
},
{
skipDoc: true,
description: "Parse: include parent information",
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",
expression: ".person.name | parent",
expected: "person\n",
scenarioType: "decode",
},
{
skipDoc: true,
description: "Parse: include path information",
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",
expression: ".person.name | path",
expected: "- person\n- name\n",
scenarioType: "decode",
},
{
description: "Encode: Scalar",
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",