Skip to content

Commit

Permalink
Unwrap scalar now works for JSON encoding when explicitly set #1409
Browse files Browse the repository at this point in the history
  • Loading branch information
mikefarah committed Nov 10, 2022
1 parent fae1dbf commit 1d35134
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 18 deletions.
74 changes: 70 additions & 4 deletions acceptance_tests/output-format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,55 @@ EOM
assertEquals "$expected" "$X"
}

testOutputYamlRawDefault() {
cat >test.yml <<EOL
a: "cat"
EOL

X=$(./yq e '.a' test.yml)
assertEquals "cat" "$X"

X=$(./yq ea '.a' test.yml)
assertEquals "cat" "$X"
}

testOutputYamlRawOff() {
cat >test.yml <<EOL
a: "cat"
EOL

X=$(./yq e -r=false '.a' test.yml)
assertEquals "\"cat\"" "$X"

X=$(./yq ea -r=false '.a' test.yml)
assertEquals "\"cat\"" "$X"
}

testOutputJsonRaw() {
cat >test.yml <<EOL
a: cat
EOL

X=$(./yq e -r --output-format=json '.a' test.yml)
assertEquals "cat" "$X"

X=$(./yq ea -r --output-format=json '.a' test.yml)
assertEquals "cat" "$X"
}

testOutputJsonDefault() {
cat >test.yml <<EOL
a: cat
EOL

X=$(./yq e --output-format=json '.a' test.yml)
assertEquals "\"cat\"" "$X"

X=$(./yq ea --output-format=json '.a' test.yml)
assertEquals "\"cat\"" "$X"
}


testOutputJsonShort() {
cat >test.yml <<EOL
a: {b: ["cat"]}
Expand All @@ -72,11 +121,11 @@ EOM

testOutputProperties() {
cat >test.yml <<EOL
a: {b: {c: ["cat"]}}
a: {b: {c: ["cat cat"]}}
EOL

read -r -d '' expected << EOM
a.b.c.0 = cat
a.b.c.0 = cat cat
EOM

X=$(./yq e --output-format=props test.yml)
Expand All @@ -86,13 +135,30 @@ EOM
assertEquals "$expected" "$X"
}

testOutputPropertiesDontUnwrap() {
cat >test.yml <<EOL
a: {b: {c: ["cat cat"]}}
EOL

read -r -d '' expected << EOM
a.b.c.0 = "cat cat"
EOM

X=$(./yq e -r=false --output-format=props test.yml)
assertEquals "$expected" "$X"

X=$(./yq ea -r=false --output-format=props test.yml)
assertEquals "$expected" "$X"
}


testOutputPropertiesShort() {
cat >test.yml <<EOL
a: {b: {c: ["cat"]}}
a: {b: {c: ["cat cat"]}}
EOL

read -r -d '' expected << EOM
a.b.c.0 = cat
a.b.c.0 = cat cat
EOM

X=$(./yq e -o=p test.yml)
Expand Down
49 changes: 48 additions & 1 deletion cmd/constant.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,53 @@
package cmd

var unwrapScalar = true
import (
"strconv"

"github.com/spf13/pflag"
)

type boolFlag interface {
pflag.Value
IsExplicitySet() bool
IsSet() bool
}

type unwrapScalarFlagStrc struct {
explicitySet bool
value bool
}

func newFlag() boolFlag {
return &unwrapScalarFlagStrc{value: true}
}

func (f *unwrapScalarFlagStrc) IsExplicitySet() bool {
return f.explicitySet
}

func (f *unwrapScalarFlagStrc) IsSet() bool {
return f.value
}

func (f *unwrapScalarFlagStrc) String() string {
return strconv.FormatBool(f.value)
}

func (f *unwrapScalarFlagStrc) Set(value string) error {

v, err := strconv.ParseBool(value)
f.value = v
f.explicitySet = true
return err
}

func (*unwrapScalarFlagStrc) Type() string {
return "bool"
}

var unwrapScalarFlag = newFlag()

var unwrapScalar = false

var writeInplace = false
var outputToJSON = false
Expand Down
12 changes: 11 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ yq -P sample.json
"`+` please set that value explicityly with --xml-attribute-prefix.")
}

if outputFormat == "y" || outputFormat == "yaml" ||
outputFormat == "p" || outputFormat == "props" {
unwrapScalar = true
}
if unwrapScalarFlag.IsExplicitySet() {
unwrapScalar = unwrapScalarFlag.IsSet()
}

//copy preference form global setting
yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar

Expand Down Expand Up @@ -94,7 +102,9 @@ yq -P sample.json
rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output")
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
rootCmd.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the file inplace of first file given.")
rootCmd.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "r", true, "unwrap scalar, print the value with no quotes, colors or comments")
rootCmd.PersistentFlags().VarP(unwrapScalarFlag, "unwrapScalar", "r", "unwrap scalar, print the value with no quotes, colors or comments. Defaults to true for yaml")
rootCmd.PersistentFlags().Lookup("unwrapScalar").NoOptDefVal = "true"

rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print, shorthand for '... style = \"\"'")
rootCmd.PersistentFlags().BoolVarP(&exitStatus, "exit-status", "e", false, "set exit status if there are no matches or null or false is returned")

