mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
simple anchors
This commit is contained in:
parent
4edb3e9021
commit
643f2467ee
@ -31,6 +31,7 @@ func (n *CandidateNode) UpdateFrom(other *CandidateNode) {
|
||||
n.UpdateAttributesFrom(other)
|
||||
n.Node.Content = other.Node.Content
|
||||
n.Node.Value = other.Node.Value
|
||||
n.Node.Alias = other.Node.Alias
|
||||
}
|
||||
|
||||
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
|
||||
|
@ -49,8 +49,6 @@ var Select = &OperationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler:
|
||||
|
||||
var DeleteChild = &OperationType{Type: "DELETE", NumArgs: 2, Precedence: 40, Handler: DeleteChildOperator}
|
||||
|
||||
// var Splat = &OperationType{Type: "SPLAT", NumArgs: 0, Precedence: 40, Handler: SplatOperator}
|
||||
|
||||
// var Exists = &OperationType{Type: "Length", NumArgs: 2, Precedence: 35}
|
||||
// filters matches if they have the existing path
|
||||
|
||||
@ -59,6 +57,7 @@ type Operation struct {
|
||||
Value interface{}
|
||||
StringValue string
|
||||
CandidateNode *CandidateNode // used for Value Path elements
|
||||
Preferences interface{}
|
||||
}
|
||||
|
||||
func CreateValueOperation(value interface{}, stringValue string) *Operation {
|
||||
@ -132,6 +131,8 @@ func NodeToString(node *CandidateNode) string {
|
||||
tag := value.Tag
|
||||
if value.Kind == yaml.DocumentNode {
|
||||
tag = "doc"
|
||||
} else if value.Kind == yaml.AliasNode {
|
||||
tag = "alias"
|
||||
}
|
||||
return fmt.Sprintf(`D%v, P%v, (%v)::%v`, node.Document, node.Path, tag, buf.String())
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ func applyAssignment(d *dataTreeNavigator, pathIndexToStartFrom int, lhs *Candid
|
||||
lhsPath := rhs.Path[pathIndexToStartFrom:]
|
||||
|
||||
assignmentOp := &Operation{OperationType: AssignAttributes}
|
||||
if rhs.Node.Kind == yaml.ScalarNode {
|
||||
if rhs.Node.Kind == yaml.ScalarNode || rhs.Node.Kind == yaml.AliasNode {
|
||||
assignmentOp.OperationType = Assign
|
||||
}
|
||||
rhsOp := &Operation{OperationType: ValueOp, CandidateNode: rhs}
|
||||
|
@ -81,6 +81,20 @@ b:
|
||||
"D0, P[], (!!map)::{a: {c: cat}}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{a: &cat {c: frog}, b: {f: *cat}, c: {g: thongs}}`,
|
||||
expression: `.c * .b`,
|
||||
expected: []string{
|
||||
"D0, P[c], (!!map)::{g: thongs, f: *cat}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{a: {c: &cat frog}, b: {f: *cat}, c: {g: thongs}}`,
|
||||
expression: `.c * .a`,
|
||||
expected: []string{
|
||||
"D0, P[c], (!!map)::{g: thongs, c: frog}\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestMultiplyOperatorScenarios(t *testing.T) {
|
||||
|
@ -2,6 +2,8 @@ package treeops
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
@ -24,14 +26,17 @@ func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.Li
|
||||
log.Debugf("Recursive Decent, added %v", NodeToString(candidate))
|
||||
results.PushBack(candidate)
|
||||
|
||||
children, err := Splat(d, nodeToMap(candidate))
|
||||
if candidate.Node.Kind != yaml.AliasNode {
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = recursiveDecent(d, results, children)
|
||||
if err != nil {
|
||||
return err
|
||||
children, err := Splat(d, nodeToMap(candidate))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = recursiveDecent(d, results, children)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -50,6 +50,16 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
||||
"D0, P[2], (!!bool)::true\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||
expression: `..`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: &cat {c: frog}, b: *cat}\n",
|
||||
"D0, P[a], (!!map)::&cat {c: frog}\n",
|
||||
"D0, P[a c], (!!str)::frog\n",
|
||||
"D0, P[b], (alias)::*cat\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestRecursiveDescentOperatorScenarios(t *testing.T) {
|
||||
|
@ -8,8 +8,13 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type TraversePreferences struct {
|
||||
DontFollowAlias bool
|
||||
}
|
||||
|
||||
func Splat(d *dataTreeNavigator, matches *list.List) (*list.List, error) {
|
||||
splatOperation := &Operation{OperationType: TraversePath, Value: "[]"}
|
||||
preferences := &TraversePreferences{DontFollowAlias: true}
|
||||
splatOperation := &Operation{OperationType: TraversePath, Value: "[]", Preferences: preferences}
|
||||
splatTreeNode := &PathTreeNode{Operation: splatOperation}
|
||||
return TraversePathOperator(d, matches, splatTreeNode)
|
||||
}
|
||||
@ -33,14 +38,20 @@ func TraversePathOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *P
|
||||
return matchingNodeMap, nil
|
||||
}
|
||||
|
||||
func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, pathNode *Operation) ([]*CandidateNode, error) {
|
||||
func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, operation *Operation) ([]*CandidateNode, error) {
|
||||
log.Debug("Traversing %v", NodeToString(matchingNode))
|
||||
value := matchingNode.Node
|
||||
|
||||
if value.Tag == "!!null" && pathNode.Value != "[]" {
|
||||
followAlias := true
|
||||
|
||||
// if operation.Preferences != nil {
|
||||
// followAlias = !operation.Preferences.(*TraversePreferences).DontFollowAlias
|
||||
// }
|
||||
|
||||
if value.Tag == "!!null" && operation.Value != "[]" {
|
||||
log.Debugf("Guessing kind")
|
||||
// we must ahve added this automatically, lets guess what it should be now
|
||||
switch pathNode.Value.(type) {
|
||||
switch operation.Value.(type) {
|
||||
case int, int64:
|
||||
log.Debugf("probably an array")
|
||||
value.Kind = yaml.SequenceNode
|
||||
@ -54,33 +65,24 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, pathNode *Opera
|
||||
switch value.Kind {
|
||||
case yaml.MappingNode:
|
||||
log.Debug("its a map with %v entries", len(value.Content)/2)
|
||||
return traverseMap(matchingNode, pathNode)
|
||||
return traverseMap(matchingNode, operation)
|
||||
|
||||
case yaml.SequenceNode:
|
||||
log.Debug("its a sequence of %v things!", len(value.Content))
|
||||
return traverseArray(matchingNode, pathNode)
|
||||
// default:
|
||||
return traverseArray(matchingNode, operation)
|
||||
|
||||
// if head == "+" {
|
||||
// return n.appendArray(value, head, tail, pathStack)
|
||||
// } else if len(value.Content) == 0 && head == "**" {
|
||||
// return n.navigationStrategy.Visit(nodeContext)
|
||||
// }
|
||||
// return n.splatArray(value, head, tail, pathStack)
|
||||
// }
|
||||
// case yaml.AliasNode:
|
||||
// log.Debug("its an alias!")
|
||||
// DebugNode(value.Alias)
|
||||
// if n.navigationStrategy.FollowAlias(nodeContext) {
|
||||
// log.Debug("following the alias")
|
||||
// return n.recurse(value.Alias, head, tail, pathStack)
|
||||
// }
|
||||
// return nil
|
||||
case yaml.AliasNode:
|
||||
log.Debug("its an alias!")
|
||||
if followAlias {
|
||||
matchingNode.Node = matchingNode.Node.Alias
|
||||
return traverse(d, matchingNode, operation)
|
||||
}
|
||||
return []*CandidateNode{matchingNode}, nil
|
||||
case yaml.DocumentNode:
|
||||
log.Debug("digging into doc node")
|
||||
return traverse(d, &CandidateNode{
|
||||
Node: matchingNode.Node.Content[0],
|
||||
Document: matchingNode.Document}, pathNode)
|
||||
Document: matchingNode.Document}, operation)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -83,6 +83,27 @@ var traversePathOperatorScenarios = []expressionScenario{
|
||||
"D0, P[a mad], (!!str)::things\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||
expression: `.b`,
|
||||
expected: []string{
|
||||
"D0, P[b], (alias)::*cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||
expression: `.b.[]`,
|
||||
expected: []string{
|
||||
"D0, P[b c], (!!str)::frog\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||
expression: `.b.c`,
|
||||
expected: []string{
|
||||
"D0, P[b c], (!!str)::frog\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestTraversePathOperatorScenarios(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user