encoding

package
v0.1.24 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 13, 2026 License: GPL-3.0 Imports: 11 Imported by: 0

README

encoding

encoding is a Go library providing utilities for JSON encoding, decoding, and formatting. It offers convenient wrappers around Go's standard encoding/json package plus advanced features like pretty-printing, minification, and colorized output for JSON data.

Overview

The encoding package simplifies JSON operations in Go by providing:

  • JSON Marshaling/Unmarshaling: Simplified wrappers for encoding and decoding
  • Pretty Printing: Format JSON with customizable indentation and styling
  • Minification: Remove whitespace from JSON (uglify)
  • Color Styling: Apply syntax highlighting for terminal output
  • Flexible Options: Customize width, sorting, indentation, and prefixes

Problem Solved: Working with JSON in Go requires verbose error handling and lacks built-in pretty-printing with customization. This package provides clean, reusable functions with sensible defaults while offering advanced formatting options when needed.

Use Cases

When to Use
  • API development - marshal/unmarshal JSON request/response bodies
  • Configuration files - read/write JSON config with pretty formatting
  • Logging - format JSON logs with indentation for readability
  • CLI tools - output formatted JSON to terminals with colors
  • Debugging - pretty-print JSON for easier inspection
  • JSON minification - reduce JSON size for transmission
  • Testing - create readable JSON test fixtures
  • Documentation - generate formatted JSON examples
When Not to Use
  • High-performance streaming - use encoding/json Encoder/Decoder directly
  • Custom JSON parsers - when you need non-standard JSON handling
  • Binary protocols - use Protocol Buffers, MessagePack, etc.
  • Complex transformations - consider dedicated JSON processing libraries
  • Schema validation - use JSON Schema validators

Installation

go get github.com/sivaosorg/replify

Import the package in your Go code:

import "github.com/sivaosorg/replify/pkg/encoding"

Requirements: Go 1.13 or higher

Usage

Quick Start
package main

import (
    "fmt"
    "github.com/sivaosorg/replify/pkg/encoding"
)

func main() {
    // Create a struct
    type User struct {
        Name  string `json:"name"`
        Age   int    `json:"age"`
        Email string `json:"email"`
    }
    
    user := User{Name: "Alice", Age: 30, Email: "alice@example.com"}
    
    // Marshal to JSON
    jsonBytes, err := encoding.MarshalJSONb(user)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(jsonBytes))
    // Output: {"name":"Alice","age":30,"email":"alice@example.com"}
    
    // Pretty print
    pretty := encoding.Pretty(jsonBytes)
    fmt.Println(string(pretty))
    // Output:
    // {
    //   "name": "Alice",
    //   "age": 30,
    //   "email": "alice@example.com"
    // }
}

Examples

1. Basic JSON Marshaling
package main

import (
	"fmt"
	"log"

	"github.com/sivaosorg/replify/pkg/encoding"
)

func main() {
	type Product struct {
		ID    int     `json:"id"`
		Name  string  `json:"name"`
		Price float64 `json:"price"`
	}

	product := Product{ID: 1, Name: "Laptop", Price: 999.99}

	// Marshal to bytes
	jsonBytes, err := encoding.MarshalJSONb(product)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(jsonBytes))
	// Output: {"id":1,"name":"Laptop","price":999.99}

	// Marshal to string directly
	jsonString, err := encoding.MarshalJSONs(product)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(jsonString)
	// Output: {"id":1,"name":"Laptop","price":999.99}

	// Marshal with indentation
	indented, err := encoding.MarshalJSONIndent(product, "", "  ")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(indented))
	// Output:
	//
	//	{
	//	  "id": 1,
	//	  "name": "Laptop",
	//	  "price": 999.99
	//	}
}
2. JSON Unmarshaling
package main

import (
	"fmt"
	"log"

	"github.com/sivaosorg/replify/pkg/encoding"
)

func main() {
	type User struct {
		Name  string `json:"name"`
		Age   int    `json:"age"`
		Email string `json:"email"`
	}

	// From bytes
	jsonBytes := []byte(`{"name":"Bob","age":25,"email":"bob@example.com"}`)
	var user User
	err := encoding.UnmarshalBytes(jsonBytes, &user)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", user)
	// Output: {Name:Bob Age:25 Email:bob@example.com}

	// From string
	jsonString := `{"name":"Charlie","age":35,"email":"charlie@example.com"}`
	var anotherUser User
	err = encoding.UnmarshalJSON(jsonString, &anotherUser)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%+v\n", anotherUser)
	// Output: {Name:Charlie Age:35 Email:charlie@example.com}
}
3. Pretty Printing JSON
// Compact JSON
compact := []byte(`{"name":"Alice","age":30,"hobbies":["reading","coding","gaming"],"address":{"city":"New York","zip":"10001"}}`)

// Default pretty printing
pretty := encoding.Pretty(compact)
fmt.Println(string(pretty))
// Output:
// {
//   "name": "Alice",
//   "age": 30,
//   "hobbies": [
//     "reading",
//     "coding",
//     "gaming"
//   ],
//   "address": {
//     "city": "New York",
//     "zip": "10001"
//   }
// }

// Custom options
options := &encoding.OptionsConfig{
    Width:    120,
    Prefix:   "  ",
    Indent:   "    ",
    SortKeys: true,
}
customPretty := encoding.PrettyOptions(compact, options)
fmt.Println(string(customPretty))
// Output: (with custom indentation and sorted keys)
4. JSON Minification (Uglify)
// Pretty JSON with whitespace
prettyJSON := []byte(`{
  "name": "Alice",
  "age": 30,
  "email": "alice@example.com"
}`)

