Upgrade gjson

This commit is contained in:
tidwall 2021-03-30 07:17:01 -07:00
parent f4b7efeb8c
commit 31a0fbd228
11 changed files with 260 additions and 70 deletions

6
go.mod
View File

@ -1,6 +1,6 @@
module github.com/tidwall/tile38 module github.com/tidwall/tile38
go 1.15 go 1.16
require ( require (
github.com/Shopify/sarama v1.27.2 github.com/Shopify/sarama v1.27.2
@ -17,9 +17,9 @@ require (
github.com/tidwall/buntdb v1.2.0 github.com/tidwall/buntdb v1.2.0
github.com/tidwall/geoindex v1.4.1 github.com/tidwall/geoindex v1.4.1
github.com/tidwall/geojson v1.2.4 github.com/tidwall/geojson v1.2.4
github.com/tidwall/gjson v1.6.8 github.com/tidwall/gjson v1.7.4
github.com/tidwall/match v1.0.3 github.com/tidwall/match v1.0.3
github.com/tidwall/pretty v1.0.2 github.com/tidwall/pretty v1.1.0
github.com/tidwall/redbench v0.1.0 github.com/tidwall/redbench v0.1.0
github.com/tidwall/redcon v1.4.0 github.com/tidwall/redcon v1.4.0
github.com/tidwall/resp v0.1.0 github.com/tidwall/resp v0.1.0

9
go.sum
View File

@ -83,7 +83,6 @@ github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8Bz
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mmcloughlin/geohash v0.10.0 h1:9w1HchfDfdeLc+jFEf/04D27KP7E2QmpDu52wPbJWRE= github.com/mmcloughlin/geohash v0.10.0 h1:9w1HchfDfdeLc+jFEf/04D27KP7E2QmpDu52wPbJWRE=
github.com/mmcloughlin/geohash v0.10.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= github.com/mmcloughlin/geohash v0.10.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c=
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/jwt v1.1.0 h1:+vOlgtM0ZsF46GbmUoadq0/2rChNS45gtxHEa3H1gqM= github.com/nats-io/jwt v1.1.0 h1:+vOlgtM0ZsF46GbmUoadq0/2rChNS45gtxHEa3H1gqM=
github.com/nats-io/jwt v1.1.0/go.mod h1:n3cvmLfBfnpV4JJRN7lRYCyZnw48ksGsbThGXEk4w9M= github.com/nats-io/jwt v1.1.0/go.mod h1:n3cvmLfBfnpV4JJRN7lRYCyZnw48ksGsbThGXEk4w9M=
@ -96,7 +95,6 @@ github.com/nats-io/nkeys v0.1.4 h1:aEsHIssIk6ETN5m2/MD8Y4B2X7FfXrBAUdkyRvbVYzA=
github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/peterh/liner v1.2.1 h1:O4BlKaq/LWu6VRWmol4ByWfzx6MfXc5Op5HETyIy5yg= github.com/peterh/liner v1.2.1 h1:O4BlKaq/LWu6VRWmol4ByWfzx6MfXc5Op5HETyIy5yg=
github.com/peterh/liner v1.2.1/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/peterh/liner v1.2.1/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
@ -128,8 +126,9 @@ github.com/tidwall/geoindex v1.4.1/go.mod h1:NQJQszWCH4+KlD0wY+mgQ2hK/GdSH+9+ZRk
github.com/tidwall/geojson v1.2.4 h1:INKsEJULXKiKSuFQZQ7Vy3v9zchg0VPtcQl2+KeTlvc= github.com/tidwall/geojson v1.2.4 h1:INKsEJULXKiKSuFQZQ7Vy3v9zchg0VPtcQl2+KeTlvc=
github.com/tidwall/geojson v1.2.4/go.mod h1:ZaA93utbJL8CLGaJ5L/M8gV/YC81lvW3ydzo5fI7yp0= github.com/tidwall/geojson v1.2.4/go.mod h1:ZaA93utbJL8CLGaJ5L/M8gV/YC81lvW3ydzo5fI7yp0=
github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
github.com/tidwall/gjson v1.6.8 h1:CTmXMClGYPAmln7652e69B7OLXfTi5ABcPPwjIWUv7w=
github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
github.com/tidwall/gjson v1.7.4 h1:19cchw8FOxkG5mdLRkGf9jqIqEyqdZhPqW60XfyFxk8=
github.com/tidwall/gjson v1.7.4/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
github.com/tidwall/grect v0.1.0 h1:ICcKWD5uu5A5fmxApGIa0QRvfGnSWKRd07POT08CQSA= github.com/tidwall/grect v0.1.0 h1:ICcKWD5uu5A5fmxApGIa0QRvfGnSWKRd07POT08CQSA=
github.com/tidwall/grect v0.1.0/go.mod h1:sa5O42oP6jWfTShL9ka6Sgmg3TgIK649veZe05B7+J8= github.com/tidwall/grect v0.1.0/go.mod h1:sa5O42oP6jWfTShL9ka6Sgmg3TgIK649veZe05B7+J8=
github.com/tidwall/lotsa v1.0.1 h1:w4gpDvI7RdkgbMC0q5ndKqG2ffrwCgerUY/gM2TYkH4= github.com/tidwall/lotsa v1.0.1 h1:w4gpDvI7RdkgbMC0q5ndKqG2ffrwCgerUY/gM2TYkH4=
@ -137,8 +136,9 @@ github.com/tidwall/lotsa v1.0.1/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UM
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/redbench v0.1.0 h1:UZYUMhwMMObQRq5xU4SA3lmlJRztXzqtushDii+AmPo= github.com/tidwall/redbench v0.1.0 h1:UZYUMhwMMObQRq5xU4SA3lmlJRztXzqtushDii+AmPo=
github.com/tidwall/redbench v0.1.0/go.mod h1:zxcRGCq/JcqV48YjK9WxBNJL7JSpMzbLXaHvMcnanKQ= github.com/tidwall/redbench v0.1.0/go.mod h1:zxcRGCq/JcqV48YjK9WxBNJL7JSpMzbLXaHvMcnanKQ=
github.com/tidwall/redcon v1.4.0 h1:y2PmDD55STRdy4S98qP/Dn+gZG+cPVvIDi9BJV2aOwA= github.com/tidwall/redcon v1.4.0 h1:y2PmDD55STRdy4S98qP/Dn+gZG+cPVvIDi9BJV2aOwA=
@ -231,7 +231,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=

View File

@ -14,6 +14,8 @@ It has features such as [one line retrieval](#get-a-value), [dot notation paths]
Also check out [SJSON](https://github.com/tidwall/sjson) for modifying json, and the [JJ](https://github.com/tidwall/jj) command line tool. Also check out [SJSON](https://github.com/tidwall/sjson) for modifying json, and the [JJ](https://github.com/tidwall/jj) command line tool.
For the Rust version go to [gjson.rs](https://github.com/tidwall/gjson.rs).
Getting Started Getting Started
=============== ===============
@ -482,11 +484,3 @@ widget.text.onMouseUp
``` ```
*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.8 and can be found [here](https://github.com/tidwall/gjson-benchmarks).* *These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.8 and can be found [here](https://github.com/tidwall/gjson-benchmarks).*
## Contact
Josh Baker [@tidwall](http://twitter.com/tidwall)
## License
GJSON source code is available under the MIT [License](/LICENSE).

View File

@ -77,14 +77,21 @@ Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`.
fav\.movie "Deer Hunter" fav\.movie "Deer Hunter"
``` ```
You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in source code. You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in you source code.
```go ```go
res := gjson.Get(json, "fav\\.movie") // must escape the slash // Go
res := gjson.Get(json, `fav\.movie`) // no need to escape the slash val := gjson.Get(json, "fav\\.movie") // must escape the slash
val := gjson.Get(json, `fav\.movie`) // no need to escape the slash
``` ```
```rust
// Rust
let val = gjson::get(json, "fav\\.movie") // must escape the slash
let val = gjson::get(json, r#"fav\.movie"#) // no need to escape the slash
```
### Arrays ### Arrays
The `#` character allows for digging into JSON Arrays. The `#` character allows for digging into JSON Arrays.
@ -248,6 +255,8 @@ gjson.AddModifier("case", func(json, arg string) string {
"children.@case:lower.@reverse" ["jack","alex","sara"] "children.@case:lower.@reverse" ["jack","alex","sara"]
``` ```
*Note: Custom modifiers are not yet available in the Rust version*
### Multipaths ### Multipaths
Starting with v1.3.0, GJSON added the ability to join multiple paths together Starting with v1.3.0, GJSON added the ability to join multiple paths together

View File

@ -731,8 +731,13 @@ func parseArrayPath(path string) (r arrayPathResult) {
} }
if path[i] == '.' { if path[i] == '.' {
r.part = path[:i] r.part = path[:i]
if !r.arrch && i < len(path)-1 && isDotPiperChar(path[i+1]) {
r.pipe = path[i+1:]
r.piped = true
} else {
r.path = path[i+1:] r.path = path[i+1:]
r.more = true r.more = true
}
return return
} }
if path[i] == '#' { if path[i] == '#' {
@ -978,6 +983,11 @@ right:
return s return s
} }
// peek at the next byte and see if it's a '@', '[', or '{'.
func isDotPiperChar(c byte) bool {
return !DisableModifiers && (c == '@' || c == '[' || c == '{')
}
type objectPathResult struct { type objectPathResult struct {
part string part string
path string path string
@ -996,12 +1006,8 @@ func parseObjectPath(path string) (r objectPathResult) {
return return
} }
if path[i] == '.' { if path[i] == '.' {
// peek at the next byte and see if it's a '@', '[', or '{'.
r.part = path[:i] r.part = path[:i]
if !DisableModifiers && if i < len(path)-1 && isDotPiperChar(path[i+1]) {
i < len(path)-1 &&
(path[i+1] == '@' ||
path[i+1] == '[' || path[i+1] == '{') {
r.pipe = path[i+1:] r.pipe = path[i+1:]
r.piped = true r.piped = true
} else { } else {
@ -1031,14 +1037,11 @@ func parseObjectPath(path string) (r objectPathResult) {
continue continue
} else if path[i] == '.' { } else if path[i] == '.' {
r.part = string(epart) r.part = string(epart)
// peek at the next byte and see if it's a '@' modifier if i < len(path)-1 && isDotPiperChar(path[i+1]) {
if !DisableModifiers &&
i < len(path)-1 && path[i+1] == '@' {
r.pipe = path[i+1:] r.pipe = path[i+1:]
r.piped = true r.piped = true
} else { } else {
r.path = path[i+1:] r.path = path[i+1:]
r.more = true
} }
r.more = true r.more = true
return return
@ -1403,7 +1406,6 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
} }
return false return false
} }
for i < len(c.json)+1 { for i < len(c.json)+1 {
if !rp.arrch { if !rp.arrch {
pmatch = partidx == h pmatch = partidx == h
@ -1605,11 +1607,18 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
c.calcd = true c.calcd = true
return i + 1, true return i + 1, true
} }
if len(multires) > 0 && !c.value.Exists() { if !c.value.Exists() {
if len(multires) > 0 {
c.value = Result{ c.value = Result{
Raw: string(append(multires, ']')), Raw: string(append(multires, ']')),
Type: JSON, Type: JSON,
} }
} else if rp.query.all {
c.value = Result{
Raw: "[]",
Type: JSON,
}
}
} }
return i + 1, false return i + 1, false
} }
@ -2173,11 +2182,6 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
return i, res, false return i, res, false
} }
var ( // used for testing
testWatchForFallback bool
testLastWasFallback bool
)
// GetMany searches json for the multiple paths. // GetMany searches json for the multiple paths.
// The return value is a Result array where the number of items // The return value is a Result array where the number of items
// will be equal to the number of input paths. // will be equal to the number of input paths.
@ -2378,6 +2382,12 @@ func validnumber(data []byte, i int) (outi int, ok bool) {
// sign // sign
if data[i] == '-' { if data[i] == '-' {
i++ i++
if i == len(data) {
return i, false
}
if data[i] < '0' || data[i] > '9' {
return i, false
}
} }
// int // int
if i == len(data) { if i == len(data) {
@ -2528,7 +2538,10 @@ func parseInt(s string) (n int64, ok bool) {
return n, true return n, true
} }
// safeInt validates a given JSON number
// ensures it lies within the minimum and maximum representable JSON numbers
func safeInt(f float64) (n int64, ok bool) { func safeInt(f float64) (n int64, ok bool) {
// https://tc39.es/ecma262/#sec-number.min_safe_integer || https://tc39.es/ecma262/#sec-number.max_safe_integer
if f < -9007199254740991 || f > 9007199254740991 { if f < -9007199254740991 || f > 9007199254740991 {
return 0, false return 0, false
} }
@ -2739,19 +2752,24 @@ func modFlatten(json, arg string) string {
out = append(out, '[') out = append(out, '[')
var idx int var idx int
res.ForEach(func(_, value Result) bool { res.ForEach(func(_, value Result) bool {
var raw string
if value.IsArray() {
if deep {
raw = unwrap(modFlatten(value.Raw, arg))
} else {
raw = unwrap(value.Raw)
}
} else {
raw = value.Raw
}
raw = strings.TrimSpace(raw)
if len(raw) > 0 {
if idx > 0 { if idx > 0 {
out = append(out, ',') out = append(out, ',')
} }
if value.IsArray() { out = append(out, raw...)
if deep {
out = append(out, unwrap(modFlatten(value.Raw, arg))...)
} else {
out = append(out, unwrap(value.Raw)...)
}
} else {
out = append(out, value.Raw...)
}
idx++ idx++
}
return true return true
}) })
out = append(out, ']') out = append(out, ']')

View File

@ -4,5 +4,5 @@ go 1.12
require ( require (
github.com/tidwall/match v1.0.3 github.com/tidwall/match v1.0.3
github.com/tidwall/pretty v1.0.2 github.com/tidwall/pretty v1.1.0
) )

View File

@ -1,6 +1,4 @@
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=

View File

@ -1 +0,0 @@
language: go

View File

@ -1,8 +1,6 @@
# Pretty # Pretty
[![Build Status](https://img.shields.io/travis/tidwall/pretty.svg?style=flat-square)](https://travis-ci.org/tidwall/prettty)
[![Coverage Status](https://img.shields.io/badge/coverage-100%25-brightgreen.svg?style=flat-square)](http://gocover.io/github.com/tidwall/pretty)
[![GoDoc](https://img.shields.io/badge/api-reference-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/tidwall/pretty)
[![GoDoc](https://img.shields.io/badge/api-reference-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/tidwall/pretty)
Pretty is a Go package that provides [fast](#performance) methods for formatting JSON for human readability, or to compact JSON for smaller payloads. Pretty is a Go package that provides [fast](#performance) methods for formatting JSON for human readability, or to compact JSON for smaller payloads.
@ -81,6 +79,45 @@ Will format the json to:
{"name":{"first":"Tom","last":"Anderson"},"age":37,"children":["Sara","Alex","Jack"],"fav.movie":"Deer Hunter","friends":[{"first":"Janet","last":"Murphy","age":44}]}``` {"name":{"first":"Tom","last":"Anderson"},"age":37,"children":["Sara","Alex","Jack"],"fav.movie":"Deer Hunter","friends":[{"first":"Janet","last":"Murphy","age":44}]}```
``` ```
## Spec
Spec cleans comments and trailing commas from input JSON, converting it to
valid JSON per the official spec: https://tools.ietf.org/html/rfc8259
The resulting JSON will always be the same length as the input and it will
include all of the same line breaks at matching offsets. This is to ensure
the result can be later processed by a external parser and that that
parser will report messages or errors with the correct offsets.
The following example uses a JSON document that has comments and trailing
commas and converts it prior to unmarshalling to using the standard Go
JSON library.
```go
data := `
{
/* Dev Machine */
"dbInfo": {
"host": "localhost",
"port": 5432, // use full email address
"username": "josh",
"password": "pass123", // use a hashed password
}
/* Only SMTP Allowed */
"emailInfo": {
"email": "josh@example.com",
"password": "pass123",
"smtp": "smpt.example.com",
}
}
`
err := json.Unmarshal(pretty.Spec(data), &config)
```
## Customized output ## Customized output

View File

@ -118,21 +118,27 @@ type pair struct {
vstart, vend int vstart, vend int
} }
type byKey struct { type byKeyVal struct {
sorted bool sorted bool
json []byte json []byte
pairs []pair pairs []pair
} }
func (arr *byKey) Len() int { func (arr *byKeyVal) Len() int {
return len(arr.pairs) return len(arr.pairs)
} }
func (arr *byKey) Less(i, j int) bool { func (arr *byKeyVal) Less(i, j int) bool {
key1 := arr.json[arr.pairs[i].kstart+1 : arr.pairs[i].kend-1] key1 := arr.json[arr.pairs[i].kstart+1 : arr.pairs[i].kend-1]
key2 := arr.json[arr.pairs[j].kstart+1 : arr.pairs[j].kend-1] key2 := arr.json[arr.pairs[j].kstart+1 : arr.pairs[j].kend-1]
return string(key1) < string(key2) if string(key1) < string(key2) {
return true
}
if string(key1) > string(key2) {
return false
}
return arr.pairs[i].vstart < arr.pairs[j].vstart
} }
func (arr *byKey) Swap(i, j int) { func (arr *byKeyVal) Swap(i, j int) {
arr.pairs[i], arr.pairs[j] = arr.pairs[j], arr.pairs[i] arr.pairs[i], arr.pairs[j] = arr.pairs[j], arr.pairs[i]
arr.sorted = true arr.sorted = true
} }
@ -174,8 +180,12 @@ func appendPrettyObject(buf, json []byte, i int, open, close byte, pretty bool,
} }
if n > 0 { if n > 0 {
nl = len(buf) nl = len(buf)
if buf[nl-1] == ' ' {
buf[nl-1] = '\n'
} else {
buf = append(buf, '\n') buf = append(buf, '\n')
} }
}
if buf[len(buf)-1] != open { if buf[len(buf)-1] != open {
buf = appendTabs(buf, prefix, indent, tabs) buf = appendTabs(buf, prefix, indent, tabs)
} }
@ -193,7 +203,11 @@ func appendPrettyObject(buf, json []byte, i int, open, close byte, pretty bool,
var p pair var p pair
if pretty { if pretty {
nl = len(buf) nl = len(buf)
if buf[nl-1] == ' ' {
buf[nl-1] = '\n'
} else {
buf = append(buf, '\n') buf = append(buf, '\n')
}
if open == '{' && sortkeys { if open == '{' && sortkeys {
p.kstart = i p.kstart = i
p.vstart = len(buf) p.vstart = len(buf)
@ -235,8 +249,8 @@ func sortPairs(json, buf []byte, pairs []pair) []byte {
} }
vstart := pairs[0].vstart vstart := pairs[0].vstart
vend := pairs[len(pairs)-1].vend vend := pairs[len(pairs)-1].vend
arr := byKey{false, json, pairs} arr := byKeyVal{false, json, pairs}
sort.Sort(&arr) sort.Stable(&arr)
if !arr.sorted { if !arr.sorted {
return buf return buf
} }
@ -305,6 +319,7 @@ func appendTabs(buf []byte, prefix, indent string, tabs int) []byte {
type Style struct { type Style struct {
Key, String, Number [2]string Key, String, Number [2]string
True, False, Null [2]string True, False, Null [2]string
Escape [2]string
Append func(dst []byte, c byte) []byte Append func(dst []byte, c byte) []byte
} }
@ -328,6 +343,7 @@ func init() {
True: [2]string{"\x1B[96m", "\x1B[0m"}, True: [2]string{"\x1B[96m", "\x1B[0m"},
False: [2]string{"\x1B[96m", "\x1B[0m"}, False: [2]string{"\x1B[96m", "\x1B[0m"},
Null: [2]string{"\x1B[91m", "\x1B[0m"}, Null: [2]string{"\x1B[91m", "\x1B[0m"},
Escape: [2]string{"\x1B[35m", "\x1B[0m"},
Append: func(dst []byte, c byte) []byte { Append: func(dst []byte, c byte) []byte {
if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') { if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') {
dst = append(dst, "\\u00"...) dst = append(dst, "\\u00"...)
@ -367,8 +383,39 @@ func Color(src []byte, style *Style) []byte {
dst = append(dst, style.String[0]...) dst = append(dst, style.String[0]...)
} }
dst = apnd(dst, '"') dst = apnd(dst, '"')
esc := false
uesc := 0
for i = i + 1; i < len(src); i++ { for i = i + 1; i < len(src); i++ {
if src[i] == '\\' {
if key {
dst = append(dst, style.Key[1]...)
} else {
dst = append(dst, style.String[1]...)
}
dst = append(dst, style.Escape[0]...)
dst = apnd(dst, src[i]) dst = apnd(dst, src[i])
esc = true
if i+1 < len(src) && src[i+1] == 'u' {
uesc = 5
} else {
uesc = 1
}
} else if esc {
dst = apnd(dst, src[i])
if uesc == 1 {
esc = false
dst = append(dst, style.Escape[1]...)
if key {
dst = append(dst, style.Key[0]...)
} else {
dst = append(dst, style.String[0]...)
}
} else {
uesc--
}
} else {
dst = apnd(dst, src[i])
}
if src[i] == '"' { if src[i] == '"' {
j := i - 1 j := i - 1
for ; ; j-- { for ; ; j-- {
@ -381,7 +428,9 @@ func Color(src []byte, style *Style) []byte {
} }
} }
} }
if key { if esc {
dst = append(dst, style.Escape[1]...)
} else if key {
dst = append(dst, style.Key[1]...) dst = append(dst, style.Key[1]...)
} else { } else {
dst = append(dst, style.String[1]...) dst = append(dst, style.String[1]...)
@ -434,3 +483,90 @@ func Color(src []byte, style *Style) []byte {
} }
return dst return dst
} }
// Spec strips out comments and trailing commas and convert the input to a
// valid JSON per the official spec: https://tools.ietf.org/html/rfc8259
//
// The resulting JSON will always be the same length as the input and it will
// include all of the same line breaks at matching offsets. This is to ensure
// the result can be later processed by a external parser and that that
// parser will report messages or errors with the correct offsets.
func Spec(src []byte) []byte {
return spec(src, nil)
}
// SpecInPlace is the same as Spec, but this method reuses the input json
// buffer to avoid allocations. Do not use the original bytes slice upon return.
func SpecInPlace(src []byte) []byte {
return spec(src, src)
}
func spec(src, dst []byte) []byte {
dst = dst[:0]
for i := 0; i < len(src); i++ {
if src[i] == '/' {
if i < len(src)-1 {
if src[i+1] == '/' {
dst = append(dst, ' ', ' ')
i += 2
for ; i < len(src); i++ {
if src[i] == '\n' {
dst = append(dst, '\n')
break
} else if src[i] == '\t' || src[i] == '\r' {
dst = append(dst, src[i])
} else {
dst = append(dst, ' ')
}
}
continue
}
if src[i+1] == '*' {
dst = append(dst, ' ', ' ')
i += 2
for ; i < len(src)-1; i++ {
if src[i] == '*' && src[i+1] == '/' {
dst = append(dst, ' ', ' ')
i++
break
} else if src[i] == '\n' || src[i] == '\t' ||
src[i] == '\r' {
dst = append(dst, src[i])
} else {
dst = append(dst, ' ')
}
}
continue
}
}
}
dst = append(dst, src[i])
if src[i] == '"' {
for i = i + 1; i < len(src); i++ {
dst = append(dst, src[i])
if src[i] == '"' {
j := i - 1
for ; ; j-- {
if src[j] != '\\' {
break
}
}
if (j-i)%2 != 0 {
break
}
}
}
} else if src[i] == '}' || src[i] == ']' {
for j := len(dst) - 2; j >= 0; j-- {
if dst[j] <= ' ' {
continue
}
if dst[j] == ',' {
dst[j] = ' '
}
break
}
}
}
return dst
}

4
vendor/modules.txt vendored
View File

@ -132,7 +132,7 @@ github.com/tidwall/geoindex/child
github.com/tidwall/geojson github.com/tidwall/geojson
github.com/tidwall/geojson/geo github.com/tidwall/geojson/geo
github.com/tidwall/geojson/geometry github.com/tidwall/geojson/geometry
# github.com/tidwall/gjson v1.6.8 # github.com/tidwall/gjson v1.7.4
## explicit ## explicit
github.com/tidwall/gjson github.com/tidwall/gjson
# github.com/tidwall/grect v0.1.0 # github.com/tidwall/grect v0.1.0
@ -142,7 +142,7 @@ github.com/tidwall/lotsa
# github.com/tidwall/match v1.0.3 # github.com/tidwall/match v1.0.3
## explicit ## explicit
github.com/tidwall/match github.com/tidwall/match
# github.com/tidwall/pretty v1.0.2 # github.com/tidwall/pretty v1.1.0
## explicit ## explicit
github.com/tidwall/pretty github.com/tidwall/pretty
# github.com/tidwall/redbench v0.1.0 # github.com/tidwall/redbench v0.1.0