json

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

README

go-jsonc

Go Reference CI

go-jsonc is a zero-dependency facade for Go's encoding/json with native JSONC comments and trailing commas.

The module requires Go 1.26.0 or newer. Its package name is json, so most callers can migrate by changing only the import path:

-import "encoding/json"
+import "github.com/FloraSync/go-jsonc"

Callers migrating from github.com/marcozac/go-jsonc may preserve the local jsonc identifier temporarily by aliasing the FloraSync import:

import jsonc "github.com/FloraSync/go-jsonc"

Supported syntax

The FloraSync JSONC Profile v1 accepts strict RFC 8259 JSON plus:

  • // line comments, ending at CR, LF, CRLF, or EOF;
  • /* ... */ block comments; and
  • one trailing comma after the final member or element of a non-empty object or array.
{
  // Comments are allowed wherever JSON permits whitespace.
  "service": "flora",
  "ports": [8080, 8443,],
}

Comment markers inside strings remain string data. Comments cannot split JSON tokens, block comments cannot nest, and unsupported JSON5 features such as single-quoted strings, unquoted keys, hexadecimal numbers, NaN, and Infinity remain invalid.

Profile v1 is pinned to the JSONC.org draft at commit 84b0999. JSONC.org's default grammar does not enable trailing commas; FloraSync deliberately enables the extension permitted by its prose.

Usage

package main

import (
    "fmt"

    "github.com/FloraSync/go-jsonc"
)

func main() {
    input := []byte(`{
        // deployment target
        "region": "us-west-2",
    }`)

    var config map[string]string
    if err := json.Unmarshal(input, &config); err != nil {
        panic(err)
    }
    fmt.Println(config["region"])
}

Unmarshal, Valid, Compact, Indent, and NewDecoder accept the FloraSync JSONC profile. Encoding operations delegate directly to the standard library. The complete stable Go 1.26 encoding/json API is mirrored, including all documented types and decoder/encoder methods.

Sanitize is an additional API for obtaining the normalized JSON view:

normalized, err := json.Sanitize(input)

Recognized comments are replaced with same-length whitespace and accepted trailing commas with one space. The input is never mutated and output offsets stay aligned with the original bytes. ErrInvalidUTF8, ErrUnterminatedBlockComment, and JSONCSyntaxError describe JSONC-specific lexical failures.

Go 1.27 and encoding/json/v2

The v1 module continues to expose the stable encoding/json v1 contract on Go 1.26 and Go 1.27. Go 1.27 implements that standard package on the new engine while preserving v1 behavior.

Applications that deliberately adopt Go 1.27's stricter encoding/json/v2 semantics can compose it with Sanitize without waiting for a second go-jsonc API:

normalized, err := json.Sanitize(input)
if err != nil {
    return err
}
if err := jsonv2.Unmarshal(normalized, &config); err != nil {
    return err
}

Here json is github.com/FloraSync/go-jsonc and jsonv2 is encoding/json/v2. This explicit boundary preserves v2 defaults such as rejecting duplicate object names and invalid UTF-8. A future go-jsonc v2 API can build on the same sanitizer boundary without changing v1 semantics.

Compatibility and security notes

  • Strict slice input is passed to encoding/json without allocating a normalized buffer; streaming always uses the incremental normalizing reader.
  • Invalid UTF-8 outside comments retains the standard library's behavior. Invalid UTF-8 inside comments is rejected.
  • The custom JSONC-aware Decoder preserves the documented standard methods and normalized byte offsets, but its pointer type is necessarily distinct from *encoding/json.Decoder.
  • The implementation uses a deterministic linear lexer: no regular expressions, recursion, unsafe code, or third-party Go modules.

When multiple systems parse security-sensitive input, ensure they all use the same JSONC profile. Differences involving duplicate object keys, case-insensitive struct matching, number precision, or other standard encoding/json behaviors remain the standard library's responsibility.

Development

The repository may live beneath a parent Go workspace, so the supplied scripts force module-local operation:

./scripts/test.sh
./scripts/benchmark.sh

License

This project is an intentional, independent continuation of Marco Zaccaro's github.com/marcozac/go-jsonc, used and modified under the Apache License 2.0. The upstream main branch has had no source change since August 2023. Copyright and license notices for retained upstream material are preserved. FloraSync's continuation is independently maintained and is not endorsed by the upstream author.

Licensed under Apache-2.0. See LICENSE and NOTICE.

Documentation

Overview

Package json implements the stable encoding/json API with support for the FloraSync JSONC Profile v1.

The profile adds JavaScript-style line and block comments and permits one trailing comma after the final member of a non-empty object or element of a non-empty array. All encoding operations emit ordinary JSON.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidUTF8 reports malformed UTF-8 in a JSONC comment body.
	// Malformed UTF-8 outside comments retains encoding/json behavior.
	ErrInvalidUTF8 = errors.New("jsonc: invalid UTF-8 in comment")

	// ErrUnterminatedBlockComment reports a block comment without a closing */.
	ErrUnterminatedBlockComment = errors.New("jsonc: unterminated block comment")
)

Functions

func Compact