// Remove all whitespace
minified := encoding.Ugly(prettyJSON)
fmt.Println(string(minified))
// Output: {"name":"Alice","age":30,"email":"alice@example.com"}

// In-place uglification (reuses buffer)
encoding.UglyInPlace(prettyJSON)
fmt.Println(string(prettyJSON))
// Output: {"name":"Alice","age":30,"email":"alice@example.com"}
5. Pretty Printing with Custom Options
type Config struct {
    Server   string            `json:"server"`
    Port     int               `json:"port"`
    Features map[string]bool   `json:"features"`
    Users    []string          `json:"users"`
}

config := Config{
    Server: "localhost",
    Port:   8080,
    Features: map[string]bool{
        "logging":     true,
        "compression": false,
        "caching":     true,
    },
    Users: []string{"admin", "user1", "user2"},
}

jsonBytes, _ := encoding.Marshal(config)

// Option 1: Wide format (arrays on single line if they fit)
wideOptions := &encoding.OptionsConfig{
    Width:    120,
    Indent:   "  ",
    SortKeys: true,
}
wide := encoding.PrettyOptions(jsonBytes, wideOptions)
fmt.Println(string(wide))

// Option 2: Narrow format (more line breaks)
narrowOptions := &encoding.OptionsConfig{
    Width:    40,
    Indent:   "  ",
    SortKeys: false,
}
narrow := encoding.PrettyOptions(jsonBytes, narrowOptions)
fmt.Println(string(narrow))

// Option 3: With prefix (useful for logs)
prefixOptions := &encoding.OptionsConfig{
    Width:    80,
    Prefix:   "[JSON] ",
    Indent:   "  ",
    SortKeys: true,
}
prefixed := encoding.PrettyOptions(jsonBytes, prefixOptions)
fmt.Println(string(prefixed))
6. Sorting JSON Keys
unsortedJSON := []byte(`{"zebra":1,"apple":2,"banana":3}`)

// Pretty print with sorted keys
options := &encoding.OptionsConfig{
    Width:    80,
    Indent:   "  ",
    SortKeys: true,
}
sorted := encoding.PrettyOptions(unsortedJSON, options)
fmt.Println(string(sorted))
// Output:
// {
//   "apple": 2,
//   "banana": 3,
//   "zebra": 1
// }
7. Practical Use Cases
API Response Formatting
type APIResponse struct {
    Status  string      `json:"status"`
    Data    interface{} `json:"data"`
    Message string      `json:"message"`
}

func formatResponse(data interface{}) (string, error) {
    response := APIResponse{
        Status:  "success",
        Data:    data,
        Message: "Request processed successfully",
    }
    
    return encoding.MarshalJSONs(response)
}

// Usage
jsonString, err := formatResponse(map[string]int{"count": 42})
if err != nil {
    log.Fatal(err)
}
fmt.Println(jsonString)
Configuration File Handling
type AppConfig struct {
    Database DatabaseConfig `json:"database"`
    Server   ServerConfig   `json:"server"`
    Logging  LoggingConfig  `json:"logging"`
}

func SaveConfig(config AppConfig, filename string) error {
    // Marshal with indentation for readability
    data, err := encoding.MarshalJSONIndent(config, "", "  ")
    if err != nil {
        return err
    }
    
    return os.WriteFile(filename, data, 0644)
}

func LoadConfig(filename string) (*AppConfig, error) {
    data, err := os.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    
    var config AppConfig
    err = encoding.UnmarshalBytes(data, &config)
    return &config, err
}
Debug Logging
func LogJSON(label string, data interface{}) {
    jsonBytes, err := encoding.MarshalJSONb(data)
    if err != nil {
        log.Printf("[ERROR] Failed to marshal %s: %v", label, err)
        return
    }
    
    // Pretty print for logs
    pretty := encoding.Pretty(jsonBytes)
    log.Printf("[DEBUG] %s:\n%s", label, string(pretty))
}

// Usage
user := User{Name: "Alice", Age: 30}
LogJSON("User Data", user)
HTTP Request/Response
func HandleRequest(w http.ResponseWriter, r *http.Request) {
    var requestData map[string]interface{}
    
    // Unmarshal request body
    body, _ := io.ReadAll(r.Body)
    if err := encoding.UnmarshalBytes(body, &requestData); err != nil {
        http.Error(w, "Invalid JSON", http.StatusBadRequest)
        return
    }
    
    // Process data...
    responseData := map[string]interface{}{
        "status": "success",
        "data":   requestData,
    }
    
    // Marshal response
    jsonBytes, _ := encoding.MarshalJSONb(responseData)
    w.Header().Set("Content-Type", "application/json")
    w.Write(jsonBytes)
}
CLI Output Formatting
func DisplayResults(results []Result) {
    jsonBytes, err := encoding.MarshalJSONb(results)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        return
    }
    
    // Pretty print for terminal
    pretty := encoding.Pretty(jsonBytes)
    fmt.Println(string(pretty))
}
8. Working with Complex Nested Structures
type Company struct {
    Name       string       `json:"name"`
    Employees  []Employee   `json:"employees"`
    Departments []Department `json:"departments"`
}

type Employee struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

