From 1be3b31bbcd753cfc047acc14f7bd82fbd39301a Mon Sep 17 00:00:00 2001 From: evnp Date: Sat, 16 Jan 2021 22:09:22 -0800 Subject: [PATCH] Don't escape HTML chars when converting to json json.Encoder and json.Marshal implicitly use HTMLEscape to convert >, <, &, with \u003c, \u003e, \u0026. This behavior carries over to yq, where chars will be escaped when outputting json but not when outputting yaml. This changeset disables this behavior via encoder.SetEscapeHTML(false). Unfortunately there is no equivalent option for json.Marshal, so its single usage has been replaced with an encoder (with escaping disabled). --- pkg/yqlib/encoder.go | 12 ++++++--- pkg/yqlib/encoder_test.go | 51 +++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/pkg/yqlib/encoder.go b/pkg/yqlib/encoder.go index b15be07..a77b57c 100644 --- a/pkg/yqlib/encoder.go +++ b/pkg/yqlib/encoder.go @@ -76,6 +76,8 @@ func mapKeysToStrings(node *yaml.Node) { func NewJsonEncoder(destination io.Writer, indent int) Encoder { var encoder = json.NewEncoder(destination) + encoder.SetEscapeHTML(false) // do not escape html chars e.g. &, <, > + var indentString = "" for index := 0; index < indent; index++ { @@ -153,11 +155,15 @@ func (o *orderedMap) UnmarshalJSON(data []byte) error { } func (o orderedMap) MarshalJSON() ([]byte, error) { - if o.kv == nil { - return json.Marshal(o.altVal) - } buf := new(bytes.Buffer) enc := json.NewEncoder(buf) + enc.SetEscapeHTML(false) // do not escape html chars e.g. &, <, > + if o.kv == nil { + if err := enc.Encode(o.altVal); err != nil { + return nil, err + } + return buf.Bytes(), nil + } buf.WriteByte('{') for idx, el := range o.kv { if err := enc.Encode(el.K); err != nil { diff --git a/pkg/yqlib/encoder_test.go b/pkg/yqlib/encoder_test.go index d721173..333749d 100644 --- a/pkg/yqlib/encoder_test.go +++ b/pkg/yqlib/encoder_test.go @@ -9,29 +9,11 @@ import ( "github.com/mikefarah/yq/v4/test" ) -var sampleYaml = `zabbix: winner -apple: great -banana: -- {cobra: kai, angus: bob} -` - -var expectedJson = `{ - "zabbix": "winner", - "apple": "great", - "banana": [ - { - "cobra": "kai", - "angus": "bob" - } - ] -} -` - -func TestJsonEncoderPreservesObjectOrder(t *testing.T) { +func yamlToJson(sampleYaml string, indent int) string { var output bytes.Buffer writer := bufio.NewWriter(&output) - var jsonEncoder = NewJsonEncoder(writer, 2) + var jsonEncoder = NewJsonEncoder(writer, indent) inputs, err := readDocuments(strings.NewReader(sampleYaml), "sample.yml", 0) if err != nil { panic(err) @@ -42,6 +24,33 @@ func TestJsonEncoderPreservesObjectOrder(t *testing.T) { panic(err) } writer.Flush() - test.AssertResult(t, expectedJson, output.String()) + return strings.TrimSuffix(output.String(), "\n") +} + +func TestJsonEncoderPreservesObjectOrder(t *testing.T) { + var sampleYaml = `zabbix: winner +apple: great +banana: +- {cobra: kai, angus: bob} +` + var expectedJson = `{ + "zabbix": "winner", + "apple": "great", + "banana": [ + { + "cobra": "kai", + "angus": "bob" + } + ] +}` + var actualJson = yamlToJson(sampleYaml, 2) + test.AssertResult(t, expectedJson, actualJson) +} + +func TestJsonEncoderDoesNotEscapeHTMLChars(t *testing.T) { + var sampleYaml = `build: "( ./lint && ./format && ./compile ) < src.code"` + var expectedJson = `{"build":"( ./lint && ./format && ./compile ) < src.code"}` + var actualJson = yamlToJson(sampleYaml, 0) + test.AssertResult(t, expectedJson, actualJson) }