Added kind operator

This commit is contained in:
Mike Farah 2023-10-02 14:43:12 +11:00
parent a198f72367
commit ee900ec997
5 changed files with 167 additions and 0 deletions

View File

@ -0,0 +1,77 @@
## Get kind
Given a sample.yml file of:
```yaml
a: cat
b: 5
c: 3.2
e: true
f: []
g: {}
h: null
```
then
```bash
yq '.. | kind' sample.yml
```
will output
```yaml
map
scalar
scalar
scalar
scalar
seq
map
scalar
```
## Get kind, ignores custom tags
Unlike tag, kind is not affected by custom tags.
Given a sample.yml file of:
```yaml
a: !!thing cat
b: !!foo {}
c: !!bar []
```
then
```bash
yq '.. | kind' sample.yml
```
will output
```yaml
map
scalar
map
seq
```
## Add comments only to scalars
An example of how you can use kind
Given a sample.yml file of:
```yaml
a:
b: 5
c: 3.2
e: true
f: []
g: {}
h: null
```
then
```bash
yq '(.. | select(kind == "scalar")) line_comment = "this is a scalar"' sample.yml
```
will output
```yaml
a:
b: 5 # this is a scalar
c: 3.2 # this is a scalar
e: true # this is a scalar
f: []
g: {}
h: null # this is a scalar
```

View File

@ -152,6 +152,7 @@ var participleYqRules = []*participleYqRule{
assignableOp("style", getStyleOpType, assignStyleOpType), assignableOp("style", getStyleOpType, assignStyleOpType),
assignableOp("tag|type", getTagOpType, assignTagOpType), assignableOp("tag|type", getTagOpType, assignTagOpType),
simpleOp("kind", getKindOpType),
assignableOp("anchor", getAnchorOpType, assignAnchorOpType), assignableOp("anchor", getAnchorOpType, assignAnchorOpType),
assignableOp("alias", getAliasOpType, assignAliasOpType), assignableOp("alias", getAliasOpType, assignAliasOpType),

View File

@ -120,6 +120,7 @@ var splitDocumentOpType = &operationType{Type: "SPLIT_DOC", NumArgs: 0, Preceden
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}
var getTagOpType = &operationType{Type: "GET_TAG", NumArgs: 0, Precedence: 50, Handler: getTagOperator} var getTagOpType = &operationType{Type: "GET_TAG", NumArgs: 0, Precedence: 50, Handler: getTagOperator}
var getKindOpType = &operationType{Type: "GET_KIND", NumArgs: 0, Precedence: 50, Handler: getKindOperator}
var getKeyOpType = &operationType{Type: "GET_KEY", NumArgs: 0, Precedence: 50, Handler: getKeyOperator} var getKeyOpType = &operationType{Type: "GET_KEY", NumArgs: 0, Precedence: 50, Handler: getKeyOperator}
var isKeyOpType = &operationType{Type: "IS_KEY", NumArgs: 0, Precedence: 50, Handler: isKeyOperator} var isKeyOpType = &operationType{Type: "IS_KEY", NumArgs: 0, Precedence: 50, Handler: isKeyOperator}

View File

@ -0,0 +1,39 @@
package yqlib
import (
"container/list"
yaml "gopkg.in/yaml.v3"
)
func kindToText(kind yaml.Kind) string {
switch kind {
case yaml.MappingNode:
return "map"
case yaml.SequenceNode:
return "seq"
case yaml.DocumentNode:
return "doc"
case yaml.ScalarNode:
return "scalar"
case yaml.AliasNode:
return "alias"
default:
return "unknown"
}
}
func getKindOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("GetKindOperator")
var results = list.New()
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
node := &yaml.Node{Kind: yaml.ScalarNode, Value: kindToText(candidate.Node.Kind), Tag: "!!str"}
result := candidate.CreateReplacement(node)
results.PushBack(result)
}
return context.ChildContext(results), nil
}

View File

@ -0,0 +1,49 @@
package yqlib
import (
"testing"
)
var kindOperatorScenarios = []expressionScenario{
{
description: "Get kind",
document: `{a: cat, b: 5, c: 3.2, e: true, f: [], g: {}, h: null}`,
expression: `.. | kind`,
expected: []string{
"D0, P[], (!!str)::map\n",
"D0, P[a], (!!str)::scalar\n",
"D0, P[b], (!!str)::scalar\n",
"D0, P[c], (!!str)::scalar\n",
"D0, P[e], (!!str)::scalar\n",
"D0, P[f], (!!str)::seq\n",
"D0, P[g], (!!str)::map\n",
"D0, P[h], (!!str)::scalar\n",
},
},
{
description: "Get kind, ignores custom tags",
subdescription: "Unlike tag, kind is not affected by custom tags.",
document: `{a: !!thing cat, b: !!foo {}, c: !!bar []}`,
expression: `.. | kind`,
expected: []string{
"D0, P[], (!!str)::map\n",
"D0, P[a], (!!str)::scalar\n",
"D0, P[b], (!!str)::map\n",
"D0, P[c], (!!str)::seq\n",
},
},
{
description: "Add comments only to scalars",
subdescription: "An example of how you can use kind",
document: "a:\n b: 5\n c: 3.2\ne: true\nf: []\ng: {}\nh: null",
expression: `(.. | select(kind == "scalar")) line_comment = "this is a scalar"`,
expected: []string{"D0, P[], (!!map)::a:\n b: 5 # this is a scalar\n c: 3.2 # this is a scalar\ne: true # this is a scalar\nf: []\ng: {}\nh: null # this is a scalar\n"},
},
}
func TestKindOperatorScenarios(t *testing.T) {
for _, tt := range kindOperatorScenarios {
testScenario(t, &tt)
}
documentOperatorScenarios(t, "kind", kindOperatorScenarios)
}