json5

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 2, 2026 License: MIT Imports: 13 Imported by: 0

README

json5

A Go package for encoding and decoding JSON5 data. The API mirrors the standard library encoding/json package, making it a drop-in replacement for projects that need JSON5 support.

What is JSON5?

JSON5 is a superset of JSON that adds several features from ECMAScript 5.1:

  • Comments — single-line (//) and multi-line (/* */)
  • Trailing commas — in objects and arrays
  • Unquoted object keys — any valid ECMAScript identifier
  • Single-quoted strings'like this'
  • Multiline strings — using backslash line continuation
  • Extended escape sequences\x41, \v, \0
  • Hexadecimal numbers0xFF
  • Infinity and NaN — as number literals
  • Leading/trailing decimal points.5 and 5.
  • Positive sign on numbers+42
  • Extended whitespace — vertical tab, form feed, BOM, non-breaking space, and Unicode Zs category

Every valid JSON document is also valid JSON5.

Installation

go get github.com/alchemy/json5

Usage

Unmarshal

Parse JSON5 data into Go values:

package main

import (
    "fmt"
    "github.com/alchemy/json5"
)

func main() {
    data := []byte(`{
        // Database configuration
        host: 'localhost',
        port: 5432,
        ssl: true,
        maxConns: 0xFF,
        timeout: .5,  // seconds
        tags: ['primary', 'fast',],
    }`)

    var config map[string]any
    if err := json5.Unmarshal(data, &config); err != nil {
        panic(err)
    }
    fmt.Println(config)
}
Unmarshal into structs

Struct tags use json5 (with fallback to json):

type Config struct {
    Host     string   `json5:"host"`
    Port     int      `json5:"port"`
    SSL      bool     `json5:"ssl"`
    MaxConns int      `json5:"maxConns"`
    Timeout  float64  `json5:"timeout"`
    Tags     []string `json5:"tags"`
    Debug    bool     `json5:"debug,omitempty"`
}

var config Config
err := json5.Unmarshal(data, &config)
Marshal

Encode Go values to JSON5:

b, err := json5.Marshal(config)
// {"host":"localhost","port":5432,"ssl":true,"maxConns":255,"timeout":0.5,"tags":["primary","fast"]}

Output is valid JSON for standard types. For float64 values of Infinity and NaN, the encoder outputs JSON5-specific literals:

b, _ := json5.Marshal(math.Inf(1))   // Infinity
b, _ = json5.Marshal(math.NaN())     // NaN
MarshalIndent

Pretty-print with indentation:

b, err := json5.MarshalIndent(config, "", "  ")
Streaming with Decoder/Encoder
// Decode from a reader
dec := json5.NewDecoder(file)
dec.UseNumber()                // decode numbers as json5.Number
dec.DisallowUnknownFields()    // error on unknown struct fields

var config Config
err := dec.Decode(&config)

// Encode to a writer
enc := json5.NewEncoder(os.Stdout)
err = enc.Encode(config)
Validation
if json5.Valid(data) {
    fmt.Println("valid JSON5")
}
RawMessage

Delay parsing of a JSON5 value:

type Event struct {
    Type    string          `json5:"type"`
    Payload json5.RawMessage `json5:"payload"`
}

var event Event
json5.Unmarshal(data, &event)

// Parse payload later based on type
switch event.Type {
case "click":
    var click ClickPayload
    json5.Unmarshal(event.Payload, &click)
}
Number type

Preserve exact number representation. The Float64() and Int64() methods handle all JSON5 number formats including hexadecimal, Infinity, and NaN:

dec := json5.NewDecoder(reader)
dec.UseNumber()

var v any
dec.Decode(&v)

n := v.(json5.Number)
f, _ := n.Float64()    // as float64 (handles 0xFF, Infinity, NaN)
i, _ := n.Int64()      // as int64 (handles 0xFF)
s := n.String()        // original text

Struct Tags

The package recognizes json5 struct tags with the same syntax as encoding/json:

type Example struct {
    Field1 string `json5:"name"`              // custom name
    Field2 int    `json5:"count,omitempty"`    // omit if zero value
    Field3 bool   `json5:",omitempty"`         // default name, omit if zero
    Field4 int    `json5:"val,string"`         // encode/decode as string
    Field5 string `json5:"-"`                  // skip this field
}

If no json5 tag is present, the package falls back to the json tag, enabling compatibility with existing types.

Interface Compatibility

The package checks for these interfaces in order:

  1. json5.Marshaler / json5.Unmarshaler — JSON5-specific
  2. json.Marshaler / json.Unmarshaler — standard library compatibility
  3. encoding.TextMarshaler / encoding.TextUnmarshaler

This means types that already implement json.Marshaler or json.Unmarshaler work without modification.

License

MIT

Documentation

Overview

Package json5 implements encoding and decoding of JSON5 as defined by https://spec.json5.org/. The API mirrors the standard library encoding/json package so that migrating existing code is straightforward.

JSON5 is a superset of JSON that adds support for comments, trailing commas, unquoted object keys, single-quoted strings, hexadecimal numbers, Infinity, NaN, and additional whitespace characters.

Struct tags use the key "json5" (falling back to "json" if "json5" is absent) and follow the same conventions as encoding/json.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Marshal

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

Marshal returns the JSON5 encoding of v.

Marshal traverses the value v recursively using the same rules as encoding/json.Marshal, but outputs valid JSON (which is also valid JSON5).

func MarshalIndent

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

MarshalIndent is like Marshal but applies Indent to format the output.

func Unmarshal

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

Unmarshal parses the JSON5-encoded data and stores the result in the value pointed to by v. If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.

func Valid

func Valid(data []byte) bool

Valid reports whether data is a valid JSON5 encoding.

Types

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

A Decoder reads and decodes JSON5 values from an input stream. It reads input incrementally using a sliding window buffer, so it can decode a stream of values without loading the entire input into memory.

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a new decoder that reads from r.

func (*Decoder) Decode

func (dec *Decoder) Decode(v any) error

Decode reads the next JSON5 value from its input and stores it in the value pointed to by v.

func (*Decoder) DisallowUnknownFields

func (dec *Decoder) DisallowUnknownFields()

DisallowUnknownFields causes the Decoder to return an error when the destination is a struct and the input contains object keys which do not match any non-ignored, exported fields in the destination.

func (*Decoder) UseNumber

func (dec *Decoder) UseNumber()

UseNumber causes the Decoder to unmarshal a number into an interface{} as a Number instead of as a float64.

func (*Decoder) UseOrderedMap

func (dec *Decoder) UseOrderedMap()

UseOrderedMap causes the Decoder to unmarshal objects into *OrderedMap instead of map[string]any when the target is an interface{}. This preserves the insertion order of keys.

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

An Encoder writes JSON5 values to an output stream.

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns a new encoder that writes to w.

func (*Encoder) Encode

func (enc *Encoder) Encode(v any) error

Encode writes the JSON5 encoding of v to the stream, followed by a newline.

type Entry

type Entry struct {
	Key           string
	Value         any
	Comment       string // comment text above the key (without // or /* */ markers)
	InlineComment string // comment text on the same line after the value
}

Entry is a key-value pair in an OrderedMap.

type InvalidUnmarshalError

type InvalidUnmarshalError struct {
	Type reflect.Type
}

InvalidUnmarshalError describes an invalid argument passed to Unmarshal.

func (*InvalidUnmarshalError) Error

func (e *InvalidUnmarshalError) Error() string

type Marshaler

type Marshaler interface {
	MarshalJSON5() ([]byte, error)
}

Marshaler is the interface implemented by types that can marshal themselves into valid JSON5.

type MarshalerError

type MarshalerError struct {
	Type reflect.Type
	Err  error
	// contains filtered or unexported fields
}

MarshalerError describes an error from calling MarshalJSON5 or MarshalJSON.

func (*MarshalerError) Error

func (e *MarshalerError) Error() string

func (*MarshalerError) Unwrap

func (e *MarshalerError) Unwrap() error

type Number

type Number string

Number represents a JSON5 number literal.

func (Number) Float64

func (n Number) Float64() (float64, error)

Float64 returns the number as a float64. It handles JSON5 number formats including hexadecimal, Infinity, and NaN.

func (Number) Int64

func (n Number) Int64() (int64, error)

Int64 returns the number as an int64. It handles JSON5 number formats including hexadecimal.

func (Number) String

func (n Number) String() string

String returns the literal text of the number.

type OrderedMap

type OrderedMap struct {
	// contains filtered or unexported fields
}

OrderedMap is a JSON5 object that preserves the insertion order of keys. It supports O(1) key lookup and O(1) amortized append.

func NewOrderedMap

func NewOrderedMap() *OrderedMap

NewOrderedMap returns a new empty OrderedMap.

func (*OrderedMap) Delete

func (m *OrderedMap) Delete(key string)

Delete removes a key. It preserves the order of remaining keys.

func (*OrderedMap) Entries

func (m *OrderedMap) Entries() []Entry

Entries returns all entries in insertion order.

func (*OrderedMap) Get

func (m *OrderedMap) Get(key string) (any, bool)

Get returns the value for key and whether it was found.

func (*OrderedMap) Keys

func (m *OrderedMap) Keys() []string

Keys returns the keys in insertion order.

func (*OrderedMap) Len

func (m *OrderedMap) Len() int

Len returns the number of entries.

func (*OrderedMap) MarshalJSON5

func (m *OrderedMap) MarshalJSON5() ([]byte, error)

MarshalJSON5 implements the Marshaler interface, emitting keys in insertion order with comments preserved.

func (*OrderedMap) Set

func (m *OrderedMap) Set(key string, value any)

Set adds or updates a key-value pair. If the key already exists, its value is updated in place (preserving order). If the key is new, it is appended.

func (*OrderedMap) SetWithComment added in v0.2.0

func (m *OrderedMap) SetWithComment(key string, value any, comment, inlineComment string)

SetWithComment adds or updates a key-value pair with associated comments.

func (*OrderedMap) UnmarshalJSON5

func (m *OrderedMap) UnmarshalJSON5(data []byte) error

UnmarshalJSON5 implements the Unmarshaler interface.

type RawMessage

type RawMessage []byte

RawMessage is a raw encoded JSON5 value. It implements Marshaler and Unmarshaler and can be used to delay JSON5 decoding or precompute a JSON5 encoding.

func (RawMessage) MarshalJSON5

func (m RawMessage) MarshalJSON5() ([]byte, error)

MarshalJSON5 returns m as the JSON5 encoding of m.

func (*RawMessage) UnmarshalJSON5

func (m *RawMessage) UnmarshalJSON5(data []byte) error

UnmarshalJSON5 sets *m to a copy of data.

type SyntaxError

type SyntaxError struct {
	Offset int64
	// contains filtered or unexported fields
}

SyntaxError is a description of a JSON5 syntax error.

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

type UnmarshalTypeError

type UnmarshalTypeError struct {
	Value  string
	Type   reflect.Type
	Offset int64
	Struct string
	Field  string
}

UnmarshalTypeError describes a JSON5 value that was not appropriate for a value of a specific Go type.

func (*UnmarshalTypeError) Error

func (e *UnmarshalTypeError) Error() string

type Unmarshaler

type Unmarshaler interface {
	UnmarshalJSON5([]byte) error
}

Unmarshaler is the interface implemented by types that can unmarshal a JSON5 description of themselves.

Jump to

Keyboard shortcuts

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