jsonpretty 1.0.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.goreleaser.yaml +30 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/History.txt +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +45 -0
- data/Rakefile +1 -25
- data/{bin → exe}/jsonpretty +0 -0
- data/go.mod +3 -0
- data/jsonpretty.gemspec +28 -0
- data/lib/jsonpretty/version.rb +3 -0
- data/lib/jsonpretty.rb +14 -4
- data/main.go +199 -0
- data/main_test.go +180 -0
- metadata +66 -49
- data/README.txt +0 -54
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 89641014acab0632260843ff87e190604e7342d386109dfa77245ec343ff1ee4
|
4
|
+
data.tar.gz: 7fe4a6155fed431b9c64735fa3a8c133354c293a60d9a03c5786a15f3e31348d
|
5
|
+
SHA512:
|
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/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at nick@nicksieger.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/History.txt
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
=== 1.2.0 / 2021-12-30
|
2
|
+
|
3
|
+
* New version to correspond with go port
|
4
|
+
|
5
|
+
=== 1.1.2 / 2021-12-27
|
6
|
+
|
7
|
+
* Fix regex typo, thanks Sami Samhuri
|
8
|
+
|
9
|
+
=== 1.1.1 / 2021-12-17
|
10
|
+
|
11
|
+
* Handles any HTTP version
|
12
|
+
|
13
|
+
=== 1.1.0 / 2010-01-20
|
14
|
+
|
15
|
+
* Parses and displays jsonp–flavored json
|
16
|
+
|
1
17
|
=== 1.0.0 / 2009-02-20
|
2
18
|
|
3
19
|
* 1 major enhancement
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2007-2021 Nick Sieger <nick@nicksieger.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# jsonpretty
|
2
|
+
|
3
|
+
- http://github.com/nicksieger/jsonpretty
|
4
|
+
|
5
|
+
## DESCRIPTION
|
6
|
+
|
7
|
+
Command-line JSON pretty-printer, using the json gem.
|
8
|
+
|
9
|
+
## FEATURES/PROBLEMS
|
10
|
+
|
11
|
+
- Parse and pretty-print JSON/JSONP either from stdin or from command-line
|
12
|
+
arguments.
|
13
|
+
- All arguments are concatenated together in a single string for
|
14
|
+
pretty-printing.
|
15
|
+
- Use '@filename' as an argument to include the contents of the file.
|
16
|
+
- Use '-' or '@-' as an argument (or use no arguments) to read stdin.
|
17
|
+
- Detects HTTP response/headers, prints them untouched, and skips to
|
18
|
+
the body (for use with `curl -i').
|
19
|
+
|
20
|
+
## SYNOPSIS
|
21
|
+
|
22
|
+
```
|
23
|
+
curl -i http://api.com/json | jsonpretty
|
24
|
+
```
|
25
|
+
|
26
|
+
## REQUIREMENTS
|
27
|
+
|
28
|
+
json or json_pure
|
29
|
+
|
30
|
+
## INSTALL
|
31
|
+
|
32
|
+
```
|
33
|
+
gem install jsonpretty
|
34
|
+
```
|
35
|
+
|
36
|
+
or install globally with brew-gem:
|
37
|
+
|
38
|
+
```
|
39
|
+
brew install brew-gem
|
40
|
+
brew gem install jsonpretty
|
41
|
+
```
|
42
|
+
|
43
|
+
## LICENSE
|
44
|
+
|
45
|
+
See [LICENSE](LICENSE.txt).
|
data/Rakefile
CHANGED
@@ -1,28 +1,4 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'hoe'
|
5
|
-
require './lib/jsonpretty.rb'
|
3
|
+
require "bundler/gem_tasks"
|
6
4
|
|
7
|
-
h = Hoe.new('jsonpretty', Jsonpretty::VERSION) do |p|
|
8
|
-
p.rubyforge_name = 'caldersphere'
|
9
|
-
p.developer('Nick Sieger', 'nick@nicksieger.com')
|
10
|
-
p.url = 'http://github.com/nicksieger/jsonpretty'
|
11
|
-
p.extra_deps << ['json', '> 0'] if ENV["VERSION"]
|
12
|
-
end
|
13
|
-
spec = h.spec
|
14
|
-
spec.dependencies.delete_if { |dep| dep.name == "hoe" }
|
15
|
-
def spec.to_ruby
|
16
|
-
additional_src = %{
|
17
|
-
if defined?(JRUBY_VERSION)
|
18
|
-
s.add_dependency('json_pure', '> 0')
|
19
|
-
else
|
20
|
-
s.add_dependency('json', '> 0')
|
21
|
-
end
|
22
|
-
}
|
23
|
-
super.sub(/end\n\Z/m, "#{additional_src}\nend\n")
|
24
|
-
end
|
25
|
-
|
26
|
-
task :gemspec do
|
27
|
-
File.open("jsonpretty.gemspec", "w") {|f| f << spec.to_ruby }
|
28
|
-
end
|
data/{bin → exe}/jsonpretty
RENAMED
File without changes
|
data/go.mod
ADDED
data/jsonpretty.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "jsonpretty/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "jsonpretty"
|
8
|
+
spec.version = Jsonpretty::VERSION
|
9
|
+
spec.authors = ["Nick Sieger"]
|
10
|
+
spec.email = ["nick@nicksieger.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Command-line JSON pretty-printer, using the json gem.}
|
13
|
+
spec.description = %q{Command-line JSON pretty-printer, using the json gem.}
|
14
|
+
spec.homepage = %q{http://github.com/nicksieger/jsonpretty}
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Specify which files should be added to the gem when it is released.
|
18
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
20
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
|
+
end
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
end
|
data/lib/jsonpretty.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
3
|
class Jsonpretty
|
4
|
-
VERSION = '1.0.0'
|
5
|
-
|
6
4
|
def file_value(filename)
|
7
5
|
file = if filename == '-'
|
8
6
|
$stdin
|
@@ -10,7 +8,7 @@ class Jsonpretty
|
|
10
8
|
File.open(filename)
|
11
9
|
end
|
12
10
|
lines = file.readlines
|
13
|
-
if lines.first =~ /^HTTP
|
11
|
+
if lines.first =~ /^HTTP\/\d/ # looks like an HTTP response; we just want the body
|
14
12
|
index = lines.index("\r\n") || lines.index("\n")
|
15
13
|
puts lines[0..index]
|
16
14
|
lines[(index+1)..-1].join('')
|
@@ -25,6 +23,16 @@ class Jsonpretty
|
|
25
23
|
file_value('-')
|
26
24
|
end
|
27
25
|
|
26
|
+
def clean_jsonp(input_string)
|
27
|
+
match = input_string.match(/^(.+)\((.+)\)$/)
|
28
|
+
if match
|
29
|
+
puts "jsonp method name: #{match[1]}\n\n"
|
30
|
+
match[2]
|
31
|
+
else
|
32
|
+
input_string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
28
36
|
def main
|
29
37
|
if ARGV.length == 0
|
30
38
|
ARGV.unshift stdin_value
|
@@ -48,7 +56,9 @@ class Jsonpretty
|
|
48
56
|
end
|
49
57
|
end
|
50
58
|
|
51
|
-
|
59
|
+
input = clean_jsonp(ARGV.join(' '))
|
60
|
+
json = JSON.parse(input)
|
61
|
+
puts JSON.pretty_generate(json)
|
52
62
|
rescue => e
|
53
63
|
$stderr.puts "jsonpretty failed: #{e.message}"
|
54
64
|
exit 1
|
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,71 +1,88 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonpretty
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
|
-
authors:
|
6
|
+
authors:
|
7
7
|
- Nick Sieger
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
11
|
+
date: 2021-12-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.17'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.17'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
25
41
|
description: Command-line JSON pretty-printer, using the json gem.
|
26
|
-
email:
|
42
|
+
email:
|
27
43
|
- nick@nicksieger.com
|
28
|
-
executables:
|
44
|
+
executables:
|
29
45
|
- jsonpretty
|
30
46
|
extensions: []
|
31
|
-
|
32
|
-
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- ".goreleaser.yaml"
|
51
|
+
- CODE_OF_CONDUCT.md
|
52
|
+
- Gemfile
|
33
53
|
- History.txt
|
54
|
+
- LICENSE.txt
|
34
55
|
- Manifest.txt
|
35
|
-
- README.
|
36
|
-
files:
|
37
|
-
- History.txt
|
38
|
-
- Manifest.txt
|
39
|
-
- README.txt
|
56
|
+
- README.md
|
40
57
|
- Rakefile
|
41
|
-
-
|
58
|
+
- exe/jsonpretty
|
59
|
+
- go.mod
|
60
|
+
- jsonpretty.gemspec
|
42
61
|
- lib/jsonpretty.rb
|
43
|
-
|
62
|
+
- lib/jsonpretty/version.rb
|
63
|
+
- main.go
|
64
|
+
- main_test.go
|
44
65
|
homepage: http://github.com/nicksieger/jsonpretty
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata: {}
|
45
69
|
post_install_message:
|
46
|
-
rdoc_options:
|
47
|
-
|
48
|
-
- README.txt
|
49
|
-
require_paths:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
50
72
|
- lib
|
51
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
53
75
|
- - ">="
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version:
|
56
|
-
|
57
|
-
|
58
|
-
requirements:
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
59
80
|
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
-
version:
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
63
83
|
requirements: []
|
64
|
-
|
65
|
-
rubyforge_project: caldersphere
|
66
|
-
rubygems_version: 1.3.1
|
84
|
+
rubygems_version: 3.0.3.1
|
67
85
|
signing_key:
|
68
|
-
specification_version:
|
86
|
+
specification_version: 4
|
69
87
|
summary: Command-line JSON pretty-printer, using the json gem.
|
70
88
|
test_files: []
|
71
|
-
|
data/README.txt
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
= jsonpretty
|
2
|
-
|
3
|
-
* http://github.com/nicksieger/jsonpretty
|
4
|
-
|
5
|
-
== DESCRIPTION:
|
6
|
-
|
7
|
-
Command-line JSON pretty-printer, using the json gem.
|
8
|
-
|
9
|
-
== FEATURES/PROBLEMS:
|
10
|
-
|
11
|
-
- Parse and pretty-print JSON either from stdin or from command-line
|
12
|
-
arguments.
|
13
|
-
- All arguments are concatenated together in a single string for
|
14
|
-
pretty-printing.
|
15
|
-
- Use '@filename' as an argument to include the contents of the file.
|
16
|
-
- Use '-' or '@-' as an argument (or use no arguments) to read stdin.
|
17
|
-
- Detects HTTP response/headers, prints them untouched, and skips to
|
18
|
-
the body (for use with `curl -i').
|
19
|
-
|
20
|
-
== SYNOPSIS:
|
21
|
-
|
22
|
-
|
23
|
-
== REQUIREMENTS:
|
24
|
-
|
25
|
-
json or json_pure
|
26
|
-
|
27
|
-
== INSTALL:
|
28
|
-
|
29
|
-
gem install jsonpretty
|
30
|
-
|
31
|
-
== LICENSE:
|
32
|
-
|
33
|
-
(The MIT License)
|
34
|
-
|
35
|
-
Copyright (c) 2007-2009 Nick Sieger <nick@nicksieger.com>
|
36
|
-
|
37
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
38
|
-
a copy of this software and associated documentation files (the
|
39
|
-
'Software'), to deal in the Software without restriction, including
|
40
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
41
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
42
|
-
permit persons to whom the Software is furnished to do so, subject to
|
43
|
-
the following conditions:
|
44
|
-
|
45
|
-
The above copyright notice and this permission notice shall be
|
46
|
-
included in all copies or substantial portions of the Software.
|
47
|
-
|
48
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
49
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
50
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
51
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
52
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
53
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
54
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|