diff --git a/cmd/utils.go b/cmd/utils.go index 7d34c723..b23135e8 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -197,6 +197,8 @@ func createEncoder(format yqlib.PrinterOutputFormat) (yqlib.Encoder, error) { return yqlib.NewTomlEncoder(), nil case yqlib.ShellVariablesOutputFormat: return yqlib.NewShellVariablesEncoder(), nil + case yqlib.LuaOutputFormat: + return yqlib.NewLuaEncoder(), nil } return nil, fmt.Errorf("invalid encoder: %v", format) } diff --git a/pkg/yqlib/encoder_lua.go b/pkg/yqlib/encoder_lua.go new file mode 100644 index 00000000..4e4f09e8 --- /dev/null +++ b/pkg/yqlib/encoder_lua.go @@ -0,0 +1,122 @@ +package yqlib + +import ( + "io" + "strings" + + yaml "gopkg.in/yaml.v3" +) + +type luaEncoder struct { + docPrefix string + docSuffix string + escape *strings.Replacer +} + +func (le *luaEncoder) CanHandleAliases() bool { + return false +} + +func NewLuaEncoder() Encoder { + escape := strings.NewReplacer("\n", "\\n", "\"", "\\\"", "\\", "\\\\") + return &luaEncoder{"return ", ";\n", escape} +} + +func (le *luaEncoder) PrintDocumentSeparator(writer io.Writer) error { + return nil +} + +func (le *luaEncoder) PrintLeadingContent(writer io.Writer, content string) error { + return nil +} + +func (le *luaEncoder) encodeString(writer io.Writer, node *yaml.Node) error { + return writeString(writer, "\""+le.escape.Replace(node.Value)+"\"") +} + +func (le *luaEncoder) encodeArray(writer io.Writer, node *yaml.Node) error { + err := writeString(writer, "{") + if err != nil { + return err + } + for _, child := range node.Content { + err := le.Encode(writer, child) + if err != nil { + return err + } + err = writeString(writer, ",") + if err != nil { + return err + } + } + return writeString(writer, "}") +} + +func (le *luaEncoder) encodeMap(writer io.Writer, node *yaml.Node) error { + err := writeString(writer, "{") + if err != nil { + return err + } + for i, child := range node.Content { + if (i % 2) == 1 { + // value + err = le.Encode(writer, child) + if err != nil { + return err + } + err = writeString(writer, ";") + if err != nil { + return err + } + } else { + // key + err := writeString(writer, "[") + if err != nil { + return err + } + err = le.encodeAny(writer, child) + if err != nil { + return err + } + err = writeString(writer, "]=") + if err != nil { + return err + } + } + } + return writeString(writer, "}") +} + +func (le *luaEncoder) encodeAny(writer io.Writer, node *yaml.Node) error { + switch node.Kind { + case yaml.SequenceNode: + return le.encodeArray(writer, node) + case yaml.MappingNode: + return le.encodeMap(writer, node) + case yaml.ScalarNode: + switch node.Tag { + case "!!str": + return le.encodeString(writer, node) + case "!!null": + return writeString(writer, "nil") + default: + return writeString(writer, node.Value) + } + case yaml.DocumentNode: + err := writeString(writer, le.docPrefix) + if err != nil { + return err + } + err = le.encodeAny(writer, node.Content[0]) + if err != nil { + return err + } + return writeString(writer, le.docSuffix) + default: + return writeString(writer, "nil --[[ encoder NYI -- "+node.ShortTag()+" ]]") + } +} + +func (le *luaEncoder) Encode(writer io.Writer, node *yaml.Node) error { + return le.encodeAny(writer, node) +} diff --git a/pkg/yqlib/printer.go b/pkg/yqlib/printer.go index 9cd65753..c430fcfe 100644 --- a/pkg/yqlib/printer.go +++ b/pkg/yqlib/printer.go @@ -33,6 +33,7 @@ const ( ShOutputFormat TomlOutputFormat ShellVariablesOutputFormat + LuaOutputFormat ) func OutputFormatFromString(format string) (PrinterOutputFormat, error) { @@ -53,8 +54,10 @@ func OutputFormatFromString(format string) (PrinterOutputFormat, error) { return TomlOutputFormat, nil case "shell", "s", "sh": return ShellVariablesOutputFormat, nil + case "lua", "l": + return LuaOutputFormat, nil default: - return 0, fmt.Errorf("unknown format '%v' please use [yaml|json|props|csv|tsv|xml|toml|shell]", format) + return 0, fmt.Errorf("unknown format '%v' please use [yaml|json|props|csv|tsv|xml|toml|shell|lua]", format) } }