From 55f6a3a49d6a8ef60225b56797b31933008a0ab3 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Sat, 24 Feb 2024 15:48:59 +1100 Subject: [PATCH] Refactoring JSON encoder prefs --- cmd/utils.go | 5 +++- pkg/yqlib/encoder_json.go | 15 ++++++------ pkg/yqlib/encoder_test.go | 5 +++- pkg/yqlib/formatting_expressions_test.go | 2 +- pkg/yqlib/json.go | 25 ++++++++++++++++++++ pkg/yqlib/json_test.go | 30 ++++++++++++++++++------ pkg/yqlib/operator_encoder_decoder.go | 6 ++++- pkg/yqlib/operators_test.go | 1 + pkg/yqlib/printer_test.go | 8 +++++-- 9 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 pkg/yqlib/json.go diff --git a/cmd/utils.go b/cmd/utils.go index fe34c8e4..c02ba3ca 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -180,17 +180,20 @@ func configureEncoder() (yqlib.Encoder, error) { func createEncoder(format *yqlib.PrinterOutputFormat) (yqlib.Encoder, error) { yqlib.ConfiguredXMLPreferences.Indent = indent yqlib.ConfiguredYamlPreferences.Indent = indent + yqlib.ConfiguredJsonPreferences.Indent = indent yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar yqlib.ConfiguredPropertiesPreferences.UnwrapScalar = unwrapScalar + yqlib.ConfiguredJsonPreferences.UnwrapScalar = unwrapScalar yqlib.ConfiguredYamlPreferences.ColorsEnabled = colorsEnabled + yqlib.ConfiguredJsonPreferences.ColorsEnabled = colorsEnabled yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators switch format { case yqlib.JSONOutputFormat: - return yqlib.NewJSONEncoder(indent, colorsEnabled, unwrapScalar), nil + return yqlib.NewJSONEncoder(yqlib.ConfiguredJsonPreferences), nil case yqlib.PropsOutputFormat: return yqlib.NewPropertiesEncoder(yqlib.ConfiguredPropertiesPreferences), nil case yqlib.CSVOutputFormat: diff --git a/pkg/yqlib/encoder_json.go b/pkg/yqlib/encoder_json.go index d6011b43..54407cd0 100644 --- a/pkg/yqlib/encoder_json.go +++ b/pkg/yqlib/encoder_json.go @@ -10,19 +10,18 @@ import ( ) type jsonEncoder struct { + prefs JsonPreferences indentString string - colorise bool - UnwrapScalar bool } -func NewJSONEncoder(indent int, colorise bool, unwrapScalar bool) Encoder { +func NewJSONEncoder(prefs JsonPreferences) Encoder { var indentString = "" - for index := 0; index < indent; index++ { + for index := 0; index < prefs.Indent; index++ { indentString = indentString + " " } - return &jsonEncoder{indentString, colorise, unwrapScalar} + return &jsonEncoder{prefs, indentString} } 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("kids %v", len(node.Content)) - if node.Kind == ScalarNode && je.UnwrapScalar { + if node.Kind == ScalarNode && je.prefs.UnwrapScalar { return writeString(writer, node.Value+"\n") } destination := writer tempBuffer := bytes.NewBuffer(nil) - if je.colorise { + if je.prefs.ColorsEnabled { destination = tempBuffer } @@ -59,7 +58,7 @@ func (je *jsonEncoder) Encode(writer io.Writer, node *CandidateNode) error { if err != nil { return err } - if je.colorise { + if je.prefs.ColorsEnabled { return colorizeAndPrint(tempBuffer.Bytes(), writer) } return nil diff --git a/pkg/yqlib/encoder_test.go b/pkg/yqlib/encoder_test.go index c2fc8628..018fd7fe 100644 --- a/pkg/yqlib/encoder_test.go +++ b/pkg/yqlib/encoder_test.go @@ -16,7 +16,10 @@ func yamlToJSON(t *testing.T, sampleYaml string, indent int) string { var output bytes.Buffer 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)) if err != nil { panic(err) diff --git a/pkg/yqlib/formatting_expressions_test.go b/pkg/yqlib/formatting_expressions_test.go index 7d7bec88..3fa3927d 100644 --- a/pkg/yqlib/formatting_expressions_test.go +++ b/pkg/yqlib/formatting_expressions_test.go @@ -71,7 +71,7 @@ func documentExpressionScenario(_ *testing.T, w *bufio.Writer, i interface{}) { encoder := NewYamlEncoder(ConfiguredYamlPreferences) 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))) diff --git a/pkg/yqlib/json.go b/pkg/yqlib/json.go new file mode 100644 index 00000000..b108fd6d --- /dev/null +++ b/pkg/yqlib/json.go @@ -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() diff --git a/pkg/yqlib/json_test.go b/pkg/yqlib/json_test.go index b13d8bcb..9579be3e 100644 --- a/pkg/yqlib/json_test.go +++ b/pkg/yqlib/json_test.go @@ -85,6 +85,7 @@ var jsonScenarios = []formatScenario{ skipDoc: true, input: "[]", scenarioType: "roundtrip-ndjson", + indent: 0, expected: "[]\n", }, { @@ -92,6 +93,7 @@ var jsonScenarios = []formatScenario{ skipDoc: true, input: "[3]", scenarioType: "roundtrip-ndjson", + indent: 0, expected: "[3]\n", }, { @@ -99,6 +101,7 @@ var jsonScenarios = []formatScenario{ skipDoc: true, input: `[{"x": 3}]`, scenarioType: "roundtrip-ndjson", + indent: 0, expected: "[{\"x\":3}]\n", }, { @@ -106,6 +109,7 @@ var jsonScenarios = []formatScenario{ skipDoc: true, input: "[null]", scenarioType: "roundtrip-ndjson", + indent: 0, expected: "[null]\n", }, { @@ -114,6 +118,7 @@ var jsonScenarios = []formatScenario{ input: "[{}]", expression: `[.. | type]`, scenarioType: "roundtrip-ndjson", + indent: 0, expected: "[\"!!seq\",\"!!map\"]\n", }, { @@ -220,6 +225,7 @@ var jsonScenarios = []formatScenario{ input: sampleNdJson, expected: expectedRoundTripSampleNdJson, scenarioType: "roundtrip-ndjson", + indent: 0, }, { description: "Roundtrip multi-document JSON", @@ -322,8 +328,11 @@ func documentRoundtripNdJsonScenario(w *bufio.Writer, s formatScenario, indent i } 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) { @@ -377,19 +386,23 @@ func decodeJSON(t *testing.T, jsonString string) *CandidateNode { } func testJSONScenario(t *testing.T, s formatScenario) { + prefs := ConfiguredJsonPreferences.Copy() + prefs.Indent = s.indent + prefs.UnwrapScalar = false switch s.scenarioType { 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": - 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": test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewYamlEncoder(ConfiguredYamlPreferences)), s.description) 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": - 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": - result, err := processFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(2, false, false)) + result, err := processFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(prefs)) if err == nil { t.Errorf("Expected error '%v' but it worked: %v", s.expectedError, result) } 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, "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) { diff --git a/pkg/yqlib/operator_encoder_decoder.go b/pkg/yqlib/operator_encoder_decoder.go index 068cd72e..7e048d10 100644 --- a/pkg/yqlib/operator_encoder_decoder.go +++ b/pkg/yqlib/operator_encoder_decoder.go @@ -13,7 +13,11 @@ func configureEncoder(format *PrinterOutputFormat, indent int) Encoder { switch format { case JSONOutputFormat: - return NewJSONEncoder(indent, false, false) + prefs := ConfiguredJsonPreferences.Copy() + prefs.Indent = indent + prefs.ColorsEnabled = false + prefs.UnwrapScalar = false + return NewJSONEncoder(prefs) case PropsOutputFormat: return NewPropertiesEncoder(ConfiguredPropertiesPreferences) case CSVOutputFormat: diff --git a/pkg/yqlib/operators_test.go b/pkg/yqlib/operators_test.go index 1224a830..17131bde 100644 --- a/pkg/yqlib/operators_test.go +++ b/pkg/yqlib/operators_test.go @@ -34,6 +34,7 @@ type expressionScenario struct { func TestMain(m *testing.M) { logging.SetLevel(logging.ERROR, "") ConfiguredYamlPreferences.ColorsEnabled = false + ConfiguredJsonPreferences.ColorsEnabled = false Now = func() time.Time { return time.Date(2021, time.May, 19, 1, 2, 3, 4, time.UTC) } diff --git a/pkg/yqlib/printer_test.go b/pkg/yqlib/printer_test.go index f53f1ed4..899e1627 100644 --- a/pkg/yqlib/printer_test.go +++ b/pkg/yqlib/printer_test.go @@ -314,7 +314,9 @@ func TestPrinterMultipleDocsJson(t *testing.T) { var writer = bufio.NewWriter(&output) // note printDocSeparators is true, it should still not print document separators // when outputting JSON. - encoder := NewJSONEncoder(0, false, false) + prefs := ConfiguredJsonPreferences.Copy() + prefs.Indent = 0 + encoder := NewJSONEncoder(prefs) if encoder == nil { t.Skipf("no support for %s output format", "json") } @@ -366,7 +368,9 @@ func TestPrinterNulSeparatorWithJson(t *testing.T) { var writer = bufio.NewWriter(&output) // note printDocSeparators is true, it should still not print document separators // when outputting JSON. - encoder := NewJSONEncoder(0, false, false) + prefs := ConfiguredJsonPreferences.Copy() + prefs.Indent = 0 + encoder := NewJSONEncoder(prefs) if encoder == nil { t.Skipf("no support for %s output format", "json") }