type Department struct {
    Name    string   `json:"name"`
    Manager string   `json:"manager"`
    Members []int    `json:"member_ids"`
}

company := Company{
    Name: "TechCorp",
    Employees: []Employee{
        {ID: 1, Name: "Alice", Email: "alice@techcorp.com"},
        {ID: 2, Name: "Bob", Email: "bob@techcorp.com"},
    },
    Departments: []Department{
        {Name: "Engineering", Manager: "Alice", Members: []int{1, 2}},
    },
}

// Marshal and pretty print
jsonBytes, _ := encoding.MarshalJSONb(company)
pretty := encoding.Pretty(jsonBytes)
fmt.Println(string(pretty))

API Reference

Core Functions
Marshal Functions
Function Signature Description
MarshalJSONb (v any) ([]byte, error) Convert Go value to JSON bytes
MarshalJSONs (v any) (string, error) Convert Go value to JSON string
MarshalJSONIndent (v any, prefix, indent string) ([]byte, error) Convert Go value to indented JSON

Examples:

bytes, err := encoding.MarshalJSONb(data)
str, err := encoding.MarshalJSONs(data)
indented, err := encoding.MarshalJSONIndent(data, "", "  ")

Unmarshal Functions
Function Signature Description
UnmarshalBytes (data []byte, v any) error Parse JSON bytes into Go value
UnmarshalJSON (str string, v any) error Parse JSON string into Go value

Examples:

err := encoding.UnmarshalBytes(jsonBytes, &myStruct)
err := encoding.UnmarshalJSON(jsonString, &myStruct)

Formatting Functions
Function Signature Description
Pretty (json []byte) []byte Format JSON with default options
PrettyOptions (json []byte, opts *OptionsConfig) []byte Format JSON with custom options
Ugly (json []byte) []byte Remove whitespace (minify JSON)
UglyInPlace (json []byte) []byte Minify JSON in-place (reuses buffer)

Examples:

pretty := encoding.Pretty(compactJSON)
custom := encoding.PrettyOptions(json, options)
minified := encoding.Ugly(prettyJSON)

Options Configuration
OptionsConfig Struct
type OptionsConfig struct {
    Width    int    // Max column width for single-line arrays (default: 80)
    Prefix   string // Prefix for all lines (default: "")
    Indent   string // Indentation string (default: "  ")
    SortKeys bool   // Sort object keys alphabetically (default: false)
}

Fields:

  • Width: Maximum column width before wrapping arrays/objects (default: 80 characters)
  • Prefix: String prepended to each line (useful for logging)
  • Indent: Indentation string (typically " " or " ")
  • SortKeys: Whether to sort JSON object keys alphabetically

Example:

options := &encoding.OptionsConfig{
    Width:    120,
    Prefix:   "[LOG] ",
    Indent:   "    ",
    SortKeys: true,
}
formatted := encoding.PrettyOptions(jsonBytes, options)

Default Configuration
var DefaultOptionsConfig = &OptionsConfig{
    Width:    80,
    Prefix:   "",
    Indent:   "  ",
    SortKeys: false,
}

Use this when calling Pretty() or pass nil to PrettyOptions().

Best Practices & Notes

⚠️ Common Pitfalls
  1. Forgetting Error Handling

    // ❌ Bad: ignoring errors
    jsonBytes, _ := encoding.MarshalJSONb(data)
    
    // ✅ Good: handle errors
    jsonBytes, err := encoding.MarshalJSONb(data)
    if err != nil {
        log.Printf("Failed to marshal: %v", err)
        return err
    }
    
  2. Unmarshaling into Wrong Type

    // ❌ Bad: unmarshaling into non-pointer
    var user User
    encoding.UnmarshalBytes(data, user) // Won't work!
    
    // ✅ Good: pass pointer
    var user User
    encoding.UnmarshalBytes(data, &user)
    
  3. Using Pretty in Production APIs

    // ❌ Bad: pretty-printing adds overhead
    jsonBytes, _ := encoding.MarshalJSONb(data)
    pretty := encoding.Pretty(jsonBytes)
    w.Write(pretty) // Extra processing!
    
    // ✅ Good: use compact format
    jsonBytes, _ := encoding.MarshalJSONb(data)
    w.Write(jsonBytes)
    
  4. Modifying Original Buffer with UglyInPlace

    // ⚠️ Warning: modifies original
    original := []byte(`{ "key": "value" }`)
    minified := encoding.UglyInPlace(original)
    // original is now modified!
    
    // ✅ Safe: use Ugly for new buffer
    minified := encoding.Ugly(original)
    // original unchanged
    
💡 Recommendations

Use appropriate functions for the context

// For APIs: compact format
jsonBytes, _ := encoding.MarshalJSONb(data)

// For configuration files: indented format
indented, _ := encoding.MarshalJSONIndent(config, "", "  ")

// For debugging: pretty print
pretty := encoding.Pretty(jsonBytes)

// For transmission: minified
minified := encoding.Ugly(jsonBytes)

Validate input before unmarshaling

func SafeUnmarshal(data []byte, v interface{}) error {
    if len(data) == 0 {
        return errors.New("empty JSON data")
    }
    
    if !json.Valid(data) {
        return errors.New("invalid JSON")
    }
    
    return encoding.UnmarshalBytes(data, v)
}

Use struct tags for control

