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.UpdateAttributesFrom(other)
|
||||||
n.Node.Content = other.Node.Content
|
n.Node.Content = other.Node.Content
|
||||||
n.Node.Value = other.Node.Value
|
n.Node.Value = other.Node.Value
|
||||||
|
n.Node.Alias = other.Node.Alias
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
|
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 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}
|
// var Exists = &OperationType{Type: "Length", NumArgs: 2, Precedence: 35}
|
||||||
// filters matches if they have the existing path
|
// filters matches if they have the existing path
|
||||||
|
|
||||||
@ -59,6 +57,7 @@ type Operation struct {
|
|||||||
Value interface{}
|
Value interface{}
|
||||||
StringValue string
|
StringValue string
|
||||||
CandidateNode *CandidateNode // used for Value Path elements
|
CandidateNode *CandidateNode // used for Value Path elements
|
||||||
|
Preferences interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateValueOperation(value interface{}, stringValue string) *Operation {
|
func CreateValueOperation(value interface{}, stringValue string) *Operation {
|
||||||
@ -132,6 +131,8 @@ func NodeToString(node *CandidateNode) string {
|
|||||||
tag := value.Tag
|
tag := value.Tag
|
||||||
if value.Kind == yaml.DocumentNode {
|
if value.Kind == yaml.DocumentNode {
|
||||||
tag = "doc"
|
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())
|
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:]
|
lhsPath := rhs.Path[pathIndexToStartFrom:]
|
||||||
|
|
||||||
assignmentOp := &Operation{OperationType: AssignAttributes}
|
assignmentOp := &Operation{OperationType: AssignAttributes}
|
||||||
if rhs.Node.Kind == yaml.ScalarNode {
|
if rhs.Node.Kind == yaml.ScalarNode || rhs.Node.Kind == yaml.AliasNode {
|
||||||
assignmentOp.OperationType = Assign
|
assignmentOp.OperationType = Assign
|
||||||
}
|
}
|
||||||
rhsOp := &Operation{OperationType: ValueOp, CandidateNode: rhs}
|
rhsOp := &Operation{OperationType: ValueOp, CandidateNode: rhs}
|
||||||
|
@ -81,6 +81,20 @@ b:
|
|||||||
"D0, P[], (!!map)::{a: {c: cat}}\n",
|
"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) {
|
func TestMultiplyOperatorScenarios(t *testing.T) {
|
||||||
|
@ -2,6 +2,8 @@ package treeops
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
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))
|
log.Debugf("Recursive Decent, added %v", NodeToString(candidate))
|
||||||
results.PushBack(candidate)
|
results.PushBack(candidate)
|
||||||
|
|
||||||
children, err := Splat(d, nodeToMap(candidate))
|
if candidate.Node.Kind != yaml.AliasNode {
|
||||||
|
|
||||||
if err != nil {
|
children, err := Splat(d, nodeToMap(candidate))
|
||||||
return err
|
|
||||||
}
|
if err != nil {
|
||||||
err = recursiveDecent(d, results, children)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
err = recursiveDecent(d, results, children)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -50,6 +50,16 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[2], (!!bool)::true\n",
|
"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) {
|
func TestRecursiveDescentOperatorScenarios(t *testing.T) {
|
||||||
|
@ -8,8 +8,13 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TraversePreferences struct {
|
||||||
|
DontFollowAlias bool
|
||||||
|
}
|
||||||
|
|
||||||
func Splat(d *dataTreeNavigator, matches *list.List) (*list.List, error) {
|
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}
|
splatTreeNode := &PathTreeNode{Operation: splatOperation}
|
||||||
return TraversePathOperator(d, matches, splatTreeNode)
|
return TraversePathOperator(d, matches, splatTreeNode)
|
||||||
}
|
}
|
||||||
@ -33,14 +38,20 @@ func TraversePathOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *P
|
|||||||
return matchingNodeMap, nil
|
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))
|
log.Debug("Traversing %v", NodeToString(matchingNode))
|
||||||
value := matchingNode.Node
|
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")
|
log.Debugf("Guessing kind")
|
||||||
// we must ahve added this automatically, lets guess what it should be now
|
// we must ahve added this automatically, lets guess what it should be now
|
||||||
switch pathNode.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
|
value.Kind = yaml.SequenceNode
|
||||||
@ -54,33 +65,24 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, pathNode *Opera
|
|||||||
switch value.Kind {
|
switch value.Kind {
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
log.Debug("its a map with %v entries", len(value.Content)/2)
|
log.Debug("its a map with %v entries", len(value.Content)/2)
|
||||||
return traverseMap(matchingNode, pathNode)
|
return traverseMap(matchingNode, operation)
|
||||||
|
|
||||||
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))
|
||||||
return traverseArray(matchingNode, pathNode)
|
return traverseArray(matchingNode, operation)
|
||||||
// default:
|
|
||||||
|
|
||||||
// if head == "+" {
|
case yaml.AliasNode:
|
||||||
// return n.appendArray(value, head, tail, pathStack)
|
log.Debug("its an alias!")
|
||||||
// } else if len(value.Content) == 0 && head == "**" {
|
if followAlias {
|
||||||
// return n.navigationStrategy.Visit(nodeContext)
|
matchingNode.Node = matchingNode.Node.Alias
|
||||||
// }
|
return traverse(d, matchingNode, operation)
|
||||||
// return n.splatArray(value, head, tail, pathStack)
|
}
|
||||||
// }
|
return []*CandidateNode{matchingNode}, nil
|
||||||
// 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.DocumentNode:
|
case yaml.DocumentNode:
|
||||||
log.Debug("digging into doc node")
|
log.Debug("digging into doc node")
|
||||||
return traverse(d, &CandidateNode{
|
return traverse(d, &CandidateNode{
|
||||||
Node: matchingNode.Node.Content[0],
|
Node: matchingNode.Node.Content[0],
|
||||||
Document: matchingNode.Document}, pathNode)
|
Document: matchingNode.Document}, operation)
|
||||||
default:
|
default:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,27 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a mad], (!!str)::things\n",
|
"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) {
|
func TestTraversePathOperatorScenarios(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user