mirror of
				https://github.com/taigrr/yq
				synced 2025-01-18 04:53:17 -08: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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user