Extracted out is path expression checking logic

This commit is contained in:
Mike Farah 2020-01-11 19:30:27 +11:00
parent 2d237e7e8e
commit 35fd5b7ae4
8 changed files with 21 additions and 9 deletions

View File

@ -2,7 +2,6 @@ package yqlib
import ( import (
"strconv" "strconv"
"strings"
errors "github.com/pkg/errors" errors "github.com/pkg/errors"
yaml "gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"
@ -70,7 +69,7 @@ func (n *navigator) recurse(value *yaml.Node, head string, tail []string, pathSt
return n.recurseMap(value, head, tail, pathStack) return n.recurseMap(value, head, tail, pathStack)
case yaml.SequenceNode: case yaml.SequenceNode:
log.Debug("its a sequence of %v things!", len(value.Content)) log.Debug("its a sequence of %v things!", len(value.Content))
if head == "*" || head == "**" || strings.Contains(head, "==") { if n.navigationStrategy.GetPathParser().IsPathExpression(head) {
return n.splatArray(value, head, tail, pathStack) return n.splatArray(value, head, tail, pathStack)
} else if head == "+" { } else if head == "+" {
return n.appendArray(value, head, tail, pathStack) return n.appendArray(value, head, tail, pathStack)
@ -117,7 +116,7 @@ func (n *navigator) recurseMap(value *yaml.Node, head string, tail []string, pat
return errorVisiting return errorVisiting
} }
if traversedEntry || head == "*" || head == "**" || !n.navigationStrategy.AutoCreateMap(NewNodeContext(value, head, tail, pathStack)) { if traversedEntry || n.navigationStrategy.GetPathParser().IsPathExpression(head) || !n.navigationStrategy.AutoCreateMap(NewNodeContext(value, head, tail, pathStack)) {
return nil return nil
} }

View File

@ -10,6 +10,7 @@ func DeleteNavigationStrategy(pathElementToDelete string) NavigationStrategy {
parser := NewPathParser() parser := NewPathParser()
return &NavigationStrategyImpl{ return &NavigationStrategyImpl{
visitedNodes: []*NodeContext{}, visitedNodes: []*NodeContext{},
pathParser: parser,
followAlias: func(nodeContext NodeContext) bool { followAlias: func(nodeContext NodeContext) bool {
return false return false
}, },

View File

@ -3,6 +3,7 @@ package yqlib
func FilterMatchingNodesNavigationStrategy(value string) NavigationStrategy { func FilterMatchingNodesNavigationStrategy(value string) NavigationStrategy {
return &NavigationStrategyImpl{ return &NavigationStrategyImpl{
visitedNodes: []*NodeContext{}, visitedNodes: []*NodeContext{},
pathParser: NewPathParser(),
followAlias: func(nodeContext NodeContext) bool { followAlias: func(nodeContext NodeContext) bool {
return true return true
}, },

View File

@ -74,7 +74,8 @@ func guessKind(head string, tail []string, guess yaml.Kind) yaml.Kind {
if tail[0] == "+" || errorParsingInt == nil { if tail[0] == "+" || errorParsingInt == nil {
return yaml.SequenceNode return yaml.SequenceNode
} }
if (tail[0] == "*" || tail[0] == "**" || head == "**") && (guess == yaml.SequenceNode || guess == yaml.MappingNode) { pathParser := NewPathParser()
if (pathParser.IsPathExpression(tail[0]) || head == "**") && (guess == yaml.SequenceNode || guess == yaml.MappingNode) {
return guess return guess
} }
if guess == yaml.AliasNode { if guess == yaml.AliasNode {

View File

@ -36,6 +36,7 @@ type NavigationStrategy interface {
ShouldTraverse(nodeContext NodeContext, nodeKey string) bool ShouldTraverse(nodeContext NodeContext, nodeKey string) bool
GetVisitedNodes() []*NodeContext GetVisitedNodes() []*NodeContext
DebugVisitedNodes() DebugVisitedNodes()
GetPathParser() PathParser
} }
type NavigationStrategyImpl struct { type NavigationStrategyImpl struct {
@ -44,6 +45,11 @@ type NavigationStrategyImpl struct {
visit func(nodeContext NodeContext) error visit func(nodeContext NodeContext) error
shouldVisitExtraFn func(nodeContext NodeContext) bool shouldVisitExtraFn func(nodeContext NodeContext) bool
visitedNodes []*NodeContext visitedNodes []*NodeContext
pathParser PathParser
}
func (ns *NavigationStrategyImpl) GetPathParser() PathParser {
return ns.pathParser
} }
func (ns *NavigationStrategyImpl) GetVisitedNodes() []*NodeContext { func (ns *NavigationStrategyImpl) GetVisitedNodes() []*NodeContext {
@ -68,10 +74,8 @@ func (ns *NavigationStrategyImpl) ShouldTraverse(nodeContext NodeContext, nodeKe
return false return false
} }
parser := NewPathParser()
return (nodeKey == "<<" && ns.FollowAlias(nodeContext)) || (nodeKey != "<<" && return (nodeKey == "<<" && ns.FollowAlias(nodeContext)) || (nodeKey != "<<" &&
parser.MatchesNextPathElement(nodeContext, nodeKey)) ns.pathParser.MatchesNextPathElement(nodeContext, nodeKey))
} }
func (ns *NavigationStrategyImpl) shouldVisit(nodeContext NodeContext) bool { func (ns *NavigationStrategyImpl) shouldVisit(nodeContext NodeContext) bool {
@ -88,11 +92,10 @@ func (ns *NavigationStrategyImpl) shouldVisit(nodeContext NodeContext) bool {
nodeKey := fmt.Sprintf("%v", pathStack[len(pathStack)-1]) nodeKey := fmt.Sprintf("%v", pathStack[len(pathStack)-1])
log.Debug("nodeKey: %v, nodeContext.Head: %v", nodeKey, nodeContext.Head) log.Debug("nodeKey: %v, nodeContext.Head: %v", nodeKey, nodeContext.Head)
parser := NewPathParser()
// only visit aliases if its an exact match // only visit aliases if its an exact match
return ((nodeKey == "<<" && nodeContext.Head == "<<") || (nodeKey != "<<" && return ((nodeKey == "<<" && nodeContext.Head == "<<") || (nodeKey != "<<" &&
parser.MatchesNextPathElement(nodeContext, nodeKey))) && (ns.shouldVisitExtraFn == nil || ns.shouldVisitExtraFn(nodeContext)) ns.pathParser.MatchesNextPathElement(nodeContext, nodeKey))) && (ns.shouldVisitExtraFn == nil || ns.shouldVisitExtraFn(nodeContext))
} }
func (ns *NavigationStrategyImpl) Visit(nodeContext NodeContext) error { func (ns *NavigationStrategyImpl) Visit(nodeContext NodeContext) error {

View File

@ -8,6 +8,7 @@ import (
type PathParser interface { type PathParser interface {
ParsePath(path string) []string ParsePath(path string) []string
MatchesNextPathElement(nodeContext NodeContext, nodeKey string) bool MatchesNextPathElement(nodeContext NodeContext, nodeKey string) bool
IsPathExpression(pathElement string) bool
} }
type pathParser struct{} type pathParser struct{}
@ -16,6 +17,10 @@ func NewPathParser() PathParser {
return &pathParser{} return &pathParser{}
} }
func (p *pathParser) IsPathExpression(pathElement string) bool {
return pathElement == "*" || pathElement == "**" || strings.Contains(pathElement, "==")
}
/** /**
* node: node that we may traverse/visit * node: node that we may traverse/visit
* head: path element expression to match against * head: path element expression to match against

View File

@ -3,6 +3,7 @@ package yqlib
func ReadNavigationStrategy() NavigationStrategy { func ReadNavigationStrategy() NavigationStrategy {
return &NavigationStrategyImpl{ return &NavigationStrategyImpl{
visitedNodes: []*NodeContext{}, visitedNodes: []*NodeContext{},
pathParser: NewPathParser(),
followAlias: func(nodeContext NodeContext) bool { followAlias: func(nodeContext NodeContext) bool {
return true return true
}, },

View File

@ -3,6 +3,7 @@ package yqlib
func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) NavigationStrategy { func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) NavigationStrategy {
return &NavigationStrategyImpl{ return &NavigationStrategyImpl{
visitedNodes: []*NodeContext{}, visitedNodes: []*NodeContext{},
pathParser: NewPathParser(),
followAlias: func(nodeContext NodeContext) bool { followAlias: func(nodeContext NodeContext) bool {
return false return false
}, },