type User struct {
    ID        int    `json:"id"`
    Name      string `json:"name"`
    Password  string `json:"-"`              // Never marshaled
    CreatedAt time.Time `json:"created_at,omitempty"` // Omit if zero
}

Cache OptionsConfig for reuse

var prettyOptions = &encoding.OptionsConfig{
    Width:    120,
    Indent:   "  ",
    SortKeys: true,
}

// Reuse in multiple places
formatted1 := encoding.PrettyOptions(json1, prettyOptions)
formatted2 := encoding.PrettyOptions(json2, prettyOptions)

Handle edge cases

// Empty JSON
empty := []byte(`{}`)
pretty := encoding.Pretty(empty) // Safe

// Null values
null := []byte(`null`)
pretty = encoding.Pretty(null) // Safe

// Arrays
array := []byte(`[1,2,3]`)
pretty = encoding.Pretty(array) // Safe
🔒 Thread Safety

All functions are thread-safe as they don't maintain internal state. Safe for concurrent use:

var wg sync.WaitGroup
for i := 0; i < 100; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        data := getData(id)
        jsonBytes, _ := encoding.MarshalJSONb(data)
        pretty := encoding.Pretty(jsonBytes)
        // Safe concurrent use
    }(i)
}
wg.Wait()
⚡ Performance Tips

Fast operations:

  • MarshalJSONb - Direct encoding/json wrapper
  • UnmarshalBytes - Direct encoding/json wrapper
  • UglyInPlace - Modifies in-place (no allocation)

Moderate operations:

  • Ugly - Creates new buffer
  • Pretty - Formatting overhead
  • MarshalJSONIndent - Extra formatting

Slower operations:

  • PrettyOptions with SortKeys: true - Sorting overhead

Optimization strategies:

// ✅ Reuse buffers
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.Encode(data)

// ✅ Skip pretty-printing in production
if !debug {
    w.Write(jsonBytes) // Compact
} else {
    w.Write(encoding.Pretty(jsonBytes)) // Readable
}

// ✅ Use streaming for large data
encoder := json.NewEncoder(w)
encoder.Encode(data)
🐛 Debugging Tips

Validate JSON before processing:

import "encoding/json"

if !json.Valid(data) {
    fmt.Println("Invalid JSON")
}

Pretty-print for inspection:

fmt.Println("Before:", string(data))
pretty := encoding.Pretty(data)
fmt.Println("After:", string(pretty))

Check types:

var v interface{}
encoding.UnmarshalBytes(data, &v)
fmt.Printf("Type: %T, Value: %v\n", v, v)
📝 Testing

Example test cases:

func TestMarshalUnmarshal(t *testing.T) {
    type TestStruct struct {
        Name  string `json:"name"`
        Value int    `json:"value"`
    }
    
    original := TestStruct{Name: "test", Value: 42}
    
    // Marshal
    jsonBytes, err := encoding.MarshalJSONb(original)
    if err != nil {
        t.Fatalf("Marshal failed: %v", err)
    }
    
    // Unmarshal
    var result TestStruct
    err = encoding.UnmarshalBytes(jsonBytes, &result)
    if err != nil {
        t.Fatalf("Unmarshal failed: %v", err)
    }
    
    if result != original {
        t.Errorf("Got %+v, want %+v", result, original)
    }
}

func TestPrettyFormatting(t *testing.T) {
    compact := []byte(`{"name":"test","value":42}`)
    pretty := encoding.Pretty(compact)
    
    // Check that output is longer (has whitespace)
    if len(pretty) <= len(compact) {
        t.Error("Pretty output should be longer than compact")
    }
    
    // Check it's still valid JSON
    var v interface{}
    if err := encoding.UnmarshalBytes(pretty, &v); err != nil {
        t.Errorf("Pretty output is not valid JSON: %v", err)
    }
}

Limitations

  • Not a JSON validator: Use json.Valid() from standard library for validation
  • No streaming support: For large files, use json.Encoder/Decoder
  • No custom encoding: Uses standard encoding/json under the hood
  • Pretty-printing overhead: Adds processing time and memory
  • No comments support: JSON doesn't support comments by spec

When to Use Standard Library

Use encoding/json directly when you need:

  • Streaming: json.Encoder/json.Decoder for large files
  • Custom marshaling: Implement json.Marshaler/json.Unmarshaler
  • Raw messages: json.RawMessage for deferred parsing
  • Number precision: json.Number for exact numeric handling

Contributing

Contributions are welcome! Please see the main replify repository for contribution guidelines.

License

This library is part of the replify project.

Part of the replify ecosystem:

  • replify - API response wrapping library
  • conv - Type conversion utilities
  • hashy - Deterministic hashing
  • match - Wildcard pattern matching
  • coll - Collection utilities
  • strutil - String utilities
  • randn - Random data generation

Documentation

Overview

Package encoding provides utilities for marshalling, unmarshalling, validating, normalising, and pretty-printing JSON data.

The package wraps the standard encoding/json library with additional safety, convenience, and formatting capabilities used throughout replify.

Marshalling and Unmarshalling

MarshalJSONb and MarshalJSONs marshal any Go value to []byte or string respectively. MarshalJSONIndent produces human-readable output with a configurable prefix and indent string. UnmarshalBytes and UnmarshalJSON are thin wrappers around json.Unmarshal; their Safe variants additionally reject empty input and syntactically invalid JSON before attempting deserialisation.

Validation and Normalisation

