...

Source file src/github.com/TylerBrock/colorjson/colorjson.go

Documentation: github.com/TylerBrock/colorjson

     1  package colorjson
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"sort"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/fatih/color"
    12  )
    13  
    14  const initialDepth = 0
    15  const valueSep = ","
    16  const null = "null"
    17  const startMap = "{"
    18  const endMap = "}"
    19  const startArray = "["
    20  const endArray = "]"
    21  
    22  const emptyMap = startMap + endMap
    23  const emptyArray = startArray + endArray
    24  
    25  type Formatter struct {
    26  	KeyColor        *color.Color
    27  	StringColor     *color.Color
    28  	BoolColor       *color.Color
    29  	NumberColor     *color.Color
    30  	NullColor       *color.Color
    31  	StringMaxLength int
    32  	Indent          int
    33  	DisabledColor   bool
    34  	RawStrings      bool
    35  }
    36  
    37  func NewFormatter() *Formatter {
    38  	return &Formatter{
    39  		KeyColor:        color.New(color.FgWhite),
    40  		StringColor:     color.New(color.FgGreen),
    41  		BoolColor:       color.New(color.FgYellow),
    42  		NumberColor:     color.New(color.FgCyan),
    43  		NullColor:       color.New(color.FgMagenta),
    44  		StringMaxLength: 0,
    45  		DisabledColor:   false,
    46  		Indent:          0,
    47  		RawStrings:      false,
    48  	}
    49  }
    50  
    51  func (f *Formatter) sprintfColor(c *color.Color, format string, args ...interface{}) string {
    52  	if f.DisabledColor || c == nil {
    53  		return fmt.Sprintf(format, args...)
    54  	}
    55  	return c.SprintfFunc()(format, args...)
    56  }
    57  
    58  func (f *Formatter) sprintColor(c *color.Color, s string) string {
    59  	if f.DisabledColor || c == nil {
    60  		return fmt.Sprint(s)
    61  	}
    62  	return c.SprintFunc()(s)
    63  }
    64  
    65  func (f *Formatter) writeIndent(buf *bytes.Buffer, depth int) {
    66  	buf.WriteString(strings.Repeat(" ", f.Indent*depth))
    67  }
    68  
    69  func (f *Formatter) writeObjSep(buf *bytes.Buffer) {
    70  	if f.Indent != 0 {
    71  		buf.WriteByte('\n')
    72  	} else {
    73  		buf.WriteByte(' ')
    74  	}
    75  }
    76  
    77  func (f *Formatter) Marshal(jsonObj interface{}) ([]byte, error) {
    78  	buffer := bytes.Buffer{}
    79  	f.marshalValue(jsonObj, &buffer, initialDepth)
    80  	return buffer.Bytes(), nil
    81  }
    82  
    83  func (f *Formatter) marshalMap(m map[string]interface{}, buf *bytes.Buffer, depth int) {
    84  	remaining := len(m)
    85  
    86  	if remaining == 0 {
    87  		buf.WriteString(emptyMap)
    88  		return
    89  	}
    90  
    91  	keys := make([]string, 0)
    92  	for key := range m {
    93  		keys = append(keys, key)
    94  	}
    95  
    96  	sort.Strings(keys)
    97  
    98  	buf.WriteString(startMap)
    99  	f.writeObjSep(buf)
   100  
   101  	for _, key := range keys {
   102  		f.writeIndent(buf, depth+1)
   103  		buf.WriteString(f.KeyColor.Sprintf("\"%s\": ", key))
   104  		f.marshalValue(m[key], buf, depth+1)
   105  		remaining--
   106  		if remaining != 0 {
   107  			buf.WriteString(valueSep)
   108  		}
   109  		f.writeObjSep(buf)
   110  	}
   111  	f.writeIndent(buf, depth)
   112  	buf.WriteString(endMap)
   113  }
   114  
   115  func (f *Formatter) marshalArray(a []interface{}, buf *bytes.Buffer, depth int) {
   116  	if len(a) == 0 {
   117  		buf.WriteString(emptyArray)
   118  		return
   119  	}
   120  
   121  	buf.WriteString(startArray)
   122  	f.writeObjSep(buf)
   123  
   124  	for i, v := range a {
   125  		f.writeIndent(buf, depth+1)
   126  		f.marshalValue(v, buf, depth+1)
   127  		if i < len(a)-1 {
   128  			buf.WriteString(valueSep)
   129  		}
   130  		f.writeObjSep(buf)
   131  	}
   132  	f.writeIndent(buf, depth)
   133  	buf.WriteString(endArray)
   134  }
   135  
   136  func (f *Formatter) marshalValue(val interface{}, buf *bytes.Buffer, depth int) {
   137  	switch v := val.(type) {
   138  	case map[string]interface{}:
   139  		f.marshalMap(v, buf, depth)
   140  	case []interface{}:
   141  		f.marshalArray(v, buf, depth)
   142  	case string:
   143  		f.marshalString(v, buf)
   144  	case float64:
   145  		buf.WriteString(f.sprintColor(f.NumberColor, strconv.FormatFloat(v, 'f', -1, 64)))
   146  	case bool:
   147  		buf.WriteString(f.sprintColor(f.BoolColor, (strconv.FormatBool(v))))
   148  	case nil:
   149  		buf.WriteString(f.sprintColor(f.NullColor, null))
   150  	case json.Number:
   151  		buf.WriteString(f.sprintColor(f.NumberColor, v.String()))
   152  	}
   153  }
   154  
   155  func (f *Formatter) marshalString(str string, buf *bytes.Buffer) {
   156  	if !f.RawStrings {
   157  		strBytes, _ := json.Marshal(str)
   158  		str = string(strBytes)
   159  	}
   160  
   161  	if f.StringMaxLength != 0 && len(str) >= f.StringMaxLength {
   162  		str = fmt.Sprintf("%s...", str[0:f.StringMaxLength])
   163  	}
   164  
   165  	buf.WriteString(f.sprintColor(f.StringColor, str))
   166  }
   167  
   168  // Marshal JSON data with default options
   169  func Marshal(jsonObj interface{}) ([]byte, error) {
   170  	return NewFormatter().Marshal(jsonObj)
   171  }
   172  

View as plain text