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(`,`), opToken(unionOpType))
|
||||||
lexer.Add([]byte(`:\s*`), opToken(createMapOpType))
|
lexer.Add([]byte(`:\s*`), opToken(createMapOpType))
|
||||||
lexer.Add([]byte(`length`), opToken(lengthOpType))
|
lexer.Add([]byte(`length`), opToken(lengthOpType))
|
||||||
|
lexer.Add([]byte(`line`), opToken(lineOpType))
|
||||||
|
lexer.Add([]byte(`column`), opToken(columnOpType))
|
||||||
|
|
||||||
lexer.Add([]byte(`eval`), opToken(evalOpType))
|
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 shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence: 45, Handler: pipeOperator}
|
||||||
|
|
||||||
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
|
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 collectOpType = &operationType{Type: "COLLECT", NumArgs: 1, Precedence: 50, Handler: collectOperator}
|
||||||
var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler: mapOperator}
|
var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler: mapOperator}
|
||||||
var evalOpType = &operationType{Type: "EVAL", NumArgs: 1, Precedence: 50, Handler: evalOperator}
|
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