Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "test/JSONTestSuite"]
path = test/JSONTestSuite
url = https://github.com/nst/JSONTestSuite.git
212 changes: 156 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,125 +18,225 @@ optionally enabled.
| ---------------------------------------------------- | --------------------------------------------------------------------------------------- |


## Features
The documentation below is organized along the
[Diátaxis](https://diataxis.fr) quadrants:

- Single-line comments: `// comment`
- Block comments: `/* comment */`
- Optional trailing commas in objects and arrays
- Strict JSON value parsing (no unquoted strings or hex numbers)
- Available in both TypeScript/JavaScript and Go
- [Quick start](#quick-start) — tutorial
- [How-to guides](#how-to-guides) — task recipes
- [Reference](#reference) — API surface
- [JSONC format](#jsonc-format) — explanation


## TypeScript
## Quick start

### Install
### TypeScript

Install:

```bash
npm install @jsonic/jsonc @jsonic/jsonic-next
```

### Quick Start
Parse:

```typescript
import { Jsonic } from '@jsonic/jsonic-next'
import { Jsonc } from '@jsonic/jsonc'

const j = Jsonic.make().use(Jsonc)

// Parse JSONC with comments
const result = j('{ "name": "app", /* version */ "version": "1.0" }')
// => { name: "app", version: "1.0" }

// Enable trailing commas
const jc = Jsonic.make().use(Jsonc, { allowTrailingComma: true })
const config = jc('{ "debug": true, "verbose": false, }')
// => { debug: true, verbose: false }
// => { name: 'app', version: '1.0' }
```

### Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `allowTrailingComma` | `boolean` | `false` | Allow trailing commas in objects and arrays |
| `disallowComments` | `boolean` | `false` | Disable comment parsing (strict JSON mode) |
### Go


## Go

### Install
Install:

```bash
go get github.com/jsonicjs/jsonc/go
```

### Quick Start
Parse:

```go
package main

import (
"fmt"
jsonic "github.com/jsonicjs/jsonic/go"
jsonc "github.com/jsonicjs/jsonc/go"
)

func main() {
// Parse JSONC with comments
result, err := jsonc.Parse(`{ "name": "app", /* version */ "version": "1.0" }`)
j := jsonic.Make()
j.Use(jsonc.Jsonc)

result, err := j.Parse(`{ "name": "app", /* version */ "version": "1.0" }`)
if err != nil {
panic(err)
}
fmt.Println(result)
// => map[name:app version:1.0]
}
```

// Enable trailing commas
result, err = jsonc.Parse(
`{ "debug": true, "verbose": false, }`,
jsonc.JsoncOptions{AllowTrailingComma: boolPtr(true)},
)
fmt.Println(result)
// => map[debug:true verbose:false]

## How-to guides

### Allow trailing commas

TypeScript:

```typescript
const j = Jsonic.make().use(Jsonc, { allowTrailingComma: true })
j('{ "debug": true, "verbose": false, }')
// => { debug: true, verbose: false }
```

Go:

```go
j := jsonic.Make()
j.Use(jsonc.Jsonc, map[string]any{"allowTrailingComma": true})
result, _ := j.Parse(`{ "debug": true, "verbose": false, }`)
```

### Parse strict JSON (disable comments)

TypeScript:

```typescript
const j = Jsonic.make().use(Jsonc, { disallowComments: true })
j('{ "foo": /* not allowed */ true }') // throws
```

Go:

```go
j := jsonic.Make()
j.Use(jsonc.Jsonc, map[string]any{"disallowComments": true})
```

### Handle parse errors

TypeScript — parse errors throw:

```typescript
try {
j('{ "bad": }')
} catch (err) {
console.error(err.message)
}
```

Go — errors are returned:

```go
if _, err := j.Parse(`{ "bad": }`); err != nil {
fmt.Println(err)
}
```

func boolPtr(b bool) *bool { return &b }
### Parse a file

TypeScript:

```typescript
import { readFileSync } from 'node:fs'
const j = Jsonic.make().use(Jsonc, { allowTrailingComma: true })
const config = j(readFileSync('tsconfig.json', 'utf8'))
```

Go:

```go
src, _ := os.ReadFile("tsconfig.json")
j := jsonic.Make()
j.Use(jsonc.Jsonc, map[string]any{"allowTrailingComma": true})
config, _ := j.Parse(string(src))
```

### API

#### `Parse(src string, opts ...JsoncOptions) (any, error)`
## Reference

### TypeScript

Parse a JSONC string and return the result. Returns `map[string]any` for
objects, `[]any` for arrays, `float64` for numbers, `string`, `bool`,
or `nil`.
```typescript
function Jsonc(jsonic: Jsonic, options?: JsoncOptions): void

type JsoncOptions = {
allowTrailingComma?: boolean // default: false
disallowComments?: boolean // default: false
}
```

#### `MakeJsonic(opts ...JsoncOptions) *jsonic.Jsonic`
Register with `jsonic.use(Jsonc, options?)`. After registration, invoke
the jsonic instance as a function on a source string; it returns the
parsed value or throws on syntax errors.

Create a configured jsonic instance for JSONC parsing. Use this when you
need to parse multiple inputs with the same configuration.
| Option | Type | Default | Effect |
|--------|------|---------|--------|
| `allowTrailingComma` | `boolean` | `false` | Permit a trailing comma before `}` and `]` |
| `disallowComments` | `boolean` | `false` | Reject `//` and `/* */` comments (strict JSON) |

### Go

```go
func Jsonc(j *jsonic.Jsonic, pluginOpts map[string]any) error
```

#### `JsoncOptions`
Register with `j.Use(jsonc.Jsonc)` or `j.Use(jsonc.Jsonc, opts)` where
`opts` is a `map[string]any`. `Parse` then returns `(any, error)` —
`map[string]any` for objects, `[]any` for arrays, `float64` for numbers,
`string`, `bool`, or `nil`.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `AllowTrailingComma` | `*bool` | `false` | Allow trailing commas in objects and arrays |
| `DisallowComments` | `*bool` | `false` | Disable comment parsing |
| Key | Type | Default | Effect |
|-----|------|---------|--------|
| `allowTrailingComma` | `bool` | `false` | Permit a trailing comma before `}` and `]` |
| `disallowComments` | `bool` | `false` | Reject `//` and `/* */` comments (strict JSON) |


## JSONC Format
## JSONC format

JSONC follows [RFC 8259](https://tools.ietf.org/html/rfc8259) (JSON) with
these extensions:
JSONC follows [RFC 8259](https://tools.ietf.org/html/rfc8259) (JSON)
with these extensions:

- **Line comments**: `//` to end of line
- **Block comments**: `/* */` (non-nesting)
- **Trailing commas**: optional, in objects and arrays

All other rules follow standard JSON:
All other JSON rules apply:

- Strings must be double-quoted
- Only standard escape sequences: `\"` `\\` `\/` `\b` `\f` `\n` `\r` `\t` `\uXXXX`
- Numbers: integer, decimal, scientific notation (no hex, octal, or binary)
- Standard escapes only: `\"` `\\` `\/` `\b` `\f` `\n` `\r` `\t` `\uXXXX`
- Numbers: integer, decimal, scientific notation (no hex, octal, binary)
- Keywords: `true`, `false`, `null` (case-sensitive)
- Property names must be double-quoted strings

### Conformance notes

The plugin layers JSONC rules on top of jsonic, which is intentionally
lenient in some places vs. strict RFC 8259. The test suite runs the
[nst/JSONTestSuite](https://github.com/nst/JSONTestSuite) corpus in
strict mode (`disallowComments: true`) and pins the known-lenient
cases in `test/jsontestsuite.test.ts` (see `N_KNOWN_LENIENT`). Examples
of accepted-but-non-RFC input include numbers with leading zeros and
unquoted object keys. Use an RFC-strict parser if byte-perfect RFC 8259
rejection is required.


## Acknowledgments

Conformance testing uses third-party corpora under MIT License:

- [nst/JSONTestSuite](https://github.com/nst/JSONTestSuite) by Nicolas
Seriot — vendored as a git submodule at `test/JSONTestSuite/`.
- [microsoft/node-jsonc-parser](https://github.com/microsoft/node-jsonc-parser) —
parse-level test cases ported into `test/jsonc.test.ts`.

See [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md) for details.


## License

Expand Down
49 changes: 49 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Third-Party Notices

This project incorporates material from the projects listed below. The
original copyright notices and license texts are preserved as required.

## nst/JSONTestSuite

Used as a git submodule at `test/JSONTestSuite/` for RFC 8259 conformance
testing via `test/jsontestsuite.test.ts`. The submodule's `LICENSE` file
is preserved in place.

- Project: https://github.com/nst/JSONTestSuite
- License: MIT
- Copyright (c) 2016 Nicolas Seriot

## microsoft/node-jsonc-parser

Parse-level test cases in `test/jsonc.test.ts` were ported from
`src/test/json.test.ts` of `microsoft/node-jsonc-parser`.

- Project: https://github.com/microsoft/node-jsonc-parser
- License: MIT
- Copyright (c) Microsoft Corporation

---

Both projects are distributed under the MIT License. Full license text:

```
MIT License

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.
```
4 changes: 1 addition & 3 deletions go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@ module github.com/jsonicjs/jsonc/go

go 1.24.7

require github.com/jsonicjs/jsonic/go v0.1.18

replace github.com/jsonicjs/jsonic/go => ../../jsonic/go
require github.com/jsonicjs/jsonic/go v0.1.19
4 changes: 2 additions & 2 deletions go/go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github.com/jsonicjs/jsonic/go v0.1.18 h1:OW15hjFisrw2n7HE6zDuQAikW8A5NUW8OyP4SCG2oFg=
github.com/jsonicjs/jsonic/go v0.1.18/go.mod h1:ObNKlCG7esWoi4AHCpdgkILvPINV8bpvkbCd4llGGUg=
github.com/jsonicjs/jsonic/go v0.1.19 h1:jEP+GSxMGKV+eTJEjuU0qRMUQ8GAIl1SRigc+mbZzVo=
github.com/jsonicjs/jsonic/go v0.1.19/go.mod h1:ObNKlCG7esWoi4AHCpdgkILvPINV8bpvkbCd4llGGUg=
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"jsonic"
],
"scripts": {
"test": "node --enable-source-maps --experimental-strip-types --test test/jsonc.test.ts",
"test": "node --enable-source-maps --experimental-strip-types --test test/jsonc.test.ts test/jsontestsuite.test.ts",
"build": "node embed-grammar.js && tsc -p src",
"watch": "tsc -p src --watch",
"embed": "node embed-grammar.js",
Expand All @@ -27,7 +27,7 @@
},
"devDependencies": {
"@types/node": "^22.0.0",
"jsonic": "file:../jsonic",
"jsonic": "github:jsonicjs/jsonic#main",
"typescript": "^5.6.3"
},
"files": [
Expand Down
1 change: 1 addition & 0 deletions test/JSONTestSuite
Submodule JSONTestSuite added at 1ef36f
4 changes: 4 additions & 0 deletions test/jsonc.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
/* Copyright (c) 2021-2025 Richard Rodger and other contributors, MIT License */

// Parse-level test cases in this file were ported from
// microsoft/node-jsonc-parser (src/test/json.test.ts), Copyright (c)
// Microsoft Corporation, MIT License. See THIRD_PARTY_NOTICES.md.

import { test, describe } from 'node:test'
import assert from 'node:assert'

Expand Down
Loading
Loading