mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-13 22:38:04 +00:00
Added line and column operators
This commit is contained in:
parent
ff047d0748
commit
8698433d44
66
pkg/yqlib/doc/operators/column.md
Normal file
66
pkg/yqlib/doc/operators/column.md
Normal file
@ -0,0 +1,66 @@
|
||||
# Column
|
||||
|
||||
Returns the column of the matching node. Starts from 1, 0 indicates there was no column data.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Returns column of _value_ node
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
b: bob
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.b | column' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
4
|
||||
```
|
||||
|
||||
## Returns column of _key_ node
|
||||
Pipe through the key operator to get the column of the key
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
b: bob
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.b | key | column' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
1
|
||||
```
|
||||
|
||||
## First column is 1
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a | key | column' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
1
|
||||
```
|
||||
|
||||
## No column data is 0
|
||||
Running
|
||||
```bash
|
||||
yq --null-input '{"a": "new entry"} | column'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
0
|
||||
```
|
||||
|
3
pkg/yqlib/doc/operators/headers/column.md
Normal file
3
pkg/yqlib/doc/operators/headers/column.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Column
|
||||
|
||||
Returns the column of the matching node. Starts from 1, 0 indicates there was no column data.
|
3
pkg/yqlib/doc/operators/headers/line.md
Normal file
3
pkg/yqlib/doc/operators/headers/line.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Line
|
||||
|
||||
Returns the line of the matching node. Starts from 1, 0 indicates there was no line data.
|
68
pkg/yqlib/doc/operators/line.md
Normal file
68
pkg/yqlib/doc/operators/line.md
Normal file
@ -0,0 +1,68 @@
|
||||
# Line
|
||||
|
||||
Returns the line of the matching node. Starts from 1, 0 indicates there was no line data.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Returns line of _value_ node
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
b:
|
||||
c: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.b | line' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
3
|
||||
```
|
||||
|
||||
## Returns line of _key_ node
|
||||
Pipe through the key operator to get the line of the key
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
b:
|
||||
c: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.b | key| line' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
2
|
||||
```
|
||||
|
||||
## First line is 1
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a | line' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
1
|
||||
```
|
||||
|
||||
## No line data is 0
|
||||
Running
|
||||
```bash
|
||||
yq --null-input '{"a": "new entry"} | line'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
0
|
||||
```
|
||||
|
@ -315,6 +315,8 @@ func initLexer() (*lex.Lexer, error) {
|
||||
lexer.Add([]byte(`,`), opToken(unionOpType))
|
||||
lexer.Add([]byte(`:\s*`), opToken(createMapOpType))
|
||||
lexer.Add([]byte(`length`), opToken(lengthOpType))
|
||||
lexer.Add([]byte(`line`), opToken(lineOpType))
|
||||
lexer.Add([]byte(`column`), opToken(columnOpType))
|
||||
|
||||
lexer.Add([]byte(`eval`), opToken(evalOpType))
|
||||
|
||||
|
@ -80,6 +80,9 @@ var createMapOpType = &operationType{Type: "CREATE_MAP", NumArgs: 2, Precedence:
|
||||
var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence: 45, Handler: pipeOperator}
|
||||
|
||||
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
|
||||
var lineOpType = &operationType{Type: "LINE", NumArgs: 0, Precedence: 50, Handler: lineOperator}
|
||||
var columnOpType = &operationType{Type: "LINE", NumArgs: 0, Precedence: 50, Handler: columnOperator}
|
||||
|
||||
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator}
|
||||
var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler: mapOperator}
|
||||
var evalOpType = &operationType{Type: "EVAL", NumArgs: 1, Precedence: 50, Handler: evalOperator}
|
||||
|
23
pkg/yqlib/operator_column.go
Normal file
23
pkg/yqlib/operator_column.go
Normal file
@ -0,0 +1,23 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func columnOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
log.Debugf("columnOperator")
|
||||
|
||||
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: fmt.Sprintf("%v", candidate.Node.Column), Tag: "!!int"}
|
||||
result := candidate.CreateReplacement(node)
|
||||
results.PushBack(result)
|
||||
}
|
||||
|
||||
return context.ChildContext(results), nil
|
||||
}
|
47
pkg/yqlib/operator_column_test.go
Normal file
47
pkg/yqlib/operator_column_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var columnOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Returns column of _value_ node",
|
||||
document: "a: cat\nb: bob",
|
||||
expression: `.b | column`,
|
||||
expected: []string{
|
||||
"D0, P[b], (!!int)::4\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Returns column of _key_ node",
|
||||
subdescription: "Pipe through the key operator to get the column of the key",
|
||||
document: "a: cat\nb: bob",
|
||||
expression: `.b | key | column`,
|
||||
expected: []string{
|
||||
"D0, P[b], (!!int)::1\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "First column is 1",
|
||||
document: "a: cat",
|
||||
expression: `.a | key | column`,
|
||||
expected: []string{
|
||||
"D0, P[a], (!!int)::1\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "No column data is 0",
|
||||
expression: `{"a": "new entry"} | column`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!int)::0\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestColumnOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range columnOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentOperatorScenarios(t, "column", columnOperatorScenarios)
|
||||
}
|
23
pkg/yqlib/operator_line.go
Normal file
23
pkg/yqlib/operator_line.go
Normal file
@ -0,0 +1,23 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func lineOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
log.Debugf("lineOperator")
|
||||
|
||||
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: fmt.Sprintf("%v", candidate.Node.Line), Tag: "!!int"}
|
||||
result := candidate.CreateReplacement(node)
|
||||
results.PushBack(result)
|
||||
}
|
||||
|
||||
return context.ChildContext(results), nil
|
||||
}
|
47
pkg/yqlib/operator_line_test.go
Normal file
47
pkg/yqlib/operator_line_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var lineOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Returns line of _value_ node",
|
||||
document: "a: cat\nb:\n c: cat",
|
||||
expression: `.b | line`,
|
||||
expected: []string{
|
||||
"D0, P[b], (!!int)::3\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Returns line of _key_ node",
|
||||
subdescription: "Pipe through the key operator to get the line of the key",
|
||||
document: "a: cat\nb:\n c: cat",
|
||||
expression: `.b | key| line`,
|
||||
expected: []string{
|
||||
"D0, P[b], (!!int)::2\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "First line is 1",
|
||||
document: "a: cat",
|
||||
expression: `.a | line`,
|
||||
expected: []string{
|
||||
"D0, P[a], (!!int)::1\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "No line data is 0",
|
||||
expression: `{"a": "new entry"} | line`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!int)::0\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestLineOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range lineOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentOperatorScenarios(t, "line", lineOperatorScenarios)
|
||||
}
|
Loading…
Reference in New Issue
Block a user