PHPackages                             ustek/hujson - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. ustek/hujson

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

ustek/hujson
============

PHP port of tailscale/hujson: a parser and packer for the JWCC format (JSON With Commas and Comments).

v1.0.0(today)02↑2900%BSD-3-ClausePHPPHP &gt;=8.1

Since Aug 14Pushed todayCompare

[ Source](https://github.com/ustek-rfid/hujson-php)[ Packagist](https://packagist.org/packages/ustek/hujson)[ RSS](/packages/ustek-hujson/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (1)Versions (2)Used By (0)

ustek/hujson
============

[](#ustekhujson)

A PHP port of [tailscale/hujson](https://github.com/tailscale/hujson): a parser and packer for the **JWCC** format — *JSON With Commas and Comments* (also called "human JSON"). JWCC extends RFC 8259 JSON with line comments (`// ...`), block comments (`/* ... */`), and trailing commas.

It parses into a lossless syntax tree: comments, whitespace, and byte offsets are all preserved, so you can read, transform, and write a document back **byte-for-byte unchanged** unless you deliberately modify it.

JWCC is well suited to configuration files that benefit from comments and a forgiving syntax while staying close to standard JSON. This is a general-purpose JWCC library with no runtime dependencies beyond PHP core.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.1
- No non-core extensions (uses the bundled `json` and PCRE-with-Unicode support only)

Installation
------------

[](#installation)

```
composer require ustek/hujson
```

Quick start
-----------

[](#quick-start)

The `HuJSON` facade covers the common whole-document operations. Each throws `Ustek\HuJSON\HuJSONException` on a parse error, with a Go-compatible message such as `hujson: line 1, column 6: invalid character ',' after top-level value`.

```
use Ustek\HuJSON\HuJSON;

// Strip comments, whitespace, and trailing commas -> standard JSON.
HuJSON::minimize("// config\n{ \"a\": 1, \"b\": [1, 2,], }\n");
// => {"a":1,"b":[1,2]}

// Reformat (like gofmt, for HuJSON). Idempotent; adds one trailing newline.
HuJSON::format('{"a":1,"b":[1,2,]}');
// => {"a": 1, "b": [1, 2]}\n

// Turn HuJSON into standard JSON while preserving line numbers and byte offsets
// (comments and trailing commas become spaces).
HuJSON::standardize("// c\n{\"a\":1,}\n");
// => "    \n{\"a\":1 }\n"
```

A common pattern is to feed `standardize()` (or `minimize()`) output into `json_decode()`:

```
$data = json_decode(HuJSON::standardize($hujsonSource), true, flags: JSON_THROW_ON_ERROR);
```

The syntax tree
---------------

[](#the-syntax-tree)

`HuJSON::parse()` returns a `Value` — an exact syntactic representation of the input.

```
use Ustek\HuJSON\HuJSON;

$v = HuJSON::parse($src);
$v->pack() === $src;   // true: a parsed, untouched value re-packs identically
(string) $v;           // same as pack()
```

`Value` exposes:

MemberDescription`?string $beforeExtra`, `?string $afterExtra`Surrounding comments/whitespace (`null` = none)`int $startOffset`, `int $endOffset`Byte offsets of the value`?ValueTrimmed $value`The trimmed value: a `Literal`, `ObjectValue`, or `ArrayValue``pack(): string` / `(string) $v`Serialize to HuJSON`isStandard(): bool`True if standard JSON (no comments, no trailing commas)`minimize()`, `standardize()`, `format()`In-place transforms`find(string $pointer): ?Value`Look up a node by JSON Pointer (RFC 6901)`patch(string $patch): void`Apply a JSON Patch (RFC 6902), preserving comments`all(): Generator`, `range(callable): bool`Depth-first traversal`updateOffsets(): void`Recompute `startOffset`/`endOffset`Deep-copy a value with `clone` before mutating if you need to keep the original:

```
$copy = clone $v;   // deep copy (equivalent to Go's Value.Clone)
$copy->minimize();
```

### Navigating and editing

[](#navigating-and-editing)

```
use Ustek\HuJSON\HuJSON;

$doc = HuJSON::parse('[1, 2, {"k": 3}]');

$node = $doc->find('/2/k');   // RFC 6901 pointer -> a Value node (or null)
$node->value->asInt();        // 3

// RFC 6902 patch; comments around inserted values are preserved.
$v = HuJSON::parse('{ "foo": "bar" }');
$v->patch('[{"op":"add","path":"/baz","value":"qux"}]');
(string) $v;                  // { "foo": "bar","baz":"qux" }
```

### Literals

[](#literals)

`Literal` is immutable (`public readonly string $bytes`) with constructors and typed accessors:

```
use Ustek\HuJSON\Literal;

Literal::fromString("a\tb")->bytes;   // the 6 bytes: "a\tb"   (quoted, tab escaped)
Literal::fromInt(-42)->bytes;         // -42
Literal::fromFloat(INF)->bytes;       // "Infinity"  (JSON string, with quotes)

(new Literal('"hi"'))->asString();    // "hi"
(new Literal('42'))->asInt();         // 42
(new Literal('3.14'))->asFloat();     // 3.14
(new Literal('true'))->asBool();      // true
(new Literal('nul'))->isValid();      // false
```

Command-line tool
-----------------

[](#command-line-tool)

The package ships a `hujsonfmt` binary (a port of the upstream Go command):

```
vendor/bin/hujsonfmt [flags] [path ...]
```

FlagEffect*(none)*Format and print to stdout`-m`Minify to standard JSON`-s`Standardize to standard JSON (preserving offsets)`-d`Print a unified diff instead of the result`-l`List files whose formatting differs`-w`Rewrite the file(s) in place (with a temp backup)With no path (or `-`) it reads stdin. A directory argument is walked recursively, processing files ending in `.hujson`.

```
echo '{"a":1,}' | vendor/bin/hujsonfmt -m      # {"a":1}
vendor/bin/hujsonfmt -w config/app.hujson
```

Go → PHP API map
----------------

[](#go--php-api-map)

Go (`tailscale/hujson`)PHP (`Ustek\HuJSON`)`hujson.Parse``HuJSON::parse``hujson.Standardize` / `Minimize` / `Format``HuJSON::standardize` / `minimize` / `format``Value.Pack` / `Value.String``Value::pack` / `(string) $v``Value.Clone``clone $value``Value.IsStandard` / `Find` / `Patch` / `UpdateOffsets`same, camelCase`Value.All` / `Value.Range``Value::all` / `Value::range``hujson.Bool/String/Int/Uint/Float``Literal::fromBool/fromString/fromInt/fromUint/fromFloat``Literal.Bool/String/Int/Uint/Float/IsValid/Kind``asBool/asString/asInt/asUint/asFloat/isValid/kind``Object` / `Array` / `composite``ObjectValue` / `ArrayValue` / `Composite`Behaviour notes
---------------

[](#behaviour-notes)

- **Errors are exceptions.** Where Go returns `(originalBytes, error)` on failure, this library throws `HuJSONException`. Error messages match the Go wording.
- **`Object`/`Array` are renamed** to `ObjectValue`/`ArrayValue` (PHP reserves those names).
- **Line comments require a terminating newline.** `// foo` at end of input is an error (`parsing comment: unexpected EOF`), exactly as in the JWCC grammar; end the source with `\n`.
- **Limitations (documented, not bugs):** `Literal::fromUint`/`asUint` are bounded by PHP's signed 64-bit `int`, so values above `PHP_INT_MAX` are not representable; float formatting relies on PHP's default `serialize_precision = -1` for shortest round-trip output.

Development
-----------

[](#development)

```
composer install
vendor/bin/phpunit
```

The golden test tables in `tests/fixtures/golden.json` are extracted verbatim from the upstream Go test files, so the suite runs fully offline. An optional `tests/DifferentialTest.php` cross-checks a broad corpus against a Go reference oracle for byte-identical output; it self-skips unless that oracle is present locally, so it never runs in a normal checkout.

License
-------

[](#license)

BSD-3-Clause. This is a port of [tailscale/hujson](https://github.com/tailscale/hujson); the original copyright (Tailscale Inc &amp; AUTHORS) is retained in [LICENSE](LICENSE).

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance100

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/c3b15c12080ca5981d2fd129b4858bb2e00cf0c5c96dff7fceb840ecfab146a2?d=identicon)[bdemirkir](/maintainers/bdemirkir)

---

Top Contributors

[![ustek-berk](https://avatars.githubusercontent.com/u/250326245?v=4)](https://github.com/ustek-berk "ustek-berk (1 commits)")

---

Tags

jsonJSON5configcommentsjwcchujson

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ustek-hujson/health.svg)

```
[![Health](https://phpackages.com/badges/ustek-hujson/health.svg)](https://phpackages.com/packages/ustek-hujson)
```

###  Alternatives

[hassankhan/config

Lightweight configuration file loader that supports PHP, INI, XML, JSON, and YAML files

97413.9M195](/packages/hassankhan-config)[colinodell/json5

UTF-8 compatible JSON5 parser for PHP

30626.3M61](/packages/colinodell-json5)[laktak/hjson

JSON for Humans. A configuration file format with relaxed syntax, fewer mistakes and more comments.

86249.0k14](/packages/laktak-hjson)[m1/vars

Vars is a simple to use and easily extendable configuration loader with in built loaders for ini, json, PHP, toml, XML and yaml/yml file types. It also comes with in built support for Silex and more frameworks to come soon.

69124.3k1](/packages/m1-vars)[phppkg/config

Config manage, load, get. Supports INI,JSON,YAML,NEON,PHP format file

133.5k](/packages/phppkg-config)[thewunder/conphigure

Framework Agnostic Configuration Library

3121.7k](/packages/thewunder-conphigure)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
