Refactoring JSON encoder prefs

This commit is contained in:
Mike Farah 2024-02-24 15:48:59 +11:00
parent 7a01e216c4
commit 55f6a3a49d
9 changed files with 76 additions and 21 deletions

View File

@ -180,17 +180,20 @@ func configureEncoder() (yqlib.Encoder, error) {
func createEncoder(format *yqlib.PrinterOutputFormat) (yqlib.Encoder, error) { func createEncoder(format *yqlib.PrinterOutputFormat) (yqlib.Encoder, error) {
yqlib.ConfiguredXMLPreferences.Indent = indent yqlib.ConfiguredXMLPreferences.Indent = indent
yqlib.ConfiguredYamlPreferences.Indent = indent yqlib.ConfiguredYamlPreferences.Indent = indent
yqlib.ConfiguredJsonPreferences.Indent = indent
yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredPropertiesPreferences.UnwrapScalar = unwrapScalar yqlib.ConfiguredPropertiesPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredJsonPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredYamlPreferences.ColorsEnabled = colorsEnabled yqlib.ConfiguredYamlPreferences.ColorsEnabled = colorsEnabled
yqlib.ConfiguredJsonPreferences.ColorsEnabled = colorsEnabled
yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators
switch format { switch format {
case yqlib.JSONOutputFormat: case yqlib.JSONOutputFormat:
return yqlib.NewJSONEncoder(indent, colorsEnabled, unwrapScalar), nil return yqlib.NewJSONEncoder(yqlib.ConfiguredJsonPreferences), nil
case yqlib.PropsOutputFormat: case yqlib.PropsOutputFormat:
return yqlib.NewPropertiesEncoder(yqlib.ConfiguredPropertiesPreferences), nil return yqlib.NewPropertiesEncoder(yqlib.ConfiguredPropertiesPreferences), nil
case yqlib.CSVOutputFormat: case yqlib.CSVOutputFormat:

View File

@ -10,19 +10,18 @@ import (
) )
type jsonEncoder struct { type jsonEncoder struct {
prefs JsonPreferences
indentString string indentString string
colorise bool
UnwrapScalar bool
} }
func NewJSONEncoder(indent int, colorise bool, unwrapScalar bool) Encoder { func NewJSONEncoder(prefs JsonPreferences) Encoder {
var indentString = "" var indentString = ""
for index := 0; index < indent; index++ { for index := 0; index < prefs.Indent; index++ {
indentString = indentString + " " indentString = indentString + " "
} }
return &jsonEncoder{indentString, colorise, unwrapScalar} return &jsonEncoder{prefs, indentString}
} }
func (je *jsonEncoder) CanHandleAliases() bool { func (je *jsonEncoder) CanHandleAliases() bool {
@ -41,13 +40,13 @@ func (je *jsonEncoder) Encode(writer io.Writer, node *CandidateNode) error {
log.Debugf("I need to encode %v", NodeToString(node)) log.Debugf("I need to encode %v", NodeToString(node))
log.Debugf("kids %v", len(node.Content)) log.Debugf("kids %v", len(node.Content))
if node.Kind == ScalarNode && je.UnwrapScalar { if node.Kind == ScalarNode && je.prefs.UnwrapScalar {
return writeString(writer, node.Value+"\n") return writeString(writer, node.Value+"\n")
} }
destination := writer destination := writer
tempBuffer := bytes.NewBuffer(nil) tempBuffer := bytes.NewBuffer(nil)
if je.colorise { if je.prefs.ColorsEnabled {
destination = tempBuffer destination = tempBuffer
} }
@ -59,7 +58,7 @@ func (je *jsonEncoder) Encode(writer io.Writer, node *CandidateNode) error {
if err != nil { if err != nil {
return err return err
} }
if je.colorise { if je.prefs.ColorsEnabled {
return colorizeAndPrint(tempBuffer.Bytes(), writer) return colorizeAndPrint(tempBuffer.Bytes(), writer)
} }
return nil return nil

View File

@ -16,7 +16,10 @@ func yamlToJSON(t *testing.T, sampleYaml string, indent int) string {
var output bytes.Buffer var output bytes.Buffer
writer := bufio.NewWriter(&output) writer := bufio.NewWriter(&output)
var jsonEncoder = NewJSONEncoder(indent, false, false) prefs := ConfiguredJsonPreferences.Copy()
prefs.Indent = indent
prefs.UnwrapScalar = false
var jsonEncoder = NewJSONEncoder(prefs)
inputs, err := readDocuments(strings.NewReader(sampleYaml), "sample.yml", 0, NewYamlDecoder(ConfiguredYamlPreferences)) inputs, err := readDocuments(strings.NewReader(sampleYaml), "sample.yml", 0, NewYamlDecoder(ConfiguredYamlPreferences))
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -71,7 +71,7 @@ func documentExpressionScenario(_ *testing.T, w *bufio.Writer, i interface{}) {
encoder := NewYamlEncoder(ConfiguredYamlPreferences) encoder := NewYamlEncoder(ConfiguredYamlPreferences)
if s.scenarioType == "shebang-json" { if s.scenarioType == "shebang-json" {
encoder = NewJSONEncoder(2, false, false) encoder = NewJSONEncoder(ConfiguredJsonPreferences)
} }
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), encoder))) writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), encoder)))

25
pkg/yqlib/json.go Normal file
View File

@ -0,0 +1,25 @@
package yqlib
type JsonPreferences struct {
Indent int
ColorsEnabled bool
UnwrapScalar bool
}
func NewDefaultJsonPreferences() JsonPreferences {
return JsonPreferences{
Indent: 2,
ColorsEnabled: true,
UnwrapScalar: true,
}
}
func (p *JsonPreferences) Copy() JsonPreferences {
return JsonPreferences{
Indent: p.Indent,
ColorsEnabled: p.ColorsEnabled,
UnwrapScalar: p.UnwrapScalar,
}
}
var ConfiguredJsonPreferences = NewDefaultJsonPreferences()

View File

@ -85,6 +85,7 @@ var jsonScenarios = []formatScenario{
skipDoc: true, skipDoc: true,
input: "[]", input: "[]",
scenarioType: "roundtrip-ndjson", scenarioType: "roundtrip-ndjson",
indent: 0,
expected: "[]\n", expected: "[]\n",
}, },
{ {
@ -92,6 +93,7 @@ var jsonScenarios = []formatScenario{
skipDoc: true, skipDoc: true,
input: "[3]", input: "[3]",
scenarioType: "roundtrip-ndjson", scenarioType: "roundtrip-ndjson",
indent: 0,
expected: "[3]\n", expected: "[3]\n",
}, },
{ {
@ -99,6 +101,7 @@ var jsonScenarios = []formatScenario{
skipDoc: true, skipDoc: true,
input: `[{"x": 3}]`, input: `[{"x": 3}]`,
scenarioType: "roundtrip-ndjson", scenarioType: "roundtrip-ndjson",
indent: 0,
expected: "[{\"x\":3}]\n", expected: "[{\"x\":3}]\n",
}, },
{ {
@ -106,6 +109,7 @@ var jsonScenarios = []formatScenario{
skipDoc: true, skipDoc: true,
input: "[null]", input: "[null]",
scenarioType: "roundtrip-ndjson", scenarioType: "roundtrip-ndjson",
indent: 0,
expected: "[null]\n", expected: "[null]\n",
}, },
{ {
@ -114,6 +118,7 @@ var jsonScenarios = []formatScenario{
input: "[{}]", input: "[{}]",
expression: `[.. | type]`, expression: `[.. | type]`,
scenarioType: "roundtrip-ndjson", scenarioType: "roundtrip-ndjson",
indent: 0,
expected: "[\"!!seq\",\"!!map\"]\n", expected: "[\"!!seq\",\"!!map\"]\n",
}, },
{ {
@ -220,6 +225,7 @@ var jsonScenarios = []formatScenario{
input: sampleNdJson, input: sampleNdJson,
expected: expectedRoundTripSampleNdJson, expected: expectedRoundTripSampleNdJson,
scenarioType: "roundtrip-ndjson", scenarioType: "roundtrip-ndjson",
indent: 0,
}, },
{ {
description: "Roundtrip multi-document JSON", description: "Roundtrip multi-document JSON",
@ -322,8 +328,11 @@ func documentRoundtripNdJsonScenario(w *bufio.Writer, s formatScenario, indent i
} }
writeOrPanic(w, "will output\n") writeOrPanic(w, "will output\n")
prefs := ConfiguredJsonPreferences.Copy()
prefs.Indent = indent
prefs.UnwrapScalar = false
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(indent, false, false)))) writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(prefs))))
} }
func documentDecodeNdJsonScenario(w *bufio.Writer, s formatScenario) { func documentDecodeNdJsonScenario(w *bufio.Writer, s formatScenario) {
@ -377,19 +386,23 @@ func decodeJSON(t *testing.T, jsonString string) *CandidateNode {
} }
func testJSONScenario(t *testing.T, s formatScenario) { func testJSONScenario(t *testing.T, s formatScenario) {
prefs := ConfiguredJsonPreferences.Copy()
prefs.Indent = s.indent
prefs.UnwrapScalar = false
switch s.scenarioType { switch s.scenarioType {
case "encode": case "encode":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(s.indent, false, false)), s.description) test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(prefs)), s.description)
case "decode": case "decode":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(s.indent, false, false)), s.description) test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(prefs)), s.description)
case "decode-ndjson": case "decode-ndjson":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewYamlEncoder(ConfiguredYamlPreferences)), s.description) test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewYamlEncoder(ConfiguredYamlPreferences)), s.description)
case "roundtrip-ndjson": case "roundtrip-ndjson":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(0, false, false)), s.description) test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(prefs)), s.description)
case "roundtrip-multi": case "roundtrip-multi":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(2, false, false)), s.description) prefs.Indent = 2
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(prefs)), s.description)
case "decode-error": case "decode-error":
result, err := processFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(2, false, false)) result, err := processFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(prefs))
if err == nil { if err == nil {
t.Errorf("Expected error '%v' but it worked: %v", s.expectedError, result) t.Errorf("Expected error '%v' but it worked: %v", s.expectedError, result)
} else { } else {
@ -475,8 +488,11 @@ func documentJSONEncodeScenario(w *bufio.Writer, s formatScenario) {
writeOrPanic(w, fmt.Sprintf("```bash\nyq -o=json -I=%v '%v' sample.yml\n```\n", s.indent, expression)) writeOrPanic(w, fmt.Sprintf("```bash\nyq -o=json -I=%v '%v' sample.yml\n```\n", s.indent, expression))
} }
writeOrPanic(w, "will output\n") writeOrPanic(w, "will output\n")
prefs := ConfiguredJsonPreferences.Copy()
prefs.Indent = s.indent
prefs.UnwrapScalar = false
writeOrPanic(w, fmt.Sprintf("```json\n%v```\n\n", mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(s.indent, false, false)))) writeOrPanic(w, fmt.Sprintf("```json\n%v```\n\n", mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(prefs))))
} }
func TestJSONScenarios(t *testing.T) { func TestJSONScenarios(t *testing.T) {

View File

@ -13,7 +13,11 @@ func configureEncoder(format *PrinterOutputFormat, indent int) Encoder {
switch format { switch format {
case JSONOutputFormat: case JSONOutputFormat:
return NewJSONEncoder(indent, false, false) prefs := ConfiguredJsonPreferences.Copy()
prefs.Indent = indent
prefs.ColorsEnabled = false
prefs.UnwrapScalar = false
return NewJSONEncoder(prefs)
case PropsOutputFormat: case PropsOutputFormat:
return NewPropertiesEncoder(ConfiguredPropertiesPreferences) return NewPropertiesEncoder(ConfiguredPropertiesPreferences)
case CSVOutputFormat: case CSVOutputFormat:

View File

@ -34,6 +34,7 @@ type expressionScenario struct {
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
logging.SetLevel(logging.ERROR, "") logging.SetLevel(logging.ERROR, "")
ConfiguredYamlPreferences.ColorsEnabled = false ConfiguredYamlPreferences.ColorsEnabled = false
ConfiguredJsonPreferences.ColorsEnabled = false
Now = func() time.Time { Now = func() time.Time {
return time.Date(2021, time.May, 19, 1, 2, 3, 4, time.UTC) return time.Date(2021, time.May, 19, 1, 2, 3, 4, time.UTC)
} }

View File

@ -314,7 +314,9 @@ func TestPrinterMultipleDocsJson(t *testing.T) {
var writer = bufio.NewWriter(&output) var writer = bufio.NewWriter(&output)
// note printDocSeparators is true, it should still not print document separators // note printDocSeparators is true, it should still not print document separators
// when outputting JSON. // when outputting JSON.
encoder := NewJSONEncoder(0, false, false) prefs := ConfiguredJsonPreferences.Copy()
prefs.Indent = 0
encoder := NewJSONEncoder(prefs)
if encoder == nil { if encoder == nil {
t.Skipf("no support for %s output format", "json") t.Skipf("no support for %s output format", "json")
} }
@ -366,7 +368,9 @@ func TestPrinterNulSeparatorWithJson(t *testing.T) {
var writer = bufio.NewWriter(&output) var writer = bufio.NewWriter(&output)
// note printDocSeparators is true, it should still not print document separators // note printDocSeparators is true, it should still not print document separators
// when outputting JSON. // when outputting JSON.
encoder := NewJSONEncoder(0, false, false) prefs := ConfiguredJsonPreferences.Copy()
prefs.Indent = 0
encoder := NewJSONEncoder(prefs)
if encoder == nil { if encoder == nil {
t.Skipf("no support for %s output format", "json") t.Skipf("no support for %s output format", "json")
} }