func Compact(dst *bytes.Buffer, src []byte) error

Compact appends to dst the compacted form of the JSONC-encoded src.

func HTMLEscape

func HTMLEscape(dst *bytes.Buffer, src []byte)

HTMLEscape preserves the behavior of encoding/json.HTMLEscape. Its input contract remains ordinary JSON because the standard signature cannot report malformed JSONC extensions.

func HasCommentRunes

func HasCommentRunes(data []byte) bool

HasCommentRunes reports whether data contains a // or /* opener outside a JSON string. It does not validate the surrounding document or detect trailing commas.

func Indent

func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error

Indent appends to dst an indented form of the JSONC-encoded src.

func Marshal

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

Marshal returns the JSON encoding of v.

func MarshalIndent

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

MarshalIndent returns the indented JSON encoding of v.

func Sanitize

func Sanitize(data []byte) ([]byte, error)

Sanitize replaces JSONC comments and accepted trailing commas with byte-length-preserving JSON whitespace. It never mutates data.

Sanitize validates JSONC lexical extensions but does not otherwise validate JSON. Call Valid or Unmarshal when full validation is required.

func Unmarshal

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

Unmarshal parses JSON or JSONC data and stores the result in v.

Example
var v interface{}

data := []byte(`{/* comment */"foo": "bar"}`)

err := json.Unmarshal(data, &v)
if err != nil {
	panic(err)
}

fmt.Println(v)
Output:
map[foo:bar]
Example (SanitizeError)
var v interface{}

invalid := append([]byte("/*"), byte(0xa5))
invalid = append(invalid, []byte("*/{}")...)

err := json.Unmarshal(invalid, &v)
fmt.Println(err)
Output:
jsonc: invalid UTF-8 in comment at byte 3

func Valid

func Valid(data []byte) bool

Valid reports whether data is valid under the FloraSync JSONC Profile v1.

Types

type Decoder

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

Decoder reads JSON or JSONC values from an input stream.

Decoder preserves encoding/json's streaming behavior while presenting a byte-length-preserving normalized view to the standard decoder. As with encoding/json.Decoder, a Decoder is not safe for concurrent use.

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a decoder that reads JSON or JSONC values from r.

The decoder introduces its own buffering and may read data from r beyond the values requested.

func (*Decoder) Buffered

func (d *Decoder) Buffered() io.Reader

Buffered returns a reader of committed normalized data remaining in the Decoder's buffers. The reader is valid until the next call to Decode.

A trailing-comma candidate whose disposition depends on unread input is not committed until the normalizer encounters the following significant byte.

func (*Decoder) Decode

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

Decode reads the next JSON-encoded or JSONC-encoded value from its input and stores it in the value pointed to by v.

func (*Decoder) DisallowUnknownFields

func (d *Decoder) DisallowUnknownFields()

DisallowUnknownFields causes the Decoder to return an error when the destination is a struct and an object contains an unknown key.

func (*Decoder) InputOffset

func (d *Decoder) InputOffset() int64

InputOffset returns the original input stream byte offset of the current decoder position.

func (*Decoder) More

func (d *Decoder) More() bool

More reports whether there is another element in the current array or object being parsed.

func (*Decoder) Token

func (d *Decoder) Token() (Token, error)

Token returns the next JSON token in the input stream.

func (*Decoder) UseNumber

func (d *Decoder) UseNumber()

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

type Delim

type Delim = stdjson.Delim

type Encoder

type Encoder = stdjson.Encoder

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns a standard JSON encoder that writes to w.

type InvalidUTF8Error

type InvalidUTF8Error = stdjson.InvalidUTF8Error

type InvalidUnmarshalError

type InvalidUnmarshalError = stdjson.InvalidUnmarshalError

type JSONCSyntaxError

type JSONCSyntaxError struct {
	Offset int64
	Err    error
}

JSONCSyntaxError describes syntax that belongs to the JSONC extension rather than ordinary JSON. Offset is a one-based byte offset into the original input. Err can be inspected with errors.Is.

func (*JSONCSyntaxError) Error

func (e *JSONCSyntaxError) Error() string

func (*JSONCSyntaxError) Unwrap

func (e *JSONCSyntaxError) Unwrap() error

Unwrap returns the JSONC syntax category.

type Marshaler

type Marshaler = stdjson.Marshaler

type MarshalerError

type MarshalerError = stdjson.MarshalerError

type Number

type Number = stdjson.Number

type RawMessage

type RawMessage = stdjson.RawMessage

type SyntaxError

type SyntaxError = stdjson.SyntaxError

type Token

type Token = stdjson.Token

type UnmarshalFieldError

type UnmarshalFieldError = stdjson.UnmarshalFieldError

type UnmarshalTypeError

type UnmarshalTypeError = stdjson.UnmarshalTypeError

type Unmarshaler

type Unmarshaler = stdjson.Unmarshaler

type UnsupportedTypeError

type UnsupportedTypeError = stdjson.UnsupportedTypeError

type UnsupportedValueError

type UnsupportedValueError = stdjson.UnsupportedValueError

Jump to

Keyboard shortcuts

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