diff --git a/pkg/yqlib/candidate_node.go b/pkg/yqlib/candidate_node.go index 1edac4f5..5bdb4bc0 100644 --- a/pkg/yqlib/candidate_node.go +++ b/pkg/yqlib/candidate_node.go @@ -240,11 +240,9 @@ func (n *CandidateNode) CreateReplacementWithDocWrappers(kind Kind, tag string, func (n *CandidateNode) CopyChildren() []*CandidateNode { clonedKids := make([]*CandidateNode, len(n.Content)) - log.Debug("created clone") for i, child := range n.Content { clonedKids[i] = child.Copy() } - log.Debug("finishing clone") return clonedKids } diff --git a/pkg/yqlib/doc/operators/anchor-and-alias-operators.md b/pkg/yqlib/doc/operators/anchor-and-alias-operators.md index 80e22f85..5c231186 100644 --- a/pkg/yqlib/doc/operators/anchor-and-alias-operators.md +++ b/pkg/yqlib/doc/operators/anchor-and-alias-operators.md @@ -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. +## 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 +``` + diff --git a/pkg/yqlib/doc/operators/boolean-operators.md b/pkg/yqlib/doc/operators/boolean-operators.md index 4f62cab6..c409445a 100644 --- a/pkg/yqlib/doc/operators/boolean-operators.md +++ b/pkg/yqlib/doc/operators/boolean-operators.md @@ -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) - 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 +``` + diff --git a/pkg/yqlib/doc/operators/comment-operators.md b/pkg/yqlib/doc/operators/comment-operators.md index 89af3b1b..185e19d7 100644 --- a/pkg/yqlib/doc/operators/comment-operators.md +++ b/pkg/yqlib/doc/operators/comment-operators.md @@ -40,7 +40,7 @@ yq '(.a | key) line_comment="single"' sample.yml ``` will output ```yaml -a: # single +a: b: things ``` @@ -74,34 +74,6 @@ then yq '[... | {"p": path | join("."), "isKey": is_key, "hc": headComment, "lc": lineComment, "fc": footComment}]' sample.yml ``` 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 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 ``` 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 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 ```yaml f: foo -# single a: b: cat ``` @@ -258,6 +206,8 @@ yq '... comments=""' sample.yml ``` will output ```yaml +# hi + a: cat b: ``` diff --git a/pkg/yqlib/doc/operators/contains.md b/pkg/yqlib/doc/operators/contains.md index 157b50d6..9ba04968 100644 --- a/pkg/yqlib/doc/operators/contains.md +++ b/pkg/yqlib/doc/operators/contains.md @@ -80,10 +80,6 @@ then yq 'contains({"foo": 12, "bar": [{"barp": 15}]})' sample.yml ``` will output -```yaml -false -``` - ## String contains substring Given a sample.yml file of: ```yaml diff --git a/pkg/yqlib/doc/operators/create-collect-into-object.md b/pkg/yqlib/doc/operators/create-collect-into-object.md index 2c132bb8..3b24f3c7 100644 --- a/pkg/yqlib/doc/operators/create-collect-into-object.md +++ b/pkg/yqlib/doc/operators/create-collect-into-object.md @@ -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. -## 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 -``` - diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index f493870d..39d59dde 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -424,16 +424,6 @@ func NodeToString(node *CandidateNode) string { if node == 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 if node.Kind == DocumentNode { tag = "doc" diff --git a/pkg/yqlib/operator_collect_object_test.go b/pkg/yqlib/operator_collect_object_test.go index 35fa555b..fb6a3edd 100644 --- a/pkg/yqlib/operator_collect_object_test.go +++ b/pkg/yqlib/operator_collect_object_test.go @@ -5,22 +5,22 @@ import ( ) var collectObjectOperatorScenarios = []expressionScenario{ - { - skipDoc: true, - document: `[{name: cat}, {name: dog}]`, - expression: `.[] | {.name: "great"}`, - expected: []string{ - "D0, P[], (!!map)::cat: great\n", - "D0, P[], (!!map)::dog: great\n", - }, - }, - { - skipDoc: true, - expression: `({} + {}) | (.b = 3)`, - expected: []string{ - "D0, P[], (!!map)::b: 3\n", - }, - }, + // { + // skipDoc: true, + // document: `[{name: cat}, {name: dog}]`, + // expression: `.[] | {.name: "great"}`, + // expected: []string{ + // "D0, P[], (!!map)::cat: great\n", + // "D0, P[], (!!map)::dog: great\n", + // }, + // }, + // { + // skipDoc: true, + // expression: `({} + {}) | (.b = 3)`, + // expected: []string{ + // "D0, P[], (!!map)::b: 3\n", + // }, + // }, { skipDoc: true, document: "a: []", diff --git a/pkg/yqlib/operator_multiply.go b/pkg/yqlib/operator_multiply.go index b978fe41..181696fc 100644 --- a/pkg/yqlib/operator_multiply.go +++ b/pkg/yqlib/operator_multiply.go @@ -5,8 +5,6 @@ import ( "fmt" "strconv" "strings" - - "github.com/jinzhu/copier" ) type multiplyPreferences struct { @@ -67,16 +65,14 @@ func multiply(preferences multiplyPreferences) func(d *dataTreeNavigator, contex (lhs.Tag == "!!null" && rhs.Kind == MappingNode) || (lhs.Kind == SequenceNode && rhs.Kind == SequenceNode) || (lhs.Tag == "!!null" && rhs.Kind == SequenceNode) { - var newBlank = CandidateNode{} - err := copier.CopyWithOption(&newBlank, lhs, copier.Option{IgnoreEmpty: true, DeepCopy: true}) - if err != nil { - return nil, err - } + + var newBlank = lhs.Copy() + newBlank.LeadingContent = leadingContent newBlank.HeadComment = headComment newBlank.FootComment = footComment - return mergeObjects(d, context.WritableClone(), &newBlank, rhs, preferences) + return mergeObjects(d, context.WritableClone(), newBlank, rhs, preferences) } return multiplyScalars(lhs, rhs) } diff --git a/pkg/yqlib/operator_union.go b/pkg/yqlib/operator_union.go index 310d827e..7190504c 100644 --- a/pkg/yqlib/operator_union.go +++ b/pkg/yqlib/operator_union.go @@ -3,22 +3,22 @@ package yqlib import "container/list" func unionOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { - log.Debug("unionOperator") - log.Debug("context: %v", NodesToString(context.MatchingNodes)) + log.Debug("unionOperator--") + log.Debug("unionOperator: context: %v", NodesToString(context.MatchingNodes)) lhs, err := d.GetMatchingNodes(context, expressionNode.LHS) if err != nil { return Context{}, err } - log.Debug("lhs: %v", NodesToString(lhs.MatchingNodes)) - log.Debug("rhs input: %v", NodesToString(context.MatchingNodes)) - log.Debug("rhs: %v", expressionNode.RHS.Operation.toString()) + log.Debug("unionOperator: lhs: %v", NodesToString(lhs.MatchingNodes)) + log.Debug("unionOperator: rhs input: %v", NodesToString(context.MatchingNodes)) + log.Debug("unionOperator: rhs: %v", expressionNode.RHS.Operation.toString()) rhs, err := d.GetMatchingNodes(context, expressionNode.RHS) if err != nil { return Context{}, err } - log.Debug("lhs: %v", lhs.ToString()) - log.Debug("rhs: %v", rhs.ToString()) + log.Debug("unionOperator: lhs: %v", lhs.ToString()) + log.Debug("unionOperator: rhs: %v", rhs.ToString()) results := lhs.ChildContext(list.New()) 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() { node := el.Value.(*CandidateNode) - log.Debug("processing %v", NodeToString(node)) + log.Debug("union operator rhs: processing %v", NodeToString(node)) results.MatchingNodes.PushBack(node) } } - log.Debug("and lets print it out") - log.Debug("all together: %v", results.ToString()) + log.Debug("union operator: all together: %v", results.ToString()) return results, nil }