Skip to content

Commit 1dc4f4d

Browse files
committed
Add gron i/o
1 parent 528092a commit 1dc4f4d

File tree

10 files changed

+131
-142
lines changed

10 files changed

+131
-142
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Note: these unsupported formats are on a roadmap for inclusion.
4949
| INI | ✅ Supported | ✅ Supported |
5050
| HCL | ✅ Supported | ✅ Supported |
5151
| TF | ✅ Supported | ✅ Supported |
52+
| GRON | ✅ Supported | ✅ Supported |
5253
| CSV | ✅ Supported | ❌ Not Supported |
5354
| Protobuf | ❌ Not Supported | ❌ Not Supported |
5455
| HTML | ❌ Not Supported | ❌ Not Supported |

cli/qq.go

+9-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package cli
22

33
import (
4-
"fmt"
5-
"io"
6-
"os"
7-
"github.com/spf13/cobra"
8-
"github.com/JFryy/qq/codec"
9-
"path/filepath"
10-
"strings"
11-
"github.com/JFryy/qq/internal/tui"
12-
"github.com/itchyny/gojq"
4+
"fmt"
5+
"github.com/JFryy/qq/codec"
6+
"github.com/JFryy/qq/internal/tui"
7+
"github.com/itchyny/gojq"
8+
"github.com/spf13/cobra"
9+
"io"
10+
"os"
11+
"path/filepath"
12+
"strings"
1313
)
1414