IsValidJSON and IsValidJSONBytes report whether a string or byte slice constitutes valid JSON. NormalizeJSON attempts to repair common malformations — leading UTF-8 BOMs, embedded null bytes, escaped structural quotes, and trailing commas — returning valid JSON or an error:

normalized, err := encoding.NormalizeJSON(`{\"key\": "value",}`)
// normalized: {"key": "value"}

Safe JSON Conversion

JSON and JSONToken convert any Go value to a JSON string, handling nil interfaces, raw json.RawMessage pass-through, scalar fast paths, and non-finite floating-point values (NaN / ±Inf are mapped to "null"). JSONPretty and JSONPrettyToken produce indented output. The Token variants return an explicit error instead of an empty string sentinel.

Pretty Printing

Pretty and Color format an existing JSON byte slice with configurable indentation, key/value alignment, and optional ANSI terminal colouring. Several predefined Style values are provided: TerminalStyle, VSCodeDarkStyle, DraculaStyle, MonokaiStyle, SolarizedDarkStyle, and MinimalGrayStyle.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNilInterface          = errors.New("nil interface input")
	ErrInvalidRawMessage     = errors.New("invalid json.RawMessage")
	ErrNonFiniteFloat        = errors.New("non-finite float (NaN/Inf)")
	ErrUnsupportedValue      = errors.New("unsupported value (e.g., non-nil func, chan, etc.)")
	ErrMarshalPanicRecovered = errors.New("json marshal panic recovered")
	ErrEmptyInput            = errors.New("empty input")
	ErrInvalidJSON           = errors.New("invalid JSON")
)

Error messages for JSON operations.

  • ErrNilInterface is returned when a nil interface is passed to a JSON function.
  • ErrInvalidRawMessage is returned when an invalid json.RawMessage is passed to a JSON function.
  • ErrNonFiniteFloat is returned when a non-finite float (NaN/Inf) is passed to a JSON function.
  • ErrUnsupportedValue is returned when an unsupported value (e.g., non-nil func, chan, etc.) is passed to a JSON function.
  • ErrMarshalPanicRecovered is returned when a panic occurs during JSON marshalling.
  • ErrEmptyInput is returned when an empty or whitespace-only string is passed to a JSON function.
  • ErrInvalidJSON is returned when a byte slice or string that does not constitute valid JSON is passed to a JSON function.
View Source
var DefaultOptionsConfig = &OptionsConfig{Width: 80, Prefix: "", Indent: "  ", SortKeys: false}

DefaultOptionsConfig is a pre-configured default set of options for pretty-printing JSON. This configuration uses a width of 80, an empty prefix, two-space indentation, and does not sort keys. It is used when no custom options are provided in the PrettyOptions function.

Functions

func Color

func Color(source []byte, style *Style) []byte

Color takes a JSON source in the form of a byte slice and applies syntax highlighting based on the provided style. The function returns a new byte slice with the JSON source formatted according to the specified styles.

Parameters:

  • `source`: A byte slice containing the JSON content to be styled.
  • `style`: A pointer to a `Style` struct that defines the styling for various components of the JSON content. If `nil`, the function uses the default `TerminalStyle`.

Returns:

  • A byte slice with the styled JSON content. Each component (such as keys, values, numbers, etc.) is colored based on the provided style.

The function processes the JSON source character by character and applies the corresponding styles as follows:

  • String values are enclosed in double quotes and are styled using the `Key` and `String` style fields.
  • Numbers, booleans (`true`, `false`), and `null` values are styled using the `Number`, `True`, `False`, and `Null` fields.
  • Brackets (`{`, `}`, `[`, `]`) are styled using the `Brackets` field.
  • Escape sequences within strings are styled using the `Escape` field.
  • The function handles nested objects and arrays using a stack to track the current level of nesting.

Example:

source := []byte(`{"name": "John", "age": 30, "active": true}`)
style := &Style{
  Key:   [2]string{"\033[1;34m", "\033[0m"},
  String: [2]string{"\033[1;32m", "\033[0m"},
  Number: [2]string{"\033[1;33m", "\033[0m"},
  True: [2]string{"\033[1;35m", "\033[0m"},
  False: [2]string{"\033[1;35m", "\033[0m"},
  Null: [2]string{"\033[1;35m", "\033[0m"},
  Escape: [2]string{"\033[1;31m", "\033[0m"},
  Brackets: [2]string{"\033[1;37m", "\033[0m"},
  Append: func(dst []byte, c byte) []byte { return append(dst, c) },
}
result := Color(source, style)
fmt.Println(string(result)) // Prints the styled JSON

Notes:

  • The function handles escape sequences (e.g., `\n`, `\"`) and ensures they are properly colored as part of strings.
  • The `Append` function in the `Style` struct allows customization of how each character is appended, enabling more flexible formatting if needed.

func IsValidJSON

func IsValidJSON(s string) bool

IsValidJSON checks if a given string is a valid JSON format.

This function uses the json.Valid method from the standard json library to determine if the input string `s` is a valid JSON representation.

Parameters:

  • `s`: The string to be validated as JSON.

Returns:

  • A boolean indicating whether the input string is valid JSON.

func IsValidJSONBytes

func IsValidJSONBytes(data []byte) bool

IsValidJSONBytes checks if a given byte slice is a valid JSON format.

This function uses the json.Valid method from the standard json library to determine if the input byte slice `data` is a valid JSON representation.

Parameters:

  • `data`: The byte slice to be validated as JSON.

