mirror of
https://github.com/mikefarah/yq.git
synced 2025-02-25 17:15:48 +00:00
Added with operator
This commit is contained in:
parent
0c3334d838
commit
6002604251
@ -1,3 +1,5 @@
|
|||||||
# a1
|
Resources:
|
||||||
a: 1
|
S3Bucket:
|
||||||
# a2
|
Type: AWS::CloudFormation::Stack
|
||||||
|
Properties:
|
||||||
|
BucketName: !Ref MyBucketNameA
|
@ -18,8 +18,6 @@ a:
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Update and set style of a particular node using path variables
|
## Update and set style of a particular node using path variables
|
||||||
You can use a variable reference to re-use a path
|
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@ -28,7 +26,7 @@ a:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.a.b ref $x | $x = "new" | $x style="double"' sample.yml
|
yq eval 'with(.a.b ; . = "new" | . style="double")' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
@ -75,6 +75,8 @@ b: a_value
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Use ref to reference a path repeatedly
|
## Use ref to reference a path repeatedly
|
||||||
|
Note: You may find the `with` operator more useful.
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
|
20
pkg/yqlib/doc/With.md
Normal file
20
pkg/yqlib/doc/With.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Use the `with` operator to conveniently make multiple updates to a deeply nested path.
|
||||||
|
|
||||||
|
## Update and style
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
deeply:
|
||||||
|
nested: value
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'with(.a.deeply.nested ; . = "newValue" | . style="single")' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
deeply:
|
||||||
|
nested: 'newValue'
|
||||||
|
```
|
||||||
|
|
1
pkg/yqlib/doc/headers/With.md
Normal file
1
pkg/yqlib/doc/headers/With.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Use the `with` operator to conveniently make multiple updates to a deeply nested path.
|
@ -315,6 +315,8 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`from_entries`), opToken(fromEntriesOpType))
|
lexer.Add([]byte(`from_entries`), opToken(fromEntriesOpType))
|
||||||
lexer.Add([]byte(`with_entries`), opToken(withEntriesOpType))
|
lexer.Add([]byte(`with_entries`), opToken(withEntriesOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`with`), opToken(withOpType))
|
||||||
|
|
||||||
lexer.Add([]byte(`lineComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{LineComment: true}))
|
lexer.Add([]byte(`lineComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{LineComment: true}))
|
||||||
|
|
||||||
lexer.Add([]byte(`headComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{HeadComment: true}))
|
lexer.Add([]byte(`headComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{HeadComment: true}))
|
||||||
|
@ -69,6 +69,8 @@ var toEntriesOpType = &operationType{Type: "TO_ENTRIES", NumArgs: 0, Precedence:
|
|||||||
var fromEntriesOpType = &operationType{Type: "FROM_ENTRIES", NumArgs: 0, Precedence: 50, Handler: fromEntriesOperator}
|
var fromEntriesOpType = &operationType{Type: "FROM_ENTRIES", NumArgs: 0, Precedence: 50, Handler: fromEntriesOperator}
|
||||||
var withEntriesOpType = &operationType{Type: "WITH_ENTRIES", NumArgs: 1, Precedence: 50, Handler: withEntriesOperator}
|
var withEntriesOpType = &operationType{Type: "WITH_ENTRIES", NumArgs: 1, Precedence: 50, Handler: withEntriesOperator}
|
||||||
|
|
||||||
|
var withOpType = &operationType{Type: "WITH", NumArgs: 1, Precedence: 50, Handler: withOperator}
|
||||||
|
|
||||||
var splitDocumentOpType = &operationType{Type: "SPLIT_DOC", NumArgs: 0, Precedence: 50, Handler: splitDocumentOperator}
|
var splitDocumentOpType = &operationType{Type: "SPLIT_DOC", NumArgs: 0, Precedence: 50, Handler: splitDocumentOperator}
|
||||||
var getVariableOpType = &operationType{Type: "GET_VARIABLE", NumArgs: 0, Precedence: 55, Handler: getVariableOperator}
|
var getVariableOpType = &operationType{Type: "GET_VARIABLE", NumArgs: 0, Precedence: 55, Handler: getVariableOperator}
|
||||||
var getStyleOpType = &operationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: getStyleOperator}
|
var getStyleOpType = &operationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: getStyleOperator}
|
||||||
|
@ -14,10 +14,9 @@ var styleOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Update and set style of a particular node using path variables",
|
description: "Update and set style of a particular node using path variables",
|
||||||
subdescription: "You can use a variable reference to re-use a path",
|
document: `a: {b: thing, c: something}`,
|
||||||
document: `a: {b: thing, c: something}`,
|
expression: `with(.a.b ; . = "new" | . style="double")`,
|
||||||
expression: `.a.b ref $x | $x = "new" | $x style="double"`,
|
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (doc)::a: {b: \"new\", c: something}\n",
|
"D0, P[], (doc)::a: {b: \"new\", c: something}\n",
|
||||||
},
|
},
|
||||||
|
@ -52,9 +52,10 @@ var variableOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Use ref to reference a path repeatedly",
|
description: "Use ref to reference a path repeatedly",
|
||||||
document: `a: {b: thing, c: something}`,
|
subdescription: "Note: You may find the `with` operator more useful.",
|
||||||
expression: `.a.b ref $x | $x = "new" | $x style="double"`,
|
document: `a: {b: thing, c: something}`,
|
||||||
|
expression: `.a.b ref $x | $x = "new" | $x style="double"`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (doc)::a: {b: \"new\", c: something}\n",
|
"D0, P[], (doc)::a: {b: \"new\", c: something}\n",
|
||||||
},
|
},
|
||||||
|
30
pkg/yqlib/operator_with.go
Normal file
30
pkg/yqlib/operator_with.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func withOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
log.Debugf("-- withOperator")
|
||||||
|
// with(path, exp)
|
||||||
|
|
||||||
|
if expressionNode.Rhs.Operation.OperationType != blockOpType {
|
||||||
|
return Context{}, fmt.Errorf("with must be given a block, got %v instead", expressionNode.Rhs.Operation.OperationType.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
pathExp := expressionNode.Rhs.Lhs
|
||||||
|
|
||||||
|
updateContext, err := d.GetMatchingNodes(context, pathExp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Context{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
updateExp := expressionNode.Rhs.Rhs
|
||||||
|
|
||||||
|
_, err = d.GetMatchingNodes(updateContext, updateExp)
|
||||||
|
if err != nil {
|
||||||
|
return Context{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return context, nil
|
||||||
|
|
||||||
|
}
|
21
pkg/yqlib/operator_with_test.go
Normal file
21
pkg/yqlib/operator_with_test.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var withOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Update and style",
|
||||||
|
document: `a: {deeply: {nested: value}}`,
|
||||||
|
expression: `with(.a.deeply.nested ; . = "newValue" | . style="single")`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: {deeply: {nested: 'newValue'}}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range withOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "With", withOperatorScenarios)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user