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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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