mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Added to_entries op
This commit is contained in:
parent
ae4b606707
commit
77630ca179
37
pkg/yqlib/doc/Entries.md
Normal file
37
pkg/yqlib/doc/Entries.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
## to_entries Map
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: 1
|
||||||
|
b: 2
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'to_entries' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- key: a
|
||||||
|
value: 1
|
||||||
|
- key: b
|
||||||
|
value: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## to_entries Array
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'to_entries' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- key: 0
|
||||||
|
value: a
|
||||||
|
- key: 1
|
||||||
|
value: b
|
||||||
|
```
|
||||||
|
|
@ -278,6 +278,7 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`fileIndex`), opToken(getFileIndexOpType))
|
lexer.Add([]byte(`fileIndex`), opToken(getFileIndexOpType))
|
||||||
lexer.Add([]byte(`fi`), opToken(getFileIndexOpType))
|
lexer.Add([]byte(`fi`), opToken(getFileIndexOpType))
|
||||||
lexer.Add([]byte(`path`), opToken(getPathOpType))
|
lexer.Add([]byte(`path`), opToken(getPathOpType))
|
||||||
|
lexer.Add([]byte(`to_entries`), opToken(toEntriesOpType))
|
||||||
|
|
||||||
lexer.Add([]byte(`lineComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{LineComment: true}))
|
lexer.Add([]byte(`lineComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{LineComment: true}))
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence:
|
|||||||
|
|
||||||
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
|
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
|
||||||
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: collectOperator}
|
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: collectOperator}
|
||||||
|
var toEntriesOpType = &operationType{Type: "TO_ENTRIES", NumArgs: 0, Precedence: 50, Handler: toEntriesOperator}
|
||||||
var splitDocumentOpType = &operationType{Type: "SPLIT_DOC", NumArgs: 0, Precedence: 50, Handler: splitDocumentOperator}
|
var splitDocumentOpType = &operationType{Type: "SPLIT_DOC", NumArgs: 0, Precedence: 50, Handler: splitDocumentOperator}
|
||||||
var getVariableOpType = &operationType{Type: "GET_VARIABLE", NumArgs: 0, Precedence: 55, Handler: getVariableOperator}
|
var getVariableOpType = &operationType{Type: "GET_VARIABLE", NumArgs: 0, Precedence: 55, Handler: getVariableOperator}
|
||||||
var getStyleOpType = &operationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: getStyleOperator}
|
var getStyleOpType = &operationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: getStyleOperator}
|
||||||
|
67
pkg/yqlib/operator_entries.go
Normal file
67
pkg/yqlib/operator_entries.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func entrySeqFor(key *yaml.Node, value *yaml.Node) *yaml.Node {
|
||||||
|
var keyKey = &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "key"}
|
||||||
|
var valueKey = &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "value"}
|
||||||
|
|
||||||
|
return &yaml.Node{
|
||||||
|
Kind: yaml.MappingNode,
|
||||||
|
Tag: "!!map",
|
||||||
|
Content: []*yaml.Node{keyKey, key, valueKey, value},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toEntriesFromMap(candidateNode *CandidateNode) *CandidateNode {
|
||||||
|
var sequence = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
||||||
|
var entriesNode = candidateNode.CreateChild(nil, sequence)
|
||||||
|
|
||||||
|
var contents = unwrapDoc(candidateNode.Node).Content
|
||||||
|
for index := 0; index < len(contents); index = index + 2 {
|
||||||
|
key := contents[index]
|
||||||
|
value := contents[index+1]
|
||||||
|
|
||||||
|
sequence.Content = append(sequence.Content, entrySeqFor(key, value))
|
||||||
|
}
|
||||||
|
return entriesNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func toEntriesfromSeq(candidateNode *CandidateNode) *CandidateNode {
|
||||||
|
var sequence = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
|
||||||
|
var entriesNode = candidateNode.CreateChild(nil, sequence)
|
||||||
|
|
||||||
|
var contents = unwrapDoc(candidateNode.Node).Content
|
||||||
|
for index := 0; index < len(contents); index = index + 1 {
|
||||||
|
key := &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%v", index)}
|
||||||
|
value := contents[index]
|
||||||
|
|
||||||
|
sequence.Content = append(sequence.Content, entrySeqFor(key, value))
|
||||||
|
}
|
||||||
|
return entriesNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func toEntriesOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
var results = list.New()
|
||||||
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
candidateNode := unwrapDoc(candidate.Node)
|
||||||
|
|
||||||
|
switch candidateNode.Kind {
|
||||||
|
case yaml.MappingNode:
|
||||||
|
results.PushBack(toEntriesFromMap(candidate))
|
||||||
|
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
results.PushBack(toEntriesfromSeq(candidate))
|
||||||
|
default:
|
||||||
|
return Context{}, fmt.Errorf("%v has no keys", candidate.Node.Tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.ChildContext(results), nil
|
||||||
|
|
||||||
|
}
|
31
pkg/yqlib/operator_entries_test.go
Normal file
31
pkg/yqlib/operator_entries_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var entriesOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "to_entries Map",
|
||||||
|
document: `{a: 1, b: 2}`,
|
||||||
|
expression: `to_entries`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::- key: a\n value: 1\n- key: b\n value: 2\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "to_entries Array",
|
||||||
|
document: `[a, b]`,
|
||||||
|
expression: `to_entries`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::- key: 0\n value: a\n- key: 1\n value: b\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEntriesOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range entriesOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Entries", entriesOperatorScenarios)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user