mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Added encoder op
This commit is contained in:
parent
7d0376b8ee
commit
cdc5ef7b15
77
pkg/yqlib/doc/Encoder.md
Normal file
77
pkg/yqlib/doc/Encoder.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
Encode operators will take the piped in object structure and encode it as a string in the desired format.
|
||||||
|
## Encode value as yaml string
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
cool: thing
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.b = (.a | to_yaml)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
cool: thing
|
||||||
|
b: |
|
||||||
|
cool: thing
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encode value as yaml string, using toyaml
|
||||||
|
Does the same thing as to_yaml, matching jq naming convention.
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
cool: thing
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.b = (.a | to_yaml)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
cool: thing
|
||||||
|
b: |
|
||||||
|
cool: thing
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encode value as json string
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
cool: thing
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.b = (.a | to_json)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
cool: thing
|
||||||
|
b: |
|
||||||
|
{
|
||||||
|
"cool": "thing"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encode value as props string
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
cool: thing
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.b = (.a | to_props)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
cool: thing
|
||||||
|
b: |
|
||||||
|
cool = thing
|
||||||
|
```
|
||||||
|
|
1
pkg/yqlib/doc/headers/Encoder.md
Normal file
1
pkg/yqlib/doc/headers/Encoder.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Encode operators will take the piped in object structure and encode it as a string in the desired format.
|
@ -272,6 +272,15 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`,`), opToken(unionOpType))
|
lexer.Add([]byte(`,`), opToken(unionOpType))
|
||||||
lexer.Add([]byte(`:\s*`), opToken(createMapOpType))
|
lexer.Add([]byte(`:\s*`), opToken(createMapOpType))
|
||||||
lexer.Add([]byte(`length`), opToken(lengthOpType))
|
lexer.Add([]byte(`length`), opToken(lengthOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`toyaml`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: YamlOutputFormat}))
|
||||||
|
lexer.Add([]byte(`tojson`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: JsonOutputFormat}))
|
||||||
|
lexer.Add([]byte(`toprops`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: PropsOutputFormat}))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`to_yaml`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: YamlOutputFormat}))
|
||||||
|
lexer.Add([]byte(`to_json`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: JsonOutputFormat}))
|
||||||
|
lexer.Add([]byte(`to_props`), opTokenWithPrefs(encodeOpType, nil, encoderPreferences{format: PropsOutputFormat}))
|
||||||
|
|
||||||
lexer.Add([]byte(`sortKeys`), opToken(sortKeysOpType))
|
lexer.Add([]byte(`sortKeys`), opToken(sortKeysOpType))
|
||||||
lexer.Add([]byte(`select`), opToken(selectOpType))
|
lexer.Add([]byte(`select`), opToken(selectOpType))
|
||||||
lexer.Add([]byte(`has`), opToken(hasOpType))
|
lexer.Add([]byte(`has`), opToken(hasOpType))
|
||||||
|
@ -59,6 +59,7 @@ var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence:
|
|||||||
|
|
||||||
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
|
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
|
||||||
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: collectOperator}
|
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: collectOperator}
|
||||||
|
var encodeOpType = &operationType{Type: "TO_YAML", NumArgs: 0, Precedence: 50, Handler: encodeOperator}
|
||||||
|
|
||||||
var anyOpType = &operationType{Type: "ANY", NumArgs: 0, Precedence: 50, Handler: anyOperator}
|
var anyOpType = &operationType{Type: "ANY", NumArgs: 0, Precedence: 50, Handler: anyOperator}
|
||||||
var allOpType = &operationType{Type: "ALL", NumArgs: 0, Precedence: 50, Handler: allOperator}
|
var allOpType = &operationType{Type: "ALL", NumArgs: 0, Precedence: 50, Handler: allOperator}
|
||||||
|
40
pkg/yqlib/operator_encoder.go
Normal file
40
pkg/yqlib/operator_encoder.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"container/list"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func yamlToString(candidate *CandidateNode, prefs encoderPreferences) (string, error) {
|
||||||
|
var output bytes.Buffer
|
||||||
|
printer := NewPrinter(bufio.NewWriter(&output), prefs.format, true, false, 2, true)
|
||||||
|
elMap := list.New()
|
||||||
|
elMap.PushBack(candidate)
|
||||||
|
err := printer.PrintResults(elMap)
|
||||||
|
return output.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
type encoderPreferences struct {
|
||||||
|
format PrinterOutputFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encodes object as yaml string */
|
||||||
|
|
||||||
|
func encodeOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||||
|
preferences := expressionNode.Operation.Preferences.(encoderPreferences)
|
||||||
|
var results = list.New()
|
||||||
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
stringValue, err := yamlToString(candidate, preferences)
|
||||||
|
if err != nil {
|
||||||
|
return Context{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stringContentNode := &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: stringValue}
|
||||||
|
results.PushBack(candidate.CreateChild(nil, stringContentNode))
|
||||||
|
}
|
||||||
|
return context.ChildContext(results), nil
|
||||||
|
}
|
52
pkg/yqlib/operator_encoder_test.go
Normal file
52
pkg/yqlib/operator_encoder_test.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var encoderOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Encode value as yaml string",
|
||||||
|
document: `{a: {cool: "thing"}}`,
|
||||||
|
expression: `.b = (.a | to_yaml)`,
|
||||||
|
expected: []string{
|
||||||
|
`D0, P[], (doc)::{a: {cool: "thing"}, b: "{cool: \"thing\"}\n"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Encode value as yaml string, using toyaml",
|
||||||
|
subdescription: "Does the same thing as to_yaml, matching jq naming convention.",
|
||||||
|
document: `{a: {cool: "thing"}}`,
|
||||||
|
expression: `.b = (.a | to_yaml)`,
|
||||||
|
expected: []string{
|
||||||
|
`D0, P[], (doc)::{a: {cool: "thing"}, b: "{cool: \"thing\"}\n"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Encode value as json string",
|
||||||
|
document: `{a: {cool: "thing"}}`,
|
||||||
|
expression: `.b = (.a | to_json)`,
|
||||||
|
expected: []string{
|
||||||
|
`D0, P[], (doc)::{a: {cool: "thing"}, b: "{\n \"cool\": \"thing\"\n}\n"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Encode value as props string",
|
||||||
|
document: `{a: {cool: "thing"}}`,
|
||||||
|
expression: `.b = (.a | to_props)`,
|
||||||
|
expected: []string{
|
||||||
|
`D0, P[], (doc)::{a: {cool: "thing"}, b: "cool = thing\n"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncoderOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range encoderOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Encoder", encoderOperatorScenarios)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user