pax_global_header00006660000000000000000000000064143375436460014531gustar00rootroot0000000000000052 comment=c60042b432eb83a5b356d00e7c2db9813ac7e05f gson-0.7.3/000077500000000000000000000000001433754364600125065ustar00rootroot00000000000000gson-0.7.3/.github/000077500000000000000000000000001433754364600140465ustar00rootroot00000000000000gson-0.7.3/.github/workflows/000077500000000000000000000000001433754364600161035ustar00rootroot00000000000000gson-0.7.3/.github/workflows/go.yml000066400000000000000000000005331433754364600172340ustar00rootroot00000000000000name: Go on: [push] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/setup-go@v2 with: go-version: 1.19 - uses: actions/checkout@v2 - run: | go run github.com/ysmood/golangci-lint@latest go test -coverprofile=coverage.out go run github.com/ysmood/got/cmd/check-cov@latest gson-0.7.3/.gitignore000066400000000000000000000000241433754364600144720ustar00rootroot00000000000000.golangci.yml *.out gson-0.7.3/LICENSE000066400000000000000000000020511433754364600135110ustar00rootroot00000000000000The MIT License Copyright 2020 Yad Smood Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.gson-0.7.3/README.md000066400000000000000000000005461433754364600137720ustar00rootroot00000000000000# Overview [![Go Reference](https://pkg.go.dev/badge/github.com/ysmood/gson.svg)](https://pkg.go.dev/github.com/ysmood/gson) The tests is the doc. A tiny JSON lib to read and alter a JSON value. The data structure is lazy, it's parse-on-read so that you can replace the parser with a faster one if performance is critical, use method `JSON.Raw` to do it. gson-0.7.3/go.mod000066400000000000000000000000471433754364600136150ustar00rootroot00000000000000module github.com/ysmood/gson go 1.15 gson-0.7.3/gson_test.go000066400000000000000000000075551433754364600150560ustar00rootroot00000000000000package gson_test import ( "bytes" "encoding/json" "fmt" "reflect" "testing" "github.com/ysmood/gson" ) func ExampleJSON() { obj := gson.NewFrom(`{"a": {"b": [1, 2]}}`) fmt.Println(obj.Get("a.b.0").Int()) obj.Set("a.b.1", "ok").Set("c", 2) obj.Del("c") fmt.Println(">", obj.JSON("> ", " ")) // Output: // 1 // > { // > "a": { // > "b": [ // > 1, // > "ok" // > ] // > } // > } } func Test(t *testing.T) { eq := genEq(t) eq(gson.NewFrom("true").Bool(), true) eq(gson.New([]byte("10")).Int(), 10) eq(gson.New(10).Int(), 10) eq(gson.New(gson.New(10)).Int(), 10) eq(gson.JSON{}.Int(), 0) eq(gson.JSON{}.JSON("", ""), "null") eq(gson.New(nil).Num(), 0.0) eq(gson.New(nil).Bool(), false) buf := bytes.NewBufferString("10") fromBuf := gson.New(buf) eq(fromBuf.Int(), 10) eq(fromBuf.Int(), 10) b, _ := n(`"ok"`).MarshalJSON() eq(string(b), `"ok"`) eq(gson.JSON{}.Raw(), nil) eq(gson.New([]byte(`ok"`)).Raw(), []byte(`ok"`)) eq(n(`"ok"`).Str(), "ok") eq(n(`1`).Str(), "1") eq(n(`1.2`).Num(), 1.2) eq(n(`"ok"`).Num(), 0.0) eq(n(`1`).Int(), 1) eq(n(`"ok"`).Int(), 0) eq(n(`true`).Bool(), true) eq(n(`1`).Bool(), false) eq(n(`null`).Nil(), true) eq(n(`1`).Join(""), "") j := n(`{ "a": { "b": 1 }, "c": ["x", "y", "z"] }`) eq(j.Get("a.b").Int(), 1) eq(j.Get("c.1").Str(), "y") v, _ := j.Gets("c", gson.Query(func(i interface{}) (val interface{}, has bool) { return i.([]interface{})[1], true })) eq(v.Str(), "y") eq(j.Get("c").Arr()[1].Str(), "y") eq(gson.New([]int{1, 2}).Arr()[1].Int(), 2) eq(j.Get("c").Join(" "), "x y z") eq(j.Get("a").Map()["b"].Int(), 1) eq(gson.New(map[string]int{"a": 1}).Map()["a"].Int(), 1) eq(len(j.Get("c").Map()), 0) eq(gson.New([]gson.JSON{ gson.New(1), gson.New(map[string]int{"a": 2}), }).Get("1.a").Int(), 2) v, _ = gson.New(map[float64]int{2: 3}).Gets(2.0) eq(v.Int(), 3) _, has := j.Gets(true) eq(has, false) eq(j.Has("a.b"), true) eq(j.Has("a.x"), false) eq(j.Has("c.10"), false) onNil := gson.JSON{} eq(onNil.Set("a.b", 10).Get("a.b").Int(), 10) self := gson.New(nil) self.Set("1", "a") self.Set("a.b.1", 1) self.Sets("ok") eq(self.Str(), "ok") self.Sets(map[string]int{"a": 1}) eq(self.Get("a").Int(), 1) self.Sets([]int{1}) eq(self.Get("0").Int(), 1) j.Sets(2.0, "a", "b") eq(j.Get("a.b").Int(), 2) j.Set("c.1", 2) eq(j.Get("c.1").Int(), 2) j.Sets(3, "a", "b") eq(j.Get("a.b").Int(), 3) eq(j.Get("s.10.b").Nil(), true) eq(j.Get("c.10").Nil(), true) j.Set("s.1.a", 10) j.Set("c.5", "ok") eq(fmt.Sprint(j), `map[a:map[b:3] c:[x 2 z ok] s:[ map[a:10]]]`) eq(j.Dels("s", 1, "a"), true) eq(fmt.Sprint(j), `map[a:map[b:3] c:[x 2 z ok] s:[ map[]]]`) eq(j.Dels("s", 1), true) eq(fmt.Sprint(j), `map[a:map[b:3] c:[x 2 z ok] s:[]]`) j.Del("c.1") eq(fmt.Sprint(j), `map[a:map[b:3] c:[x z ok] s:[]]`) eq(j.Dels("c", 10), false) eq(j.Dels("c", "1"), false) eq(j.Dels("xxx", "1"), false) eq(j.Dels(1), false) d := gson.New(1) d.Dels() eq(d.Val(), nil) } func TestUnmarshal(t *testing.T) { eq := genEq(t) v := struct { A int `json:"a"` }{} g := gson.New([]byte(`{"a":1}`)) err := g.Unmarshal(&v) if err != nil { t.Fatal(err) } if v.A != 1 { t.Fatal("parse error") } g.Get("a") eq(g.Unmarshal(&v).Error(), "gson: value has been parsed") eq(gson.JSON{}.Unmarshal(&v).Error(), "gson: no value to unmarshal") } func TestConvertors(t *testing.T) { eq := genEq(t) n := 1.2 i := 1 s := "ok" b := true eq(gson.Num(n), &n) eq(gson.Int(i), &i) eq(gson.Str(s), &s) eq(gson.Bool(b), &b) } func TestLab(t *testing.T) { } func n(s string) (j gson.JSON) { _ = json.Unmarshal([]byte(s), &j) return } func genEq(t *testing.T) func(a, b interface{}) { return func(a, b interface{}) { t.Helper() if !reflect.DeepEqual(a, b) { t.Log(a, "!=", b) t.Fail() } } } gson-0.7.3/read.go000066400000000000000000000122441433754364600137530ustar00rootroot00000000000000// 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 } gson-0.7.3/write.go000066400000000000000000000065541433754364600142010ustar00rootroot00000000000000package gson import ( "encoding/json" "io" "reflect" "sync" ) // New JSON from []byte, [io.Reader], or raw value. func New(v interface{}) JSON { return JSON{&sync.Mutex{}, &v} } // NewFrom json encoded string func NewFrom(s string) JSON { return New([]byte(s)) } // UnmarshalJSON interface func (j *JSON) UnmarshalJSON(b []byte) error { *j = New(b) return nil } // Val of the underlying json value. // The first time it's called, it will try to parse the underlying data. func (j JSON) Val() interface{} { if j.value == nil { return nil } j.lock.Lock() defer j.lock.Unlock() for { val, ok := (*j.value).(JSON) if ok { *j.value = *val.value } else { break } } var val interface{} switch v := (*j.value).(type) { case []byte: _ = json.Unmarshal(v, &val) *j.value = val case io.Reader: _ = json.NewDecoder(v).Decode(&val) *j.value = val } return *j.value } // Set by json path. It's a shortcut for Sets. func (j *JSON) Set(path string, val interface{}) *JSON { return j.Sets(val, Path(path)...) } var _map map[string]interface{} var interfaceType = reflect.TypeOf(_map).Elem() // Sets element by path sections. If a section is not string or int, it will be ignored. func (j *JSON) Sets(target interface{}, sections ...interface{}) *JSON { if j.value == nil { *j = New(nil) } last := len(sections) - 1 val := reflect.ValueOf(j.Val()) override := func(v reflect.Value) { *j.value = v.Interface() } if last == -1 { *j.value = target return j } for i, s := range sections { sect := reflect.ValueOf(s) if val.Kind() == reflect.Interface { val = val.Elem() } switch sect.Kind() { case reflect.Int: k := int(sect.Int()) if val.Kind() != reflect.Slice || val.Len() <= k { nArr := reflect.ValueOf(make([]interface{}, k+1)) if val.Kind() == reflect.Slice { reflect.Copy(nArr, val) } val = nArr override(val) } if i == last { val.Index(k).Set(reflect.ValueOf(target)) return j } prev := val val = val.Index(k) override = func(v reflect.Value) { prev.Index(k).Set(v) } default: targetVal := reflect.ValueOf(target) if val.Kind() != reflect.Map { val = reflect.MakeMap(reflect.MapOf(sect.Type(), interfaceType)) override(val) } if i == last { val.SetMapIndex(sect, targetVal) } prev := val val = val.MapIndex(sect) override = func(v reflect.Value) { prev.SetMapIndex(sect, v) } } } return j } // Del deletes the element at the path. func (j *JSON) Del(path string) *JSON { j.Dels(Path(path)...) return j } // Dels deletes the element at the path sections. // Return true if it's deleted. func (j *JSON) Dels(sections ...interface{}) bool { l := len(sections) if l == 0 { j.value = nil return true } last := sections[l-1] parent, has := j.Gets(sections[:l-1]...) if !has { return false } parentVal := reflect.ValueOf(parent.Val()) lastVal := reflect.ValueOf(last) switch k := last.(type) { case int: pl := parentVal.Len() if parentVal.Kind() != reflect.Slice || k < 0 || k >= pl { return false } j.Sets(reflect.AppendSlice( parentVal.Slice(0, k), parentVal.Slice(k+1, pl), ).Interface(), sections[:l-1]...) default: if parentVal.Kind() != reflect.Map || !lastVal.Type().AssignableTo(parentVal.Type().Key()) { return false } parentVal.SetMapIndex(lastVal, reflect.Value{}) } return true }