Skip to content

Commit

Permalink
Implement Lua globals output mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Zash committed Aug 5, 2023
1 parent 69265f1 commit 2870675
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 17 deletions.
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ yq -P sample.json
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredLuaPreferences.DocPrefix, "lua-prefix", yqlib.ConfiguredLuaPreferences.DocPrefix, "prefix")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredLuaPreferences.DocSuffix, "lua-suffix", yqlib.ConfiguredLuaPreferences.DocSuffix, "suffix")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredLuaPreferences.UnquotedKeys, "lua-unquoted", yqlib.ConfiguredLuaPreferences.UnquotedKeys, "output unquoted string keys (e.g. {foo=\"bar\"})")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredLuaPreferences.Globals, "lua-globals", yqlib.ConfiguredLuaPreferences.Globals, "output keys as top-level global variables")

rootCmd.PersistentFlags().BoolVarP(&nullInput, "null-input", "n", false, "Don't read input, simply evaluate the expression given. Useful for creating docs from scratch.")
rootCmd.PersistentFlags().BoolVarP(&noDocSeparators, "no-doc", "N", false, "Don't print document separators (---)")
Expand Down
30 changes: 30 additions & 0 deletions pkg/yqlib/doc/usage/lua.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,36 @@ return {
};
```

## Globals
Uses the `--lua-globals` option to export the values into the global scope.

Given a sample.yml file of:
```yaml
---
country: Australia # this place
cities:
- Sydney
- Melbourne
- Brisbane
- Perth
```
then
```bash
yq -o=lua '.' sample.yml
```
will output
```lua
return {
["country"] = "Australia"; -- this place
["cities"] = {
"Sydney",
"Melbourne",
"Brisbane",
"Perth",
};
};
```

## Elaborate example
Given a sample.yml file of:
```yaml
Expand Down
51 changes: 36 additions & 15 deletions pkg/yqlib/encoder_lua.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type luaEncoder struct {
indent int
indentStr string
unquoted bool
globals bool
escape *strings.Replacer
}

Expand Down Expand Up @@ -68,7 +69,7 @@ func NewLuaEncoder(prefs LuaPreferences) Encoder {
"\\t", "\t",
"\\\\", "\\",
)
return &luaEncoder{unescape.Replace(prefs.DocPrefix), unescape.Replace(prefs.DocSuffix), 0, "\t", prefs.UnquotedKeys, escape}
return &luaEncoder{unescape.Replace(prefs.DocPrefix), unescape.Replace(prefs.DocSuffix), 0, "\t", prefs.UnquotedKeys, prefs.Globals, escape}
}