Returns:

  • A boolean indicating whether the input byte slice is valid JSON.

func JSON

func JSON(data any) string

JSON converts a Go value to its JSON string representation or returns an error if the marshalling fails. It uses a deferred function to recover from any panics that may occur during marshalling.

Parameters:

  • `data`: The Go value to be converted to JSON.

Returns:

  • A string containing the JSON representation of the input value.
  • An error if the marshalling fails.

Example:

 var myStruct = struct {
 	Name string
 	Age  int
 }{
 	Name: "John",
 	Age:  30,
 }
	jsonString, err := JSON(myStruct)

func JSONPretty

func JSONPretty(data any) string

JSONPretty converts a Go value to its pretty-printed JSON string representation or returns an error if the marshalling fails. It uses a deferred function to recover from any panics that may occur during marshalling.

Parameters:

  • `data`: The Go value to be converted to JSON.

Returns:

  • A string containing the JSON representation of the input value.
  • An error if the marshalling fails.

Example:

 var myStruct = struct {
 	Name string
 	Age  int
 }{
 	Name: "John",
 	Age:  30,
 }
	jsonString, err := JSONPretty(myStruct)

func JSONPrettyToken

func JSONPrettyToken(data any) (string, error)

JSONPrettyToken converts a Go value to its pretty-printed JSON string representation or returns an error if the marshalling fails. It uses a deferred function to recover from any panics that may occur during marshalling.

Parameters:

  • `data`: The Go value to be converted to JSON.

Returns:

  • A string containing the JSON representation of the input value.
  • An error if the marshalling fails.

Example:

 var myStruct = struct {
 	Name string
 	Age  int
 }{
 	Name: "John",
 	Age:  30,
 }
	jsonString, err := JSONPrettyToken(myStruct)

func JSONToken

func JSONToken(data any) (string, error)

JSONToken converts a Go value to its JSON string representation or returns an error if the marshalling fails. It uses a deferred function to recover from any panics that may occur during marshalling.

Parameters:

  • `data`: The Go value to be converted to JSON.

Returns:

  • A string containing the JSON representation of the input value.
  • An error if the marshalling fails.

Example:

 var myStruct = struct {
 	Name string
 	Age  int
 }{
 	Name: "John",
 	Age:  30,
 }
	jsonString, err := JSONToken(myStruct)

func MarshalJSONIndent

func MarshalJSONIndent(v any, prefix, indent string) ([]byte, error)

MarshalJSONIndent converts a Go value to its JSON string representation with indentation.

This function marshals the input value `v` into a formatted JSON string, allowing for easy readability by including a specified prefix and indentation. It returns the resulting JSON byte slice or an error if marshalling fails.

Parameters:

  • `v`: The Go value to be marshalled into JSON.
  • `prefix`: A string that will be prefixed to each line of the output JSON.
  • `indent`: A string used for indentation (typically a series of spaces or a tab).

Returns:

  • A byte slice containing the formatted JSON representation of the input value.
  • An error if the marshalling fails.

Example:

jsonIndented, err := MarshalJSONIndent(myStruct, "", "    ")

func MarshalJSONb

func MarshalJSONb(v any) ([]byte, error)

MarshalJSONb converts a Go value into its JSON byte representation.

This function marshals the input value `v` using the standard json library. The resulting JSON data is returned as a byte slice. If there is an error during marshalling, it returns the error.

Parameters:

  • `v`: The Go value to be marshalled into JSON.

Returns:

  • A byte slice containing the JSON representation of the input value.
  • An error if the marshalling fails.

Example:

jsonData, err := MarshalJSONb(myStruct)

func MarshalJSONs

func MarshalJSONs(v any) (string, error)

MarshalJSONs converts a Go value to its JSON string representation.

This function utilizes the standard json library to marshal the input value `v` into a JSON string. If the marshalling is successful, it returns the resulting JSON string. If an error occurs during the process, it returns an error.

Parameters:

  • `v`: The Go value to be marshalled into JSON.

Returns:

  • A string containing the JSON representation of the input value.
  • An error if the marshalling fails.

Example:

jsonString, err := MarshalJSONs(myStruct)

func NormalizeJSON

func NormalizeJSON(s string) (string, error)

NormalizeJSON attempts to normalize a malformed JSON-like string into valid JSON.

Normalization strategy — passes are applied in sequence; validity is checked after each pass that modifies the candidate. The function returns as soon as a pass produces a valid JSON string, so no unnecessary work is performed.

  1. Empty / whitespace-only input → return error.
  2. Already valid JSON → return unchanged (fast path, no allocation).
  3. Pass 1 - strip a leading UTF-8 BOM (U+FEFF / 0xEF 0xBB 0xBF).
  4. Pass 2 - remove embedded null bytes (0x00) which are invalid inside JSON text.
  5. Pass 3 - unescape literal `\"` sequences to `"`. This is the most common artifact produced when JSON is stored in Go raw string literals or travels through systems that double-escape structural quote characters.
  6. Pass 4 - remove trailing commas before `}` or `]`. These are produced by some serializers and are not permitted by the JSON grammar.

Passes are cumulative: each pass operates on the output of the previous one. The function does NOT silently corrupt already-valid JSON (step 2 guarantees this). Only inputs that fail the initial validation ever enter the pass chain.

Parameters:

  • s: The input string to normalize.

Returns:

  • A valid JSON string on success.
  • An error if the input is empty/whitespace or cannot be normalized to valid JSON.

