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
|
||||
a: 1
|
||||
# a2
|
||||
Resources:
|
||||
S3Bucket:
|
||||
Type: AWS::CloudFormation::Stack
|
||||
Properties:
|
||||
BucketName: !Ref MyBucketNameA
|
@ -18,8 +18,6 @@ a:
|
||||
```
|
||||
|
||||
## 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:
|
||||
```yaml
|
||||
a:
|
||||
@ -28,7 +26,7 @@ a:
|
||||
```
|
||||
then
|
||||
```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
|
||||
```yaml
|
||||
|
@ -75,6 +75,8 @@ b: a_value
|
||||
```
|
||||
|
||||
## Use ref to reference a path repeatedly
|
||||
Note: You may find the `with` operator more useful.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
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(`with_entries`), opToken(withEntriesOpType))
|
||||
|
||||
lexer.Add([]byte(`with`), opToken(withOpType))
|
||||
|
||||
lexer.Add([]byte(`lineComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, commentOpPreferences{LineComment: 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 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 getVariableOpType = &operationType{Type: "GET_VARIABLE", NumArgs: 0, Precedence: 55, Handler: getVariableOperator}
|
||||
var getStyleOpType = &operationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: getStyleOperator}
|
||||
|
@ -15,9 +15,8 @@ var styleOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
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}`,
|
||||
expression: `.a.b ref $x | $x = "new" | $x style="double"`,
|
||||
expression: `with(.a.b ; . = "new" | . style="double")`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: {b: \"new\", c: something}\n",
|
||||
},
|
||||
|
@ -53,6 +53,7 @@ var variableOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Use ref to reference a path repeatedly",
|
||||
subdescription: "Note: You may find the `with` operator more useful.",
|
||||
document: `a: {b: thing, c: something}`,
|
||||
expression: `.a.b ref $x | $x = "new" | $x style="double"`,
|
||||
expected: []string{
|
||||
|
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