func (le *luaEncoder) PrintDocumentSeparator(writer io.Writer) error {
Expand Down Expand Up @@ -178,16 +179,18 @@ func needsQuoting(s string) bool {
return false
}

func (le *luaEncoder) encodeMap(writer io.Writer, node *yaml.Node) error {
err := writeString(writer, "{")
if err != nil {
return err
func (le *luaEncoder) encodeMap(writer io.Writer, node *yaml.Node, global bool) error {
if !global {
err := writeString(writer, "{")
if err != nil {
return err
}
le.indent++
}
le.indent++
for i, child := range node.Content {
if (i % 2) == 1 {
// value
err = le.Encode(writer, child)
err := le.Encode(writer, child)
if err != nil {
return err
}
Expand All @@ -197,16 +200,25 @@ func (le *luaEncoder) encodeMap(writer io.Writer, node *yaml.Node) error {
}
} else {
// key
err = le.writeIndent(writer)
if err != nil {
return err
if !global || i > 0 {
err := le.writeIndent(writer)
if err != nil {
return err
}
}
if le.unquoted && child.Tag == "!!str" && !needsQuoting(child.Value) {
err = writeString(writer, child.Value+" = ")
if (le.unquoted || global) && child.Tag == "!!str" && !needsQuoting(child.Value) {
err := writeString(writer, child.Value+" = ")
if err != nil {
return err
}
} else {
if global {
// This only works in Lua 5.2+
err := writeString(writer, "_ENV")
if err != nil {
return err
}
}
err := writeString(writer, "[")
if err != nil {
return err
Expand All @@ -223,7 +235,7 @@ func (le *luaEncoder) encodeMap(writer io.Writer, node *yaml.Node) error {
}
if child.LineComment != "" {
sansPrefix, _ := strings.CutPrefix(child.LineComment, "#")
err = writeString(writer, strings.Repeat(" ", i%2)+"--"+sansPrefix)
err := writeString(writer, strings.Repeat(" ", i%2)+"--"+sansPrefix)
if err != nil {
return err
}
Expand All @@ -236,9 +248,12 @@ func (le *luaEncoder) encodeMap(writer io.Writer, node *yaml.Node) error {
}
}
}
if global {
return writeString(writer, "\n")
}
le.indent--
if len(node.Content) != 0 {
err = le.writeIndent(writer)
err := le.writeIndent(writer)
if err != nil {
return err
}
Expand All @@ -251,7 +266,7 @@ func (le *luaEncoder) encodeAny(writer io.Writer, node *yaml.Node) error {
case yaml.SequenceNode:
return le.encodeArray(writer, node)
case yaml.MappingNode:
return le.encodeMap(writer, node)
return le.encodeMap(writer, node, false)
case yaml.ScalarNode:
switch node.Tag {
case "!!str":
Expand Down Expand Up @@ -288,6 +303,12 @@ func (le *luaEncoder) encodeAny(writer io.Writer, node *yaml.Node) error {
return fmt.Errorf("Lua encoder NYI -- %s", node.ShortTag())
}
case yaml.DocumentNode:
if le.globals {
if node.Content[0].Kind != yaml.MappingNode {
return fmt.Errorf("--lua-global requires a top level MappingNode")
}
return le.encodeMap(writer, node.Content[0], true)
}
err := writeString(writer, le.docPrefix)
if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions pkg/yqlib/lua.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ type LuaPreferences struct {
DocPrefix string
DocSuffix string
UnquotedKeys bool
Globals bool
}

func NewDefaultLuaPreferences() LuaPreferences {
return LuaPreferences{
DocPrefix: "return ",
DocSuffix: ";\n",
UnquotedKeys: false,
Globals: false,
}
}

Expand Down
41 changes: 39 additions & 2 deletions pkg/yqlib/lua_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ cities:
"Perth",
};
};
`,
},
{
description: "Globals",
subdescription: "Uses the `--lua-globals` option to export the values into the global scope.",
scenarioType: "globals-encode",
input: `---
country: Australia # this place
cities:
- Sydney
- Melbourne
- Brisbane
- Perth`,
expected: `country = "Australia"; -- this place
cities = {
"Sydney",
"Melbourne",
"Brisbane",
"Perth",
};
`,
},
{
Expand Down Expand Up @@ -155,6 +175,14 @@ func testLuaScenario(t *testing.T, s formatScenario) {
DocPrefix: "return ",
DocSuffix: ";\n",
UnquotedKeys: true,
Globals: false,
})), s.description)
case "globals-encode":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewLuaEncoder(LuaPreferences{
DocPrefix: "return ",
DocSuffix: ";\n",
UnquotedKeys: false,
Globals: true,
})), s.description)
default:
panic(fmt.Sprintf("unhandled scenario type %q", s.scenarioType))
Expand All @@ -168,7 +196,7 @@ func documentLuaScenario(t *testing.T, w *bufio.Writer, i interface{}) {
return
}
switch s.scenarioType {
case "encode", "unquoted-encode":
case "encode", "unquoted-encode", "globals-encode":
documentLuaEncodeScenario(w, s)
default:
panic(fmt.Sprintf("unhandled scenario type %q", s.scenarioType))
Expand All @@ -184,11 +212,20 @@ func documentLuaEncodeScenario(w *bufio.Writer, s formatScenario) {
}

prefs := ConfiguredLuaPreferences
if s.scenarioType == "unquoted-encode" {
switch s.scenarioType {
case "unquoted-encode":
prefs = LuaPreferences{
DocPrefix: "return ",
DocSuffix: ";\n",
UnquotedKeys: true,
Globals: false,
}
case "globals-encodes":
prefs = LuaPreferences{
DocPrefix: "return ",
DocSuffix: ";\n",
UnquotedKeys: false,
Globals: true,
}
}
writeOrPanic(w, "Given a sample.yml file of:\n")
Expand Down

0 comments on commit 2870675

Please sign in to comment.