1515
func CreateRootCmd() *cobra.Command {
@@ -145,7 +145,6 @@ func handleCommand(args []string, inputtype string, outputtype string, rawInput
145145
os.Exit(0)
146146
}
147147

148-
149148
func isTerminal(f *os.File) bool {
150149
info, err := f.Stat()
151150
if err != nil {
@@ -154,7 +153,6 @@ func isTerminal(f *os.File) bool {
154153
return (info.Mode() & os.ModeCharDevice) != 0
155154
}
156155

157-
158156
func isFile(path string) bool {
159157
info, err := os.Stat(path)
160158
if err != nil {
@@ -174,7 +172,6 @@ func inferFileType(fName string) codec.EncodingType {
174172
return codec.JSON
175173
}
176174

177-
178175
func executeQuery(query *gojq.Query, data interface{}, fileType codec.EncodingType, rawOut bool) {
179176
iter := query.Run(data)
180177
for {

codec/codec.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ const (
2121
CSV
2222
XML
2323
INI
24+
GRON
2425
)
2526

2627
func (e EncodingType) String() string {
27-
return [...]string{"json", "yaml", "yml", "toml", "hcl", "tf", "csv", "xml", "ini"}[e]
28+
return [...]string{"json", "yaml", "yml", "toml", "hcl", "tf", "csv", "xml", "ini", "gron"}[e]
2829
}
2930

3031
type Encoding struct {
@@ -57,6 +58,7 @@ var SupportedFileTypes = []Encoding{
5758
{CSV, csvUnmarshal, jsonMarshalIndent},
5859
{XML, xmlUnmarshal, xmlMarshal},
5960
{INI, iniUnmarshal, iniMarshal},
61+
{GRON, gronUnmarshal, gronMarshal},
6062
}
6163

6264
func Unmarshal(input []byte, inputFileType EncodingType) (interface{}, error) {

codec/codec_test.go

-122
This file was deleted.

codec/go.mod

+1-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ require (
1111
github.com/hashicorp/hcl/v2 v2.21.0
1212
github.com/mattn/go-isatty v0.0.20
1313
github.com/mitchellh/mapstructure v1.5.0
14-
github.com/stretchr/testify v1.9.0
1514
github.com/tmccombs/hcl2json v0.6.3
1615
github.com/zclconf/go-cty v1.14.4
1716
gopkg.in/ini.v1 v1.67.0
@@ -20,18 +19,16 @@ require (
2019
require (
2120
github.com/agext/levenshtein v1.2.3 // indirect
2221
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
23-
github.com/davecgh/go-spew v1.1.1 // indirect
2422
github.com/dlclark/regexp2 v1.11.0 // indirect
2523
github.com/fatih/color v1.17.0 // indirect
2624
github.com/google/go-cmp v0.6.0 // indirect
2725
github.com/mattn/go-colorable v0.1.13 // indirect
2826
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
29-
github.com/pmezard/go-difflib v1.0.0 // indirect
27+
github.com/stretchr/testify v1.9.0 // indirect
3028
golang.org/x/mod v0.18.0 // indirect
3129
golang.org/x/sync v0.7.0 // indirect
3230
golang.org/x/sys v0.21.0 // indirect
3331
golang.org/x/text v0.16.0 // indirect
3432
golang.org/x/tools v0.22.0 // indirect
3533
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
36-
gopkg.in/yaml.v3 v3.0.1 // indirect
3734
)

codec/go.sum

-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
7171
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
7272
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
7373
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
74-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
7574
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
7675
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
7776
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

codec/gron.go

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package codec
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"github.com/goccy/go-json"
7+
"reflect"
8+
"strconv"
9+
"strings"
10+
)
11+
12+
func gronUnmarshal(data []byte, v interface{}) error {
13+
d := make(map[string]interface{})
14+
15+
lines := strings.Split(string(data), "\n")
16+
for _, line := range lines {
17+
if len(line) == 0 {
18+
continue
19+
}
20+
parts := strings.SplitN(line, " = ", 2)
21+
if len(parts) != 2 {
22+
return nil
23+
}
24+
25+
key := strings.TrimSpace(parts[0])
26+
value := strings.Trim(parts[1], `";`)
27+
28+
setValueJSON(d, key, value)
29+
}
30+
31+
*v.(*interface{}) = d
32+
return nil
33+
34+
}
35+
36+
func gronMarshal(v interface{}) ([]byte, error) {
37+
var buf bytes.Buffer
38+
traverseJSON("", v, &buf)
39+
return buf.Bytes(), nil
40+
}
41+
42+
func traverseJSON(prefix string, v interface{}, buf *bytes.Buffer) {
43+
rv := reflect.ValueOf(v)
44+
switch rv.Kind() {
45+
case reflect.Map:
46+
for _, key := range rv.MapKeys() {
47+
strKey := fmt.Sprintf("%v", key)
48+
traverseJSON(addPrefix(prefix, strKey), rv.MapIndex(key).Interface(), buf)
49+
}
50+
case reflect.Slice:
51+
for i := 0; i < rv.Len(); i++ {
52+
traverseJSON(fmt.Sprintf("%s[%d]", prefix, i), rv.Index(i).Interface(), buf)
53+
}
54+
default:
55+
buf.WriteString(fmt.Sprintf("%s = %s;\n", prefix, formatJSONValue(v)))
56+
}
57+
}
58+
59+
func addPrefix(prefix, name string) string {
60+
if prefix == "" {
61+
return name
62+
}
63+
return prefix + "." + name
64+
}
65+
66+
func formatJSONValue(v interface{}) string {
67+
switch val := v.(type) {
68+
case string:
69+
return fmt.Sprintf("%q", val)
70+
case bool:
71+
return strconv.FormatBool(val)
72+
case float64:
73+
return strconv.FormatFloat(val, 'f', -1, 64)
74+
default:
75+
if v == nil {
76+
return "null"
77+
}
78+
data, _ := json.Marshal(v)
79+
return string(data)
80+
}
81+
}
82+
83+
func setValueJSON(data map[string]interface{}, key, value string) {
84+
parts := strings.Split(key, ".")
85+
var m = data
86+
for i, part := range parts {
87+
if i == len(parts)-1 {
88+
if strings.Contains(part, "[") && strings.Contains(part, "]") {
89+
k := strings.Split(part, "[")[0]
90+
if _, ok := m[k]; !ok {
91+
m[k] = make([]interface{}, 0)
92+
}
93+
94+
m[k] = append(m[k].([]interface{}), value)
95+
} else {
96+
m[part] = value
97+
}
98+
} else {
99+
if _, ok := m[part]; !ok {
100+
m[part] = make(map[string]interface{})
101+
}
102+
m = m[part].(map[string]interface{})
103+
}
104+
}
105+
}

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ require (
77
github.com/JFryy/qq/codec v0.0.0-20240626034628-3e21f7f0cea6
88
)
99

10+
//replace github.com/JFryy/qq/codec => ./codec
11+
1012
require (
1113
github.com/BurntSushi/toml v1.4.0 // indirect
1214
github.com/JFryy/qq/internal/tui v0.0.0-20240626033059-fa396add9f28 // indirect

tests/test.gron

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
example.name = "John";
2+
example.age = 30;
3+
example.address.city = "New York";
4+
example.address.zip_code = "10001";
5+
example.skills[0] = "Go";
6+
example.skills[1] = "JavaScript";
7+
example.contacts.email = "john@example.com";
8+
example.contacts.phone = "+1234567890";

tests/test.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ done
6060
previous_ext="json"
6161
for file in ${extensions}; do
6262
print "" "============================================"
63-
print "" "Executing: cat tests/test.xml | jq . | bin/qq -o $previous_ext"
63+
print "" "Executing: cat $file | jq . | bin/qq -o $previous_ext"
6464
print "" "============================================"
65-
bin/qq tests/test.xml | jq . | bin/qq -o $previous_ext
65+
bin/qq $file | jq . | bin/qq -o $previous_ext
6666
print "green" "============================================"
6767
print "green" "Success."
6868
print "green" "============================================"

0 commit comments

Comments
 (0)