Expand Down
2 changes: 1 addition & 1 deletion cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) (yq
func configureEncoder(format yqlib.PrinterOutputFormat) yqlib.Encoder {
switch format {
case yqlib.JSONOutputFormat:
return yqlib.NewJSONEncoder(indent, colorsEnabled)
return yqlib.NewJSONEncoder(indent, colorsEnabled, unwrapScalar)
case yqlib.PropsOutputFormat:
return yqlib.NewPropertiesEncoder(unwrapScalar)
case yqlib.CSVOutputFormat:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/magiconair/properties v1.8.6
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
golang.org/x/net v0.0.0-20220708220712-1185a9018129
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
gopkg.in/yaml.v3 v3.0.1
Expand All @@ -22,7 +23,6 @@ require (
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
Expand Down
9 changes: 7 additions & 2 deletions pkg/yqlib/encoder_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
type jsonEncoder struct {
indentString string
colorise bool
UnwrapScalar bool
}

func mapKeysToStrings(node *yaml.Node) {
Expand All @@ -28,14 +29,14 @@ func mapKeysToStrings(node *yaml.Node) {
}
}

func NewJSONEncoder(indent int, colorise bool) Encoder {
func NewJSONEncoder(indent int, colorise bool, unwrapScalar bool) Encoder {
var indentString = ""

for index := 0; index < indent; index++ {
indentString = indentString + " "
}

return &jsonEncoder{indentString, colorise}
return &jsonEncoder{indentString, colorise, unwrapScalar}
}

func (je *jsonEncoder) CanHandleAliases() bool {
Expand All @@ -52,6 +53,10 @@ func (je *jsonEncoder) PrintLeadingContent(writer io.Writer, content string) err

func (je *jsonEncoder) Encode(writer io.Writer, node *yaml.Node) error {

if node.Kind == yaml.ScalarNode && je.UnwrapScalar {
return writeString(writer, node.Value+"\n")
}

destination := writer
tempBuffer := bytes.NewBuffer(nil)
if je.colorise {
Expand Down
2 changes: 1 addition & 1 deletion pkg/yqlib/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func yamlToJSON(sampleYaml string, indent int) string {
var output bytes.Buffer
writer := bufio.NewWriter(&output)

var jsonEncoder = NewJSONEncoder(indent, false)
var jsonEncoder = NewJSONEncoder(indent, false, false)
inputs, err := readDocuments(strings.NewReader(sampleYaml), "sample.yml", 0, NewYamlDecoder(ConfiguredYamlPreferences))
if err != nil {
panic(err)
Expand Down
10 changes: 5 additions & 5 deletions pkg/yqlib/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ func documentRoundtripNdJsonScenario(w *bufio.Writer, s formatScenario, indent i

writeOrPanic(w, "will output\n")

writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(indent, false))))
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(indent, false, false))))
}

func documentDecodeNdJsonScenario(w *bufio.Writer, s formatScenario) {
Expand Down Expand Up @@ -293,16 +293,16 @@ func decodeJSON(t *testing.T, jsonString string) *CandidateNode {
func testJSONScenario(t *testing.T, s formatScenario) {
switch s.scenarioType {
case "encode", "decode":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(s.indent, false)), s.description)
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(s.indent, false, false)), s.description)
case "":
var actual = resultToString(t, decodeJSON(t, s.input))
test.AssertResultWithContext(t, s.expected, actual, s.description)
case "decode-ndjson":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description)
case "roundtrip-ndjson":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(0, false)), s.description)
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(0, false, false)), s.description)
case "roundtrip-multi":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(2, false)), s.description)
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewJSONEncoder(2, false, false)), s.description)

default:
panic(fmt.Sprintf("unhandled scenario type %q", s.scenarioType))
Expand Down Expand Up @@ -385,7 +385,7 @@ func documentJSONEncodeScenario(w *bufio.Writer, s formatScenario) {
}
writeOrPanic(w, "will output\n")

writeOrPanic(w, fmt.Sprintf("```json\n%v```\n\n", mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(s.indent, false))))
writeOrPanic(w, fmt.Sprintf("```json\n%v```\n\n", mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewJSONEncoder(s.indent, false, false))))
}

func TestJSONScenarios(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/yqlib/operator_encoder_decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
func configureEncoder(format PrinterOutputFormat, indent int) Encoder {
switch format {
case JSONOutputFormat:
return NewJSONEncoder(indent, false)
return NewJSONEncoder(indent, false, false)
case PropsOutputFormat:
return NewPropertiesEncoder(true)
case CSVOutputFormat:
Expand Down
2 changes: 1 addition & 1 deletion pkg/yqlib/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ func TestPrinterMultipleDocsJson(t *testing.T) {
var writer = bufio.NewWriter(&output)
// note printDocSeparators is true, it should still not print document separators
// when outputing JSON.
printer := NewPrinter(NewJSONEncoder(0, false), NewSinglePrinterWriter(writer))
printer := NewPrinter(NewJSONEncoder(0, false, false), NewSinglePrinterWriter(writer))

inputs, err := readDocuments(strings.NewReader(multiDocSample), "sample.yml", 0, NewYamlDecoder(ConfiguredYamlPreferences))
if err != nil {
Expand Down

0 comments on commit 1d35134

Please sign in to comment.