Example:

normalized, err := NormalizeJSON(`{\"key\": "value"}`)

func Pretty

func Pretty(json []byte) []byte

Pretty takes a JSON byte slice and returns a pretty-printed version of the JSON. It uses the default configuration options specified in DefaultOptionsConfig.

Parameters:

  • json: The JSON data to be pretty-printed.

Returns:

  • A byte slice containing the pretty-printed JSON data.

func PrettyOptions

func PrettyOptions(json []byte, option *OptionsConfig) []byte

PrettyOptions takes a JSON byte slice and returns a pretty-printed version of the JSON, with customizable options specified by the `option` parameter.

Parameters:

  • json: The JSON data to be pretty-printed.
  • option: A pointer to an OptionsConfig struct containing custom options for pretty-printing. If nil, the default options (DefaultOptionsConfig) will be used.

Returns:

  • A byte slice containing the pretty-printed JSON data based on the specified options.

Notes:

  • If `option` is nil, it falls back to the default configuration (DefaultOptionsConfig).
  • The `appendPrettyAny` function is called to format the JSON with the provided options.

PrettyOptions is like Pretty but with customized options.

func SafeUnmarshalBytes

func SafeUnmarshalBytes(data []byte, v any) error

SafeUnmarshalBytes parses JSON-encoded data and stores the result in the value pointed to by `v`.

This function uses the standard json library to unmarshal JSON data (given as a byte slice) into the specified Go value `v`. If the unmarshalling is successful, it populates the value `v`. If an error occurs, it returns the error.

Parameters:

  • `data`: A byte slice containing JSON data to be unmarshalled.
  • `v`: A pointer to the Go value where the unmarshalled data will be stored.

Returns:

  • An error if the unmarshalling fails.

Example:

err := SafeUnmarshalBytes(jsonData, &myStruct)

func SafeUnmarshalJSON

func SafeUnmarshalJSON(jsonStr string, v any) error

SafeUnmarshalJSON parses JSON-encoded string and stores the result in the value pointed to by `v`.

This function uses the standard json library to unmarshal JSON data (given as a string) into the specified Go value `v`. If the unmarshalling is successful, it populates the value `v`. If an error occurs, it returns the error.

Parameters:

  • `jsonStr`: A string containing JSON data to be unmarshalled.
  • `v`: A pointer to the Go value where the unmarshalled data will be stored.

Returns:

  • An error if the unmarshalling fails.

Example:

err := SafeUnmarshalJSON(jsonString, &myStruct)

func Spec

func Spec(source []byte) []byte

Spec strips out comments and trailing commas and converts the input to a valid JSON format according to the official JSON specification (RFC 8259).

This function calls the `spec` helper function to process the input `source` byte slice. It removes all single-line (`//`) and multi-line (`/* */`) comments, as well as any trailing commas that might be present in the input JSON. The result is a valid, parsable JSON byte slice that conforms to the RFC 8259 standard.

Key characteristics of the function:

  • The output will have the same length as the input source byte slice.
  • All original line breaks (newlines) will be preserved at the same positions in the output.
  • The function ensures that the cleaned JSON remains structurally valid and compliant with the official specification, making it ready for parsing by external JSON parsers.

This function is useful for scenarios where you need to preprocessed JSON-like data, removing comments and trailing commas while maintaining the correct formatting and offsets for later parsing and error reporting.

Parameters:

  • `source`: The input byte slice containing the raw JSON-like data, which may include comments and trailing commas.

Returns:

  • A new byte slice containing the cleaned, valid JSON data with comments and trailing commas removed, while preserving original formatting and line breaks.

Example usage:

rawJSON := []byte(`{ // comment\n "key": "value", }`)
validJSON := Spec(rawJSON)
// validJSON will be cleaned and ready for parsing.

func SpecInPlace

func SpecInPlace(source []byte) []byte

SpecInPlace strips out comments and trailing commas from the input JSON-like data and modifies the input slice in-place, converting it to valid JSON format according to the official JSON specification (RFC 8259).

This function behaves similarly to the `Spec` function, but instead of returning a new byte slice with the cleaned JSON, it modifies the original `source` byte slice directly.

It removes all single-line (`//`) and multi-line (`/* */`) comments, as well as any trailing commas that might be present in the input. The result is a valid, parsable JSON byte slice that adheres to the RFC 8259 standard.

Key characteristics of the function:

  • The output is stored directly in the `source` byte slice, modifying it in place.
  • The function ensures that the cleaned JSON remains structurally valid and compliant with the official specification, making it ready for parsing by external JSON parsers.

This function is useful when you want to modify the input data directly, avoiding the need for creating a new byte slice. It ensures that the original slice is cleaned while maintaining the correct formatting and line breaks.

Parameters:

  • `source`: The input byte slice containing the raw JSON-like data, which may include comments and trailing commas. This slice will be modified in place.

Returns:

  • The same `source` byte slice, now containing the cleaned, valid JSON data with comments and trailing commas removed, while preserving original formatting and line breaks.

Example usage:

rawJSON := []byte(`{ // comment\n "key": "value", }`)
SpecInPlace(rawJSON)
// rawJSON will be cleaned in-place and ready for parsing.

func Ugly

func Ugly(json []byte) []byte

Ugly removes unwanted characters from a JSON byte slice, returning a cleaned-up copy.

