Files
phishingclub/backend/vendor/github.com/ysmood/gson/read.go
T
Ronni Skansing f5e6f53d75 update vendor
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
2026-05-24 09:57:07 +02:00

262 lines
5.2 KiB
Go

// Package gson A tiny JSON lib to read and alter a JSON value.
package gson
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
"sync"
)
// JSON represent a JSON value
type JSON struct {
lock *sync.Mutex
value *interface{}
}
// MarshalJSON interface
func (j JSON) MarshalJSON() ([]byte, error) {
return json.Marshal(j.Val())
}
// Unmarshal is the same as [json.Unmarshal] for the underlying raw value.
// It should be called before other operations.
func (j JSON) Unmarshal(v interface{}) error {
if j.value == nil {
return fmt.Errorf("gson: no value to unmarshal")
}
j.lock.Lock()
defer j.lock.Unlock()
b, ok := (*j.value).([]byte)
if !ok {
return fmt.Errorf("gson: value has been parsed")
}
return json.Unmarshal(b, v)
}
// JSON string
func (j JSON) JSON(prefix, indent string) string {
buf := bytes.NewBuffer(nil)
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
enc.SetIndent(prefix, indent)
_ = enc.Encode(j.Val())
s := buf.String()
return s[:len(s)-1]
}
// Raw underlying value
func (j JSON) Raw() interface{} {
if j.value == nil {
return nil
}
return *j.value
}
// String implements [fmt.Stringer] interface
func (j JSON) String() string {
return fmt.Sprintf("%v", j.Val())
}
// Get by json path. It's a shortcut for Gets.
func (j JSON) Get(path string) JSON {
j, _ = j.Gets(Path(path)...)
return j
}
// Has an element is found on the path
func (j JSON) Has(path string) bool {
_, has := j.Gets(Path(path)...)
return has
}
// Query section
type Query func(interface{}) (val interface{}, has bool)
// Gets element by path sections. If a section is not string, int, or func, it will be ignored.
// If it's a func, the value will be passed to it, the result of it will the next level.
// The last return value will be false if not found.
func (j JSON) Gets(sections ...interface{}) (JSON, bool) {
for _, sect := range sections {
var val interface{}
var has bool
if fn, ok := sect.(Query); ok {
val, has = fn(j.Val())
} else {
val, has = get(reflect.ValueOf(j.Val()), sect)
}
if !has {
return New(nil), false
}
j.value = &val
}
return j, true
}
func get(objVal reflect.Value, sect interface{}) (val interface{}, has bool) {
switch k := sect.(type) {
case int:
if objVal.Kind() != reflect.Slice || k >= objVal.Len() {
return
}
has = true
val = objVal.Index(k).Interface()
default:
sectVal := reflect.ValueOf(sect)
if objVal.Kind() != reflect.Map || !sectVal.Type().AssignableTo(objVal.Type().Key()) {
return
}
v := objVal.MapIndex(sectVal)
if !v.IsValid() {
return
}
has = true
val = v.Interface()
}
return
}
// Str value
func (j JSON) Str() string {
v := j.Val()
if v, ok := v.(string); ok {
return v
}
return fmt.Sprintf("%v", v)
}
var floatType = reflect.TypeOf(.0)
// Num value
// returns zero value for type if underlying JSON type is not convertible.
func (j JSON) Num() float64 {
v := reflect.ValueOf(j.Val())
if v.IsValid() && v.Type().ConvertibleTo(floatType) {
return v.Convert(floatType).Float()
}
return 0
}
// Bool value
// returns zero value for type if underlying JSON type is not boolean
func (j JSON) Bool() bool {
if v, ok := j.Val().(bool); ok {
return v
}
return false
}
// Nil or not
func (j JSON) Nil() bool {
return j.Val() == nil
}
var intType = reflect.TypeOf(0)
// Int value
// returns zero value for type if underlying JSON type is not convertible.
func (j JSON) Int() int {
v := reflect.ValueOf(j.Val())
if v.IsValid() && v.Type().ConvertibleTo(intType) {
return int(v.Convert(intType).Int())
}
return 0
}
// Map of JSON
// returns empty map if underlying JSON object is not a map.
func (j JSON) Map() map[string]JSON {
val := reflect.ValueOf(j.Val())
if val.IsValid() && val.Kind() == reflect.Map && val.Type().Key().Kind() == reflect.String {
obj := map[string]JSON{}
iter := val.MapRange()
for iter.Next() {
obj[iter.Key().String()] = New(iter.Value().Interface())
}
return obj
}
return make(map[string]JSON)
}
// Arr of JSON
// returns empty array if underlying JSON is not an array.
func (j JSON) Arr() []JSON {
val := reflect.ValueOf(j.Val())
if val.IsValid() && val.Kind() == reflect.Slice {
obj := []JSON{}
l := val.Len()
for i := 0; i < l; i++ {
obj = append(obj, New(val.Index(i).Interface()))
}
return obj
}
return make([]JSON, 0)
}
// Join elements
func (j JSON) Join(sep string) string {
list := []string{}
for _, el := range j.Arr() {
list = append(list, el.Str())
}
return strings.Join(list, sep)
}
var regIndex = regexp.MustCompile(`^0|([1-9]\d*)$`)
// Path from string
func Path(path string) []interface{} {
list := strings.Split(path, ".")
sects := make([]interface{}, len(list))
for i, s := range list {
if regIndex.MatchString(s) {
index, err := strconv.ParseInt(s, 10, 64)
if err == nil {
sects[i] = int(index)
continue
}
}
sects[i] = s
}
return sects
}
// Num returns the pointer of the v
func Num(v float64) *float64 {
return &v
}
// Int returns the pointer of the v
func Int(v int) *int {
return &v
}
// Str returns the pointer of the v
func Str(v string) *string {
return &v
}
// Bool returns the pointer of the v
func Bool(v bool) *bool {
return &v
}