From 447bf28cd89ae0d9b3bb5fd6671d4bdce9433244 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Sat, 24 Feb 2024 16:37:13 +1100 Subject: [PATCH] Introduced 'format' to encapsulate encoding and decoding formats together --- cmd/evaluate_all_command.go | 2 +- cmd/evaluate_sequence_command.go | 2 +- cmd/root.go | 16 ++- cmd/utils.go | 63 +++------ pkg/yqlib/decoder.go | 56 -------- pkg/yqlib/format.go | 180 ++++++++++++++++++++++++++ pkg/yqlib/lexer_participle.go | 50 +++---- pkg/yqlib/operator_encoder_decoder.go | 43 ++---- pkg/yqlib/operators_test.go | 6 +- pkg/yqlib/printer.go | 79 ----------- pkg/yqlib/printer_writer.go | 6 +- 11 files changed, 253 insertions(+), 250 deletions(-) create mode 100644 pkg/yqlib/format.go diff --git a/cmd/evaluate_all_command.go b/cmd/evaluate_all_command.go index 8e71a0cd..c273cd6c 100644 --- a/cmd/evaluate_all_command.go +++ b/cmd/evaluate_all_command.go @@ -76,7 +76,7 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) { }() } - format, err := yqlib.OutputFormatFromString(outputFormat) + format, err := yqlib.FormatFromString(outputFormat) if err != nil { return err } diff --git a/cmd/evaluate_sequence_command.go b/cmd/evaluate_sequence_command.go index cebe4b4d..e5641065 100644 --- a/cmd/evaluate_sequence_command.go +++ b/cmd/evaluate_sequence_command.go @@ -90,7 +90,7 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) { }() } - format, err := yqlib.OutputFormatFromString(outputFormat) + format, err := yqlib.FormatFromString(outputFormat) if err != nil { return err } diff --git a/cmd/root.go b/cmd/root.go index d6fb7fae..84019bae 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -98,12 +98,22 @@ yq -P -oy sample.json } rootCmd.PersistentFlags().StringVarP(&outputFormat, "output-format", "o", "auto", fmt.Sprintf("[auto|a|%v] output format type.", yqlib.GetAvailableOutputFormatString())) + var outputCompletions = []string{"auto"} + for _, formats := range yqlib.GetAvailableOutputFormats() { + outputCompletions = append(outputCompletions, formats.FormalName) + } - if err = rootCmd.RegisterFlagCompletionFunc("output-format", cobra.FixedCompletions([]string{"auto", "yaml", "json", "props", "xml", "tsv", "csv"}, cobra.ShellCompDirectiveNoFileComp)); err != nil { + if err = rootCmd.RegisterFlagCompletionFunc("output-format", cobra.FixedCompletions(outputCompletions, cobra.ShellCompDirectiveNoFileComp)); err != nil { panic(err) } - rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "auto", "[auto|a|yaml|y|props|p|xml|x|tsv|t|csv|c|toml] parse format for input. Note that json is a subset of yaml.") - if err = rootCmd.RegisterFlagCompletionFunc("input-format", cobra.FixedCompletions([]string{"auto", "yaml", "props", "xml", "tsv", "csv", "toml"}, cobra.ShellCompDirectiveNoFileComp)); err != nil { + rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "auto", fmt.Sprintf("[auto|a|%v] parse format for input.", yqlib.GetAvailableInputFormatString())) + + var inputCompletions = []string{"auto"} + for _, formats := range yqlib.GetAvailableInputFormats() { + inputCompletions = append(inputCompletions, formats.FormalName) + } + + if err = rootCmd.RegisterFlagCompletionFunc("input-format", cobra.FixedCompletions(inputCompletions, cobra.ShellCompDirectiveNoFileComp)); err != nil { panic(err) } diff --git a/cmd/utils.go b/cmd/utils.go index 16eb9e97..7bd96a28 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -64,9 +64,9 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) { } if inputFormat == "" || inputFormat == "auto" || inputFormat == "a" { - inputFormat = yqlib.FormatFromFilename(inputFilename) + inputFormat = yqlib.FormatStringFromFilename(inputFilename) - _, err := yqlib.InputFormatFromString(inputFormat) + _, err := yqlib.FormatFromString(inputFormat) if err != nil { // unknown file type, default to yaml yqlib.GetLogger().Debug("Unknown file format extension '%v', defaulting to yaml", inputFormat) @@ -86,14 +86,14 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) { // before this was introduced, `yq -pcsv things.csv` // would produce *yaml* output. // - outputFormat = yqlib.FormatFromFilename(inputFilename) + outputFormat = yqlib.FormatStringFromFilename(inputFilename) if inputFilename != "-" { yqlib.GetLogger().Warning("yq default output is now 'auto' (based on the filename extension). Normally yq would output '%v', but for backwards compatibility 'yaml' has been set. Please use -oy to specify yaml, or drop the -p flag.", outputFormat) } outputFormat = "yaml" } - outputFormatType, err := yqlib.OutputFormatFromString(outputFormat) + outputFormatType, err := yqlib.FormatFromString(outputFormat) if err != nil { return "", nil, err @@ -101,8 +101,8 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) { yqlib.GetLogger().Debug("Using input format %v", inputFormat) yqlib.GetLogger().Debug("Using output format %v", outputFormat) - if outputFormatType == yqlib.YamlOutputFormat || - outputFormatType == yqlib.PropsOutputFormat { + if outputFormatType == yqlib.YamlFormat || + outputFormatType == yqlib.PropertiesFormat { unwrapScalar = true } if unwrapScalarFlag.IsExplicitlySet() { @@ -113,42 +113,20 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) { } func configureDecoder(evaluateTogether bool) (yqlib.Decoder, error) { - yqlibInputFormat, err := yqlib.InputFormatFromString(inputFormat) + format, err := yqlib.FormatFromString(inputFormat) if err != nil { return nil, err } - yqlibDecoder, err := createDecoder(yqlibInputFormat, evaluateTogether) + yqlib.ConfiguredYamlPreferences.EvaluateTogether = evaluateTogether + + yqlibDecoder := format.DecoderFactory() if yqlibDecoder == nil { return nil, fmt.Errorf("no support for %s input format", inputFormat) } - return yqlibDecoder, err + return yqlibDecoder, nil } -func createDecoder(format yqlib.InputFormat, evaluateTogether bool) (yqlib.Decoder, error) { - switch format { - case yqlib.LuaInputFormat: - return yqlib.NewLuaDecoder(yqlib.ConfiguredLuaPreferences), nil - case yqlib.XMLInputFormat: - return yqlib.NewXMLDecoder(yqlib.ConfiguredXMLPreferences), nil - case yqlib.PropertiesInputFormat: - return yqlib.NewPropertiesDecoder(), nil - case yqlib.JsonInputFormat: - return yqlib.NewJSONDecoder(), nil - case yqlib.CSVObjectInputFormat: - return yqlib.NewCSVObjectDecoder(yqlib.ConfiguredCsvPreferences), nil - case yqlib.TSVObjectInputFormat: - return yqlib.NewCSVObjectDecoder(yqlib.ConfiguredTsvPreferences), nil - case yqlib.TomlInputFormat: - return yqlib.NewTomlDecoder(), nil - case yqlib.YamlInputFormat: - prefs := yqlib.ConfiguredYamlPreferences - prefs.EvaluateTogether = evaluateTogether - return yqlib.NewYamlDecoder(prefs), nil - } - return nil, fmt.Errorf("invalid decoder: %v", format) -} - -func configurePrinterWriter(format *yqlib.PrinterOutputFormat, out io.Writer) (yqlib.PrinterWriter, error) { +func configurePrinterWriter(format *yqlib.Format, out io.Writer) (yqlib.PrinterWriter, error) { var printerWriter yqlib.PrinterWriter @@ -166,18 +144,10 @@ func configurePrinterWriter(format *yqlib.PrinterOutputFormat, out io.Writer) (y } func configureEncoder() (yqlib.Encoder, error) { - yqlibOutputFormat, err := yqlib.OutputFormatFromString(outputFormat) + yqlibOutputFormat, err := yqlib.FormatFromString(outputFormat) if err != nil { return nil, err } - yqlibEncoder, err := createEncoder(yqlibOutputFormat) - if yqlibEncoder == nil { - return nil, fmt.Errorf("no support for %s output format", outputFormat) - } - return yqlibEncoder, err -} - -func createEncoder(format *yqlib.PrinterOutputFormat) (yqlib.Encoder, error) { yqlib.ConfiguredXMLPreferences.Indent = indent yqlib.ConfiguredYamlPreferences.Indent = indent yqlib.ConfiguredJSONPreferences.Indent = indent @@ -191,11 +161,12 @@ func createEncoder(format *yqlib.PrinterOutputFormat) (yqlib.Encoder, error) { yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators - encoder := format.EncoderFactory() + encoder := yqlibOutputFormat.EncoderFactory() + if encoder == nil { - return nil, fmt.Errorf("invalid encoder: %v", format) + return nil, fmt.Errorf("no support for %s output format", outputFormat) } - return encoder, nil + return encoder, err } // this is a hack to enable backwards compatibility with githubactions (which pipe /dev/null into everything) diff --git a/pkg/yqlib/decoder.go b/pkg/yqlib/decoder.go index 284b4316..6466fb62 100644 --- a/pkg/yqlib/decoder.go +++ b/pkg/yqlib/decoder.go @@ -1,66 +1,10 @@ package yqlib import ( - "fmt" "io" - "strings" -) - -type InputFormat uint - -const ( - YamlInputFormat = 1 << iota - XMLInputFormat - PropertiesInputFormat - Base64InputFormat - JsonInputFormat - CSVObjectInputFormat - TSVObjectInputFormat - TomlInputFormat - UriInputFormat - LuaInputFormat ) type Decoder interface { Init(reader io.Reader) error Decode() (*CandidateNode, error) } - -func InputFormatFromString(format string) (InputFormat, error) { - switch format { - case "yaml", "yml", "y": - return YamlInputFormat, nil - case "xml", "x": - return XMLInputFormat, nil - case "properties", "props", "p": - return PropertiesInputFormat, nil - case "json", "ndjson", "j": - return JsonInputFormat, nil - case "csv", "c": - return CSVObjectInputFormat, nil - case "tsv", "t": - return TSVObjectInputFormat, nil - case "toml": - return TomlInputFormat, nil - case "lua", "l": - return LuaInputFormat, nil - default: - return 0, fmt.Errorf("unknown format '%v' please use [yaml|json|props|csv|tsv|xml|toml]", format) - } -} - -func FormatFromFilename(filename string) string { - - if filename != "" { - GetLogger().Debugf("checking file extension '%s' for auto format detection", filename) - nPos := strings.LastIndex(filename, ".") - if nPos > -1 { - format := filename[nPos+1:] - GetLogger().Debugf("detected format '%s'", format) - return format - } - } - - GetLogger().Debugf("using default inputFormat 'yaml'") - return "yaml" -} diff --git a/pkg/yqlib/format.go b/pkg/yqlib/format.go new file mode 100644 index 00000000..a1b35226 --- /dev/null +++ b/pkg/yqlib/format.go @@ -0,0 +1,180 @@ +package yqlib + +import ( + "fmt" + "strings" +) + +type EncoderFactoryFunction func() Encoder +type DecoderFactoryFunction func() Decoder + +type Format struct { + FormalName string + Names []string + EncoderFactory EncoderFactoryFunction + DecoderFactory DecoderFactoryFunction +} + +var YamlFormat = &Format{"yaml", []string{"y", "yml"}, + func() Encoder { return NewYamlEncoder(ConfiguredYamlPreferences) }, + func() Decoder { return NewYamlDecoder(ConfiguredYamlPreferences) }, +} + +var JSONFormat = &Format{"json", []string{"j"}, + func() Encoder { return NewJSONEncoder(ConfiguredJSONPreferences) }, + func() Decoder { return NewJSONDecoder() }, +} + +var PropertiesFormat = &Format{"props", []string{"p", "properties"}, + func() Encoder { return NewPropertiesEncoder(ConfiguredPropertiesPreferences) }, + func() Decoder { return NewPropertiesDecoder() }, +} + +var CSVFormat = &Format{"csv", []string{"c"}, + func() Encoder { return NewCsvEncoder(ConfiguredCsvPreferences) }, + func() Decoder { return NewCSVObjectDecoder(ConfiguredCsvPreferences) }, +} + +var TSVFormat = &Format{"tsv", []string{"t"}, + func() Encoder { return NewCsvEncoder(ConfiguredTsvPreferences) }, + func() Decoder { return NewCSVObjectDecoder(ConfiguredTsvPreferences) }, +} + +var XMLFormat = &Format{"xml", []string{"x"}, + func() Encoder { return NewXMLEncoder(ConfiguredXMLPreferences) }, + func() Decoder { return NewXMLDecoder(ConfiguredXMLPreferences) }, +} + +var Base64Format = &Format{"base64", []string{}, + func() Encoder { return NewBase64Encoder() }, + func() Decoder { return NewBase64Decoder() }, +} + +var UriFormat = &Format{"uri", []string{}, + func() Encoder { return NewUriEncoder() }, + func() Decoder { return NewUriDecoder() }, +} + +var ShFormat = &Format{"", nil, + func() Encoder { return NewShEncoder() }, + nil, +} + +var TomlFormat = &Format{"toml", []string{}, + func() Encoder { return NewTomlEncoder() }, + func() Decoder { return NewTomlDecoder() }, +} + +var ShellVariablesFormat = &Format{"shell", []string{"s", "sh"}, + func() Encoder { return NewShellVariablesEncoder() }, + nil, +} + +var LuaFormat = &Format{"lua", []string{"l"}, + func() Encoder { return NewLuaEncoder(ConfiguredLuaPreferences) }, + func() Decoder { return NewLuaDecoder(ConfiguredLuaPreferences) }, +} + +var Formats = []*Format{ + YamlFormat, + JSONFormat, + PropertiesFormat, + CSVFormat, + TSVFormat, + XMLFormat, + Base64Format, + UriFormat, + ShFormat, + TomlFormat, + ShellVariablesFormat, + LuaFormat, +} + +func (f *Format) MatchesName(name string) bool { + if f.FormalName == name { + return true + } + for _, n := range f.Names { + if n == name { + return true + } + } + return false +} + +func (f *Format) GetConfiguredEncoder() Encoder { + return f.EncoderFactory() +} + +func FormatStringFromFilename(filename string) string { + + if filename != "" { + GetLogger().Debugf("checking file extension '%s' for auto format detection", filename) + nPos := strings.LastIndex(filename, ".") + if nPos > -1 { + format := filename[nPos+1:] + GetLogger().Debugf("detected format '%s'", format) + return format + } + } + + GetLogger().Debugf("using default inputFormat 'yaml'") + return "yaml" +} + +func FormatFromString(format string) (*Format, error) { + for _, printerFormat := range Formats { + if printerFormat.MatchesName(format) { + return printerFormat, nil + } + } + return nil, fmt.Errorf("unknown format '%v' please use [%v]", format, GetAvailableOutputFormatString()) +} + +func GetAvailableOutputFormats() []*Format { + var formats = []*Format{} + for _, printerFormat := range Formats { + if printerFormat.EncoderFactory != nil { + formats = append(formats, printerFormat) + } + } + return formats +} + +func GetAvailableOutputFormatString() string { + var formats = []string{} + for _, printerFormat := range GetAvailableOutputFormats() { + + if printerFormat.FormalName != "" { + formats = append(formats, printerFormat.FormalName) + } + if len(printerFormat.Names) >= 1 { + formats = append(formats, printerFormat.Names[0]) + } + } + return strings.Join(formats, "|") +} + +func GetAvailableInputFormats() []*Format { + var formats = []*Format{} + for _, printerFormat := range Formats { + if printerFormat.DecoderFactory != nil { + formats = append(formats, printerFormat) + } + } + return formats +} + +func GetAvailableInputFormatString() string { + var formats = []string{} + for _, printerFormat := range GetAvailableInputFormats() { + + if printerFormat.FormalName != "" { + formats = append(formats, printerFormat.FormalName) + } + if len(printerFormat.Names) >= 1 { + formats = append(formats, printerFormat.Names[0]) + } + } + return strings.Join(formats, "|") +} diff --git a/pkg/yqlib/lexer_participle.go b/pkg/yqlib/lexer_participle.go index b45a60bc..51654171 100644 --- a/pkg/yqlib/lexer_participle.go +++ b/pkg/yqlib/lexer_participle.go @@ -57,35 +57,35 @@ var participleYqRules = []*participleYqRule{ {"ArrayToMap", "array_?to_?map", expressionOpToken(`(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i)`), 0}, - {"YamlEncodeWithIndent", `to_?yaml\([0-9]+\)`, encodeParseIndent(YamlOutputFormat), 0}, - {"XMLEncodeWithIndent", `to_?xml\([0-9]+\)`, encodeParseIndent(XMLOutputFormat), 0}, - {"JSONEncodeWithIndent", `to_?json\([0-9]+\)`, encodeParseIndent(JSONOutputFormat), 0}, + {"YamlEncodeWithIndent", `to_?yaml\([0-9]+\)`, encodeParseIndent(YamlFormat), 0}, + {"XMLEncodeWithIndent", `to_?xml\([0-9]+\)`, encodeParseIndent(XMLFormat), 0}, + {"JSONEncodeWithIndent", `to_?json\([0-9]+\)`, encodeParseIndent(JSONFormat), 0}, - {"YamlDecode", `from_?yaml|@yamld|from_?json|@jsond`, decodeOp(YamlInputFormat), 0}, - {"YamlEncode", `to_?yaml|@yaml`, encodeWithIndent(YamlOutputFormat, 2), 0}, + {"YamlDecode", `from_?yaml|@yamld|from_?json|@jsond`, decodeOp(YamlFormat), 0}, + {"YamlEncode", `to_?yaml|@yaml`, encodeWithIndent(YamlFormat, 2), 0}, - {"JSONEncode", `to_?json`, encodeWithIndent(JSONOutputFormat, 2), 0}, - {"JSONEncodeNoIndent", `@json`, encodeWithIndent(JSONOutputFormat, 0), 0}, + {"JSONEncode", `to_?json`, encodeWithIndent(JSONFormat, 2), 0}, + {"JSONEncodeNoIndent", `@json`, encodeWithIndent(JSONFormat, 0), 0}, - {"PropertiesDecode", `from_?props|@propsd`, decodeOp(PropertiesInputFormat), 0}, - {"PropsEncode", `to_?props|@props`, encodeWithIndent(PropsOutputFormat, 2), 0}, + {"PropertiesDecode", `from_?props|@propsd`, decodeOp(PropertiesFormat), 0}, + {"PropsEncode", `to_?props|@props`, encodeWithIndent(PropertiesFormat, 2), 0}, - {"XmlDecode", `from_?xml|@xmld`, decodeOp(XMLInputFormat), 0}, - {"XMLEncode", `to_?xml`, encodeWithIndent(XMLOutputFormat, 2), 0}, - {"XMLEncodeNoIndent", `@xml`, encodeWithIndent(XMLOutputFormat, 0), 0}, + {"XmlDecode", `from_?xml|@xmld`, decodeOp(XMLFormat), 0}, + {"XMLEncode", `to_?xml`, encodeWithIndent(XMLFormat, 2), 0}, + {"XMLEncodeNoIndent", `@xml`, encodeWithIndent(XMLFormat, 0), 0}, - {"CSVDecode", `from_?csv|@csvd`, decodeOp(CSVObjectInputFormat), 0}, - {"CSVEncode", `to_?csv|@csv`, encodeWithIndent(CSVOutputFormat, 0), 0}, + {"CSVDecode", `from_?csv|@csvd`, decodeOp(CSVFormat), 0}, + {"CSVEncode", `to_?csv|@csv`, encodeWithIndent(CSVFormat, 0), 0}, - {"TSVDecode", `from_?tsv|@tsvd`, decodeOp(TSVObjectInputFormat), 0}, - {"TSVEncode", `to_?tsv|@tsv`, encodeWithIndent(TSVOutputFormat, 0), 0}, + {"TSVDecode", `from_?tsv|@tsvd`, decodeOp(TSVFormat), 0}, + {"TSVEncode", `to_?tsv|@tsv`, encodeWithIndent(TSVFormat, 0), 0}, - {"Base64d", `@base64d`, decodeOp(Base64InputFormat), 0}, - {"Base64", `@base64`, encodeWithIndent(Base64OutputFormat, 0), 0}, + {"Base64d", `@base64d`, decodeOp(Base64Format), 0}, + {"Base64", `@base64`, encodeWithIndent(Base64Format, 0), 0}, - {"Urid", `@urid`, decodeOp(UriInputFormat), 0}, - {"Uri", `@uri`, encodeWithIndent(UriOutputFormat, 0), 0}, - {"SH", `@sh`, encodeWithIndent(ShOutputFormat, 0), 0}, + {"Urid", `@urid`, decodeOp(UriFormat), 0}, + {"Uri", `@uri`, encodeWithIndent(UriFormat, 0), 0}, + {"SH", `@sh`, encodeWithIndent(ShFormat, 0), 0}, {"LoadXML", `load_?xml|xml_?load`, loadOp(NewXMLDecoder(ConfiguredXMLPreferences), false), 0}, @@ -496,7 +496,7 @@ func numberValue() yqAction { } } -func encodeParseIndent(outputFormat *PrinterOutputFormat) yqAction { +func encodeParseIndent(outputFormat *Format) yqAction { return func(rawToken lexer.Token) (*token, error) { value := rawToken.Value var indent, errParsingInt = extractNumberParameter(value) @@ -510,13 +510,13 @@ func encodeParseIndent(outputFormat *PrinterOutputFormat) yqAction { } } -func encodeWithIndent(outputFormat *PrinterOutputFormat, indent int) yqAction { +func encodeWithIndent(outputFormat *Format, indent int) yqAction { prefs := encoderPreferences{format: outputFormat, indent: indent} return opTokenWithPrefs(encodeOpType, nil, prefs) } -func decodeOp(inputFormat InputFormat) yqAction { - prefs := decoderPreferences{format: inputFormat} +func decodeOp(format *Format) yqAction { + prefs := decoderPreferences{format: format} return opTokenWithPrefs(decodeOpType, nil, prefs) } diff --git a/pkg/yqlib/operator_encoder_decoder.go b/pkg/yqlib/operator_encoder_decoder.go index 03d8c343..601ad672 100644 --- a/pkg/yqlib/operator_encoder_decoder.go +++ b/pkg/yqlib/operator_encoder_decoder.go @@ -9,21 +9,21 @@ import ( "strings" ) -func configureEncoder(format *PrinterOutputFormat, indent int) Encoder { +func configureEncoder(format *Format, indent int) Encoder { switch format { - case JSONOutputFormat: + case JSONFormat: prefs := ConfiguredJSONPreferences.Copy() prefs.Indent = indent prefs.ColorsEnabled = false prefs.UnwrapScalar = false return NewJSONEncoder(prefs) - case YamlOutputFormat: + case YamlFormat: var prefs = ConfiguredYamlPreferences.Copy() prefs.Indent = indent prefs.ColorsEnabled = false return NewYamlEncoder(prefs) - case XMLOutputFormat: + case XMLFormat: var xmlPrefs = ConfiguredXMLPreferences.Copy() xmlPrefs.Indent = indent return NewXMLEncoder(xmlPrefs) @@ -46,7 +46,7 @@ func encodeToString(candidate *CandidateNode, prefs encoderPreferences) (string, } type encoderPreferences struct { - format *PrinterOutputFormat + format *Format indent int } @@ -81,9 +81,9 @@ func encodeOperator(_ *dataTreeNavigator, context Context, expressionNode *Expre } // dont print a newline when printing json on a single line. - if (preferences.format == JSONOutputFormat && preferences.indent == 0) || - preferences.format == CSVOutputFormat || - preferences.format == TSVOutputFormat { + if (preferences.format == JSONFormat && preferences.indent == 0) || + preferences.format == CSVFormat || + preferences.format == TSVFormat { stringValue = chomper.ReplaceAllString(stringValue, "") } @@ -93,30 +93,7 @@ func encodeOperator(_ *dataTreeNavigator, context Context, expressionNode *Expre } type decoderPreferences struct { - format InputFormat -} - -func createDecoder(format InputFormat) Decoder { - var decoder Decoder - switch format { - case JsonInputFormat: - decoder = NewJSONDecoder() - case YamlInputFormat: - decoder = NewYamlDecoder(ConfiguredYamlPreferences) - case XMLInputFormat: - decoder = NewXMLDecoder(ConfiguredXMLPreferences) - case Base64InputFormat: - decoder = NewBase64Decoder() - case PropertiesInputFormat: - decoder = NewPropertiesDecoder() - case CSVObjectInputFormat: - decoder = NewCSVObjectDecoder(ConfiguredCsvPreferences) - case TSVObjectInputFormat: - decoder = NewCSVObjectDecoder(ConfiguredTsvPreferences) - case UriInputFormat: - decoder = NewUriDecoder() - } - return decoder + format *Format } /* takes a string and decodes it back into an object */ @@ -124,7 +101,7 @@ func decodeOperator(_ *dataTreeNavigator, context Context, expressionNode *Expre preferences := expressionNode.Operation.Preferences.(decoderPreferences) - decoder := createDecoder(preferences.format) + decoder := preferences.format.DecoderFactory() if decoder == nil { return Context{}, errors.New("no support for input format") } diff --git a/pkg/yqlib/operators_test.go b/pkg/yqlib/operators_test.go index dd8e3e73..fe6cadcc 100644 --- a/pkg/yqlib/operators_test.go +++ b/pkg/yqlib/operators_test.go @@ -110,14 +110,14 @@ func testScenario(t *testing.T, s *expressionScenario) { if s.requiresFormat != "" { format := s.requiresFormat - inputFormat, err := InputFormatFromString(format) + inputFormat, err := FormatFromString(format) if err != nil { t.Error(err) } - if decoder := createDecoder(inputFormat); decoder == nil { + if decoder := inputFormat.DecoderFactory(); decoder == nil { t.Skipf("no support for %s input format", format) } - outputFormat, err := OutputFormatFromString(format) + outputFormat, err := FormatFromString(format) if err != nil { t.Error(err) } diff --git a/pkg/yqlib/printer.go b/pkg/yqlib/printer.go index d64e2132..61f653a8 100644 --- a/pkg/yqlib/printer.go +++ b/pkg/yqlib/printer.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "regexp" - "strings" ) type Printer interface { @@ -18,84 +17,6 @@ type Printer interface { SetNulSepOutput(nulSepOutput bool) } -type EncoderFactoryFunction func() Encoder - -type PrinterOutputFormat struct { - FormalName string - Names []string - EncoderFactory EncoderFactoryFunction -} - -var YamlOutputFormat = &PrinterOutputFormat{"yaml", []string{"y", "yml"}, func() Encoder { return NewYamlEncoder(ConfiguredYamlPreferences) }} -var JSONOutputFormat = &PrinterOutputFormat{"json", []string{"j"}, func() Encoder { return NewJSONEncoder(ConfiguredJSONPreferences) }} -var PropsOutputFormat = &PrinterOutputFormat{"props", []string{"p", "properties"}, func() Encoder { return NewPropertiesEncoder(ConfiguredPropertiesPreferences) }} -var CSVOutputFormat = &PrinterOutputFormat{"csv", []string{"c"}, func() Encoder { return NewCsvEncoder(ConfiguredCsvPreferences) }} -var TSVOutputFormat = &PrinterOutputFormat{"tsv", []string{"t"}, func() Encoder { return NewCsvEncoder(ConfiguredTsvPreferences) }} -var XMLOutputFormat = &PrinterOutputFormat{"xml", []string{"x"}, func() Encoder { return NewXMLEncoder(ConfiguredXMLPreferences) }} - -var Base64OutputFormat = &PrinterOutputFormat{"base64", []string{}, func() Encoder { return NewBase64Encoder() }} -var UriOutputFormat = &PrinterOutputFormat{"uri", []string{}, func() Encoder { return NewUriEncoder() }} -var ShOutputFormat = &PrinterOutputFormat{"", nil, func() Encoder { return NewShEncoder() }} - -var TomlOutputFormat = &PrinterOutputFormat{"toml", []string{}, func() Encoder { return NewTomlEncoder() }} -var ShellVariablesOutputFormat = &PrinterOutputFormat{"shell", []string{"s", "sh"}, func() Encoder { return NewShellVariablesEncoder() }} - -var LuaOutputFormat = &PrinterOutputFormat{"lua", []string{"l"}, func() Encoder { return NewLuaEncoder(ConfiguredLuaPreferences) }} - -var Formats = []*PrinterOutputFormat{ - YamlOutputFormat, - JSONOutputFormat, - PropsOutputFormat, - CSVOutputFormat, - TSVOutputFormat, - XMLOutputFormat, - Base64OutputFormat, - UriOutputFormat, - ShOutputFormat, - TomlOutputFormat, - ShellVariablesOutputFormat, - LuaOutputFormat, -} - -func (f *PrinterOutputFormat) MatchesName(name string) bool { - if f.FormalName == name { - return true - } - for _, n := range f.Names { - if n == name { - return true - } - } - return false -} - -func (f *PrinterOutputFormat) GetConfiguredEncoder() Encoder { - return f.EncoderFactory() -} - -func OutputFormatFromString(format string) (*PrinterOutputFormat, error) { - for _, printerFormat := range Formats { - if printerFormat.MatchesName(format) { - return printerFormat, nil - } - } - - return nil, fmt.Errorf("unknown format '%v' please use [%v]", format, GetAvailableOutputFormatString()) -} - -func GetAvailableOutputFormatString() string { - var formats = []string{} - for _, printerFormat := range Formats { - if printerFormat.FormalName != "" { - formats = append(formats, printerFormat.FormalName) - } - if len(printerFormat.Names) >= 1 { - formats = append(formats, printerFormat.Names[0]) - } - } - return strings.Join(formats, "|") -} - type resultsPrinter struct { encoder Encoder printerWriter PrinterWriter diff --git a/pkg/yqlib/printer_writer.go b/pkg/yqlib/printer_writer.go index 2a72e1f6..b3e89466 100644 --- a/pkg/yqlib/printer_writer.go +++ b/pkg/yqlib/printer_writer.go @@ -33,13 +33,13 @@ type multiPrintWriter struct { index int } -func NewMultiPrinterWriter(expression *ExpressionNode, format *PrinterOutputFormat) PrinterWriter { +func NewMultiPrinterWriter(expression *ExpressionNode, format *Format) PrinterWriter { extension := "yml" switch format { - case JSONOutputFormat: + case JSONFormat: extension = "json" - case PropsOutputFormat: + case PropertiesFormat: extension = "properties" }