This function creates a new byte buffer to hold a "cleaned" version of the input JSON, then calls the `ugly` function to process the input `json` byte slice. The `ugly` function filters out non-printable characters (characters with ASCII values less than or equal to ' '), preserving quoted substrings within the JSON. Unlike `UglyInPlace`, this function does not modify the original input and instead returns a new byte slice.

Parameters:

  • `json`: A byte slice containing JSON data that may include unwanted characters or quoted substrings.

Returns:

  • A new byte slice with unwanted characters removed. The cleaned-up version of the input `json`.

Example:

json := []byte(`hello "world" 1234`)
cleanedJson := Ugly(json)
// cleanedJson will be []byte{'h', 'e', 'l', 'l', 'o', ' ', '"', 'w', 'o', 'r', 'l', 'd', '"', ' ', '1', '2', '3', '4'}
// as the function preserves printable characters and properly handles quoted substrings.

Notes:

  • This function is useful when you need a cleaned copy of the original JSON data without modifying the original byte slice.
  • The buffer created (`buf`) is pre-allocated with a capacity equal to the length of the input, optimizing memory allocation.

func UglyInPlace

func UglyInPlace(json []byte) []byte

UglyInPlace removes unwanted characters from a JSON byte slice in-place and returns the modified byte slice.

This function is a wrapper around the `ugly` function, which processes a byte slice and removes non-printable characters (i.e., characters with ASCII values less than or equal to ' '), preserving quoted substrings. `UglyInPlace` calls `ugly` with the same slice as both the source (`src`) and the destination (`dst`), effectively performing the cleaning operation in place.

Parameters:

  • `json`: A byte slice containing the JSON data to clean up. It may include unwanted characters or quoted substrings.

Returns:

  • The modified `json` byte slice with unwanted characters removed.

Example:

json := []byte(`hello "world" 1234`)
cleanedJson := UglyInPlace(json)
// cleanedJson will be []byte{'h', 'e', 'l', 'l', 'o', ' ', '"', 'w', 'o', 'r', 'l', 'd', '"', ' ', '1', '2', '3', '4'}
// as the function preserves printable characters and quoted substrings.

Notes:

  • This function is intended for cases where in-place modification of the input is acceptable.
  • The underlying `ugly` function processes each character, handling escaped double quotes to avoid breaking quoted substrings.

func UnmarshalBytes

func UnmarshalBytes(data []byte, v any) error

UnmarshalBytes parses JSON-encoded data and stores the result in the value pointed to by `v`.

This function uses the standard json library to unmarshal JSON data (given as a byte slice) into the specified Go value `v`. If the unmarshalling is successful, it populates the value `v`. If an error occurs, it returns the error.

Parameters:

  • `data`: A byte slice containing JSON data to be unmarshalled.
  • `v`: A pointer to the Go value where the unmarshalled data will be stored.

Returns:

  • An error if the unmarshalling fails.

Example:

err := UnmarshalBytes(jsonData, &myStruct)

func UnmarshalJSON

func UnmarshalJSON(jsonStr string, v any) error

UnmarshalJSON parses JSON-encoded string and stores the result in the value pointed to by `v`.

This function utilizes the standard json library to unmarshal JSON data from a string into the specified Go value `v`. If the unmarshalling is successful, it populates the value `v`. If an error occurs, it returns the error.

Parameters:

  • `jsonStr`: A string containing JSON data to be unmarshalled.
  • `v`: A pointer to the Go value where the unmarshalled data will be stored.

Returns:

  • An error if the unmarshalling fails.

Example:

err := UnmarshalJSON(jsonString, &myStruct)

Types

type OptionsConfig

type OptionsConfig struct {
	// Width is an max column width for single line arrays
	// Default is 80
	Width int `json:"width"`

	// Prefix is a prefix for all lines
	// Default is an empty string
	Prefix string `json:"prefix"`

	// Indent is the nested indentation
	// Default is two spaces
	Indent string `json:"indent"`

	// SortKeys will sort the keys alphabetically
	// Default is false
	SortKeys bool `json:"sort_keys"`
}

OptionsConfig defines the configuration options for pretty-printing JSON data. It allows customization of width, prefix, indentation, and sorting of keys. These options control how the JSON output will be formatted.

Fields:

  • Width: The maximum column width for single-line arrays. This prevents arrays from becoming too wide. Default is 80 characters.
  • Prefix: A string that will be prepended to each line of the output. Useful for adding custom prefixes or structuring the output with additional information. Default is an empty string.
  • Indent: The string used for indentation in nested JSON structures. Default is two spaces (" ").
  • SortKeys: A flag indicating whether the keys in JSON objects should be sorted alphabetically. Default is false.

type Style

type Style struct {
	Key, String, Number [2]string
	True, False, Null   [2]string
	Escape              [2]string
	Brackets            [2]string
	Append              func(dst []byte, c byte) []byte
}

Style is the color style

var (
	// TerminalStyle is for terminals
	TerminalStyle *Style

	// VSCodeDarkStyle is for VS Code dark theme
	VSCodeDarkStyle *Style

	// DraculaStyle is for Dracula theme
	DraculaStyle *Style

	// MonokaiStyle is for Monokai theme
	MonokaiStyle *Style

	// SolarizedDarkStyle is for Solarized Dark theme
	SolarizedDarkStyle *Style

	// MinimalGrayStyle is a minimal gray style
	MinimalGrayStyle *Style
)

Styles

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL