diff options
| author | Mistivia <i@mistivia.com> | 2025-11-02 15:27:18 +0800 |
|---|---|---|
| committer | Mistivia <i@mistivia.com> | 2025-11-02 15:27:18 +0800 |
| commit | e9c24f4af7ed56760f6db7941827d09f6db9020b (patch) | |
| tree | 62128c43b883ce5e3148113350978755779bb5de /teleirc/matterbridge/vendor/github.com/Jeffail/gabs | |
| parent | 58d5e7cfda4781d8a57ec52aefd02983835c301a (diff) | |
add matterbridge
Diffstat (limited to 'teleirc/matterbridge/vendor/github.com/Jeffail/gabs')
| -rw-r--r-- | teleirc/matterbridge/vendor/github.com/Jeffail/gabs/LICENSE | 19 | ||||
| -rw-r--r-- | teleirc/matterbridge/vendor/github.com/Jeffail/gabs/README.md | 290 | ||||
| -rw-r--r-- | teleirc/matterbridge/vendor/github.com/Jeffail/gabs/gabs.go | 727 | ||||
| -rw-r--r-- | teleirc/matterbridge/vendor/github.com/Jeffail/gabs/gabs_logo.png | bin | 0 -> 167771 bytes |
4 files changed, 1036 insertions, 0 deletions
diff --git a/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/LICENSE b/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/LICENSE new file mode 100644 index 0000000..99a62c6 --- /dev/null +++ b/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Ashley Jeffs + +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. diff --git a/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/README.md b/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/README.md new file mode 100644 index 0000000..962ba68 --- /dev/null +++ b/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/README.md @@ -0,0 +1,290 @@ + + +Gabs is a small utility for dealing with dynamic or unknown JSON structures in +golang. It's pretty much just a helpful wrapper around the golang +`json.Marshal/json.Unmarshal` behaviour and `map[string]interface{}` objects. +It does nothing spectacular except for being fabulous. + +https://godoc.org/github.com/Jeffail/gabs + +## Install + +``` bash +go get github.com/Jeffail/gabs +``` + +## Use + +### Parsing and searching JSON + +``` go +jsonParsed, err := gabs.ParseJSON([]byte(`{ + "outter":{ + "inner":{ + "value1":10, + "value2":22 + }, + "alsoInner":{ + "value1":20, + "array1":[ + 30, 40 + ] + } + } +}`)) + +var value float64 +var ok bool + +value, ok = jsonParsed.Path("outter.inner.value1").Data().(float64) +// value == 10.0, ok == true + +value, ok = jsonParsed.Search("outter", "inner", "value1").Data().(float64) +// value == 10.0, ok == true + +gObj, err := jsonParsed.JSONPointer("/outter/alsoInner/array1/1") +if err != nil { + panic(err) +} +value, ok = gObj.Data().(float64) +// value == 40.0, ok == true + +value, ok = jsonParsed.Path("does.not.exist").Data().(float64) +// value == 0.0, ok == false + +exists := jsonParsed.Exists("outter", "inner", "value1") +// exists == true + +exists := jsonParsed.ExistsP("does.not.exist") +// exists == false +``` + +### Iterating objects + +``` go +jsonParsed, _ := gabs.ParseJSON([]byte(`{"object":{ "first": 1, "second": 2, "third": 3 }}`)) + +// S is shorthand for Search +children, _ := jsonParsed.S("object").ChildrenMap() +for key, child := range children { + fmt.Printf("key: %v, value: %v\n", key, child.Data().(string)) +} +``` + +### Iterating arrays + +``` go +jsonParsed, err := gabs.ParseJSON([]byte(`{"array":[ "first", "second", "third" ]}`)) +if err != nil { + panic(err) +} + +// S is shorthand for Search +children, err := jsonParsed.S("array").Children() +if err != nil { + panic(err) +} + +for _, child := range children { + fmt.Println(child.Data().(string)) +} +``` + +Will print: + +``` +first +second +third +``` + +Children() will return all children of an array in order. This also works on +objects, however, the children will be returned in a random order. + +### Searching through arrays + +If your JSON structure contains arrays you can still search the fields of the +objects within the array, this returns a JSON array containing the results for +each element. + +``` go +jsonParsed, err := gabs.ParseJSON([]byte(`{"array":[ {"value":1}, {"value":2}, {"value":3} ]}`)) +if err != nil { + panic(err) +} +fmt.Println(jsonParsed.Path("array.value").String()) +``` + +Will print: + +``` +[1,2,3] +``` + +### Generating JSON + +``` go +jsonObj := gabs.New() +// or gabs.Consume(jsonObject) to work on an existing map[string]interface{} + +jsonObj.Set(10, "outter", "inner", "value") +jsonObj.SetP(20, "outter.inner.value2") +jsonObj.Set(30, "outter", "inner2", "value3") + +fmt.Println(jsonObj.String()) +``` + +Will print: + +``` +{"outter":{"inner":{"value":10,"value2":20},"inner2":{"value3":30}}} +``` + +To pretty-print: + +``` go +fmt.Println(jsonObj.StringIndent("", " ")) +``` + +Will print: + +``` +{ + "outter": { + "inner": { + "value": 10, + "value2": 20 + }, + "inner2": { + "value3": 30 + } + } +} +``` + +### Generating Arrays + +``` go +jsonObj := gabs.New() + +jsonObj.Array("foo", "array") +// Or .ArrayP("foo.array") + +jsonObj.ArrayAppend(10, "foo", "array") +jsonObj.ArrayAppend(20, "foo", "array") +jsonObj.ArrayAppend(30, "foo", "array") + +fmt.Println(jsonObj.String()) +``` + +Will print: + +``` +{"foo":{"array":[10,20,30]}} +``` + +Working with arrays by index: + +``` go +jsonObj := gabs.New() + +// Create an array with the length of 3 +jsonObj.ArrayOfSize(3, "foo") + +jsonObj.S("foo").SetIndex("test1", 0) +jsonObj.S("foo").SetIndex("test2", 1) + +// Create an embedded array with the length of 3 +jsonObj.S("foo").ArrayOfSizeI(3, 2) + +jsonObj.S("foo").Index(2).SetIndex(1, 0) +jsonObj.S("foo").Index(2).SetIndex(2, 1) +jsonObj.S("foo").Index(2).SetIndex(3, 2) + +fmt.Println(jsonObj.String()) +``` + +Will print: + +``` +{"foo":["test1","test2",[1,2,3]]} +``` + +### Converting back to JSON + +This is the easiest part: + +``` go +jsonParsedObj, _ := gabs.ParseJSON([]byte(`{ + "outter":{ + "values":{ + "first":10, + "second":11 + } + }, + "outter2":"hello world" +}`)) + +jsonOutput := jsonParsedObj.String() +// Becomes `{"outter":{"values":{"first":10,"second":11}},"outter2":"hello world"}` +``` + +And to serialize a specific segment is as simple as: + +``` go +jsonParsedObj := gabs.ParseJSON([]byte(`{ + "outter":{ + "values":{ + "first":10, + "second":11 + } + }, + "outter2":"hello world" +}`)) + +jsonOutput := jsonParsedObj.Search("outter").String() +// Becomes `{"values":{"first":10,"second":11}}` +``` + +### Merge two containers + +You can merge a JSON structure into an existing one, where collisions will be +converted into a JSON array. + +``` go +jsonParsed1, _ := ParseJSON([]byte(`{"outter": {"value1": "one"}}`)) +jsonParsed2, _ := ParseJSON([]byte(`{"outter": {"inner": {"value3": "three"}}, "outter2": {"value2": "two"}}`)) + +jsonParsed1.Merge(jsonParsed2) +// Becomes `{"outter":{"inner":{"value3":"three"},"value1":"one"},"outter2":{"value2":"two"}}` +``` + +Arrays are merged: + +``` go +jsonParsed1, _ := ParseJSON([]byte(`{"array": ["one"]}`)) +jsonParsed2, _ := ParseJSON([]byte(`{"array": ["two"]}`)) + +jsonParsed1.Merge(jsonParsed2) +// Becomes `{"array":["one", "two"]}` +``` + +### Parsing Numbers + +Gabs uses the `json` package under the bonnet, which by default will parse all +number values into `float64`. If you need to parse `Int` values then you should +use a `json.Decoder` (https://golang.org/pkg/encoding/json/#Decoder): + +``` go +sample := []byte(`{"test":{"int":10, "float":6.66}}`) +dec := json.NewDecoder(bytes.NewReader(sample)) +dec.UseNumber() + +val, err := gabs.ParseJSONDecoder(dec) +if err != nil { + t.Errorf("Failed to parse: %v", err) + return +} + +intValue, err := val.Path("test.int").Data().(json.Number).Int64() +``` diff --git a/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/gabs.go b/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/gabs.go new file mode 100644 index 0000000..011c4c3 --- /dev/null +++ b/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/gabs.go @@ -0,0 +1,727 @@ +/* +Copyright (c) 2014 Ashley Jeffs + +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. +*/ + +// Package gabs implements a simplified wrapper around creating and parsing +// unknown or dynamic JSON. +package gabs + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "strconv" + "strings" +) + +//------------------------------------------------------------------------------ + +var ( + // ErrOutOfBounds indicates an index was out of bounds. + ErrOutOfBounds = errors.New("out of bounds") + + // ErrNotObjOrArray is returned when a target is not an object or array type + // but needs to be for the intended operation. + ErrNotObjOrArray = errors.New("not an object or array") + + // ErrNotObj is returned when a target is not an object but needs to be for + // the intended operation. + ErrNotObj = errors.New("not an object") + + // ErrNotArray is returned when a target is not an array but needs to be for + // the intended operation. + ErrNotArray = errors.New("not an array") + + // ErrPathCollision is returned when creating a path failed because an + // element collided with an existing value. + ErrPathCollision = errors.New("encountered value collision whilst building path") + + // ErrInvalidInputObj is returned when the input value was not a + // map[string]interface{}. + ErrInvalidInputObj = errors.New("invalid input object") + + // ErrInvalidInputText is returned when the input data could not be parsed. + ErrInvalidInputText = errors.New("input text could not be parsed") + + // ErrInvalidPath is returned when the filepath was not valid. + ErrInvalidPath = errors.New("invalid file path") + + // ErrInvalidBuffer is returned when the input buffer contained an invalid + // JSON string. + ErrInvalidBuffer = errors.New("input buffer contained invalid JSON") +) + +//------------------------------------------------------------------------------ + +func resolveJSONPointerHierarchy(path string) ([]string, error) { + if len(path) < 1 { + return nil, errors.New("failed to resolve JSON pointer: path must not be empty") + } + if path[0] != '/' { + return nil, errors.New("failed to resolve JSON pointer: path must begin with '/'") + } + hierarchy := strings.Split(path, "/")[1:] + for i, v := range hierarchy { + v = strings.Replace(v, "~1", "/", -1) + v = strings.Replace(v, "~0", "~", -1) + hierarchy[i] = v + } + return hierarchy, nil +} + +//------------------------------------------------------------------------------ + +// Container references a specific element within a JSON structure. +type Container struct { + object interface{} +} + +// Data returns the underlying interface{} of the target element in the JSON +// structure. +func (g *Container) Data() interface{} { + if g == nil { + return nil + } + return g.object +} + +//------------------------------------------------------------------------------ + +// Path searches the JSON structure following a path in dot notation. +func (g *Container) Path(path string) *Container { + return g.Search(strings.Split(path, ".")...) +} + +// Search attempts to find and return an object within the JSON structure by +// following a provided hierarchy of field names to locate the target. If the +// search encounters an array and has not reached the end target then it will +// iterate each object of the array for the target and return all of the results +// in a JSON array. +func (g *Container) Search(hierarchy ...string) *Container { + var object interface{} + + object = g.Data() + for target := 0; target < len(hierarchy); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + object, ok = mmap[hierarchy[target]] + if !ok { + return nil + } + } else if marray, ok := object.([]interface{}); ok { + tmpArray := []interface{}{} + for _, val := range marray { + tmpGabs := &Container{val} + res := tmpGabs.Search(hierarchy[target:]...) + if res != nil { + tmpArray = append(tmpArray, res.Data()) + } + } + if len(tmpArray) == 0 { + return nil + } + return &Container{tmpArray} + } else { + return nil + } + } + return &Container{object} +} + +// JSONPointer parses a JSON pointer path (https://tools.ietf.org/html/rfc6901) +// and either returns a *gabs.Container containing the result or an error if the +// referenced item could not be found. +func (g *Container) JSONPointer(path string) (*Container, error) { + hierarchy, err := resolveJSONPointerHierarchy(path) + if err != nil { + return nil, err + } + + object := g.Data() + for target := 0; target < len(hierarchy); target++ { + pathSeg := hierarchy[target] + if mmap, ok := object.(map[string]interface{}); ok { + object, ok = mmap[pathSeg] + if !ok { + return nil, fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' was not found", target, pathSeg) + } + } else if marray, ok := object.([]interface{}); ok { + index, err := strconv.Atoi(pathSeg) + if err != nil { + return nil, fmt.Errorf("failed to resolve JSON pointer: could not parse index '%v' value '%v' into array index: %v", target, pathSeg, err) + } + if len(marray) <= index { + return nil, fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' exceeded target array size of '%v'", target, pathSeg, len(marray)) + } + object = marray[index] + } else { + return &Container{nil}, fmt.Errorf("failed to resolve JSON pointer: index '%v' field '%v' was not found", target, pathSeg) + } + } + return &Container{object}, nil +} + +// S is a shorthand alias for Search. +func (g *Container) S(hierarchy ...string) *Container { + return g.Search(hierarchy...) +} + +// Exists checks whether a path exists. +func (g *Container) Exists(hierarchy ...string) bool { + return g.Search(hierarchy...) != nil +} + +// ExistsP checks whether a dot notation path exists. +func (g *Container) ExistsP(path string) bool { + return g.Exists(strings.Split(path, ".")...) +} + +// Index attempts to find and return an element within a JSON array by an index. +func (g *Container) Index(index int) *Container { + if array, ok := g.Data().([]interface{}); ok { + if index >= len(array) { + return &Container{nil} + } + return &Container{array[index]} + } + return &Container{nil} +} + +// Children returns a slice of all children of an array element. This also works +// for objects, however, the children returned for an object will be in a random +// order and you lose the names of the returned objects this way. +func (g *Container) Children() ([]*Container, error) { + if array, ok := g.Data().([]interface{}); ok { + children := make([]*Container, len(array)) + for i := 0; i < len(array); i++ { + children[i] = &Container{array[i]} + } + return children, nil + } + if mmap, ok := g.Data().(map[string]interface{}); ok { + children := []*Container{} + for _, obj := range mmap { + children = append(children, &Container{obj}) + } + return children, nil + } + return nil, ErrNotObjOrArray +} + +// ChildrenMap returns a map of all the children of an object element. +func (g *Container) ChildrenMap() (map[string]*Container, error) { + if mmap, ok := g.Data().(map[string]interface{}); ok { + children := map[string]*Container{} + for name, obj := range mmap { + children[name] = &Container{obj} + } + return children, nil + } + return nil, ErrNotObj +} + +//------------------------------------------------------------------------------ + +// Set the value of a field at a JSON path, any parts of the path that do not +// exist will be constructed, and if a collision occurs with a non object type +// whilst iterating the path an error is returned. +func (g *Container) Set(value interface{}, path ...string) (*Container, error) { + if len(path) == 0 { + g.object = value + return g, nil + } + var object interface{} + if g.object == nil { + g.object = map[string]interface{}{} + } + object = g.object + for target := 0; target < len(path); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + if target == len(path)-1 { + mmap[path[target]] = value + } else if mmap[path[target]] == nil { + mmap[path[target]] = map[string]interface{}{} + } + object = mmap[path[target]] + } else { + return &Container{nil}, ErrPathCollision + } + } + return &Container{object}, nil +} + +// SetP sets the value of a field at a JSON path using dot notation, any parts +// of the path that do not exist will be constructed, and if a collision occurs +// with a non object type whilst iterating the path an error is returned. +func (g *Container) SetP(value interface{}, path string) (*Container, error) { + return g.Set(value, strings.Split(path, ".")...) +} + +// SetIndex attempts to set a value of an array element based on an index. +func (g *Container) SetIndex(value interface{}, index int) (*Container, error) { + if array, ok := g.Data().([]interface{}); ok { + if index >= len(array) { + return &Container{nil}, ErrOutOfBounds + } + array[index] = value + return &Container{array[index]}, nil + } + return &Container{nil}, ErrNotArray +} + +// SetJSONPointer parses a JSON pointer path +// (https://tools.ietf.org/html/rfc6901) and sets the leaf to a value. Returns +// an error if the pointer could not be resolved due to missing fields. +func (g *Container) SetJSONPointer(value interface{}, path string) error { + hierarchy, err := resolveJSONPointerHierarchy(path) + if err != nil { + return err + } + + if len(hierarchy) == 0 { + g.object = value + return nil + } + + object := g.object + + for target := 0; target < len(hierarchy); target++ { + pathSeg := hierarchy[target] + if mmap, ok := object.(map[string]interface{}); ok { + if target == len(hierarchy)-1 { + object = value + mmap[pathSeg] = object + } else if object = mmap[pathSeg]; object == nil { + return fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' was not found", target, pathSeg) + } + } else if marray, ok := object.([]interface{}); ok { + index, err := strconv.Atoi(pathSeg) + if err != nil { + return fmt.Errorf("failed to resolve JSON pointer: could not parse index '%v' value '%v' into array index: %v", target, pathSeg, err) + } + if len(marray) <= index { + return fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' exceeded target array size of '%v'", target, pathSeg, len(marray)) + } + if target == len(hierarchy)-1 { + object = value + marray[index] = object + } else if object = marray[index]; object == nil { + return fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' was not found", target, pathSeg) + } + } else { + return fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' was not found", target, pathSeg) + } + } + return nil +} + +// Object creates a new JSON object at a target path. Returns an error if the +// path contains a collision with a non object type. +func (g *Container) Object(path ...string) (*Container, error) { + return g.Set(map[string]interface{}{}, path...) +} + +// ObjectP creates a new JSON object at a target path using dot notation. +// Returns an error if the path contains a collision with a non object type. +func (g *Container) ObjectP(path string) (*Container, error) { + return g.Object(strings.Split(path, ".")...) +} + +// ObjectI creates a new JSON object at an array index. Returns an error if the +// object is not an array or the index is out of bounds. +func (g *Container) ObjectI(index int) (*Container, error) { + return g.SetIndex(map[string]interface{}{}, index) +} + +// Array creates a new JSON array at a path. Returns an error if the path +// contains a collision with a non object type. +func (g *Container) Array(path ...string) (*Container, error) { + return g.Set([]interface{}{}, path...) +} + +// ArrayP creates a new JSON array at a path using dot notation. Returns an +// error if the path contains a collision with a non object type. +func (g *Container) ArrayP(path string) (*Container, error) { + return g.Array(strings.Split(path, ".")...) +} + +// ArrayI creates a new JSON array within an array at an index. Returns an error +// if the element is not an array or the index is out of bounds. +func (g *Container) ArrayI(index int) (*Container, error) { + return g.SetIndex([]interface{}{}, index) +} + +// ArrayOfSize creates a new JSON array of a particular size at a path. Returns +// an error if the path contains a collision with a non object type. +func (g *Container) ArrayOfSize(size int, path ...string) (*Container, error) { + a := make([]interface{}, size) + return g.Set(a, path...) +} + +// ArrayOfSizeP creates a new JSON array of a particular size at a path using +// dot notation. Returns an error if the path contains a collision with a non +// object type. +func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) { + return g.ArrayOfSize(size, strings.Split(path, ".")...) +} + +// ArrayOfSizeI create a new JSON array of a particular size within an array at +// an index. Returns an error if the element is not an array or the index is out +// of bounds. +func (g *Container) ArrayOfSizeI(size, index int) (*Container, error) { + a := make([]interface{}, size) + return g.SetIndex(a, index) +} + +// Delete an element at a path, an error is returned if the element does not +// exist. +func (g *Container) Delete(path ...string) error { + var object interface{} + + if g.object == nil { + return ErrNotObj + } + object = g.object + for target := 0; target < len(path); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + if target == len(path)-1 { + if _, ok := mmap[path[target]]; ok { + delete(mmap, path[target]) + } else { + return ErrNotObj + } + } + object = mmap[path[target]] + } else { + return ErrNotObj + } + } + return nil +} + +// DeleteP deletes an element at a path using dot notation, an error is returned +// if the element does not exist. +func (g *Container) DeleteP(path string) error { + return g.Delete(strings.Split(path, ".")...) +} + +// MergeFn merges two objects using a provided function to resolve collisions. +// +// The collision function receives two interface{} arguments, destination (the +// original object) and source (the object being merged into the destination). +// Which ever value is returned becomes the new value in the destination object +// at the location of the collision. +func (g *Container) MergeFn(source *Container, collisionFn func(destination, source interface{}) interface{}) error { + var recursiveFnc func(map[string]interface{}, []string) error + recursiveFnc = func(mmap map[string]interface{}, path []string) error { + for key, value := range mmap { + newPath := append(path, key) + if g.Exists(newPath...) { + existingData := g.Search(newPath...).Data() + switch t := value.(type) { + case map[string]interface{}: + switch existingVal := existingData.(type) { + case map[string]interface{}: + if err := recursiveFnc(t, newPath); err != nil { + return err + } + default: + if _, err := g.Set(collisionFn(existingVal, t), newPath...); err != nil { + return err + } + } + default: + if _, err := g.Set(collisionFn(existingData, t), newPath...); err != nil { + return err + } + } + } else { + // path doesn't exist. So set the value + if _, err := g.Set(value, newPath...); err != nil { + return err + } + } + } + return nil + } + if mmap, ok := source.Data().(map[string]interface{}); ok { + return recursiveFnc(mmap, []string{}) + } + return nil +} + +// Merge a source object into an existing destination object. When a collision +// is found within the merged structures (both a source and destination object +// contain the same non-object keys) the result will be an array containing both +// values, where values that are already arrays will be expanded into the +// resulting array. +// +// It is possible to merge structures will different collision behaviours with +// MergeFn. +func (g *Container) Merge(source *Container) error { + return g.MergeFn(source, func(dest, source interface{}) interface{} { + destArr, destIsArray := dest.([]interface{}) + sourceArr, sourceIsArray := source.([]interface{}) + if destIsArray { + if sourceIsArray { + return append(destArr, sourceArr...) + } + return append(destArr, source) + } + if sourceIsArray { + return append(append([]interface{}{}, dest), sourceArr...) + } + return []interface{}{dest, source} + }) +} + +//------------------------------------------------------------------------------ + +/* +Array modification/search - Keeping these options simple right now, no need for +anything more complicated since you can just cast to []interface{}, modify and +then reassign with Set. +*/ + +// ArrayAppend attempts to append a value onto a JSON array at a path. If the +// target is not a JSON array then it will be converted into one, with its +// original contents set to the first element of the array. +func (g *Container) ArrayAppend(value interface{}, path ...string) error { + if array, ok := g.Search(path...).Data().([]interface{}); ok { + array = append(array, value) + _, err := g.Set(array, path...) + return err + } + + newArray := []interface{}{} + if d := g.Search(path...).Data(); d != nil { + newArray = append(newArray, d) + } + newArray = append(newArray, value) + + _, err := g.Set(newArray, path...) + return err +} + +// ArrayAppendP attempts to append a value onto a JSON array at a path using dot +// notation. If the target is not a JSON array then it will be converted into +// one, with its original contents set to the first element of the array. +func (g *Container) ArrayAppendP(value interface{}, path string) error { + return g.ArrayAppend(value, strings.Split(path, ".")...) +} + +// ArrayRemove attempts to remove an element identified by an index from a JSON +// array at a path. +func (g *Container) ArrayRemove(index int, path ...string) error { + if index < 0 { + return ErrOutOfBounds + } + array, ok := g.Search(path...).Data().([]interface{}) + if !ok { + return ErrNotArray + } + if index < len(array) { + array = append(array[:index], array[index+1:]...) + } else { + return ErrOutOfBounds + } + _, err := g.Set(array, path...) + return err +} + +// ArrayRemoveP attempts to remove an element identified by an index from a JSON +// array at a path using dot notation. +func (g *Container) ArrayRemoveP(index int, path string) error { + return g.ArrayRemove(index, strings.Split(path, ".")...) +} + +// ArrayElement attempts to access an element by an index from a JSON array at a +// path. +func (g *Container) ArrayElement(index int, path ...string) (*Container, error) { + if index < 0 { + return &Container{nil}, ErrOutOfBounds + } + array, ok := g.Search(path...).Data().([]interface{}) + if !ok { + return &Container{nil}, ErrNotArray + } + if index < len(array) { + return &Container{array[index]}, nil + } + return &Container{nil}, ErrOutOfBounds +} + +// ArrayElementP attempts to access an element by an index from a JSON array at +// a path using dot notation. +func (g *Container) ArrayElementP(index int, path string) (*Container, error) { + return g.ArrayElement(index, strings.Split(path, ".")...) +} + +// ArrayCount counts the number of elements in a JSON array at a path. +func (g *Container) ArrayCount(path ...string) (int, error) { + if array, ok := g.Search(path...).Data().([]interface{}); ok { + return len(array), nil + } + return 0, ErrNotArray +} + +// ArrayCountP counts the number of elements in a JSON array at a path using dot +// notation. +func (g *Container) ArrayCountP(path string) (int, error) { + return g.ArrayCount(strings.Split(path, ".")...) +} + +//------------------------------------------------------------------------------ + +// Bytes marshals an element to a JSON []byte blob. +func (g *Container) Bytes() []byte { + if g.Data() != nil { + if bytes, err := json.Marshal(g.object); err == nil { + return bytes + } + } + return []byte("{}") +} + +// BytesIndent marshals an element to a JSON []byte blob formatted with a prefix +// and indent string. +func (g *Container) BytesIndent(prefix string, indent string) []byte { + if g.object != nil { + if bytes, err := json.MarshalIndent(g.object, prefix, indent); err == nil { + return bytes + } + } + return []byte("{}") +} + +// String marshals an element to a JSON formatted string. +func (g *Container) String() string { + return string(g.Bytes()) +} + +// StringIndent marshals an element to a JSON string formatted with a prefix and +// indent string. +func (g *Container) StringIndent(prefix string, indent string) string { + return string(g.BytesIndent(prefix, indent)) +} + +// EncodeOpt is a functional option for the EncodeJSON method. +type EncodeOpt func(e *json.Encoder) + +// EncodeOptHTMLEscape sets the encoder to escape the JSON for html. +func EncodeOptHTMLEscape(doEscape bool) EncodeOpt { + return func(e *json.Encoder) { + e.SetEscapeHTML(doEscape) + } +} + +// EncodeOptIndent sets the encoder to indent the JSON output. +func EncodeOptIndent(prefix string, indent string) EncodeOpt { + return func(e *json.Encoder) { + e.SetIndent(prefix, indent) + } +} + +// EncodeJSON marshals an element to a JSON formatted []byte using a variant +// list of modifier functions for the encoder being used. Functions for +// modifying the output are prefixed with EncodeOpt, e.g. EncodeOptHTMLEscape. +func (g *Container) EncodeJSON(encodeOpts ...EncodeOpt) []byte { + var b bytes.Buffer + encoder := json.NewEncoder(&b) + encoder.SetEscapeHTML(false) // Do not escape by default. + for _, opt := range encodeOpts { + opt(encoder) + } + if err := encoder.Encode(g.object); err != nil { + return []byte("{}") + } + result := b.Bytes() + if len(result) > 0 { + result = result[:len(result)-1] + } + return result +} + +// New creates a new gabs JSON object. +func New() *Container { + return &Container{map[string]interface{}{}} +} + +// Consume an already unmarshalled JSON object (or a new map[string]interface{}) +// into a *Container. +func Consume(root interface{}) (*Container, error) { + return &Container{root}, nil +} + +// ParseJSON unmarshals a JSON byte slice into a *Container. +func ParseJSON(sample []byte) (*Container, error) { + var gabs Container + + if err := json.Unmarshal(sample, &gabs.object); err != nil { + return nil, err + } + + return &gabs, nil +} + +// ParseJSONDecoder applies a json.Decoder to a *Container. +func ParseJSONDecoder(decoder *json.Decoder) (*Container, error) { + var gabs Container + + if err := decoder.Decode(&gabs.object); err != nil { + return nil, err + } + + return &gabs, nil +} + +// ParseJSONFile reads a file and unmarshals the contents into a *Container. +func ParseJSONFile(path string) (*Container, error) { + if len(path) > 0 { + cBytes, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + + container, err := ParseJSON(cBytes) + if err != nil { + return nil, err + } + + return container, nil + } + return nil, ErrInvalidPath +} + +// ParseJSONBuffer reads a buffer and unmarshals the contents into a *Container. +func ParseJSONBuffer(buffer io.Reader) (*Container, error) { + var gabs Container + jsonDecoder := json.NewDecoder(buffer) + if err := jsonDecoder.Decode(&gabs.object); err != nil { + return nil, err + } + + return &gabs, nil +} + +//------------------------------------------------------------------------------ diff --git a/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/gabs_logo.png b/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/gabs_logo.png Binary files differnew file mode 100644 index 0000000..b6c1fad --- /dev/null +++ b/teleirc/matterbridge/vendor/github.com/Jeffail/gabs/gabs_logo.png |
