Compare commits

...
Author SHA1 Message Date
Mike Farah c35ec752e3 Bumping version 2024-03-24 10:54:14 +11:00
Mike Farah fbd4c8428a Remove old JSON warning 2024-03-23 17:17:23 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d9ef03a2d1 Bump github.com/pelletier/go-toml/v2 from 2.1.1 to 2.2.0 (#1986)
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.1.1 to 2.2.0.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.1.1...v2.2.0)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-23 17:15:56 +11:00
Matt BensonandGitHub f5bfe5a248 omit operator (#1989) 2024-03-23 17:15:45 +11:00
Matt BensonandGitHub 3b85cef340 support string X int multiplication as jq (#1988) 2024-03-22 20:44:49 +11:00
14 changed files with 303 additions and 11 deletions
-4
View File
@@ -75,10 +75,6 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
outputFormat = "yaml"
}
} else if isAutomaticOutputFormat() {
// automatic input worked, we can do it for output too unless specified
if inputFormat == "json" {
yqlib.GetLogger().Warning("JSON file output is now JSON by default (instead of yaml). Use '-oy' or '--output-format=yaml' for yaml output")
}
outputFormat = inputFormat
}
} else if isAutomaticOutputFormat() {
+1 -1
View File
@@ -11,7 +11,7 @@ var (
GitDescribe string
// Version is main version number that is being run at the moment.
Version = "v4.42.1"
Version = "v4.43.1"
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
+1 -1
View File
@@ -11,7 +11,7 @@ require (
github.com/goccy/go-yaml v1.11.3
github.com/jinzhu/copier v0.4.0
github.com/magiconair/properties v1.8.7
github.com/pelletier/go-toml/v2 v2.1.1
github.com/pelletier/go-toml/v2 v2.2.0
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
+5 -3
View File
@@ -43,8 +43,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -57,11 +57,13 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
+56
View File
@@ -55,6 +55,62 @@ a: 12
b: 4
```
## Multiply string node X int
Given a sample.yml file of:
```yaml
b: banana
```
then
```bash
yq '.b * 4' sample.yml
```
will output
```yaml
bananabananabananabanana
```
## Multiply int X string node
Given a sample.yml file of:
```yaml
b: banana
```
then
```bash
yq '4 * .b' sample.yml
```
will output
```yaml
bananabananabananabanana
```
## Multiply string X int node
Given a sample.yml file of:
```yaml
n: 4
```
then
```bash
yq '"banana" * .n' sample.yml
```
will output
```yaml
bananabananabananabanana
```
## Multiply int node X string
Given a sample.yml file of:
```yaml
n: 4
```
then
```bash
yq '.n * "banana"' sample.yml
```
will output
```yaml
bananabananabananabanana
```
## Merge objects together, returning merged result only
Given a sample.yml file of:
```yaml
+41
View File
@@ -0,0 +1,41 @@
## Omit keys from map
Note that the order of the keys matches the omit order and non existent keys are skipped.
Given a sample.yml file of:
```yaml
myMap:
cat: meow
dog: bark
thing: hamster
hamster: squeak
```
then
```bash
yq '.myMap |= omit(["hamster", "cat", "goat"])' sample.yml
```
will output
```yaml
myMap:
dog: bark
thing: hamster
```
## Omit indices from array
Note that the order of the indices matches the omit order and non existent indices are skipped.
Given a sample.yml file of:
```yaml
- cat
- leopard
- lion
```
then
```bash
yq 'omit([2, 0, 734, -5])' sample.yml
```
will output
```yaml
- leopard
```
+1
View File
@@ -40,6 +40,7 @@ var participleYqRules = []*participleYqRule{
simpleOp("map", mapOpType),
simpleOp("filter", filterOpType),
simpleOp("pick", pickOpType),
simpleOp("omit", omitOpType),
{"FlattenWithDepth", `flatten\([0-9]+\)`, flattenWithDepth(), 0},
{"Flatten", `flatten`, opTokenWithPrefs(flattenOpType, nil, flattenPreferences{depth: -1}), 0},
+1
View File
@@ -90,6 +90,7 @@ var mapOpType = &operationType{Type: "MAP", NumArgs: 1, Precedence: 50, Handler:
var filterOpType = &operationType{Type: "FILTER", NumArgs: 1, Precedence: 50, Handler: filterOperator}
var errorOpType = &operationType{Type: "ERROR", NumArgs: 1, Precedence: 50, Handler: errorOperator}
var pickOpType = &operationType{Type: "PICK", NumArgs: 1, Precedence: 50, Handler: pickOperator}
var omitOpType = &operationType{Type: "OMIT", NumArgs: 1, Precedence: 50, Handler: omitOperator}
var evalOpType = &operationType{Type: "EVAL", NumArgs: 1, Precedence: 50, Handler: evalOperator}
var mapValuesOpType = &operationType{Type: "MAP_VALUES", NumArgs: 1, Precedence: 50, Handler: mapValuesOperator}
+24
View File
@@ -91,6 +91,8 @@ func multiplyScalars(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, er
return multiplyIntegers(lhs, rhs)
} else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") {
return multiplyFloats(lhs, rhs, lhsIsCustom)
} else if (lhsTag == "!!str" && rhsTag == "!!int") || (lhsTag == "!!int" && rhsTag == "!!str") {
return repeatString(lhs, rhs)
}
return nil, fmt.Errorf("cannot multiply %v with %v", lhs.Tag, rhs.Tag)
}
@@ -135,6 +137,28 @@ func multiplyIntegers(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, e
return target, nil
}
func repeatString(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
var stringNode *CandidateNode
var intNode *CandidateNode
if lhs.Tag == "!!str" {
stringNode = lhs
intNode = rhs
} else {
stringNode = rhs
intNode = lhs
}
target := lhs.CopyWithoutContent()
target.UpdateAttributesFrom(stringNode, assignPreferences{})
count, err := parseInt(intNode.Value)
if err != nil {
return nil, err
}
target.Value = strings.Repeat(stringNode.Value, count)
return target, nil
}
func mergeObjects(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode, preferences multiplyPreferences) (*CandidateNode, error) {
var results = list.New()
+36
View File
@@ -1,6 +1,8 @@
package yqlib
import (
"fmt"
"strings"
"testing"
)
@@ -174,6 +176,40 @@ var multiplyOperatorScenarios = []expressionScenario{
"D0, P[], (!!map)::a: 12\nb: 4\n",
},
},
{
description: "Multiply string node X int",
document: docNoComments,
expression: ".b * 4",
expected: []string{
fmt.Sprintf("D0, P[b], (!!str)::%s\n", strings.Repeat("banana", 4)),
},
},
{
description: "Multiply int X string node",
document: docNoComments,
expression: "4 * .b",
expected: []string{
fmt.Sprintf("D0, P[], (!!str)::%s\n", strings.Repeat("banana", 4)),
},
},
{
description: "Multiply string X int node",
document: `n: 4
`,
expression: `"banana" * .n`,
expected: []string{
fmt.Sprintf("D0, P[], (!!str)::%s\n", strings.Repeat("banana", 4)),
},
},
{
description: "Multiply int node X string",
document: `n: 4
`,
expression: `.n * "banana"`,
expected: []string{
fmt.Sprintf("D0, P[n], (!!str)::%s\n", strings.Repeat("banana", 4)),
},
},
{
skipDoc: true,
document: doc1,
+73
View File
@@ -0,0 +1,73 @@
package yqlib
import (
"container/list"
"strconv"
)
func omitMap(original *CandidateNode, indices *CandidateNode) *CandidateNode {
filteredContent := make([]*CandidateNode, 0, max(0, len(original.Content)-len(indices.Content)*2))
for index := 0; index < len(original.Content); index += 2 {
pos := findInArray(indices, original.Content[index])
if pos < 0 {
clonedKey := original.Content[index].Copy()
clonedValue := original.Content[index+1].Copy()
filteredContent = append(filteredContent, clonedKey, clonedValue)
}
}
result := original.CopyWithoutContent()
result.AddChildren(filteredContent)
return result
}
func omitSequence(original *CandidateNode, indices *CandidateNode) *CandidateNode {
filteredContent := make([]*CandidateNode, 0, max(0, len(original.Content)-len(indices.Content)))
for index := 0; index < len(original.Content); index++ {
pos := findInArray(indices, createScalarNode(index, strconv.Itoa(index)))
if pos < 0 {
filteredContent = append(filteredContent, original.Content[index].Copy())
}
}
result := original.CopyWithoutContent()
result.AddChildren(filteredContent)
return result
}
func omitOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("Omit")
contextIndicesToOmit, err := d.GetMatchingNodes(context, expressionNode.RHS)
if err != nil {
return Context{}, err
}
indicesToOmit := &CandidateNode{}
if contextIndicesToOmit.MatchingNodes.Len() > 0 {
indicesToOmit = contextIndicesToOmit.MatchingNodes.Front().Value.(*CandidateNode)
}
if len(indicesToOmit.Content) == 0 {
log.Debugf("No omit indices specified")
return context, nil
}
var results = list.New()
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
node := el.Value.(*CandidateNode)
var replacement *CandidateNode
if node.Kind == MappingNode {
replacement = omitMap(node, indicesToOmit)
} else if node.Kind == SequenceNode {
replacement = omitSequence(node, indicesToOmit)
} else {
log.Debugf("Omit from type %v (%v) is noop", node.Tag, node.GetNicePath())
return context, nil
}
replacement.LeadingContent = node.LeadingContent
results.PushBack(replacement)
}
return context.ChildContext(results), nil
}
+60
View File
@@ -0,0 +1,60 @@
package yqlib
import (
"testing"
)
var omitOperatorScenarios = []expressionScenario{
{
description: "Omit keys from map",
subdescription: "Note that the order of the keys matches the omit order and non existent keys are skipped.",
document: "myMap: {cat: meow, dog: bark, thing: hamster, hamster: squeak}\n",
expression: `.myMap |= omit(["hamster", "cat", "goat"])`,
expected: []string{
"D0, P[], (!!map)::myMap: {dog: bark, thing: hamster}\n",
},
},
{
description: "Omit keys from map",
skipDoc: true,
document: "!things myMap: {cat: meow, dog: bark, thing: hamster, hamster: squeak}\n",
expression: `.myMap |= omit(["hamster", "cat", "goat"])`,
expected: []string{
"D0, P[], (!!map)::!things myMap: {dog: bark, thing: hamster}\n",
},
},
{
description: "Omit keys from map with comments",
skipDoc: true,
document: "# abc\nmyMap: {cat: meow, dog: bark, thing: hamster, hamster: squeak}\n# xyz\n",
expression: `.myMap |= omit(["hamster", "cat", "goat"])`,
expected: []string{
"D0, P[], (!!map)::# abc\nmyMap: {dog: bark, thing: hamster}\n# xyz\n",
},
},
{
description: "Omit indices from array",
subdescription: "Note that the order of the indices matches the omit order and non existent indices are skipped.",
document: `[cat, leopard, lion]`,
expression: `omit([2, 0, 734, -5])`,
expected: []string{
"D0, P[], (!!seq)::[leopard]\n",
},
},
{
description: "Omit indices from array with comments",
skipDoc: true,
document: "# abc\n[cat, leopard, lion]\n# xyz",
expression: `omit([2, 0, 734, -5])`,
expected: []string{
"D0, P[], (!!seq)::# abc\n[leopard]\n# xyz\n",
},
},
}
func TestOmitOperatorScenarios(t *testing.T) {
for _, tt := range omitOperatorScenarios {
testScenario(t, &tt)
}
documentOperatorScenarios(t, "omit", omitOperatorScenarios)
}
+2
View File
@@ -1,7 +1,9 @@
4.43.1: (not released yet)
- Added omit operator #1989 thanks @mbenson!
- Added tostring #72
- Added string interpolation #1149
- Can specify parent(n) levels #1970
- Can now multiply strings by numbers #1988 thanks @mbenson!
- Fixed CSV line break issue #1974
- Adding a EvaluateAll function to StringEvaluator #1966
- yqlib, default to colors off when using yaml library #1964
+2 -2
View File
@@ -1,5 +1,5 @@
name: yq
version: 'v4.42.1'
version: 'v4.43.1'
summary: A lightweight and portable command-line data file processor
description: |
`yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml, json, xml, csv, properties and TOML files.
@@ -21,6 +21,6 @@ parts:
yq:
plugin: go
source: https://github.com/mikefarah/yq.git
source-tag: v4.42.1
source-tag: v4.43.1
build-snaps:
- go/latest/stable