jsonpretty 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.goreleaser.yaml +30 -0
- data/History.txt +4 -0
- data/README.md +1 -1
- data/go.mod +3 -0
- data/lib/jsonpretty/version.rb +1 -1
- data/main.go +199 -0
- data/main_test.go +180 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89641014acab0632260843ff87e190604e7342d386109dfa77245ec343ff1ee4
|
4
|
+
data.tar.gz: 7fe4a6155fed431b9c64735fa3a8c133354c293a60d9a03c5786a15f3e31348d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17e783dbab3458c8c46ef6b9cb3f6065f6552eccbe65b6ba408003709bed7cbc92e98ab4f3d09750363fd2fbd7426df7accb2ea4716ec24f53b5c92e24789d14
|
7
|
+
data.tar.gz: d3b01927f851234aba103921e43b8db1cc2d07383ea73c825b78027cd6bfacf8b763be0112aff91ba8e08dd53a1b27d61129aa1dd10861a4267e438d3d7dd6e2
|
data/.goreleaser.yaml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# This is an example .goreleaser.yml file with some sensible defaults.
|
2
|
+
# Make sure to check the documentation at https://goreleaser.com
|
3
|
+
before:
|
4
|
+
hooks:
|
5
|
+
# You may remove this if you don't use go modules.
|
6
|
+
- go mod tidy
|
7
|
+
builds:
|
8
|
+
- env:
|
9
|
+
- CGO_ENABLED=0
|
10
|
+
goos:
|
11
|
+
- linux
|
12
|
+
- windows
|
13
|
+
- darwin
|
14
|
+
archives:
|
15
|
+
- replacements:
|
16
|
+
darwin: Darwin
|
17
|
+
linux: Linux
|
18
|
+
windows: Windows
|
19
|
+
386: i386
|
20
|
+
amd64: x86_64
|
21
|
+
checksum:
|
22
|
+
name_template: 'checksums.txt'
|
23
|
+
snapshot:
|
24
|
+
name_template: "{{ incpatch .Version }}-next"
|
25
|
+
changelog:
|
26
|
+
sort: asc
|
27
|
+
filters:
|
28
|
+
exclude:
|
29
|
+
- '^docs:'
|
30
|
+
- '^test:'
|
data/History.txt
CHANGED
data/README.md
CHANGED
data/go.mod
ADDED
data/lib/jsonpretty/version.rb
CHANGED
data/main.go
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"bytes"
|
5
|
+
"encoding/json"
|
6
|
+
"fmt"
|
7
|
+
"io"
|
8
|
+
"os"
|
9
|
+
"regexp"
|
10
|
+
"strings"
|
11
|
+
)
|
12
|
+
|
13
|
+
var (
|
14
|
+
version = "dev"
|
15
|
+
commit = ""
|
16
|
+
date = ""
|
17
|
+
builtBy = ""
|
18
|
+
)
|
19
|
+
|
20
|
+
type JsonArg struct {
|
21
|
+
file *os.File
|
22
|
+
content []byte
|
23
|
+
}
|
24
|
+
|
25
|
+
func (j JsonArg) Close() error {
|
26
|
+
if j.file != nil {
|
27
|
+
return j.file.Close()
|
28
|
+
}
|
29
|
+
return nil
|
30
|
+
}
|
31
|
+
|
32
|
+
func usage(code int) {
|
33
|
+
fmt.Printf("usage: %s [args|@filename|@- (stdin)]\n", os.Args[0])
|
34
|
+
fmt.Printf("Parse and pretty-print JSON, either from stdin or from arguments concatenated together\n")
|
35
|
+
os.Exit(code)
|
36
|
+
}
|
37
|
+
|
38
|
+
func versionInfo() string {
|
39
|
+
if commit != "" && date != "" {
|
40
|
+
return fmt.Sprintf("%s (%s on %s)", version, commit[0:7], date[0:10])
|
41
|
+
}
|
42
|
+
return version
|
43
|
+
}
|
44
|
+
|
45
|
+
func checkFlags(arg string) {
|
46
|
+
if arg[0] == '-' && len(arg) > 1 {
|
47
|
+
code := 1
|
48
|
+
if arg == "-v" || strings.HasPrefix(arg, "--v") {
|
49
|
+
fmt.Printf("jsonpretty version %s\n", versionInfo())
|
50
|
+
os.Exit(0)
|
51
|
+
} else if arg == "-h" || strings.HasPrefix(arg, "--h") {
|
52
|
+
code = 0
|
53
|
+
}
|
54
|
+
if code == 1 {
|
55
|
+
fmt.Printf("unrecognized flag %s\n", arg)
|
56
|
+
}
|
57
|
+
usage(code)
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
func buildJsonSource(args []JsonArg) *bytes.Buffer {
|
62
|
+
buffer := bytes.NewBuffer(nil)
|
63
|
+
for _, arg := range args {
|
64
|
+
if arg.file != nil {
|
65
|
+
_, err := buffer.ReadFrom(arg.file)
|
66
|
+
if err != nil {
|
67
|
+
fmt.Fprintf(os.Stderr, "error reading file: %v\n", err)
|
68
|
+
}
|
69
|
+
} else {
|
70
|
+
_, err := buffer.Write(arg.content)
|
71
|
+
if err != nil {
|
72
|
+
fmt.Fprintf(os.Stderr, "error appending content: %v\n", err)
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
return buffer
|
77
|
+
}
|
78
|
+
|
79
|
+
func readArguments(args []string) *bytes.Buffer {
|
80
|
+
jsonArgs := []JsonArg{}
|
81
|
+
defer func() {
|
82
|
+
for _, j := range jsonArgs {
|
83
|
+
_ = j.Close()
|
84
|
+
}
|
85
|
+
}()
|
86
|
+
for _, arg := range args {
|
87
|
+
checkFlags(arg)
|
88
|
+
|
89
|
+
if arg == "-" || arg == "@-" {
|
90
|
+
jsonArgs = append(jsonArgs, JsonArg{file: os.Stdin})
|
91
|
+
} else if strings.HasPrefix(arg, "@") {
|
92
|
+
file, err := os.Open(arg[1:])
|
93
|
+
if err != nil {
|
94
|
+
fmt.Fprintf(os.Stderr, "skipping '%s' due to error: %v\n", arg, err)
|
95
|
+
continue
|
96
|
+
}
|
97
|
+
jsonArgs = append(jsonArgs, JsonArg{file: file})
|
98
|
+
} else {
|
99
|
+
jsonArgs = append(jsonArgs, JsonArg{content: []byte(arg)})
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
if len(jsonArgs) == 0 {
|
104
|
+
jsonArgs = append(jsonArgs, JsonArg{file: os.Stdin})
|
105
|
+
}
|
106
|
+
return buildJsonSource(jsonArgs)
|
107
|
+
}
|
108
|
+
|
109
|
+
var httpRegex *regexp.Regexp = regexp.MustCompile("^HTTP/\\d")
|
110
|
+
|
111
|
+
func parseHeaders(src *bytes.Buffer) ([]byte, []byte, error) {
|
112
|
+
headerBuffer := bytes.NewBuffer(nil)
|
113
|
+
line, err := src.ReadBytes('\n')
|
114
|
+
if err != nil && err != io.EOF {
|
115
|
+
return nil, nil, err
|
116
|
+
}
|
117
|
+
|
118
|
+
if httpRegex.Match(line) {
|
119
|
+
for {
|
120
|
+
_, err = headerBuffer.Write(line)
|
121
|
+
if err != nil {
|
122
|
+
return nil, nil, err
|
123
|
+
}
|
124
|
+
if (len(line) == 1 && line[0] == '\n') ||
|
125
|
+
(len(line) == 2 && line[0] == '\r' && line[1] == '\n') {
|
126
|
+
break
|
127
|
+
}
|
128
|
+
|
129
|
+
line, err = src.ReadBytes('\n')
|
130
|
+
|
131
|
+
if err == io.EOF {
|
132
|
+
_, err = headerBuffer.Write(line)
|
133
|
+
if err != nil {
|
134
|
+
return nil, nil, err
|
135
|
+
}
|
136
|
+
break
|
137
|
+
}
|
138
|
+
|
139
|
+
if err != nil && err != io.EOF {
|
140
|
+
return nil, nil, err
|
141
|
+
}
|
142
|
+
}
|
143
|
+
} else {
|
144
|
+
newsrc := bytes.NewBuffer(line)
|
145
|
+
_, err = newsrc.Write(src.Bytes())
|
146
|
+
if err != nil {
|
147
|
+
return nil, nil, err
|
148
|
+
}
|
149
|
+
src = newsrc
|
150
|
+
}
|
151
|
+
return headerBuffer.Bytes(), src.Bytes(), nil
|
152
|
+
}
|
153
|
+
|
154
|
+
var jsonpRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z$_][^ \t\r\n(]+)\\(")
|
155
|
+
var endingParen *regexp.Regexp = regexp.MustCompile("\\)[ \t\r\n]*$")
|
156
|
+
|
157
|
+
func cleanJsonp(jsonSrc []byte) ([]byte, string) {
|
158
|
+
match := jsonpRegexp.FindSubmatch(jsonSrc)
|
159
|
+
ending := endingParen.FindSubmatch(jsonSrc)
|
160
|
+
if match != nil && ending != nil {
|
161
|
+
return jsonSrc[len(match[0]) : len(jsonSrc)-len(ending[0])], string(match[1])
|
162
|
+
}
|
163
|
+
return jsonSrc, ""
|
164
|
+
}
|
165
|
+
|
166
|
+
func handleParseError(err error, jsonSrc []byte) {
|
167
|
+
if err != nil {
|
168
|
+
fmt.Fprintf(os.Stderr, "error parsing json: %v\ninput:\n%s\n", err, string(jsonSrc))
|
169
|
+
os.Exit(1)
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
func main() {
|
174
|
+
buffer := readArguments(os.Args[1:])
|
175
|
+
headers, jsonSrc, err := parseHeaders(buffer)
|
176
|
+
handleParseError(err, jsonSrc)
|
177
|
+
|
178
|
+
jsonSrc, jsonpName := cleanJsonp(jsonSrc)
|
179
|
+
|
180
|
+
if len(headers) > 0 {
|
181
|
+
fmt.Print(string(headers))
|
182
|
+
}
|
183
|
+
|
184
|
+
if jsonpName != "" {
|
185
|
+
fmt.Printf("jsonp method name: %s\n\n", jsonpName)
|
186
|
+
}
|
187
|
+
|
188
|
+
var jsonObj interface{}
|
189
|
+
err = json.Unmarshal(jsonSrc, &jsonObj)
|
190
|
+
handleParseError(err, jsonSrc)
|
191
|
+
|
192
|
+
enc := json.NewEncoder(os.Stdout)
|
193
|
+
enc.SetIndent("", " ")
|
194
|
+
err = enc.Encode(&jsonObj)
|
195
|
+
if err != nil {
|
196
|
+
fmt.Fprintf(os.Stderr, "error encoding json: %v\n", err)
|
197
|
+
os.Exit(1)
|
198
|
+
}
|
199
|
+
}
|
data/main_test.go
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"bytes"
|
5
|
+
"fmt"
|
6
|
+
"os"
|
7
|
+
"testing"
|
8
|
+
)
|
9
|
+
|
10
|
+
type Testfile struct {
|
11
|
+
name string
|
12
|
+
content string
|
13
|
+
file *os.File
|
14
|
+
}
|
15
|
+
|
16
|
+
var stdinSaved *os.File = os.Stdin
|
17
|
+
|
18
|
+
func Setup(contents []string, t *testing.T) []Testfile {
|
19
|
+
var err error
|
20
|
+
os.Stdin, err = os.CreateTemp("", "stdin")
|
21
|
+
if err != nil {
|
22
|
+
t.FailNow()
|
23
|
+
}
|
24
|
+
|
25
|
+
testfiles := make([]Testfile, len(contents))
|
26
|
+
for i, c := range contents {
|
27
|
+
testfiles[i] = Testfile{content: c}
|
28
|
+
file, err := os.CreateTemp("", fmt.Sprintf("tf%d", i))
|
29
|
+
if err != nil {
|
30
|
+
t.Logf("unable to create tempfile for '%s'", c)
|
31
|
+
t.FailNow()
|
32
|
+
}
|
33
|
+
_, err = file.Write([]byte(c))
|
34
|
+
if err != nil {
|
35
|
+
t.Logf("unable to write tempfile with '%s'", c)
|
36
|
+
t.FailNow()
|
37
|
+
}
|
38
|
+
err = file.Close()
|
39
|
+
if err != nil {
|
40
|
+
t.Logf("unable to close tempfile for '%s'", c)
|
41
|
+
t.FailNow()
|
42
|
+
}
|
43
|
+
testfiles[i].file = file
|
44
|
+
testfiles[i].name = file.Name()
|
45
|
+
}
|
46
|
+
return testfiles
|
47
|
+
}
|
48
|
+
|
49
|
+
func TearDown(testfiles []Testfile) {
|
50
|
+
for _, tf := range testfiles {
|
51
|
+
_ = os.Remove(tf.name)
|
52
|
+
}
|
53
|
+
_ = os.Stdin.Close()
|
54
|
+
os.Stdin = stdinSaved
|
55
|
+
}
|
56
|
+
|
57
|
+
func assertEqual(expect []byte, actual []byte, t *testing.T) {
|
58
|
+
if bytes.Compare(expect, actual) != 0 {
|
59
|
+
t.Errorf("bytes did not match:\n. expected:\n %s\n actual:\n %s\n",
|
60
|
+
string(expect), string(actual))
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
func TestReadArguments(t *testing.T) {
|
65
|
+
files := Setup([]string{"1", "2", "{\"foo\": true, \"bar\": false}"}, t)
|
66
|
+
defer TearDown(files)
|
67
|
+
|
68
|
+
tests := [][]Testfile{
|
69
|
+
{}, // nothing
|
70
|
+
{Testfile{content: "{\"hello\":\"world\"}"}},
|
71
|
+
{Testfile{content: "["}, files[0], Testfile{content: ","}, files[1], Testfile{content: "]"}},
|
72
|
+
{files[2]},
|
73
|
+
}
|
74
|
+
|
75
|
+
for i, test := range tests {
|
76
|
+
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
|
77
|
+
expected := bytes.NewBuffer(nil)
|
78
|
+
args := make([]string, len(test))
|
79
|
+
for j, testfile := range test {
|
80
|
+
if testfile.name != "" {
|
81
|
+
args[j] = fmt.Sprintf("@%s", testfile.name)
|
82
|
+
} else {
|
83
|
+
args[j] = testfile.content
|
84
|
+
}
|
85
|
+
expected.WriteString(testfile.content)
|
86
|
+
}
|
87
|
+
expect := expected.Bytes()
|
88
|
+
actual := readArguments(args)
|
89
|
+
assertEqual(expect, actual.Bytes(), t)
|
90
|
+
})
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
func TestReadArgumentsStdin(t *testing.T) {
|
95
|
+
f := Setup([]string{}, t)
|
96
|
+
defer TearDown(f)
|
97
|
+
|
98
|
+
expect := []byte("{\"foo\": true, \"bar\": false}")
|
99
|
+
_, err := os.Stdin.Write(expect)
|
100
|
+
if err != nil {
|
101
|
+
t.Logf("unable to write to stdin\n")
|
102
|
+
t.FailNow()
|
103
|
+
}
|
104
|
+
_ = os.Stdin.Close()
|
105
|
+
|
106
|
+
reopen := func(t *testing.T) {
|
107
|
+
f, err := os.Open(os.Stdin.Name())
|
108
|
+
if err != nil {
|
109
|
+
t.Logf("unable to reopen stdin")
|
110
|
+
t.FailNow()
|
111
|
+
}
|
112
|
+
os.Stdin = f
|
113
|
+
}
|
114
|
+
|
115
|
+
t.Run("no args", func(t *testing.T) {
|
116
|
+
reopen(t)
|
117
|
+
actual := readArguments([]string{})
|
118
|
+
assertEqual(expect, actual.Bytes(), t)
|
119
|
+
})
|
120
|
+
|
121
|
+
t.Run("-", func(t *testing.T) {
|
122
|
+
reopen(t)
|
123
|
+
actual := readArguments([]string{"-"})
|
124
|
+
assertEqual(expect, actual.Bytes(), t)
|
125
|
+
})
|
126
|
+
|
127
|
+
t.Run("@-", func(t *testing.T) {
|
128
|
+
reopen(t)
|
129
|
+
actual := readArguments([]string{"@-"})
|
130
|
+
assertEqual(expect, actual.Bytes(), t)
|
131
|
+
})
|
132
|
+
}
|
133
|
+
|
134
|
+
func TestParseHeaders(t *testing.T) {
|
135
|
+
tests := [][]string{
|
136
|
+
{"", "", ""},
|
137
|
+
{"{}", "", "{}"},
|
138
|
+
{"not http\n\nhello\nworld", "", "not http\n\nhello\nworld"},
|
139
|
+
{"HTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 19\n\n{\"hello\":\"world\"}\n",
|
140
|
+
"HTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 19\n\n",
|
141
|
+
"{\"hello\":\"world\"}\n"},
|
142
|
+
{"HTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 0\n\n",
|
143
|
+
"HTTP/1.1 200 OK\nContent-Type: application/json\nContent-Length: 0\n\n",
|
144
|
+
""},
|
145
|
+
{"myfunc(1,2,3)", "", "myfunc(1,2,3)"},
|
146
|
+
}
|
147
|
+
|
148
|
+
for i, test := range tests {
|
149
|
+
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
|
150
|
+
buffer := bytes.NewBuffer(nil)
|
151
|
+
buffer.WriteString(test[0])
|
152
|
+
headers, jsonsrc, err := parseHeaders(buffer)
|
153
|
+
if err != nil {
|
154
|
+
t.Logf("error parseHeaders: %v", err)
|
155
|
+
t.FailNow()
|
156
|
+
}
|
157
|
+
assertEqual([]byte(test[1]), headers, t)
|
158
|
+
assertEqual([]byte(test[2]), jsonsrc, t)
|
159
|
+
})
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
func TestCleanJsonp(t *testing.T) {
|
164
|
+
tests := [][]string{
|
165
|
+
{"jsonp(true)", "true", "jsonp"},
|
166
|
+
{"true", "true", ""},
|
167
|
+
{"myJSFunc({\"hello\":\"world\"})", "{\"hello\":\"world\"}", "myJSFunc"},
|
168
|
+
{"[1,2,3]", "[1,2,3]", ""},
|
169
|
+
{"myfunc(1,2,3)", "1,2,3", "myfunc"},
|
170
|
+
{"myfunc(1,2,3)\n", "1,2,3", "myfunc"},
|
171
|
+
}
|
172
|
+
|
173
|
+
for i, test := range tests {
|
174
|
+
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
|
175
|
+
jsonSrc, jsonpName := cleanJsonp([]byte(test[0]))
|
176
|
+
assertEqual([]byte(test[1]), jsonSrc, t)
|
177
|
+
assertEqual([]byte(test[2]), []byte(jsonpName), t)
|
178
|
+
})
|
179
|
+
}
|
180
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonpretty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sieger
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -47,6 +47,7 @@ extensions: []
|
|
47
47
|
extra_rdoc_files: []
|
48
48
|
files:
|
49
49
|
- ".gitignore"
|
50
|
+
- ".goreleaser.yaml"
|
50
51
|
- CODE_OF_CONDUCT.md
|
51
52
|
- Gemfile
|
52
53
|
- History.txt
|
@@ -55,9 +56,12 @@ files:
|
|
55
56
|
- README.md
|
56
57
|
- Rakefile
|
57
58
|
- exe/jsonpretty
|
59
|
+
- go.mod
|
58
60
|
- jsonpretty.gemspec
|
59
61
|
- lib/jsonpretty.rb
|
60
62
|
- lib/jsonpretty/version.rb
|
63
|
+
- main.go
|
64
|
+
- main_test.go
|
61
65
|
homepage: http://github.com/nicksieger/jsonpretty
|
62
66
|
licenses:
|
63
67
|
- MIT
|