feat(colorsync): hard fork for maintenance

This commit is contained in:
AJ ONeal 2025-10-02 23:10:11 -06:00
parent 5eb3592744
commit 535bf2f824
No known key found for this signature in database
9 changed files with 390 additions and 0 deletions

22
colorjson/LICENSE Normal file
View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2017 Tyler Brock
Copyright (c) 2025 AJ ONeal
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.

65
colorjson/README.md Normal file
View File

@ -0,0 +1,65 @@
# ColorJSON: The Fast Color JSON Marshaller for Go
![ColorJSON Output](https://i.imgur.com/pLtCXhb.png)
## What is this?
This package is based heavily on hokaccha/go-prettyjson but has some noticeable differences:
- Over twice as fast (recursive descent serialization uses buffer instead of string concatenation)
```
BenchmarkColorJSONMarshall-4 500000 2498 ns/op
BenchmarkPrettyJSON-4 200000 6145 ns/op
```
- more customizable (ability to have zero indent, print raw json strings, etc...)
- better defaults (less bold colors)
ColorJSON was built in order to produce fast beautiful colorized JSON output for [Saw](http://github.com/TylerBrock/saw).
## Installation
```sh
go get -u github.com/therootcompany/golib/colorjson
```
## Usage
Setup
```go
import "github.com/therootcompany/golib/colorjson"
str := `{
"str": "foo",
"num": 100,
"bool": false,
"null": null,
"array": ["foo", "bar", "baz"],
"obj": { "a": 1, "b": 2 }
}`
// Create an intersting JSON object to marshal in a pretty format
var obj map[string]interface{}
json.Unmarshal([]byte(str), &obj)
```
Vanilla Usage
```go
s, _ := colorjson.Marshal(obj)
fmt.Println(string(s))
```
Customization (Custom Indent)
```go
f := colorjson.NewFormatter()
f.Indent = 2
s, _ := f.Marshal(v)
fmt.Println(string(s))
```
## License
This is a fork of <https://github.com/TylerBrock/colorjson> for maintenance.

View File

@ -0,0 +1,39 @@
package colorjson_test
import (
"testing"
"github.com/therootcompany/golib/colorjson"
"github.com/hokaccha/go-prettyjson"
)
func benchmarkMarshall(i int, b *testing.B) {
simpleMap := make(map[string]interface{})
simpleMap["a"] = 1
simpleMap["b"] = "bee"
simpleMap["c"] = [3]float64{1, 2, 3}
simpleMap["d"] = [3]string{"one", "two", "three"}
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
colorjson.Marshal(simpleMap)
}
}
func benchmarkPrettyJSON(i int, b *testing.B) {
simpleMap := make(map[string]interface{})
simpleMap["a"] = 1
simpleMap["b"] = "bee"
simpleMap["c"] = [3]float64{1, 2, 3}
simpleMap["d"] = [3]string{"one", "two", "three"}
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
prettyjson.Marshal(simpleMap)
}
}
func BenchmarkMarshall(b *testing.B) { benchmarkMarshall(100, b) }
func BenchmarkMarshall1k(b *testing.B) { benchmarkMarshall(1000, b) }
func BenchmarkPrettyJSON(b *testing.B) { benchmarkPrettyJSON(100, b) }
func BenchmarkPrettyJSON1k(b *testing.B) { benchmarkPrettyJSON(1000, b) }

View File

@ -0,0 +1,15 @@
module github.com/therootcompany/golib/colorjson/benchmarks
go 1.18.0
require (
github.com/therootcompany/golib/colorjson v0.0.0-20200706003622-8a50f05110d2
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f
)
require (
github.com/fatih/color v1.18.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.25.0 // indirect
)

171
colorjson/colorjson.go Normal file
View File

