Adds @uri/@urid #1529

This commit is contained in:
Mike Farah 2023-01-23 11:37:18 +11:00
parent dd6cf3df14
commit 6d7d76a3f1
9 changed files with 152 additions and 0 deletions

View File

@ -15,6 +15,7 @@ const (
JsonInputFormat
CSVObjectInputFormat
TSVObjectInputFormat
UriInputFormat
)
type Decoder interface {

60
pkg/yqlib/decoder_uri.go Normal file
View File

@ -0,0 +1,60 @@
package yqlib
import (
"bytes"
"io"
"net/url"
yaml "gopkg.in/yaml.v3"
)
type uriDecoder struct {
reader io.Reader
finished bool
readAnything bool
}
func NewUriDecoder() Decoder {
return &uriDecoder{finished: false}
}
func (dec *uriDecoder) Init(reader io.Reader) error {
dec.reader = reader
dec.readAnything = false
dec.finished = false
return nil
}
func (dec *uriDecoder) Decode() (*CandidateNode, error) {
if dec.finished {
return nil, io.EOF
}
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(dec.reader); err != nil {
return nil, err
}
if buf.Len() == 0 {
dec.finished = true
// if we've read _only_ an empty string, lets return that
// otherwise if we've already read some bytes, and now we get
// an empty string, then we are done.
if dec.readAnything {
return nil, io.EOF
}
}
newValue, err := url.QueryUnescape(buf.String())
if err != nil {
return nil, err
}
dec.readAnything = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: newValue,
},
}, nil
}

View File

@ -16,6 +16,7 @@ These operators are useful to process yaml documents that have stringified embed
| TSV | from_tsv/@tsvd | to_tsv/@tsv |
| XML | from_xml/@xmld | to_xml(i)/@xml |
| Base64 | @base64d | @base64 |
| URI | @urid | @uri |
See CSV and TSV [documentation](https://mikefarah.gitbook.io/yq/usage/csv-tsv) for accepted formats.
@ -435,6 +436,34 @@ will output
YTogYXBwbGUK
```
## Encode a string to uri
Given a sample.yml file of:
```yaml
coolData: this has & special () characters *
```
then
```bash
yq '.coolData | @uri' sample.yml
```
will output
```yaml
this+has+%26+special+%28%29+characters+%2A
```
## Decode a URI to a string
Given a sample.yml file of:
```yaml
this+has+%26+special+%28%29+characters+%2A
```
then
```bash
yq '@urid' sample.yml
```
will output
```yaml
this has & special () characters *
```
## Decode a base64 encoded string
Decoded data is assumed to be a string.

View File

@ -16,6 +16,7 @@ These operators are useful to process yaml documents that have stringified embed
| TSV | from_tsv/@tsvd | to_tsv/@tsv |
| XML | from_xml/@xmld | to_xml(i)/@xml |
| Base64 | @base64d | @base64 |
| URI | @urid | @uri |
See CSV and TSV [documentation](https://mikefarah.gitbook.io/yq/usage/csv-tsv) for accepted formats.

37
pkg/yqlib/encoder_uri.go Normal file
View File

@ -0,0 +1,37 @@
package yqlib
import (
"fmt"
"io"
"net/url"
yaml "gopkg.in/yaml.v3"
)
type uriEncoder struct {
}
func NewUriEncoder() Encoder {
return &uriEncoder{}
}
func (e *uriEncoder) CanHandleAliases() bool {
return false
}
func (e *uriEncoder) PrintDocumentSeparator(writer io.Writer) error {
return nil
}
func (e *uriEncoder) PrintLeadingContent(writer io.Writer, content string) error {
return nil
}
func (e *uriEncoder) Encode(writer io.Writer, originalNode *yaml.Node) error {
node := unwrapDoc(originalNode)
if guessTagFromCustomType(node) != "!!str" {
return fmt.Errorf("cannot encode %v as url, can only operate on strings. Please first pipe through another encoding operator to convert the value to a string", node.Tag)
}
_, err := writer.Write([]byte(url.QueryEscape(originalNode.Value)))
return err
}

View File

@ -78,6 +78,9 @@ var participleYqRules = []*participleYqRule{
{"Base64d", `@base64d`, decodeOp(Base64InputFormat), 0},
{"Base64", `@base64`, encodeWithIndent(Base64OutputFormat, 0), 0},
{"Urld", `@urid`, decodeOp(UriInputFormat), 0},
{"Url", `@uri`, encodeWithIndent(UriOutputFormat, 0), 0},
{"LoadXML", `load_?xml|xml_?load`, loadOp(NewXMLDecoder(ConfiguredXMLPreferences), false), 0},
{"LoadBase64", `load_?base64`, loadOp(NewBase64Decoder(), false), 0},

View File

@ -26,6 +26,8 @@ func configureEncoder(format PrinterOutputFormat, indent int) Encoder {
return NewXMLEncoder(indent, ConfiguredXMLPreferences)
case Base64OutputFormat:
return NewBase64Encoder()
case UriOutputFormat:
return NewUriEncoder()
}
panic("invalid encoder")
}
@ -113,6 +115,8 @@ func decodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
decoder = NewCSVObjectDecoder(',')
case TSVObjectInputFormat:
decoder = NewCSVObjectDecoder('\t')
case UriInputFormat:
decoder = NewUriDecoder()
}
var results = list.New()

View File

@ -241,6 +241,22 @@ var encoderDecoderOperatorScenarios = []expressionScenario{
"D0, P[], (!!str)::YTogYXBwbGUK\n",
},
},
{
description: "Encode a string to uri",
document: "coolData: this has & special () characters *",
expression: ".coolData | @uri",
expected: []string{
"D0, P[coolData], (!!str)::this+has+%26+special+%28%29+characters+%2A\n",
},
},
{
description: "Decode a URI to a string",
document: "this+has+%26+special+%28%29+characters+%2A",
expression: "@urid",
expected: []string{
"D0, P[], (!!str)::this has & special () characters *\n",
},
},
{
description: "Decode a base64 encoded string",
subdescription: "Decoded data is assumed to be a string.",

View File

@ -27,6 +27,7 @@ const (
TSVOutputFormat
XMLOutputFormat
Base64OutputFormat
UriOutputFormat
)
func OutputFormatFromString(format string) (PrinterOutputFormat, error) {