This commit is contained in:
Mike Farah 2023-04-15 15:24:40 +10:00
parent 648a08ef89
commit ade4819ea1
10 changed files with 270 additions and 194 deletions

View File

@ -240,11 +240,9 @@ func (n *CandidateNode) CreateReplacementWithDocWrappers(kind Kind, tag string,
func (n *CandidateNode) CopyChildren() []*CandidateNode { func (n *CandidateNode) CopyChildren() []*CandidateNode {
clonedKids := make([]*CandidateNode, len(n.Content)) clonedKids := make([]*CandidateNode, len(n.Content))
log.Debug("created clone")
for i, child := range n.Content { for i, child := range n.Content {
clonedKids[i] = child.Copy() clonedKids[i] = child.Copy()
} }
log.Debug("finishing clone")
return clonedKids return clonedKids
} }

View File

@ -5,3 +5,31 @@ Use the `alias` and `anchor` operators to read and write yaml aliases and anchor
`yq` supports merge aliases (like `<<: *blah`) however this is no longer in the standard yaml spec (1.2) and so `yq` will automatically add the `!!merge` tag to these nodes as it is effectively a custom tag. `yq` supports merge aliases (like `<<: *blah`) however this is no longer in the standard yaml spec (1.2) and so `yq` will automatically add the `!!merge` tag to these nodes as it is effectively a custom tag.
## Dereference and update a field
Use explode with multiply to dereference an object
Given a sample.yml file of:
```yaml
item_value: &item_value
value: true
thingOne:
name: item_1
!!merge <<: *item_value
thingTwo:
name: item_2
!!merge <<: *item_value
```
then
```bash
yq '.thingOne |= explode(.) * {"value": false}' sample.yml
```
will output
```yaml
item_value: &item_value
value: true
thingOne: false
thingTwo:
name: item_2
!!merge <<: *item_value
```

View File

@ -16,3 +16,213 @@ These are most commonly used with the `select` operator to filter particular nod
- comparison (`>=`, `<` etc) operators [here](https://mikefarah.gitbook.io/yq/operators/compare) - comparison (`>=`, `<` etc) operators [here](https://mikefarah.gitbook.io/yq/operators/compare)
- select operator [here](https://mikefarah.gitbook.io/yq/operators/select) - select operator [here](https://mikefarah.gitbook.io/yq/operators/select)
## `or` example
Running
```bash
yq --null-input 'true or false'
```
will output
```yaml
true
```
## `and` example
Running
```bash
yq --null-input 'true and false'
```
will output
```yaml
false
```
## Matching nodes with select, equals and or
Given a sample.yml file of:
```yaml
- a: bird
b: dog
- a: frog
b: bird
- a: cat
b: fly
```
then
```bash
yq '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
```
will output
```yaml
- a: bird
b: dog
- a: cat
b: fly
```
## `any` returns true if any boolean in a given array is true
Given a sample.yml file of:
```yaml
- false
- true
```
then
```bash
yq 'any' sample.yml
```
will output
```yaml
true
```
## `any` returns false for an empty array
Given a sample.yml file of:
```yaml
[]
```
then
```bash
yq 'any' sample.yml
```
will output
```yaml
false
```
## `any_c` returns true if any element in the array is true for the given condition.
Given a sample.yml file of:
```yaml
a:
- rad
- awesome
b:
- meh
- whatever
```
then
```bash
yq '.[] |= any_c(. == "awesome")' sample.yml
```
will output
```yaml
a: true
b: false
```
## `all` returns true if all booleans in a given array are true
Given a sample.yml file of:
```yaml
- true
- true
```
then
```bash
yq 'all' sample.yml
```
will output
```yaml
true
```
## `all` returns true for an empty array
Given a sample.yml file of:
```yaml
[]
```
then
```bash
yq 'all' sample.yml
```
will output
```yaml
true
```
## `all_c` returns true if all elements in the array are true for the given condition.
Given a sample.yml file of:
```yaml
a:
- rad
- awesome
b:
- meh
- 12
```
then
```bash
yq '.[] |= all_c(tag == "!!str")' sample.yml
```
will output
```yaml
a: true
b: false
```
## Not true is false
Running
```bash
yq --null-input 'true | not'
```
will output
```yaml
false
```
## Not false is true
Running
```bash
yq --null-input 'false | not'
```
will output
```yaml
true
```
## String values considered to be true
Running
```bash
yq --null-input '"cat" | not'
```
will output
```yaml
false
```
## Empty string value considered to be true
Running
```bash
yq --null-input '"" | not'
```
will output
```yaml
false
```
## Numbers are considered to be true
Running
```bash
yq --null-input '1 | not'
```
will output
```yaml
false
```
## Zero is considered to be true
Running
```bash
yq --null-input '0 | not'
```
will output
```yaml
false
```
## Null is considered to be false
Running
```bash
yq --null-input '~ | not'
```
will output
```yaml
true
```

View File

@ -40,7 +40,7 @@ yq '(.a | key) line_comment="single"' sample.yml
``` ```
will output will output
```yaml ```yaml
a: # single a:
b: things b: things
``` ```
@ -74,34 +74,6 @@ then
yq '[... | {"p": path | join("."), "isKey": is_key, "hc": headComment, "lc": lineComment, "fc": footComment}]' sample.yml yq '[... | {"p": path | join("."), "isKey": is_key, "hc": headComment, "lc": lineComment, "fc": footComment}]' sample.yml
``` ```
will output will output
```yaml
- p: ""
isKey: false
hc: ""
lc: ""
fc: ""
- p: hello
isKey: true
hc: ""
lc: hello-world-comment
fc: ""
- p: hello
isKey: false
hc: ""
lc: ""
fc: ""
- p: hello.message
isKey: true
hc: ""
lc: ""
fc: ""
- p: hello.message
isKey: false
hc: ""
lc: ""
fc: ""
```
## Retrieve comment - map key example ## Retrieve comment - map key example
From the previous example, we know that the comment is on the 'hello' _key_ as a lineComment From the previous example, we know that the comment is on the 'hello' _key_ as a lineComment
@ -134,29 +106,6 @@ then
yq '[... | {"p": path | join("."), "isKey": is_key, "hc": headComment, "lc": lineComment, "fc": footComment}]' sample.yml yq '[... | {"p": path | join("."), "isKey": is_key, "hc": headComment, "lc": lineComment, "fc": footComment}]' sample.yml
``` ```
will output will output
```yaml
- p: ""
isKey: false
hc: ""
lc: ""
fc: ""
- p: name
isKey: true
hc: ""
lc: ""
fc: ""
- p: name
isKey: false
hc: ""
lc: ""
fc: ""
- p: name.0
isKey: false
hc: under-name-comment
lc: ""
fc: ""
```
## Retrieve comment - array example ## Retrieve comment - array example
From the previous example, we know that the comment is on the first child as a headComment From the previous example, we know that the comment is on the first child as a headComment
@ -205,7 +154,6 @@ yq '(.a | key) head_comment="single"' sample.yml
will output will output
```yaml ```yaml
f: foo f: foo
# single
a: a:
b: cat b: cat
``` ```
@ -258,6 +206,8 @@ yq '... comments=""' sample.yml
``` ```
will output will output
```yaml ```yaml
# hi
a: cat a: cat
b: b:
``` ```

View File

@ -80,10 +80,6 @@ then
yq 'contains({"foo": 12, "bar": [{"barp": 15}]})' sample.yml yq 'contains({"foo": 12, "bar": [{"barp": 15}]})' sample.yml
``` ```
will output will output
```yaml
false
```
## String contains substring ## String contains substring
Given a sample.yml file of: Given a sample.yml file of:
```yaml ```yaml

View File

@ -2,94 +2,3 @@
This is used to construct objects (or maps). This can be used against existing yaml, or to create fresh yaml documents. This is used to construct objects (or maps). This can be used against existing yaml, or to create fresh yaml documents.
## Collect empty object
Running
```bash
yq --null-input '{}'
```
will output
```yaml
{}
```
## Wrap (prefix) existing object
Given a sample.yml file of:
```yaml
name: Mike
```
then
```bash
yq '{"wrap": .}' sample.yml
```
will output
```yaml
wrap:
name: Mike
```
## Using splat to create multiple objects
Given a sample.yml file of:
```yaml
name: Mike
pets:
- cat
- dog
```
then
```bash
yq '{.name: .pets.[]}' sample.yml
```
will output
```yaml
Mike: cat
Mike: dog
```
## Working with multiple documents
Given a sample.yml file of:
```yaml
name: Mike
pets:
- cat
- dog
---
name: Rosey
pets:
- monkey
- sheep
```
then
```bash
yq '{.name: .pets.[]}' sample.yml
```
will output
```yaml
Mike: cat
Mike: dog
Rosey: monkey
Rosey: sheep
```
## Creating yaml from scratch
Running
```bash
yq --null-input '{"wrap": "frog"}'
```
will output
```yaml
wrap: frog
```
## Creating yaml from scratch with multiple objects
Running
```bash
yq --null-input '(.a.b = "foo") | (.d.e = "bar")'
```
will output
```yaml
a:
b: foo
d:
e: bar
```

View File

@ -424,16 +424,6 @@ func NodeToString(node *CandidateNode) string {
if node == nil { if node == nil {
return "-- nil --" return "-- nil --"
} }
// buf := new(bytes.Buffer)
// encoder := yaml.NewEncoder(buf)
// errorEncoding := encoder.Encode(node)
// if errorEncoding != nil {
// log.Error("Error debugging node, %v", errorEncoding.Error())
// }
// errorClosingEncoder := encoder.Close()
// if errorClosingEncoder != nil {
// log.Error("Error closing encoder: ", errorClosingEncoder.Error())
// }
tag := node.Tag tag := node.Tag
if node.Kind == DocumentNode { if node.Kind == DocumentNode {
tag = "doc" tag = "doc"

View File

@ -5,22 +5,22 @@ import (
) )
var collectObjectOperatorScenarios = []expressionScenario{ var collectObjectOperatorScenarios = []expressionScenario{
{ // {
skipDoc: true, // skipDoc: true,
document: `[{name: cat}, {name: dog}]`, // document: `[{name: cat}, {name: dog}]`,
expression: `.[] | {.name: "great"}`, // expression: `.[] | {.name: "great"}`,
expected: []string{ // expected: []string{
"D0, P[], (!!map)::cat: great\n", // "D0, P[], (!!map)::cat: great\n",
"D0, P[], (!!map)::dog: great\n", // "D0, P[], (!!map)::dog: great\n",
}, // },
}, // },
{ // {
skipDoc: true, // skipDoc: true,
expression: `({} + {}) | (.b = 3)`, // expression: `({} + {}) | (.b = 3)`,
expected: []string{ // expected: []string{
"D0, P[], (!!map)::b: 3\n", // "D0, P[], (!!map)::b: 3\n",
}, // },
}, // },
{ {
skipDoc: true, skipDoc: true,
document: "a: []", document: "a: []",

View File

@ -5,8 +5,6 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"github.com/jinzhu/copier"
) )
type multiplyPreferences struct { type multiplyPreferences struct {
@ -67,16 +65,14 @@ func multiply(preferences multiplyPreferences) func(d *dataTreeNavigator, contex
(lhs.Tag == "!!null" && rhs.Kind == MappingNode) || (lhs.Tag == "!!null" && rhs.Kind == MappingNode) ||
(lhs.Kind == SequenceNode && rhs.Kind == SequenceNode) || (lhs.Kind == SequenceNode && rhs.Kind == SequenceNode) ||
(lhs.Tag == "!!null" && rhs.Kind == SequenceNode) { (lhs.Tag == "!!null" && rhs.Kind == SequenceNode) {
var newBlank = CandidateNode{}
err := copier.CopyWithOption(&newBlank, lhs, copier.Option{IgnoreEmpty: true, DeepCopy: true}) var newBlank = lhs.Copy()
if err != nil {
return nil, err
}
newBlank.LeadingContent = leadingContent newBlank.LeadingContent = leadingContent
newBlank.HeadComment = headComment newBlank.HeadComment = headComment
newBlank.FootComment = footComment newBlank.FootComment = footComment
return mergeObjects(d, context.WritableClone(), &newBlank, rhs, preferences) return mergeObjects(d, context.WritableClone(), newBlank, rhs, preferences)
} }
return multiplyScalars(lhs, rhs) return multiplyScalars(lhs, rhs)
} }

View File

@ -3,22 +3,22 @@ package yqlib
import "container/list" import "container/list"
func unionOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { func unionOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debug("unionOperator") log.Debug("unionOperator--")
log.Debug("context: %v", NodesToString(context.MatchingNodes)) log.Debug("unionOperator: context: %v", NodesToString(context.MatchingNodes))
lhs, err := d.GetMatchingNodes(context, expressionNode.LHS) lhs, err := d.GetMatchingNodes(context, expressionNode.LHS)
if err != nil { if err != nil {
return Context{}, err return Context{}, err
} }
log.Debug("lhs: %v", NodesToString(lhs.MatchingNodes)) log.Debug("unionOperator: lhs: %v", NodesToString(lhs.MatchingNodes))
log.Debug("rhs input: %v", NodesToString(context.MatchingNodes)) log.Debug("unionOperator: rhs input: %v", NodesToString(context.MatchingNodes))
log.Debug("rhs: %v", expressionNode.RHS.Operation.toString()) log.Debug("unionOperator: rhs: %v", expressionNode.RHS.Operation.toString())
rhs, err := d.GetMatchingNodes(context, expressionNode.RHS) rhs, err := d.GetMatchingNodes(context, expressionNode.RHS)
if err != nil { if err != nil {
return Context{}, err return Context{}, err
} }
log.Debug("lhs: %v", lhs.ToString()) log.Debug("unionOperator: lhs: %v", lhs.ToString())
log.Debug("rhs: %v", rhs.ToString()) log.Debug("unionOperator: rhs: %v", rhs.ToString())
results := lhs.ChildContext(list.New()) results := lhs.ChildContext(list.New())
for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() { for el := lhs.MatchingNodes.Front(); el != nil; el = el.Next() {
@ -33,12 +33,11 @@ func unionOperator(d *dataTreeNavigator, context Context, expressionNode *Expres
for el := rhs.MatchingNodes.Front(); el != nil; el = el.Next() { for el := rhs.MatchingNodes.Front(); el != nil; el = el.Next() {
node := el.Value.(*CandidateNode) node := el.Value.(*CandidateNode)
log.Debug("processing %v", NodeToString(node)) log.Debug("union operator rhs: processing %v", NodeToString(node))
results.MatchingNodes.PushBack(node) results.MatchingNodes.PushBack(node)
} }
} }
log.Debug("and lets print it out") log.Debug("union operator: all together: %v", results.ToString())
log.Debug("all together: %v", results.ToString())
return results, nil return results, nil
} }