@ -0,0 +1,171 @@
package colorjson
import (
"bytes"
"encoding/json"
"fmt"
"sort"
"strconv"
"strings"
"github.com/fatih/color"
)
const initialDepth = 0
const valueSep = ","
const null = "null"
const startMap = "{"
const endMap = "}"
const startArray = "["
const endArray = "]"
const emptyMap = startMap + endMap
const emptyArray = startArray + endArray
type Formatter struct {
KeyColor *color.Color
StringColor *color.Color
BoolColor *color.Color
NumberColor *color.Color
NullColor *color.Color
StringMaxLength int
Indent int
DisabledColor bool
RawStrings bool
}
func NewFormatter() *Formatter {
return &Formatter{
KeyColor: color.New(color.FgWhite),
StringColor: color.New(color.FgGreen),
BoolColor: color.New(color.FgYellow),
NumberColor: color.New(color.FgCyan),
NullColor: color.New(color.FgMagenta),
StringMaxLength: 0,
DisabledColor: false,
Indent: 0,
RawStrings: false,
}
}
func (f *Formatter) sprintfColor(c *color.Color, format string, args ...interface{}) string {
if f.DisabledColor || c == nil {
return fmt.Sprintf(format, args...)
}
return c.SprintfFunc()(format, args...)
}
func (f *Formatter) sprintColor(c *color.Color, s string) string {
if f.DisabledColor || c == nil {
return fmt.Sprint(s)
}
return c.SprintFunc()(s)
}
func (f *Formatter) writeIndent(buf *bytes.Buffer, depth int) {
buf.WriteString(strings.Repeat(" ", f.Indent*depth))
}
func (f *Formatter) writeObjSep(buf *bytes.Buffer) {
if f.Indent != 0 {
buf.WriteByte('\n')
} else {
buf.WriteByte(' ')
}
}
func (f *Formatter) Marshal(jsonObj interface{}) ([]byte, error) {
buffer := bytes.Buffer{}
f.marshalValue(jsonObj, &buffer, initialDepth)
return buffer.Bytes(), nil
}
func (f *Formatter) marshalMap(m map[string]interface{}, buf *bytes.Buffer, depth int) {
remaining := len(m)
if remaining == 0 {
buf.WriteString(emptyMap)
return
}
keys := make([]string, 0)
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
buf.WriteString(startMap)
f.writeObjSep(buf)
for _, key := range keys {
f.writeIndent(buf, depth+1)
buf.WriteString(f.KeyColor.Sprintf("\"%s\": ", key))
f.marshalValue(m[key], buf, depth+1)
remaining--
if remaining != 0 {
buf.WriteString(valueSep)
}
f.writeObjSep(buf)
}
f.writeIndent(buf, depth)
buf.WriteString(endMap)
}
func (f *Formatter) marshalArray(a []interface{}, buf *bytes.Buffer, depth int) {
if len(a) == 0 {
buf.WriteString(emptyArray)
return
}
buf.WriteString(startArray)
f.writeObjSep(buf)
for i, v := range a {
f.writeIndent(buf, depth+1)
f.marshalValue(v, buf, depth+1)
if i < len(a)-1 {
buf.WriteString(valueSep)
}
f.writeObjSep(buf)
}
f.writeIndent(buf, depth)
buf.WriteString(endArray)
}
func (f *Formatter) marshalValue(val interface{}, buf *bytes.Buffer, depth int) {
switch v := val.(type) {
case map[string]interface{}:
f.marshalMap(v, buf, depth)
case []interface{}:
f.marshalArray(v, buf, depth)
case string:
f.marshalString(v, buf)
case float64:
buf.WriteString(f.sprintColor(f.NumberColor, strconv.FormatFloat(v, 'f', -1, 64)))
case bool:
buf.WriteString(f.sprintColor(f.BoolColor, (strconv.FormatBool(v))))
case nil:
buf.WriteString(f.sprintColor(f.NullColor, null))
case json.Number:
buf.WriteString(f.sprintColor(f.NumberColor, v.String()))
}
}
func (f *Formatter) marshalString(str string, buf *bytes.Buffer) {
if !f.RawStrings {
strBytes, _ := json.Marshal(str)
str = string(strBytes)
}
if f.StringMaxLength != 0 && len(str) >= f.StringMaxLength {
str = fmt.Sprintf("%s...", str[0:f.StringMaxLength])
}
buf.WriteString(f.sprintColor(f.StringColor, str))
}
// Marshal JSON data with default options
func Marshal(jsonObj interface{}) ([]byte, error) {
return NewFormatter().Marshal(jsonObj)
}

View File

@ -0,0 +1,30 @@
package main
import (
"encoding/json"
"fmt"
"github.com/therootcompany/golib/colorjson"
)
func main() {
str := `{
"str": "foo",
"num": 100,
"bool": false,
"null": null,
"array": ["foo", "bar", "baz"],
"obj": { "a": 1, "b": 2 }
}`
var obj map[string]interface{}
json.Unmarshal([]byte(str), &obj)
// Make a custom formatter with indent set
f := colorjson.NewFormatter()
f.Indent = 4
// Marshall the Colorized JSON
s, _ := f.Marshal(obj)
fmt.Println(string(s))
}

View File

@ -0,0 +1,26 @@
package main
import (
"encoding/json"
"fmt"
"github.com/therootcompany/golib/colorjson"
)
func main() {
str := `{
"str": "foo",
"num": 100,
"bool": false,
"null": null,
"array": ["foo", "bar", "baz"],
"obj": { "a": 1, "b": 2 }
}`
var obj map[string]interface{}
json.Unmarshal([]byte(str), &obj)
// Marshall the Colorized JSON
s, _ := colorjson.Marshal(obj)
fmt.Println(string(s))
}

11
colorjson/go.mod Normal file
View File

@ -0,0 +1,11 @@
module github.com/therootcompany/golib/colorjson
go 1.18.0
require github.com/fatih/color v1.18.0
require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.25.0 // indirect
)

11
colorjson/go.sum Normal file
View File

@ -0,0 +1,11 @@
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=