mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f42355cf9f | ||
|
|
44bc9971c1 | ||
|
|
54cf6cf282 | ||
|
|
29db5ebf4d | ||
|
|
abaf299115 | ||
|
|
e9c5573a89 | ||
|
|
e0fdbe7f35 | ||
|
|
ebfc7212e2 | ||
|
|
ca10ede102 | ||
|
|
e76a2f3de6 | ||
|
|
b702686891 | ||
|
|
c284d4c6b1 | ||
|
|
63883d3000 | ||
|
|
3014192ce8 | ||
|
|
ebeb1146ba | ||
|
|
0bb53ec770 | ||
|
|
a50e154652 | ||
|
|
f91d30e46c | ||
|
|
07b053f040 | ||
|
|
35c97e832e | ||
|
|
8a5c47906e | ||
|
|
a366cacad3 | ||
|
|
7c8d3b9e70 | ||
|
|
ca10642e23 | ||
|
|
73518f3915 | ||
|
|
348ddb7a59 | ||
|
|
f46fe384bd | ||
|
|
071ec3c08c | ||
|
|
c2ed3a3e6d | ||
|
|
cc4c69bc89 | ||
|
|
917fd0eb6a | ||
|
|
b2056a2056 | ||
|
|
ba59201217 | ||
|
|
cfddee9101 | ||
|
|
1941bb66a5 | ||
|
|
29af9e4c63 | ||
|
|
af3a9ae846 | ||
|
|
5fb88627ca | ||
|
|
4fc3793fcb | ||
|
|
d612897e89 | ||
|
|
806f906041 | ||
|
|
e8b2f6e383 | ||
|
|
e419b5a39d | ||
|
|
a5b6e08282 | ||
|
|
2417c0ee8f | ||
|
|
d3b2e37b66 | ||
|
|
54723c1a36 | ||
|
|
0318c80d33 | ||
|
|
8980846632 | ||
|
|
0fb62d3ae1 | ||
|
|
85398727ad | ||
|
|
0bf3d781f6 | ||
|
|
5c15936bf3 | ||
|
|
b0735d8152 | ||
|
|
f17cbfd007 | ||
|
|
7b7ab70286 | ||
|
|
43165fa340 | ||
|
|
feda9f044d | ||
|
|
85629af59c | ||
|
|
5fc26e9453 | ||
|
|
07a6fa4df5 | ||
|
|
ec29ee7c14 | ||
|
|
24538c0cc7 | ||
|
|
61398bfd3a | ||
|
|
f7d95021c1 | ||
|
|
6bb8b1fb77 | ||
|
|
5e2c19cc86 | ||
|
|
30c269a66c | ||
|
|
70a1c60d7b | ||
|
|
e4d48bbc0d | ||
|
|
369ff94ad0 | ||
|
|
1c7fb14631 | ||
|
|
f4de5c4300 | ||
|
|
a72c14f06b | ||
|
|
5ed52aca66 | ||
|
|
5a5ac0dfef | ||
|
|
5a55869745 | ||
|
|
15e18bb98b | ||
|
|
644063646e | ||
|
|
aabed1a237 | ||
|
|
c12764dba8 | ||
|
|
1d5ecb244d | ||
|
|
7798a141cf | ||
|
|
b7583a538d | ||
|
|
529e88b630 | ||
|
|
658006eb93 | ||
|
|
2743a7e058 | ||
|
|
f95862fba3 | ||
|
|
3f58c4bc38 | ||
|
|
a7975df7cd | ||
|
|
3d5a5e0360 | ||
|
|
155755ae2f | ||
|
|
601c13531c | ||
|
|
69d00c89df | ||
|
|
2faff7b05f | ||
|
|
165949041d | ||
|
|
dbd7ab0f13 | ||
|
|
6d512ad718 | ||
|
|
4fef4a7ab1 | ||
|
|
dcb17b51a9 | ||
|
|
385417556d |
@@ -11,7 +11,7 @@ var (
|
|||||||
GitDescribe string
|
GitDescribe string
|
||||||
|
|
||||||
// Version is main version number that is being run at the moment.
|
// Version is main version number that is being run at the moment.
|
||||||
Version = "4.6.0"
|
Version = "4.5.1"
|
||||||
|
|
||||||
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
|
// 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
|
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM mikefarah/yq:4.6.0
|
FROM mikefarah/yq:4.5.1
|
||||||
|
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
|
||||||
|
|||||||
@@ -35,26 +35,6 @@ will output
|
|||||||
0
|
0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get file indices of multiple documents
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
```
|
|
||||||
And another sample another.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval-all 'fileIndex' sample.yml another.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
0
|
|
||||||
---
|
|
||||||
1
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get file index alias
|
## Get file index alias
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -1,34 +1,19 @@
|
|||||||
Like the multiple operator in jq, depending on the operands, this multiply operator will do different things. Currently numbers, arrays and objects are supported.
|
Like the multiple operator in jq, depending on the operands, this multiply operator will do different things. Currently only objects are supported, which have the effect of merging the RHS into the LHS.
|
||||||
|
|
||||||
## Objects and arrays - merging
|
To concatenate arrays when merging objects, use the *+ form (see examples below). This will recursively merge objects, appending arrays when it encounters them.
|
||||||
Objects are merged deeply matching on matching keys. By default, array values override and are not deeply merged.
|
|
||||||
|
|
||||||
|
To merge only existing fields, use the *? form. Note that this can be used with the concatenate arrays too *+?.
|
||||||
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
|
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
|
||||||
|
|
||||||
### Merge Flags
|
Multiplication of strings and numbers are not yet supported.
|
||||||
You can control how objects are merged by using one or more of the following flags. Multiple flags can be used together, e.g. `.a *+? .b`. See examples below
|
|
||||||
|
|
||||||
- `+` to append arrays
|
## Merging files
|
||||||
- `?` to only merge existing fields
|
|
||||||
- `d` to deeply merge arrays
|
|
||||||
|
|
||||||
### Merging files
|
|
||||||
Note the use of `eval-all` to ensure all documents are loaded into memory.
|
Note the use of `eval-all` to ensure all documents are loaded into memory.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' file1.yaml file2.yaml
|
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' file1.yaml file2.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
## Multiply integers
|
|
||||||
Running
|
|
||||||
```bash
|
|
||||||
yq eval --null-input '3 * 4'
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
12
|
|
||||||
```
|
|
||||||
|
|
||||||
## Merge objects together, returning merged result only
|
## Merge objects together, returning merged result only
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
@@ -205,32 +190,6 @@ thing:
|
|||||||
- 4
|
- 4
|
||||||
```
|
```
|
||||||
|
|
||||||
## Merge, deeply merging arrays
|
|
||||||
Merging arrays deeply means arrays are merge like objects, with indexes as their key. In this case, we merge the first item in the array, and do nothing with the second.
|
|
||||||
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a:
|
|
||||||
- name: fred
|
|
||||||
age: 12
|
|
||||||
- name: bob
|
|
||||||
age: 32
|
|
||||||
b:
|
|
||||||
- name: fred
|
|
||||||
age: 34
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '.a *d .b' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- name: fred
|
|
||||||
age: 34
|
|
||||||
- name: bob
|
|
||||||
age: 32
|
|
||||||
```
|
|
||||||
|
|
||||||
## Merge to prefix an element
|
## Merge to prefix an element
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
Reduce is a powerful way to process a collection of data into a new form.
|
|
||||||
|
|
||||||
```
|
|
||||||
<exp> as $<name> ireduce (<init>; <block>)
|
|
||||||
```
|
|
||||||
|
|
||||||
e.g.
|
|
||||||
|
|
||||||
```
|
|
||||||
.[] as $item ireduce (0; . + $item)
|
|
||||||
```
|
|
||||||
|
|
||||||
On the LHS we are configuring the collection of items that will be reduced `<exp>` as well as what each element will be called `$<name>`. Note that the array has been splatted into its individual elements.
|
|
||||||
|
|
||||||
On the RHS there is `<init>`, the starting value of the accumulator and `<block>`, the expression that will update the accumulator for each element in the collection. Note that within the block expression, `.` will evaluate to the current value of the accumulator.
|
|
||||||
|
|
||||||
## yq vs jq syntax
|
|
||||||
Reduce syntax in `yq` is a little different from `jq` - as `yq` (currently) isn't as sophisticated as `jq` and its only supports infix notation (e.g. a + b, where the operator is in the middle of the two parameters) - where as `jq` uses a mix of infix notation with _prefix_ notation (e.g. `reduce a b` is like writing `+ a b`).
|
|
||||||
|
|
||||||
To that end, the reduce operator is called `ireduce` for backwards compatability if a `jq` like prefix version of `reduce` is ever added.
|
|
||||||
|
|
||||||
|
|
||||||
## Sum numbers
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
- 10
|
|
||||||
- 2
|
|
||||||
- 5
|
|
||||||
- 3
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '.[] as $item ireduce (0; . + $item)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
20
|
|
||||||
```
|
|
||||||
|
|
||||||
## Merge all yaml files together
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
```
|
|
||||||
And another sample another.yml file of:
|
|
||||||
```yaml
|
|
||||||
b: dog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval-all '. as $item ireduce ({}; . * $item )' sample.yml another.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
b: dog
|
|
||||||
```
|
|
||||||
|
|
||||||
## Convert an array to an object
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
- name: Cathy
|
|
||||||
has: apples
|
|
||||||
- name: Bob
|
|
||||||
has: bananas
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '.[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
Cathy: apples
|
|
||||||
Bob: bananas
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,18 +1,13 @@
|
|||||||
Like the multiple operator in jq, depending on the operands, this multiply operator will do different things. Currently numbers, arrays and objects are supported.
|
Like the multiple operator in jq, depending on the operands, this multiply operator will do different things. Currently only objects are supported, which have the effect of merging the RHS into the LHS.
|
||||||
|
|
||||||
## Objects and arrays - merging
|
To concatenate arrays when merging objects, use the *+ form (see examples below). This will recursively merge objects, appending arrays when it encounters them.
|
||||||
Objects are merged deeply matching on matching keys. By default, array values override and are not deeply merged.
|
|
||||||
|
|
||||||
|
To merge only existing fields, use the *? form. Note that this can be used with the concatenate arrays too *+?.
|
||||||
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
|
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
|
||||||
|
|
||||||
### Merge Flags
|
Multiplication of strings and numbers are not yet supported.
|
||||||
You can control how objects are merged by using one or more of the following flags. Multiple flags can be used together, e.g. `.a *+? .b`. See examples below
|
|
||||||
|
|
||||||
- `+` to append arrays
|
## Merging files
|
||||||
- `?` to only merge existing fields
|
|
||||||
- `d` to deeply merge arrays
|
|
||||||
|
|
||||||
### Merging files
|
|
||||||
Note the use of `eval-all` to ensure all documents are loaded into memory.
|
Note the use of `eval-all` to ensure all documents are loaded into memory.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
Reduce is a powerful way to process a collection of data into a new form.
|
|
||||||
|
|
||||||
```
|
|
||||||
<exp> as $<name> ireduce (<init>; <block>)
|
|
||||||
```
|
|
||||||
|
|
||||||
e.g.
|
|
||||||
|
|
||||||
```
|
|
||||||
.[] as $item ireduce (0; . + $item)
|
|
||||||
```
|
|
||||||
|
|
||||||
On the LHS we are configuring the collection of items that will be reduced `<exp>` as well as what each element will be called `$<name>`. Note that the array has been splatted into its individual elements.
|
|
||||||
|
|
||||||
On the RHS there is `<init>`, the starting value of the accumulator and `<block>`, the expression that will update the accumulator for each element in the collection. Note that within the block expression, `.` will evaluate to the current value of the accumulator.
|
|
||||||
|
|
||||||
## yq vs jq syntax
|
|
||||||
Reduce syntax in `yq` is a little different from `jq` - as `yq` (currently) isn't as sophisticated as `jq` and its only supports infix notation (e.g. a + b, where the operator is in the middle of the two parameters) - where as `jq` uses a mix of infix notation with _prefix_ notation (e.g. `reduce a b` is like writing `+ a b`).
|
|
||||||
|
|
||||||
To that end, the reduce operator is called `ireduce` for backwards compatability if a `jq` like prefix version of `reduce` is ever added.
|
|
||||||
|
|
||||||
@@ -12,11 +12,6 @@ var pathTests = []struct {
|
|||||||
expectedTokens []interface{}
|
expectedTokens []interface{}
|
||||||
expectedPostFix []interface{}
|
expectedPostFix []interface{}
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
`.a as $item ireduce (0; . + $item)`, // note - add code to shuffle reduce to this position for postfix
|
|
||||||
append(make([]interface{}, 0), "a", "ASSIGN_VARIABLE", "GET_VARIABLE", "REDUCE", "(", "0 (int64)", "BLOCK", "SELF", "ADD", "GET_VARIABLE", ")"),
|
|
||||||
append(make([]interface{}, 0), "a", "GET_VARIABLE", "ASSIGN_VARIABLE", "0 (int64)", "SELF", "GET_VARIABLE", "ADD", "BLOCK", "REDUCE"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
`.a | .b | .c`,
|
`.a | .b | .c`,
|
||||||
append(make([]interface{}, 0), "a", "PIPE", "b", "PIPE", "c"),
|
append(make([]interface{}, 0), "a", "PIPE", "b", "PIPE", "c"),
|
||||||
|
|||||||
@@ -100,9 +100,6 @@ func multiplyWithPrefs() lex.Action {
|
|||||||
if strings.Contains(options, "?") {
|
if strings.Contains(options, "?") {
|
||||||
prefs.TraversePrefs = traversePreferences{DontAutoCreate: true}
|
prefs.TraversePrefs = traversePreferences{DontAutoCreate: true}
|
||||||
}
|
}
|
||||||
if strings.Contains(options, "d") {
|
|
||||||
prefs.DeepMergeArrays = true
|
|
||||||
}
|
|
||||||
op := &Operation{OperationType: multiplyOpType, Value: multiplyOpType.Type, StringValue: options, Preferences: prefs}
|
op := &Operation{OperationType: multiplyOpType, Value: multiplyOpType.Type, StringValue: options, Preferences: prefs}
|
||||||
return &token{TokenType: operationToken, Operation: op}, nil
|
return &token{TokenType: operationToken, Operation: op}, nil
|
||||||
}
|
}
|
||||||
@@ -189,7 +186,7 @@ func getVariableOpToken() lex.Action {
|
|||||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
value := string(m.Bytes)
|
value := string(m.Bytes)
|
||||||
|
|
||||||
value = value[1:]
|
value = value[1 : len(value)-1]
|
||||||
|
|
||||||
getVarOperation := createValueOperation(value, value)
|
getVarOperation := createValueOperation(value, value)
|
||||||
getVarOperation.OperationType = getVariableOpType
|
getVarOperation.OperationType = getVariableOpType
|
||||||
@@ -255,8 +252,6 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`or`), opToken(orOpType))
|
lexer.Add([]byte(`or`), opToken(orOpType))
|
||||||
lexer.Add([]byte(`and`), opToken(andOpType))
|
lexer.Add([]byte(`and`), opToken(andOpType))
|
||||||
lexer.Add([]byte(`not`), opToken(notOpType))
|
lexer.Add([]byte(`not`), opToken(notOpType))
|
||||||
lexer.Add([]byte(`ireduce`), opToken(reduceOpType))
|
|
||||||
lexer.Add([]byte(`;`), opToken(blockOpType))
|
|
||||||
lexer.Add([]byte(`\/\/`), opToken(alternativeOpType))
|
lexer.Add([]byte(`\/\/`), opToken(alternativeOpType))
|
||||||
|
|
||||||
lexer.Add([]byte(`documentIndex`), opToken(getDocumentIndexOpType))
|
lexer.Add([]byte(`documentIndex`), opToken(getDocumentIndexOpType))
|
||||||
@@ -322,7 +317,7 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`\]`), literalToken(closeCollect, true))
|
lexer.Add([]byte(`\]`), literalToken(closeCollect, true))
|
||||||
lexer.Add([]byte(`\{`), literalToken(openCollectObject, false))
|
lexer.Add([]byte(`\{`), literalToken(openCollectObject, false))
|
||||||
lexer.Add([]byte(`\}`), literalToken(closeCollectObject, true))
|
lexer.Add([]byte(`\}`), literalToken(closeCollectObject, true))
|
||||||
lexer.Add([]byte(`\*[\+|\?d]*`), multiplyWithPrefs())
|
lexer.Add([]byte(`\*[\+|\?]*`), multiplyWithPrefs())
|
||||||
lexer.Add([]byte(`\+`), opToken(addOpType))
|
lexer.Add([]byte(`\+`), opToken(addOpType))
|
||||||
lexer.Add([]byte(`\+=`), opToken(addAssignOpType))
|
lexer.Add([]byte(`\+=`), opToken(addAssignOpType))
|
||||||
lexer.Add([]byte(`\$[a-zA-Z_-0-9]+`), getVariableOpToken())
|
lexer.Add([]byte(`\$[a-zA-Z_-0-9]+`), getVariableOpToken())
|
||||||
|
|||||||
@@ -25,9 +25,6 @@ type operationType struct {
|
|||||||
|
|
||||||
var orOpType = &operationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: orOperator}
|
var orOpType = &operationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: orOperator}
|
||||||
var andOpType = &operationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: andOperator}
|
var andOpType = &operationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: andOperator}
|
||||||
var reduceOpType = &operationType{Type: "REDUCE", NumArgs: 2, Precedence: 35, Handler: reduceOperator}
|
|
||||||
|
|
||||||
var blockOpType = &operationType{Type: "BLOCK", Precedence: 10, NumArgs: 2, Handler: emptyOperator}
|
|
||||||
|
|
||||||
var unionOpType = &operationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: unionOperator}
|
var unionOpType = &operationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: unionOperator}
|
||||||
|
|
||||||
@@ -83,7 +80,7 @@ var selfReferenceOpType = &operationType{Type: "SELF", NumArgs: 0, Precedence: 5
|
|||||||
var valueOpType = &operationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: valueOperator}
|
var valueOpType = &operationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: valueOperator}
|
||||||
var envOpType = &operationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler: envOperator}
|
var envOpType = &operationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler: envOperator}
|
||||||
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
||||||
var emptyOpType = &operationType{Type: "EMPTY", Precedence: 50, Handler: emptyOperator}
|
var emptyOpType = &operationType{Type: "EMPTY", NumArgs: 50, Handler: emptyOperator}
|
||||||
|
|
||||||
var recursiveDescentOpType = &operationType{Type: "RECURSIVE_DESCENT", NumArgs: 0, Precedence: 50, Handler: recursiveDescentOperator}
|
var recursiveDescentOpType = &operationType{Type: "RECURSIVE_DESCENT", NumArgs: 0, Precedence: 50, Handler: recursiveDescentOperator}
|
||||||
|
|
||||||
|
|||||||
@@ -21,16 +21,6 @@ var fileOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!int)::0\n",
|
"D0, P[], (!!int)::0\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
description: "Get file indices of multiple documents",
|
|
||||||
document: `{a: cat}`,
|
|
||||||
document2: `{a: cat}`,
|
|
||||||
expression: `fileIndex`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!int)::0\n",
|
|
||||||
"D0, P[], (!!int)::1\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: "Get file index alias",
|
description: "Get file index alias",
|
||||||
document: `{a: cat}`,
|
document: `{a: cat}`,
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type multiplyPreferences struct {
|
type multiplyPreferences struct {
|
||||||
AppendArrays bool
|
AppendArrays bool
|
||||||
DeepMergeArrays bool
|
TraversePrefs traversePreferences
|
||||||
TraversePrefs traversePreferences
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func multiplyOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
func multiplyOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
@@ -38,31 +37,11 @@ func multiply(preferences multiplyPreferences) func(d *dataTreeNavigator, contex
|
|||||||
return mergeObjects(d, context, newThing, rhs, preferences)
|
return mergeObjects(d, context, newThing, rhs, preferences)
|
||||||
} else if lhs.Node.Tag == "!!int" && rhs.Node.Tag == "!!int" {
|
} else if lhs.Node.Tag == "!!int" && rhs.Node.Tag == "!!int" {
|
||||||
return multiplyIntegers(lhs, rhs)
|
return multiplyIntegers(lhs, rhs)
|
||||||
} else if (lhs.Node.Tag == "!!int" || lhs.Node.Tag == "!!float") && (rhs.Node.Tag == "!!int" || rhs.Node.Tag == "!!float") {
|
|
||||||
return multiplyFloats(lhs, rhs)
|
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Cannot multiply %v with %v", lhs.Node.Tag, rhs.Node.Tag)
|
return nil, fmt.Errorf("Cannot multiply %v with %v", lhs.Node.Tag, rhs.Node.Tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func multiplyFloats(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
|
||||||
target := lhs.CreateChild(nil, &yaml.Node{})
|
|
||||||
target.Node.Kind = yaml.ScalarNode
|
|
||||||
target.Node.Style = lhs.Node.Style
|
|
||||||
target.Node.Tag = "!!float"
|
|
||||||
|
|
||||||
lhsNum, err := strconv.ParseFloat(lhs.Node.Value, 64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rhsNum, err := strconv.ParseFloat(rhs.Node.Value, 64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
target.Node.Value = fmt.Sprintf("%v", lhsNum*rhsNum)
|
|
||||||
return target, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func multiplyIntegers(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
func multiplyIntegers(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
target := lhs.CreateChild(nil, &yaml.Node{})
|
target := lhs.CreateChild(nil, &yaml.Node{})
|
||||||
target.Node.Kind = yaml.ScalarNode
|
target.Node.Kind = yaml.ScalarNode
|
||||||
@@ -119,12 +98,11 @@ func applyAssignment(d *dataTreeNavigator, context Context, pathIndexToStartFrom
|
|||||||
lhsPath := rhs.Path[pathIndexToStartFrom:]
|
lhsPath := rhs.Path[pathIndexToStartFrom:]
|
||||||
|
|
||||||
assignmentOp := &Operation{OperationType: assignAttributesOpType}
|
assignmentOp := &Operation{OperationType: assignAttributesOpType}
|
||||||
if shouldAppendArrays && rhs.Node.Kind == yaml.SequenceNode {
|
if rhs.Node.Kind == yaml.ScalarNode || rhs.Node.Kind == yaml.AliasNode {
|
||||||
assignmentOp.OperationType = addAssignOpType
|
|
||||||
} else if !preferences.DeepMergeArrays && rhs.Node.Kind == yaml.SequenceNode ||
|
|
||||||
(rhs.Node.Kind == yaml.ScalarNode || rhs.Node.Kind == yaml.AliasNode) {
|
|
||||||
assignmentOp.OperationType = assignOpType
|
assignmentOp.OperationType = assignOpType
|
||||||
assignmentOp.UpdateAssign = false
|
assignmentOp.UpdateAssign = false
|
||||||
|
} else if shouldAppendArrays && rhs.Node.Kind == yaml.SequenceNode {
|
||||||
|
assignmentOp.OperationType = addAssignOpType
|
||||||
}
|
}
|
||||||
rhsOp := &Operation{OperationType: valueOpType, CandidateNode: rhs}
|
rhsOp := &Operation{OperationType: valueOpType, CandidateNode: rhs}
|
||||||
|
|
||||||
|
|||||||
@@ -5,27 +5,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var multiplyOperatorScenarios = []expressionScenario{
|
var multiplyOperatorScenarios = []expressionScenario{
|
||||||
{
|
|
||||||
description: "Multiply integers",
|
|
||||||
expression: `3 * 4`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!int)::12\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
expression: `3 * 4.5`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!float)::13.5\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
expression: `4.5 * 3`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!float)::13.5\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{a: {also: [1]}, b: {also: me}}`,
|
document: `{a: {also: [1]}, b: {also: me}}`,
|
||||||
@@ -178,7 +157,7 @@ var multiplyOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{a: [{thing: one}], b: [{missing: two, thing: two}]}`,
|
document: `{a: [{thing: one}], b: [{missing: two, thing: two}]}`,
|
||||||
expression: `.a *?d .b`,
|
expression: `.a *? .b`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[a], (!!seq)::[{thing: two}]\n",
|
"D0, P[a], (!!seq)::[{thing: two}]\n",
|
||||||
},
|
},
|
||||||
@@ -207,15 +186,6 @@ var multiplyOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a], (!!map)::{thing: [1, 2, 3, 4]}\n",
|
"D0, P[a], (!!map)::{thing: [1, 2, 3, 4]}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
description: "Merge, deeply merging arrays",
|
|
||||||
subdescription: "Merging arrays deeply means arrays are merge like objects, with indexes as their key. In this case, we merge the first item in the array, and do nothing with the second.",
|
|
||||||
document: `{a: [{name: fred, age: 12}, {name: bob, age: 32}], b: [{name: fred, age: 34}]}`,
|
|
||||||
expression: `.a *d .b`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[a], (!!seq)::[{name: fred, age: 34}, {name: bob, age: 32}]\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: "Merge to prefix an element",
|
description: "Merge to prefix an element",
|
||||||
document: `{a: cat, b: dog}`,
|
document: `{a: cat, b: dog}`,
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
package yqlib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"container/list"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func reduceOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
|
||||||
log.Debugf("-- reduceOp")
|
|
||||||
//.a as $var reduce (0; . + $var)
|
|
||||||
//lhs is the assignment operator
|
|
||||||
//rhs is the reduce block
|
|
||||||
// '.' refers to the current accumulator, initialised to 0
|
|
||||||
// $var references a single element from the .a
|
|
||||||
|
|
||||||
//ensure lhs is actually an assignment
|
|
||||||
//and rhs is a block (empty)
|
|
||||||
if expressionNode.Lhs.Operation.OperationType != assignVariableOpType {
|
|
||||||
return Context{}, fmt.Errorf("reduce must be given a variables assignment, got %v instead", expressionNode.Lhs.Operation.OperationType.Type)
|
|
||||||
} else if expressionNode.Rhs.Operation.OperationType != blockOpType {
|
|
||||||
return Context{}, fmt.Errorf("reduce must be given a block, got %v instead", expressionNode.Rhs.Operation.OperationType.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
arrayExpNode := expressionNode.Lhs.Lhs
|
|
||||||
array, err := d.GetMatchingNodes(context, arrayExpNode)
|
|
||||||
|
|
||||||
log.Debugf("array of %v things", array.MatchingNodes.Len())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Context{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
variableName := expressionNode.Lhs.Rhs.Operation.StringValue
|
|
||||||
|
|
||||||
initExp := expressionNode.Rhs.Lhs
|
|
||||||
|
|
||||||
accum, err := d.GetMatchingNodes(context, initExp)
|
|
||||||
if err != nil {
|
|
||||||
return Context{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("with variable %v", variableName)
|
|
||||||
|
|
||||||
blockExp := expressionNode.Rhs.Rhs
|
|
||||||
for el := array.MatchingNodes.Front(); el != nil; el = el.Next() {
|
|
||||||
candidate := el.Value.(*CandidateNode)
|
|
||||||
log.Debugf("REDUCING WITH %v", NodeToString(candidate))
|
|
||||||
l := list.New()
|
|
||||||
l.PushBack(candidate)
|
|
||||||
accum.SetVariable(variableName, l)
|
|
||||||
|
|
||||||
accum, err = d.GetMatchingNodes(accum, blockExp)
|
|
||||||
if err != nil {
|
|
||||||
return Context{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return accum, nil
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package yqlib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var reduceOperatorScenarios = []expressionScenario{
|
|
||||||
{
|
|
||||||
description: "Sum numbers",
|
|
||||||
document: `[10,2, 5, 3]`,
|
|
||||||
expression: `.[] as $item ireduce (0; . + $item)`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!int)::20\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Merge all yaml files together",
|
|
||||||
document: `a: cat`,
|
|
||||||
document2: `b: dog`,
|
|
||||||
expression: `. as $item ireduce ({}; . * $item )`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::a: cat\nb: dog\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Convert an array to an object",
|
|
||||||
document: `[{name: Cathy, has: apples},{name: Bob, has: bananas}]`,
|
|
||||||
expression: `.[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )`,
|
|
||||||
expected: []string{
|
|
||||||
"D0, P[], (!!map)::Cathy: apples\nBob: bananas\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReduceOperatorScenarios(t *testing.T) {
|
|
||||||
for _, tt := range reduceOperatorScenarios {
|
|
||||||
testScenario(t, &tt)
|
|
||||||
}
|
|
||||||
documentScenarios(t, "Reduce", reduceOperatorScenarios)
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: yq
|
name: yq
|
||||||
version: '4.6.0'
|
version: '4.5.1'
|
||||||
summary: A lightweight and portable command-line YAML processor
|
summary: A lightweight and portable command-line YAML processor
|
||||||
description: |
|
description: |
|
||||||
The aim of the project is to be the jq or sed of yaml files.
|
The aim of the project is to be the jq or sed of yaml files.
|
||||||
|
|||||||
BIN
yq_linux_amd64.tar.gz
Normal file
BIN
yq_linux_amd64.tar.gz
Normal file
Binary file not shown.
Reference in New Issue
Block a user