Repository: mikefarah/yq
Pull request #657 (2021-01-12 18:59:47)

added EvaluateNodes and EvaluateCandidateNodes to yqlib
In an attempt to reproduce v3 yqlib's  `Get`
```go
Yqlib.Get(rootNode *yaml.Node, path string) ([]*NodeContext, error)
```

Two functions have been added:
* `func EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error)`
* `func EvaluateCandidateNodes(expression string, inputCandidates *list.List) (*list.List, error)`


This attempts to address the feature suggested in https://github.com/mikefarah/yq/issues/640




Patch:
diff --git a/pkg/yqlib/candidate_node.go b/pkg/yqlib/candidate_node.go
index 89c40645..0fd2fe59 100644
--- a/pkg/yqlib/candidate_node.go
+++ b/pkg/yqlib/candidate_node.go
@@ -61,6 +61,7 @@ func (n *CandidateNode) UpdateFrom(other *CandidateNode) {
 	n.Node.Content = other.Node.Content
 	n.Node.Value = other.Node.Value
 	n.Node.Alias = other.Node.Alias
+	n.Node.Anchor = other.Node.Anchor
 }
 
 func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
diff --git a/pkg/yqlib/doc/Multiply.md b/pkg/yqlib/doc/Multiply.md
index 3fc98d53..87ea2d89 100644
--- a/pkg/yqlib/doc/Multiply.md
+++ b/pkg/yqlib/doc/Multiply.md
@@ -180,7 +180,7 @@ g: thongs
 f: *cat
 ```
 
-## Merge does not copy anchor names
+## Merge copies anchor names
 Given a sample.yml file of:
 ```yaml
 a:
@@ -197,7 +197,7 @@ yq eval '.c * .a' sample.yml
 will output
 ```yaml
 g: thongs
-c: frog
+c: &cat frog
 ```
 
 ## Merge with merge anchors
diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go
index 6fc0b168..2bab479e 100644
--- a/pkg/yqlib/lib.go
+++ b/pkg/yqlib/lib.go
@@ -166,6 +166,24 @@ func NodeToString(node *CandidateNode) string {
 	return fmt.Sprintf(`D%v, P%v, (%v)::%v`, node.Document, node.Path, tag, buf.String())
 }
 
+// EvaluateNodes takes an expression and one or more yaml nodes, returning a list of matching candidate nodes
+func EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) {
+	inputCandidates := list.New()
+	for _, node := range nodes {
+		inputCandidates.PushBack(&CandidateNode{Node: node})
+	}
+	return EvaluateCandidateNodes(expression, inputCandidates)
+}
+
+// EvaluateCandidateNodes takes an expression and list of candidate nodes, returning a list of matching candidate nodes
+func EvaluateCandidateNodes(expression string, inputCandidates *list.List) (*list.List, error) {
+	node, err := treeCreator.ParsePath(expression)
+	if err != nil {
+		return nil, err
+	}
+	return treeNavigator.GetMatchingNodes(inputCandidates, node)
+}
+
 func KindString(kind yaml.Kind) string {
 	switch kind {
 	case yaml.ScalarNode:


Test patch:
diff --git a/pkg/yqlib/lib_test.go b/pkg/yqlib/lib_test.go
new file mode 100644
index 00000000..b62ba39b
--- /dev/null
+++ b/pkg/yqlib/lib_test.go
@@ -0,0 +1,39 @@
+package yqlib
+
+import (
+	"testing"
+
+	"github.com/mikefarah/yq/v4/test"
+)
+
+var evaluateNodesScenario = []expressionScenario{
+	{
+		document:   `a: hello`,
+		expression: `.a`,
+		expected: []string{
+			"D0, P[a], (!!str)::hello\n",
+		},
+	},
+	{
+		document:   `a: hello`,
+		expression: `.`,
+		expected: []string{
+			"D0, P[], (doc)::a: hello\n",
+		},
+	},
+	{
+		document:   `- a: "yes"`,
+		expression: `.[] | has("a")`,
+		expected: []string{
+			"D0, P[0], (!!bool)::true\n",
+		},
+	},
+}
+
+func TestEvaluateNodesScenarios(t *testing.T) {
+	for _, tt := range evaluateNodesScenario {
+		node := test.ParseData(tt.document)
+		list, _ := EvaluateNodes(tt.expression, &node)
+		test.AssertResultComplex(t, tt.expected, resultsToString(list))
+	}
+}
diff --git a/pkg/yqlib/operator_multiply_test.go b/pkg/yqlib/operator_multiply_test.go
index d900c000..40819c3a 100644
--- a/pkg/yqlib/operator_multiply_test.go
+++ b/pkg/yqlib/operator_multiply_test.go
@@ -132,11 +132,11 @@ b:
 		},
 	},
 	{
-		description: "Merge does not copy anchor names",
+		description: "Merge copies anchor names",
 		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",
+			"D0, P[c], (!!map)::{g: thongs, c: &cat frog}\n",
 		},
 	},
 	{