mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 21:04:37 +03:00
Upgrade to go 1.19 and update dependencies (#3069)
* Update to go 1.19 * Update dependencies * Update cross-compile script * Add missing targets to cross-compile-all * Update cache action to remove warning
This commit is contained in:
32
vendor/github.com/tidwall/gjson/README.md
generated
vendored
32
vendor/github.com/tidwall/gjson/README.md
generated
vendored
@@ -4,7 +4,9 @@
|
||||
width="240" height="78" border="0" alt="GJSON">
|
||||
<br>
|
||||
<a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
|
||||
<a href="http://tidwall.com/gjson-play"><img src="https://img.shields.io/badge/%F0%9F%8F%90-playground-9900cc.svg?style=flat-square" alt="GJSON Playground"></a>
|
||||
<a href="https://tidwall.com/gjson-play"><img src="https://img.shields.io/badge/%F0%9F%8F%90-playground-9900cc.svg?style=flat-square" alt="GJSON Playground"></a>
|
||||
<a href="SYNTAX.md"><img src="https://img.shields.io/badge/{}-syntax-33aa33.svg?style=flat-square" alt="GJSON Syntax"></a>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">get json values quickly</a></p>
|
||||
@@ -14,6 +16,10 @@ 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.
|
||||
|
||||
This README is a quick overview of how to use GJSON, for more information check out [GJSON Syntax](SYNTAX.md).
|
||||
|
||||
GJSON is also available for [Python](https://github.com/volans-/gjson-py) and [Rust](https://github.com/tidwall/gjson.rs)
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
@@ -200,6 +206,11 @@ There are currently the following built-in modifiers:
|
||||
- `@valid`: Ensure the json document is valid.
|
||||
- `@flatten`: Flattens an array.
|
||||
- `@join`: Joins multiple objects into a single object.
|
||||
- `@keys`: Returns an array of keys for an object.
|
||||
- `@values`: Returns an array of values for an object.
|
||||
- `@tostr`: Converts json to a string. Wraps a json string.
|
||||
- `@fromstr`: Converts a string from json. Unwraps a json string.
|
||||
- `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db).
|
||||
|
||||
### Modifier arguments
|
||||
|
||||
@@ -434,14 +445,15 @@ Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/js
|
||||
and [json-iterator](https://github.com/json-iterator/go)
|
||||
|
||||
```
|
||||
BenchmarkGJSONGet-8 3000000 372 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGJSONUnmarshalMap-8 900000 4154 ns/op 1920 B/op 26 allocs/op
|
||||
BenchmarkJSONUnmarshalMap-8 600000 9019 ns/op 3048 B/op 69 allocs/op
|
||||
BenchmarkJSONDecoder-8 300000 14120 ns/op 4224 B/op 184 allocs/op
|
||||
BenchmarkFFJSONLexer-8 1500000 3111 ns/op 896 B/op 8 allocs/op
|
||||
BenchmarkEasyJSONLexer-8 3000000 887 ns/op 613 B/op 6 allocs/op
|
||||
BenchmarkJSONParserGet-8 3000000 499 ns/op 21 B/op 0 allocs/op
|
||||
BenchmarkJSONIterator-8 3000000 812 ns/op 544 B/op 9 allocs/op
|
||||
BenchmarkGJSONGet-16 11644512 311 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGJSONUnmarshalMap-16 1122678 3094 ns/op 1920 B/op 26 allocs/op
|
||||
BenchmarkJSONUnmarshalMap-16 516681 6810 ns/op 2944 B/op 69 allocs/op
|
||||
BenchmarkJSONUnmarshalStruct-16 697053 5400 ns/op 928 B/op 13 allocs/op
|
||||
BenchmarkJSONDecoder-16 330450 10217 ns/op 3845 B/op 160 allocs/op
|
||||
BenchmarkFFJSONLexer-16 1424979 2585 ns/op 880 B/op 8 allocs/op
|
||||
BenchmarkEasyJSONLexer-16 3000000 729 ns/op 501 B/op 5 allocs/op
|
||||
BenchmarkJSONParserGet-16 3000000 366 ns/op 21 B/op 0 allocs/op
|
||||
BenchmarkJSONIterator-16 3000000 869 ns/op 693 B/op 14 allocs/op
|
||||
```
|
||||
|
||||
JSON document used:
|
||||
@@ -482,4 +494,4 @@ widget.image.hOffset
|
||||
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 16" 2.4 GHz Intel Core i9 using Go 1.17 and can be found [here](https://github.com/tidwall/gjson-benchmarks).*
|
||||
|
||||
35
vendor/github.com/tidwall/gjson/SYNTAX.md
generated
vendored
35
vendor/github.com/tidwall/gjson/SYNTAX.md
generated
vendored
@@ -13,16 +13,16 @@ This document is designed to explain the structure of a GJSON Path through examp
|
||||
- [Dot vs Pipe](#dot-vs-pipe)
|
||||
- [Modifiers](#modifiers)
|
||||
- [Multipaths](#multipaths)
|
||||
- [Literals](#literals)
|
||||
|
||||
The definitive implemenation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson).
|
||||
Use the [GJSON Playground](https://gjson.dev) to experiment with the syntax online.
|
||||
|
||||
|
||||
## Path structure
|
||||
|
||||
A GJSON Path is intended to be easily expressed as a series of components seperated by a `.` character.
|
||||
|
||||
Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, and `?`.
|
||||
Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, `!`, and `?`.
|
||||
|
||||
## Example
|
||||
|
||||
@@ -77,7 +77,7 @@ Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`.
|
||||
fav\.movie "Deer Hunter"
|
||||
```
|
||||
|
||||
You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in you source code.
|
||||
You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in your source code.
|
||||
|
||||
```go
|
||||
// Go
|
||||
@@ -236,6 +236,11 @@ There are currently the following built-in modifiers:
|
||||
- `@valid`: Ensure the json document is valid.
|
||||
- `@flatten`: Flattens an array.
|
||||
- `@join`: Joins multiple objects into a single object.
|
||||
- `@keys`: Returns an array of keys for an object.
|
||||
- `@values`: Returns an array of values for an object.
|
||||
- `@tostr`: Converts json to a string. Wraps a json string.
|
||||
- `@fromstr`: Converts a string from json. Unwraps a json string.
|
||||
- `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db).
|
||||
|
||||
#### Modifier arguments
|
||||
|
||||
@@ -294,7 +299,7 @@ Starting with v1.3.0, GJSON added the ability to join multiple paths together
|
||||
to form new documents. Wrapping comma-separated paths between `[...]` or
|
||||
`{...}` will result in a new array or object, respectively.
|
||||
|
||||
For example, using the given multipath
|
||||
For example, using the given multipath:
|
||||
|
||||
```
|
||||
{name.first,age,"the_murphys":friends.#(last="Murphy")#.first}
|
||||
@@ -310,8 +315,28 @@ determined, then "_" is used.
|
||||
|
||||
This results in
|
||||
|
||||
```
|
||||
```json
|
||||
{"first":"Tom","age":37,"the_murphys":["Dale","Jane"]}
|
||||
```
|
||||
|
||||
### Literals
|
||||
|
||||
Starting with v1.12.0, GJSON added support of json literals, which provides a way for constructing static blocks of json. This is can be particularly useful when constructing a new json document using [multipaths](#multipaths).
|
||||
|
||||
A json literal begins with the '!' declaration character.
|
||||
|
||||
For example, using the given multipath:
|
||||
|
||||
```
|
||||
{name.first,age,"company":!"Happysoft","employed":!true}
|
||||
```
|
||||
|
||||
Here we selected the first name and age. Then add two new fields, "company" and "employed".
|
||||
|
||||
This results in
|
||||
|
||||
```json
|
||||
{"first":"Tom","age":37,"company":"Happysoft","employed":true}
|
||||
```
|
||||
|
||||
*See issue [#249](https://github.com/tidwall/gjson/issues/249) for additional context on JSON Literals.*
|
||||
|
||||
687
vendor/github.com/tidwall/gjson/gjson.go
generated
vendored
687
vendor/github.com/tidwall/gjson/gjson.go
generated
vendored
@@ -2,7 +2,6 @@
|
||||
package gjson
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -189,14 +188,15 @@ func (t Result) Time() time.Time {
|
||||
}
|
||||
|
||||
// Array returns back an array of values.
|
||||
// If the result represents a non-existent value, then an empty array will be
|
||||
// returned. If the result is not a JSON array, the return value will be an
|
||||
// If the result represents a null value or is non-existent, then an empty
|
||||
// array will be returned.
|
||||
// If the result is not a JSON array, the return value will be an
|
||||
// array containing one result.
|
||||
func (t Result) Array() []Result {
|
||||
if t.Type == Null {
|
||||
return []Result{}
|
||||
}
|
||||
if t.Type != JSON {
|
||||
if !t.IsArray() {
|
||||
return []Result{t}
|
||||
}
|
||||
r := t.arrayOrMap('[', false)
|
||||
@@ -213,6 +213,11 @@ func (t Result) IsArray() bool {
|
||||
return t.Type == JSON && len(t.Raw) > 0 && t.Raw[0] == '['
|
||||
}
|
||||
|
||||
// IsBool returns true if the result value is a JSON boolean.
|
||||
func (t Result) IsBool() bool {
|
||||
return t.Type == True || t.Type == False
|
||||
}
|
||||
|
||||
// ForEach iterates through values.
|
||||
// If the result represents a non-existent value, then no values will be
|
||||
// iterated. If the result is an Object, the iterator will pass the key and
|
||||
@@ -228,17 +233,19 @@ func (t Result) ForEach(iterator func(key, value Result) bool) {
|
||||
return
|
||||
}
|
||||
json := t.Raw
|
||||
var keys bool
|
||||
var obj bool
|
||||
var i int
|
||||
var key, value Result
|
||||
for ; i < len(json); i++ {
|
||||
if json[i] == '{' {
|
||||
i++
|
||||
key.Type = String
|
||||
keys = true
|
||||
obj = true
|
||||
break
|
||||
} else if json[i] == '[' {
|
||||
i++
|
||||
key.Type = Number
|
||||
key.Num = -1
|
||||
break
|
||||
}
|
||||
if json[i] > ' ' {
|
||||
@@ -248,8 +255,9 @@ func (t Result) ForEach(iterator func(key, value Result) bool) {
|
||||
var str string
|
||||
var vesc bool
|
||||
var ok bool
|
||||
var idx int
|
||||
for ; i < len(json); i++ {
|
||||
if keys {
|
||||
if obj {
|
||||
if json[i] != '"' {
|
||||
continue
|
||||
}
|
||||
@@ -264,7 +272,9 @@ func (t Result) ForEach(iterator func(key, value Result) bool) {
|
||||
key.Str = str[1 : len(str)-1]
|
||||
}
|
||||
key.Raw = str
|
||||
key.Index = s
|
||||
key.Index = s + t.Index
|
||||
} else {
|
||||
key.Num += 1
|
||||
}
|
||||
for ; i < len(json); i++ {
|
||||
if json[i] <= ' ' || json[i] == ',' || json[i] == ':' {
|
||||
@@ -277,10 +287,17 @@ func (t Result) ForEach(iterator func(key, value Result) bool) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
value.Index = s
|
||||
if t.Indexes != nil {
|
||||
if idx < len(t.Indexes) {
|
||||
value.Index = t.Indexes[idx]
|
||||
}
|
||||
} else {
|
||||
value.Index = s + t.Index
|
||||
}
|
||||
if !iterator(key, value) {
|
||||
return
|
||||
}
|
||||
idx++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +314,15 @@ func (t Result) Map() map[string]Result {
|
||||
// Get searches result for the specified path.
|
||||
// The result should be a JSON array or object.
|
||||
func (t Result) Get(path string) Result {
|
||||
return Get(t.Raw, path)
|
||||
r := Get(t.Raw, path)
|
||||
if r.Indexes != nil {
|
||||
for i := 0; i < len(r.Indexes); i++ {
|
||||
r.Indexes[i] += t.Index
|
||||
}
|
||||
} else {
|
||||
r.Index += t.Index
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
type arrayOrMapResult struct {
|
||||
@@ -388,6 +413,8 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
|
||||
value.Raw, value.Str = tostr(json[i:])
|
||||
value.Num = 0
|
||||
}
|
||||
value.Index = i + t.Index
|
||||
|
||||
i += len(value.Raw) - 1
|
||||
|
||||
if r.vc == '{' {
|
||||
@@ -414,6 +441,17 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
|
||||
}
|
||||
}
|
||||
end:
|
||||
if t.Indexes != nil {
|
||||
if len(t.Indexes) != len(r.a) {
|
||||
for i := 0; i < len(r.a); i++ {
|
||||
r.a[i].Index = 0
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(r.a); i++ {
|
||||
r.a[i].Index = t.Indexes[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -425,7 +463,8 @@ end:
|
||||
// use the Valid function first.
|
||||
func Parse(json string) Result {
|
||||
var value Result
|
||||
for i := 0; i < len(json); i++ {
|
||||
i := 0
|
||||
for ; i < len(json); i++ {
|
||||
if json[i] == '{' || json[i] == '[' {
|
||||
value.Type = JSON
|
||||
value.Raw = json[i:] // just take the entire raw
|
||||
@@ -435,16 +474,20 @@ func Parse(json string) Result {
|
||||
continue
|
||||
}
|
||||
switch json[i] {
|
||||
default:
|
||||
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
|
||||
case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'i', 'I', 'N':
|
||||
value.Type = Number
|
||||
value.Raw, value.Num = tonum(json[i:])
|
||||
case 'n':
|
||||
if i+1 < len(json) && json[i+1] != 'u' {
|
||||
// nan
|
||||
value.Type = Number
|
||||
value.Raw, value.Num = tonum(json[i:])
|
||||
} else {
|
||||
return Result{}
|
||||
// null
|
||||
value.Type = Null
|
||||
value.Raw = tolit(json[i:])
|
||||
}
|
||||
case 'n':
|
||||
value.Type = Null
|
||||
value.Raw = tolit(json[i:])
|
||||
case 't':
|
||||
value.Type = True
|
||||
value.Raw = tolit(json[i:])
|
||||
@@ -454,9 +497,14 @@ func Parse(json string) Result {
|
||||
case '"':
|
||||
value.Type = String
|
||||
value.Raw, value.Str = tostr(json[i:])
|
||||
default:
|
||||
return Result{}
|
||||
}
|
||||
break
|
||||
}
|
||||
if value.Exists() {
|
||||
value.Index = i
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -530,20 +578,12 @@ func tonum(json string) (raw string, num float64) {
|
||||
return
|
||||
}
|
||||
// could be a '+' or '-'. let's assume so.
|
||||
continue
|
||||
} else if json[i] == ']' || json[i] == '}' {
|
||||
// break on ']' or '}'
|
||||
raw = json[:i]
|
||||
num, _ = strconv.ParseFloat(raw, 64)
|
||||
return
|
||||
}
|
||||
if json[i] < ']' {
|
||||
// probably a valid number
|
||||
continue
|
||||
}
|
||||
if json[i] == 'e' || json[i] == 'E' {
|
||||
// allow for exponential numbers
|
||||
continue
|
||||
}
|
||||
// likely a ']' or '}'
|
||||
raw = json[:i]
|
||||
num, _ = strconv.ParseFloat(raw, 64)
|
||||
return
|
||||
}
|
||||
raw = json
|
||||
num, _ = strconv.ParseFloat(raw, 64)
|
||||
@@ -735,7 +775,7 @@ func parseArrayPath(path string) (r arrayPathResult) {
|
||||
}
|
||||
if path[i] == '.' {
|
||||
r.part = path[:i]
|
||||
if !r.arrch && i < len(path)-1 && isDotPiperChar(path[i+1]) {
|
||||
if !r.arrch && i < len(path)-1 && isDotPiperChar(path[i+1:]) {
|
||||
r.pipe = path[i+1:]
|
||||
r.piped = true
|
||||
} else {
|
||||
@@ -760,7 +800,7 @@ func parseArrayPath(path string) (r arrayPathResult) {
|
||||
// bad query, end now
|
||||
break
|
||||
}
|
||||
if len(value) > 2 && value[0] == '"' &&
|
||||
if len(value) >= 2 && value[0] == '"' &&
|
||||
value[len(value)-1] == '"' {
|
||||
value = value[1 : len(value)-1]
|
||||
if vesc {
|
||||
@@ -896,8 +936,23 @@ right:
|
||||
}
|
||||
|
||||
// peek at the next byte and see if it's a '@', '[', or '{'.
|
||||
func isDotPiperChar(c byte) bool {
|
||||
return !DisableModifiers && (c == '@' || c == '[' || c == '{')
|
||||
func isDotPiperChar(s string) bool {
|
||||
if DisableModifiers {
|
||||
return false
|
||||
}
|
||||
c := s[0]
|
||||
if c == '@' {
|
||||
// check that the next component is *not* a modifier.
|
||||
i := 1
|
||||
for ; i < len(s); i++ {
|
||||
if s[i] == '.' || s[i] == '|' || s[i] == ':' {
|
||||
break
|
||||
}
|
||||
}
|
||||
_, ok := modifiers[s[1:i]]
|
||||
return ok
|
||||
}
|
||||
return c == '[' || c == '{'
|
||||
}
|
||||
|
||||
type objectPathResult struct {
|
||||
@@ -919,7 +974,7 @@ func parseObjectPath(path string) (r objectPathResult) {
|
||||
}
|
||||
if path[i] == '.' {
|
||||
r.part = path[:i]
|
||||
if i < len(path)-1 && isDotPiperChar(path[i+1]) {
|
||||
if i < len(path)-1 && isDotPiperChar(path[i+1:]) {
|
||||
r.pipe = path[i+1:]
|
||||
r.piped = true
|
||||
} else {
|
||||
@@ -949,7 +1004,7 @@ func parseObjectPath(path string) (r objectPathResult) {
|
||||
continue
|
||||
} else if path[i] == '.' {
|
||||
r.part = string(epart)
|
||||
if i < len(path)-1 && isDotPiperChar(path[i+1]) {
|
||||
if i < len(path)-1 && isDotPiperChar(path[i+1:]) {
|
||||
r.pipe = path[i+1:]
|
||||
r.piped = true
|
||||
} else {
|
||||
@@ -1102,6 +1157,7 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
|
||||
}
|
||||
hit = pmatch && !rp.more
|
||||
for ; i < len(c.json); i++ {
|
||||
var num bool
|
||||
switch c.json[i] {
|
||||
default:
|
||||
continue
|
||||
@@ -1149,15 +1205,13 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
i, val = parseNumber(c.json, i)
|
||||
if hit {
|
||||
c.value.Raw = val
|
||||
c.value.Type = Number
|
||||
c.value.Num, _ = strconv.ParseFloat(val, 64)
|
||||
return i, true
|
||||
case 'n':
|
||||
if i+1 < len(c.json) && c.json[i+1] != 'u' {
|
||||
num = true
|
||||
break
|
||||
}
|
||||
case 't', 'f', 'n':
|
||||
fallthrough
|
||||
case 't', 'f':
|
||||
vc := c.json[i]
|
||||
i, val = parseLiteral(c.json, i)
|
||||
if hit {
|
||||
@@ -1170,6 +1224,18 @@ func parseObject(c *parseContext, i int, path string) (int, bool) {
|
||||
}
|
||||
return i, true
|
||||
}
|
||||
case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'i', 'I', 'N':
|
||||
num = true
|
||||
}
|
||||
if num {
|
||||
i, val = parseNumber(c.json, i)
|
||||
if hit {
|
||||
c.value.Raw = val
|
||||
c.value.Type = Number
|
||||
c.value.Num, _ = strconv.ParseFloat(val, 64)
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -1357,6 +1423,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||
} else {
|
||||
ch = c.json[i]
|
||||
}
|
||||
var num bool
|
||||
switch ch {
|
||||
default:
|
||||
continue
|
||||
@@ -1439,26 +1506,13 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
i, val = parseNumber(c.json, i)
|
||||
if rp.query.on {
|
||||
var qval Result
|
||||
qval.Raw = val
|
||||
qval.Type = Number
|
||||
qval.Num, _ = strconv.ParseFloat(val, 64)
|
||||
if procQuery(qval) {
|
||||
return i, true
|
||||
}
|
||||
} else if hit {
|
||||
if rp.alogok {
|
||||
break
|
||||
}
|
||||
c.value.Raw = val
|
||||
c.value.Type = Number
|
||||
c.value.Num, _ = strconv.ParseFloat(val, 64)
|
||||
return i, true
|
||||
case 'n':
|
||||
if i+1 < len(c.json) && c.json[i+1] != 'u' {
|
||||
num = true
|
||||
break
|
||||
}
|
||||
case 't', 'f', 'n':
|
||||
fallthrough
|
||||
case 't', 'f':
|
||||
vc := c.json[i]
|
||||
i, val = parseLiteral(c.json, i)
|
||||
if rp.query.on {
|
||||
@@ -1486,6 +1540,9 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||
}
|
||||
return i, true
|
||||
}
|
||||
case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'i', 'I', 'N':
|
||||
num = true
|
||||
case ']':
|
||||
if rp.arrch && rp.part == "#" {
|
||||
if rp.alogok {
|
||||
@@ -1510,7 +1567,6 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||
}
|
||||
if idx < len(c.json) && c.json[idx] != ']' {
|
||||
_, res, ok := parseAny(c.json, idx, true)
|
||||
parentIndex := res.Index
|
||||
if ok {
|
||||
res := res.Get(rp.alogkey)
|
||||
if res.Exists() {
|
||||
@@ -1522,8 +1578,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||
raw = res.String()
|
||||
}
|
||||
jsons = append(jsons, []byte(raw)...)
|
||||
indexes = append(indexes,
|
||||
res.Index+parentIndex)
|
||||
indexes = append(indexes, res.Index)
|
||||
k++
|
||||
}
|
||||
}
|
||||
@@ -1561,6 +1616,26 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||
}
|
||||
return i + 1, false
|
||||
}
|
||||
if num {
|
||||
i, val = parseNumber(c.json, i)
|
||||
if rp.query.on {
|
||||
var qval Result
|
||||
qval.Raw = val
|
||||
qval.Type = Number
|
||||
qval.Num, _ = strconv.ParseFloat(val, 64)
|
||||
if procQuery(qval) {
|
||||
return i, true
|
||||
}
|
||||
} else if hit {
|
||||
if rp.alogok {
|
||||
break
|
||||
}
|
||||
c.value.Raw = val
|
||||
c.value.Type = Number
|
||||
c.value.Num, _ = strconv.ParseFloat(val, 64)
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -1676,7 +1751,7 @@ type subSelector struct {
|
||||
// first character in path is either '[' or '{', and has already been checked
|
||||
// prior to calling this function.
|
||||
func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) {
|
||||
modifer := 0
|
||||
modifier := 0
|
||||
depth := 1
|
||||
colon := 0
|
||||
start := 1
|
||||
@@ -1691,6 +1766,7 @@ func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) {
|
||||
}
|
||||
sels = append(sels, sel)
|
||||
colon = 0
|
||||
modifier = 0
|
||||
start = i + 1
|
||||
}
|
||||
for ; i < len(path); i++ {
|
||||
@@ -1698,11 +1774,11 @@ func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) {
|
||||
case '\\':
|
||||
i++
|
||||
case '@':
|
||||
if modifer == 0 && i > 0 && (path[i-1] == '.' || path[i-1] == '|') {
|
||||
modifer = i
|
||||
if modifier == 0 && i > 0 && (path[i-1] == '.' || path[i-1] == '|') {
|
||||
modifier = i
|
||||
}
|
||||
case ':':
|
||||
if modifer == 0 && colon == 0 && depth == 1 {
|
||||
if modifier == 0 && colon == 0 && depth == 1 {
|
||||
colon = i
|
||||
}
|
||||
case ',':
|
||||
@@ -1755,24 +1831,71 @@ func isSimpleName(component string) bool {
|
||||
return false
|
||||
}
|
||||
switch component[i] {
|
||||
case '[', ']', '{', '}', '(', ')', '#', '|':
|
||||
case '[', ']', '{', '}', '(', ')', '#', '|', '!':
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func appendJSONString(dst []byte, s string) []byte {
|
||||
var hexchars = [...]byte{
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f',
|
||||
}
|
||||
|
||||
func appendHex16(dst []byte, x uint16) []byte {
|
||||
return append(dst,
|
||||
hexchars[x>>12&0xF], hexchars[x>>8&0xF],
|
||||
hexchars[x>>4&0xF], hexchars[x>>0&0xF],
|
||||
)
|
||||
}
|
||||
|
||||
// AppendJSONString is a convenience function that converts the provided string
|
||||
// to a valid JSON string and appends it to dst.
|
||||
func AppendJSONString(dst []byte, s string) []byte {
|
||||
dst = append(dst, make([]byte, len(s)+2)...)
|
||||
dst = append(dst[:len(dst)-len(s)-2], '"')
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] < ' ' || s[i] == '\\' || s[i] == '"' || s[i] > 126 {
|
||||
d, _ := json.Marshal(s)
|
||||
return append(dst, string(d)...)
|
||||
if s[i] < ' ' {
|
||||
dst = append(dst, '\\')
|
||||
switch s[i] {
|
||||
case '\n':
|
||||
dst = append(dst, 'n')
|
||||
case '\r':
|
||||
dst = append(dst, 'r')
|
||||
case '\t':
|
||||
dst = append(dst, 't')
|
||||
default:
|
||||
dst = append(dst, 'u')
|
||||
dst = appendHex16(dst, uint16(s[i]))
|
||||
}
|
||||
} else if s[i] == '>' || s[i] == '<' || s[i] == '&' {
|
||||
dst = append(dst, '\\', 'u')
|
||||
dst = appendHex16(dst, uint16(s[i]))
|
||||
} else if s[i] == '\\' {
|
||||
dst = append(dst, '\\', '\\')
|
||||
} else if s[i] == '"' {
|
||||
dst = append(dst, '\\', '"')
|
||||
} else if s[i] > 127 {
|
||||
// read utf8 character
|
||||
r, n := utf8.DecodeRuneInString(s[i:])
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
if r == utf8.RuneError && n == 1 {
|
||||
dst = append(dst, `\ufffd`...)
|
||||
} else if r == '\u2028' || r == '\u2029' {
|
||||
dst = append(dst, `\u202`...)
|
||||
dst = append(dst, hexchars[r&0xF])
|
||||
} else {
|
||||
dst = append(dst, s[i:i+n]...)
|
||||
}
|
||||
i = i + n - 1
|
||||
} else {
|
||||
dst = append(dst, s[i])
|
||||
}
|
||||
}
|
||||
dst = append(dst, '"')
|
||||
dst = append(dst, s...)
|
||||
dst = append(dst, '"')
|
||||
return dst
|
||||
return append(dst, '"')
|
||||
}
|
||||
|
||||
type parseContext struct {
|
||||
@@ -1819,23 +1942,25 @@ type parseContext struct {
|
||||
// use the Valid function first.
|
||||
func Get(json, path string) Result {
|
||||
if len(path) > 1 {
|
||||
if !DisableModifiers {
|
||||
if path[0] == '@' {
|
||||
// possible modifier
|
||||
var ok bool
|
||||
var npath string
|
||||
var rjson string
|
||||
if (path[0] == '@' && !DisableModifiers) || path[0] == '!' {
|
||||
// possible modifier
|
||||
var ok bool
|
||||
var npath string
|
||||
var rjson string
|
||||
if path[0] == '@' && !DisableModifiers {
|
||||
npath, rjson, ok = execModifier(json, path)
|
||||
if ok {
|
||||
path = npath
|
||||
if len(path) > 0 && (path[0] == '|' || path[0] == '.') {
|
||||
res := Get(rjson, path[1:])
|
||||
res.Index = 0
|
||||
res.Indexes = nil
|
||||
return res
|
||||
}
|
||||
return Parse(rjson)
|
||||
} else if path[0] == '!' {
|
||||
npath, rjson, ok = execStatic(json, path)
|
||||
}
|
||||
if ok {
|
||||
path = npath
|
||||
if len(path) > 0 && (path[0] == '|' || path[0] == '.') {
|
||||
res := Get(rjson, path[1:])
|
||||
res.Index = 0
|
||||
res.Indexes = nil
|
||||
return res
|
||||
}
|
||||
return Parse(rjson)
|
||||
}
|
||||
}
|
||||
if path[0] == '[' || path[0] == '{' {
|
||||
@@ -1860,14 +1985,14 @@ func Get(json, path string) Result {
|
||||
if sub.name[0] == '"' && Valid(sub.name) {
|
||||
b = append(b, sub.name...)
|
||||
} else {
|
||||
b = appendJSONString(b, sub.name)
|
||||
b = AppendJSONString(b, sub.name)
|
||||
}
|
||||
} else {
|
||||
last := nameOfLast(sub.path)
|
||||
if isSimpleName(last) {
|
||||
b = appendJSONString(b, last)
|
||||
b = AppendJSONString(b, last)
|
||||
} else {
|
||||
b = appendJSONString(b, "_")
|
||||
b = AppendJSONString(b, "_")
|
||||
}
|
||||
}
|
||||
b = append(b, ':')
|
||||
@@ -2080,6 +2205,7 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
|
||||
if json[i] <= ' ' {
|
||||
continue
|
||||
}
|
||||
var num bool
|
||||
switch json[i] {
|
||||
case '"':
|
||||
i++
|
||||
@@ -2099,15 +2225,13 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
|
||||
}
|
||||
}
|
||||
return i, res, true
|
||||
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
i, val = parseNumber(json, i)
|
||||
if hit {
|
||||
res.Raw = val
|
||||
res.Type = Number
|
||||
res.Num, _ = strconv.ParseFloat(val, 64)
|
||||
case 'n':
|
||||
if i+1 < len(json) && json[i+1] != 'u' {
|
||||
num = true
|
||||
break
|
||||
}
|
||||
return i, res, true
|
||||
case 't', 'f', 'n':
|
||||
fallthrough
|
||||
case 't', 'f':
|
||||
vc := json[i]
|
||||
i, val = parseLiteral(json, i)
|
||||
if hit {
|
||||
@@ -2120,7 +2244,20 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
|
||||
}
|
||||
return i, res, true
|
||||
}
|
||||
case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'i', 'I', 'N':
|
||||
num = true
|
||||
}
|
||||
if num {
|
||||
i, val = parseNumber(json, i)
|
||||
if hit {
|
||||
res.Raw = val
|
||||
res.Type = Number
|
||||
res.Num, _ = strconv.ParseFloat(val, 64)
|
||||
}
|
||||
return i, res, true
|
||||
}
|
||||
|
||||
}
|
||||
return i, res, false
|
||||
}
|
||||
@@ -2492,8 +2629,40 @@ func safeInt(f float64) (n int64, ok bool) {
|
||||
return int64(f), true
|
||||
}
|
||||
|
||||
// execStatic parses the path to find a static value.
|
||||
// The input expects that the path already starts with a '!'
|
||||
func execStatic(json, path string) (pathOut, res string, ok bool) {
|
||||
name := path[1:]
|
||||
if len(name) > 0 {
|
||||
switch name[0] {
|
||||
case '{', '[', '"', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9':
|
||||
_, res = parseSquash(name, 0)
|
||||
pathOut = name[len(res):]
|
||||
return pathOut, res, true
|
||||
}
|
||||
}
|
||||
for i := 1; i < len(path); i++ {
|
||||
if path[i] == '|' {
|
||||
pathOut = path[i:]
|
||||
name = path[1:i]
|
||||
break
|
||||
}
|
||||
if path[i] == '.' {
|
||||
pathOut = path[i:]
|
||||
name = path[1:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(name) {
|
||||
case "true", "false", "null", "nan", "inf":
|
||||
return pathOut, name, true
|
||||
}
|
||||
return pathOut, res, false
|
||||
}
|
||||
|
||||
// execModifier parses the path to find a matching modifier function.
|
||||
// then input expects that the path already starts with a '@'
|
||||
// The input expects that the path already starts with a '@'
|
||||
func execModifier(json, path string) (pathOut, res string, ok bool) {
|
||||
name := path[1:]
|
||||
var hasArgs bool
|
||||
@@ -2564,6 +2733,11 @@ var modifiers = map[string]func(json, arg string) string{
|
||||
"flatten": modFlatten,
|
||||
"join": modJoin,
|
||||
"valid": modValid,
|
||||
"keys": modKeys,
|
||||
"values": modValues,
|
||||
"tostr": modToStr,
|
||||
"fromstr": modFromStr,
|
||||
"group": modGroup,
|
||||
}
|
||||
|
||||
// AddModifier binds a custom modifier command to the GJSON syntax.
|
||||
@@ -2720,6 +2894,58 @@ func modFlatten(json, arg string) string {
|
||||
return bytesString(out)
|
||||
}
|
||||
|
||||
// @keys extracts the keys from an object.
|
||||
// {"first":"Tom","last":"Smith"} -> ["first","last"]
|
||||
func modKeys(json, arg string) string {
|
||||
v := Parse(json)
|
||||
if !v.Exists() {
|
||||
return "[]"
|
||||
}
|
||||
obj := v.IsObject()
|
||||
var out strings.Builder
|
||||
out.WriteByte('[')
|
||||
var i int
|
||||
v.ForEach(func(key, _ Result) bool {
|
||||
if i > 0 {
|
||||
out.WriteByte(',')
|
||||
}
|
||||
if obj {
|
||||
out.WriteString(key.Raw)
|
||||
} else {
|
||||
out.WriteString("null")
|
||||
}
|
||||
i++
|
||||
return true
|
||||
})
|
||||
out.WriteByte(']')
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// @values extracts the values from an object.
|
||||
// {"first":"Tom","last":"Smith"} -> ["Tom","Smith"]
|
||||
func modValues(json, arg string) string {
|
||||
v := Parse(json)
|
||||
if !v.Exists() {
|
||||
return "[]"
|
||||
}
|
||||
if v.IsArray() {
|
||||
return json
|
||||
}
|
||||
var out strings.Builder
|
||||
out.WriteByte('[')
|
||||
var i int
|
||||
v.ForEach(func(_, value Result) bool {
|
||||
if i > 0 {
|
||||
out.WriteByte(',')
|
||||
}
|
||||
out.WriteString(value.Raw)
|
||||
i++
|
||||
return true
|
||||
})
|
||||
out.WriteByte(']')
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// @join multiple objects into a single object.
|
||||
// [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"}
|
||||
// The arg can be "true" to specify that duplicate keys should be preserved.
|
||||
@@ -2797,6 +3023,56 @@ func modValid(json, arg string) string {
|
||||
return json
|
||||
}
|
||||
|
||||
// @fromstr converts a string to json
|
||||
// "{\"id\":1023,\"name\":\"alert\"}" -> {"id":1023,"name":"alert"}
|
||||
func modFromStr(json, arg string) string {
|
||||
if !Valid(json) {
|
||||
return ""
|
||||
}
|
||||
return Parse(json).String()
|
||||
}
|
||||
|
||||
// @tostr converts a string to json
|
||||
// {"id":1023,"name":"alert"} -> "{\"id\":1023,\"name\":\"alert\"}"
|
||||
func modToStr(str, arg string) string {
|
||||
return string(AppendJSONString(nil, str))
|
||||
}
|
||||
|
||||
func modGroup(json, arg string) string {
|
||||
res := Parse(json)
|
||||
if !res.IsObject() {
|
||||
return ""
|
||||
}
|
||||
var all [][]byte
|
||||
res.ForEach(func(key, value Result) bool {
|
||||
if !value.IsArray() {
|
||||
return true
|
||||
}
|
||||
var idx int
|
||||
value.ForEach(func(_, value Result) bool {
|
||||
if idx == len(all) {
|
||||
all = append(all, []byte{})
|
||||
}
|
||||
all[idx] = append(all[idx], ("," + key.Raw + ":" + value.Raw)...)
|
||||
idx++
|
||||
return true
|
||||
})
|
||||
return true
|
||||
})
|
||||
var data []byte
|
||||
data = append(data, '[')
|
||||
for i, item := range all {
|
||||
if i > 0 {
|
||||
data = append(data, ',')
|
||||
}
|
||||
data = append(data, '{')
|
||||
data = append(data, item[1:]...)
|
||||
data = append(data, '}')
|
||||
}
|
||||
data = append(data, ']')
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// stringHeader instead of reflect.StringHeader
|
||||
type stringHeader struct {
|
||||
data unsafe.Pointer
|
||||
@@ -2882,3 +3158,202 @@ func stringBytes(s string) []byte {
|
||||
func bytesString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
func revSquash(json string) string {
|
||||
// reverse squash
|
||||
// expects that the tail character is a ']' or '}' or ')' or '"'
|
||||
// squash the value, ignoring all nested arrays and objects.
|
||||
i := len(json) - 1
|
||||
var depth int
|
||||
if json[i] != '"' {
|
||||
depth++
|
||||
}
|
||||
if json[i] == '}' || json[i] == ']' || json[i] == ')' {
|
||||
i--
|
||||
}
|
||||
for ; i >= 0; i-- {
|
||||
switch json[i] {
|
||||
case '"':
|
||||
i--
|
||||
for ; i >= 0; i-- {
|
||||
if json[i] == '"' {
|
||||
esc := 0
|
||||
for i > 0 && json[i-1] == '\\' {
|
||||
i--
|
||||
esc++
|
||||
}
|
||||
if esc%2 == 1 {
|
||||
continue
|
||||
}
|
||||
i += esc
|
||||
break
|
||||
}
|
||||
}
|
||||
if depth == 0 {
|
||||
if i < 0 {
|
||||
i = 0
|
||||
}
|
||||
return json[i:]
|
||||
}
|
||||
case '}', ']', ')':
|
||||
depth++
|
||||
case '{', '[', '(':
|
||||
depth--
|
||||
if depth == 0 {
|
||||
return json[i:]
|
||||
}
|
||||
}
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
// Paths returns the original GJSON paths for a Result where the Result came
|
||||
// from a simple query path that returns an array, like:
|
||||
//
|
||||
// gjson.Get(json, "friends.#.first")
|
||||
//
|
||||
// The returned value will be in the form of a JSON array:
|
||||
//
|
||||
// ["friends.0.first","friends.1.first","friends.2.first"]
|
||||
//
|
||||
// The param 'json' must be the original JSON used when calling Get.
|
||||
//
|
||||
// Returns an empty string if the paths cannot be determined, which can happen
|
||||
// when the Result came from a path that contained a multipath, modifier,
|
||||
// or a nested query.
|
||||
func (t Result) Paths(json string) []string {
|
||||
if t.Indexes == nil {
|
||||
return nil
|
||||
}
|
||||
paths := make([]string, 0, len(t.Indexes))
|
||||
t.ForEach(func(_, value Result) bool {
|
||||
paths = append(paths, value.Path(json))
|
||||
return true
|
||||
})
|
||||
if len(paths) != len(t.Indexes) {
|
||||
return nil
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
// Path returns the original GJSON path for a Result where the Result came
|
||||
// from a simple path that returns a single value, like:
|
||||
//
|
||||
// gjson.Get(json, "friends.#(last=Murphy)")
|
||||
//
|
||||
// The returned value will be in the form of a JSON string:
|
||||
//
|
||||
// "friends.0"
|
||||
//
|
||||
// The param 'json' must be the original JSON used when calling Get.
|
||||
//
|
||||
// Returns an empty string if the paths cannot be determined, which can happen
|
||||
// when the Result came from a path that contained a multipath, modifier,
|
||||
// or a nested query.
|
||||
func (t Result) Path(json string) string {
|
||||
var path []byte
|
||||
var comps []string // raw components
|
||||
i := t.Index - 1
|
||||
if t.Index+len(t.Raw) > len(json) {
|
||||
// JSON cannot safely contain Result.
|
||||
goto fail
|
||||
}
|
||||
if !strings.HasPrefix(json[t.Index:], t.Raw) {
|
||||
// Result is not at the JSON index as exepcted.
|
||||
goto fail
|
||||
}
|
||||
for ; i >= 0; i-- {
|
||||
if json[i] <= ' ' {
|
||||
continue
|
||||
}
|
||||
if json[i] == ':' {
|
||||
// inside of object, get the key
|
||||
for ; i >= 0; i-- {
|
||||
if json[i] != '"' {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
raw := revSquash(json[:i+1])
|
||||
i = i - len(raw)
|
||||
comps = append(comps, raw)
|
||||
// key gotten, now squash the rest
|
||||
raw = revSquash(json[:i+1])
|
||||
i = i - len(raw)
|
||||
i++ // increment the index for next loop step
|
||||
} else if json[i] == '{' {
|
||||
// Encountered an open object. The original result was probably an
|
||||
// object key.
|
||||
goto fail
|
||||
} else if json[i] == ',' || json[i] == '[' {
|
||||
// inside of an array, count the position
|
||||
var arrIdx int
|
||||
if json[i] == ',' {
|
||||
arrIdx++
|
||||
i--
|
||||
}
|
||||
for ; i >= 0; i-- {
|
||||
if json[i] == ':' {
|
||||
// Encountered an unexpected colon. The original result was
|
||||
// probably an object key.
|
||||
goto fail
|
||||
} else if json[i] == ',' {
|
||||
arrIdx++
|
||||
} else if json[i] == '[' {
|
||||
comps = append(comps, strconv.Itoa(arrIdx))
|
||||
break
|
||||
} else if json[i] == ']' || json[i] == '}' || json[i] == '"' {
|
||||
raw := revSquash(json[:i+1])
|
||||
i = i - len(raw) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(comps) == 0 {
|
||||
if DisableModifiers {
|
||||
goto fail
|
||||
}
|
||||
return "@this"
|
||||
}
|
||||
for i := len(comps) - 1; i >= 0; i-- {
|
||||
rcomp := Parse(comps[i])
|
||||
if !rcomp.Exists() {
|
||||
goto fail
|
||||
}
|
||||
comp := escapeComp(rcomp.String())
|
||||
path = append(path, '.')
|
||||
path = append(path, comp...)
|
||||
}
|
||||
if len(path) > 0 {
|
||||
path = path[1:]
|
||||
}
|
||||
return string(path)
|
||||
fail:
|
||||
return ""
|
||||
}
|
||||
|
||||
// isSafePathKeyChar returns true if the input character is safe for not
|
||||
// needing escaping.
|
||||
func isSafePathKeyChar(c byte) bool {
|
||||
return c <= ' ' || c > '~' || c == '_' || c == '-' || c == ':' ||
|
||||
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9')
|
||||
}
|
||||
|
||||
// escapeComp escaped a path compontent, making it safe for generating a
|
||||
// path for later use.
|
||||
func escapeComp(comp string) string {
|
||||
for i := 0; i < len(comp); i++ {
|
||||
if !isSafePathKeyChar(comp[i]) {
|
||||
ncomp := []byte(comp[:i])
|
||||
for ; i < len(comp); i++ {
|
||||
if !isSafePathKeyChar(comp[i]) {
|
||||
ncomp = append(ncomp, '\\')
|
||||
}
|
||||
ncomp = append(ncomp, comp[i])
|
||||
}
|
||||
return string(ncomp)
|
||||
}
|
||||
}
|
||||
return comp
|
||||
}
|
||||
|
||||
2
vendor/github.com/tidwall/pretty/README.md
generated
vendored
2
vendor/github.com/tidwall/pretty/README.md
generated
vendored
@@ -59,7 +59,7 @@ Will format the json to:
|
||||
|
||||
Color will colorize the json for outputing to the screen.
|
||||
|
||||
```json
|
||||
```go
|
||||
result = pretty.Color(json, nil)
|
||||
```
|
||||
|
||||
|
||||
22
vendor/github.com/tidwall/pretty/pretty.go
generated
vendored
22
vendor/github.com/tidwall/pretty/pretty.go
generated
vendored
@@ -422,6 +422,7 @@ type Style struct {
|
||||
Key, String, Number [2]string
|
||||
True, False, Null [2]string
|
||||
Escape [2]string
|
||||
Brackets [2]string
|
||||
Append func(dst []byte, c byte) []byte
|
||||
}
|
||||
|
||||
@@ -439,13 +440,14 @@ var TerminalStyle *Style
|
||||
|
||||
func init() {
|
||||
TerminalStyle = &Style{
|
||||
Key: [2]string{"\x1B[94m", "\x1B[0m"},
|
||||
String: [2]string{"\x1B[92m", "\x1B[0m"},
|
||||
Number: [2]string{"\x1B[93m", "\x1B[0m"},
|
||||
True: [2]string{"\x1B[96m", "\x1B[0m"},
|
||||
False: [2]string{"\x1B[96m", "\x1B[0m"},
|
||||
Null: [2]string{"\x1B[91m", "\x1B[0m"},
|
||||
Escape: [2]string{"\x1B[35m", "\x1B[0m"},
|
||||
Key: [2]string{"\x1B[1m\x1B[94m", "\x1B[0m"},
|
||||
String: [2]string{"\x1B[32m", "\x1B[0m"},
|
||||
Number: [2]string{"\x1B[33m", "\x1B[0m"},
|
||||
True: [2]string{"\x1B[36m", "\x1B[0m"},
|
||||
False: [2]string{"\x1B[36m", "\x1B[0m"},
|
||||
Null: [2]string{"\x1B[2m", "\x1B[0m"},
|
||||
Escape: [2]string{"\x1B[35m", "\x1B[0m"},
|
||||
Brackets: [2]string{"\x1B[1m", "\x1B[0m"},
|
||||
Append: func(dst []byte, c byte) []byte {
|
||||
if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') {
|
||||
dst = append(dst, "\\u00"...)
|
||||
@@ -539,13 +541,19 @@ func Color(src []byte, style *Style) []byte {
|
||||
}
|
||||
} else if src[i] == '{' || src[i] == '[' {
|
||||
stack = append(stack, stackt{src[i], src[i] == '{'})
|
||||
dst = append(dst, style.Brackets[0]...)
|
||||
dst = apnd(dst, src[i])
|
||||
dst = append(dst, style.Brackets[1]...)
|
||||
} else if (src[i] == '}' || src[i] == ']') && len(stack) > 0 {
|
||||
stack = stack[:len(stack)-1]
|
||||
dst = append(dst, style.Brackets[0]...)
|
||||
dst = apnd(dst, src[i])
|
||||
dst = append(dst, style.Brackets[1]...)
|
||||
} else if (src[i] == ':' || src[i] == ',') && len(stack) > 0 && stack[len(stack)-1].kind == '{' {
|
||||
stack[len(stack)-1].key = !stack[len(stack)-1].key
|
||||
dst = append(dst, style.Brackets[0]...)
|
||||
dst = apnd(dst, src[i])
|
||||
dst = append(dst, style.Brackets[1]...)
|
||||
} else {
|
||||
var kind byte
|
||||
if (src[i] >= '0' && src[i] <= '9') || src[i] == '-' || isNaNOrInf(src[i:]) {
|
||||
|
||||
Reference in New Issue
Block a user