PHPackages                             kestrelwp/php-jsonc-parser - 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. kestrelwp/php-jsonc-parser

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

kestrelwp/php-jsonc-parser
==========================

Scanner and parser for JSON with comments (JSONC) - PHP port of Microsoft's node-jsonc-parser

0.2.0(3mo ago)0372↓33.3%MITPHPPHP ^8.4CI passing

Since Jan 20Pushed 3mo agoCompare

[ Source](https://github.com/kestrelwp/php-jsonc-parser)[ Packagist](https://packagist.org/packages/kestrelwp/php-jsonc-parser)[ Docs](https://github.com/kestrelwp/php-jsonc-parser)[ RSS](/packages/kestrelwp-php-jsonc-parser/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (4)Versions (3)Used By (0)

PHP JSONC Parser
================

[](#php-jsonc-parser)

A PHP 8.4+ port of [Microsoft's node-jsonc-parser](https://github.com/microsoft/node-jsonc-parser) - a scanner and fault-tolerant parser for JSON with Comments (JSONC).

[![Latest Version on Packagist](https://camo.githubusercontent.com/14070040471d6330dc61fb445fe5aec5954f965991675d8a52b4ee4a80fab2d2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b65737472656c77702f7068702d6a736f6e632d7061727365722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kestrelwp/php-jsonc-parser)[![Tests](https://github.com/kestrelwp/php-jsonc-parser/actions/workflows/tests.yml/badge.svg)](https://github.com/kestrelwp/php-jsonc-parser/actions/workflows/tests.yml)[![Total Downloads](https://camo.githubusercontent.com/aa15741bf70f3e1c7d275b1920164e372d25ef5c487e143006b14d75a8907108/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6b65737472656c77702f7068702d6a736f6e632d7061727365722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kestrelwp/php-jsonc-parser)[![PHP Version](https://camo.githubusercontent.com/0751c5c7ed417028d6909f393af80b98d84b224db16e8307c3988e7eefc8ecdb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e342d626c7565)](https://php.net)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE.md)

Features
--------

[](#features)

- 🔍 **Scanner/Tokenizer** - Character-by-character lexical analysis
- 🌳 **Parser** - Three parsing modes:
    - SAX-style visitor pattern with event callbacks
    - DOM-style tree builder with AST nodes
    - Direct evaluation to PHP arrays/objects
- 💬 **Comment Support** - Handles `//` line comments and `/* */` block comments
- ⚡ **Fault Tolerant** - Continues parsing on errors and collects error information
- 🎨 **Formatter** - Configurable indentation, line breaks, and comment handling
- ✏️ **Editor** - Modify JSON with insert, update, and delete operations
- 🧭 **Navigation** - Find nodes by path, offset, or location matching
- 🚀 **Performance** - String interning for optimized formatting

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

[](#installation)

```
composer require kestrelwp/php-jsonc-parser
```

Quick Start
-----------

[](#quick-start)

```
use Kestrel\JsoncParser\JsoncParser;

// Parse JSONC to PHP array
$json = '{"name": "John", /* comment */ "age": 30}';
$errors = [];
$data = JsoncParser::parse($json, $errors);
// ['name' => 'John', 'age' => 30]

// Strip comments
$clean = JsoncParser::stripComments($json);
// '{"name": "John",  "age": 30}'

// Format JSON
use Kestrel\JsoncParser\Format\FormattingOptions;

$formatted = JsoncParser::applyEdits(
    $json,
    JsoncParser::format($json, null, new FormattingOptions(
        insertSpaces: true,
        tabSize: 2
    ))
);
```

Usage
-----

[](#usage)

### Parsing

[](#parsing)

#### Direct Evaluation

[](#direct-evaluation)

Parse JSON/JSONC and convert to PHP arrays and objects:

```
use Kestrel\JsoncParser\JsoncParser;

$json = '{
  "name": "Alice",
  "age": 25,
  "hobbies": ["reading", "coding"]
}';

$errors = [];
$data = JsoncParser::parse($json, $errors);

// $data = [
//     'name' => 'Alice',
//     'age' => 25,
//     'hobbies' => ['reading', 'coding']
// ]

// Check for errors
if (!empty($errors)) {
    foreach ($errors as $error) {
        echo "Error: {$error->error->value} at offset {$error->offset}\n";
    }
}
```

#### DOM Tree

[](#dom-tree)

Build an Abstract Syntax Tree (AST):

```
use Kestrel\JsoncParser\JsoncParser;

$json = '{"x": 1, "y": 2}';
$errors = [];
$tree = JsoncParser::parseTree($json, $errors);

// Navigate the tree
foreach ($tree->children as $property) {
    $key = $property->children[0]->value;   // Property name
    $value = $property->children[1]->value; // Property value
    echo "$key = $value\n";
}
```

#### Visitor Pattern

[](#visitor-pattern)

Process JSON with event callbacks (SAX-style):

```
use Kestrel\JsoncParser\JsoncParser;
use Kestrel\JsoncParser\Parser\JsonVisitor;

$visitor = new class implements JsonVisitor {
    public function onObjectBegin(int $offset, int $length, int $startLine, int $startCharacter, \Closure $pathSupplier): bool|null {
        echo "Object started at offset $offset\n";
        return null;
    }

    public function onObjectProperty(string $property, int $offset, int $length, int $startLine, int $startCharacter, \Closure $pathSupplier): bool|null {
        echo "Property: $property\n";
        return null;
    }

    public function onLiteralValue(mixed $value, int $offset, int $length, int $startLine, int $startCharacter, \Closure $pathSupplier): bool|null {
        echo "Value: $value\n";
        return null;
    }

    // Implement other interface methods...
    public function onObjectEnd(int $offset, int $length, int $startLine, int $startCharacter): bool|null { return null; }
    public function onArrayBegin(int $offset, int $length, int $startLine, int $startCharacter, \Closure $pathSupplier): bool|null { return null; }
    public function onArrayEnd(int $offset, int $length, int $startLine, int $startCharacter): bool|null { return null; }
    public function onSeparator(string $character, int $offset, int $length, int $startLine, int $startCharacter): bool|null { return null; }
    public function onComment(int $offset, int $length, int $startLine, int $startCharacter): bool|null { return null; }
    public function onError(int $error, int $offset, int $length, int $startLine, int $startCharacter): bool|null { return null; }
};

$json = '{"name": "Bob", "age": 30}';
JsoncParser::visit($json, $visitor);
```

### Scanning/Tokenization

[](#scanningtokenization)

Low-level token scanning:

```
use Kestrel\JsoncParser\JsoncParser;
use Kestrel\JsoncParser\Scanner\SyntaxKind;

$scanner = JsoncParser::createScanner('{"key": 123}');

while (($token = $scanner->scan()) !== SyntaxKind::EOF) {
    echo $token->name . ': ' . $scanner->getTokenValue() . "\n";
}
// OpenBraceToken: {
// StringLiteral: "key"
// ColonToken: :
// NumericLiteral: 123
// CloseBraceToken: }
```

### Navigation

[](#navigation)

Find nodes in the AST:

```
use Kestrel\JsoncParser\JsoncParser;

$json = '{"user": {"name": "Alice", "age": 30}}';
$tree = JsoncParser::parseTree($json);

// Find by path
$nameNode = JsoncParser::findNodeAtLocation($tree, ['user', 'name']);
echo JsoncParser::getNodeValue($nameNode); // "Alice"

// Find by offset
$node = JsoncParser::findNodeAtOffset($tree, 15);

// Get node path
$path = JsoncParser::getNodePath($nameNode);
// ['user', 'name']

// Get location at position
$location = JsoncParser::getLocation($json, 15);
echo implode('.', $location->path); // "user.name"
```

### Formatting

[](#formatting)

Format JSON with configurable options:

```
use Kestrel\JsoncParser\JsoncParser;
use Kestrel\JsoncParser\Format\FormattingOptions;

$json = '{"name":"Alice","age":30}';

$options = new FormattingOptions(
    insertSpaces: true,     // Use spaces instead of tabs
    tabSize: 2,            // Indent size
    insertFinalNewline: true,
    eol: "\n",             // Line ending
    keepLines: false       // Don't preserve original line breaks
);

$edits = JsoncParser::format($json, null, $options);
$formatted = JsoncParser::applyEdits($json, $edits);

echo $formatted;
// {
//   "name": "Alice",
//   "age": 30
// }
```

### Modification

[](#modification)

Modify JSON documents:

```
use Kestrel\JsoncParser\JsoncParser;
use Kestrel\JsoncParser\Edit\ModificationOptions;
use Kestrel\JsoncParser\Edit\RemoveMarker;
use Kestrel\JsoncParser\Format\FormattingOptions;

$json = '{"name": "Alice", "age": 30}';

$options = new ModificationOptions(
    formattingOptions: new FormattingOptions(
        insertSpaces: true,
        tabSize: 2
    )
);

// Set a value
$edits = JsoncParser::modify($json, ['email'], 'alice@example.com', $options);
$json = JsoncParser::applyEdits($json, $edits);

// Update a value
$edits = JsoncParser::modify($json, ['age'], 31, $options);
$json = JsoncParser::applyEdits($json, $edits);

// Delete a property (use RemoveMarker, not null - null is a valid JSON value)
$edits = JsoncParser::modify($json, ['age'], RemoveMarker::instance(), $options);
$json = JsoncParser::applyEdits($json, $edits);

// Array operations
$json = '{"items": [1, 2, 3]}';

// Insert at end (-1)
$edits = JsoncParser::modify($json, ['items', -1], 4, $options);

// Insert at specific index
$edits = JsoncParser::modify($json, ['items', 1], 99, new ModificationOptions(
    formattingOptions: $options->formattingOptions,
    isArrayInsertion: true  // Insert, don't replace
));

// Delete array element
$edits = JsoncParser::modify($json, ['items', 0], RemoveMarker::instance(), $options);
```

### Comment Handling

[](#comment-handling)

```
use Kestrel\JsoncParser\JsoncParser;

$jsonc = '{
  "name": "Alice", // user name
  /* age field */ "age": 30
}';

// Strip comments
$clean = JsoncParser::stripComments($jsonc);
// {"name": "Alice",  "age": 30}

// Replace comments with spaces (preserves formatting)
$replaced = JsoncParser::stripComments($jsonc, ' ');

// Parse with comments (automatically handled)
$data = JsoncParser::parse($jsonc);
```

API Reference
-------------

[](#api-reference)

### JsoncParser (Facade)

[](#jsoncparser-facade)

Main entry point for all operations.

#### Scanner

[](#scanner)

- `createScanner(string $text, bool $ignoreTrivia = false): JsonScanner`

#### Parser

[](#parser)

- `parse(string $text, array &$errors = [], ?ParseOptions $options = null): mixed`
- `parseTree(string $text, array &$errors = [], ?ParseOptions $options = null): ?Node`
- `visit(string $text, JsonVisitor $visitor, ?ParseOptions $options = null): mixed`
- `stripComments(string $text, ?string $replaceCh = null): string`

#### Navigation

[](#navigation-1)

- `getLocation(string $text, int $position): Location`
- `findNodeAtLocation(?Node $root, array $path): ?Node`
- `findNodeAtOffset(Node $node, int $offset, bool $includeRightBound = false): ?Node`
- `getNodePath(Node $node): array`
- `getNodeValue(Node $node): mixed`

#### Formatting

[](#formatting-1)

- `format(string $documentText, ?Range $range, FormattingOptions $options): array`

#### Editing

[](#editing)

- `modify(string $text, array $path, mixed $value, ModificationOptions $options): array`
- `applyEdits(string $text, array $edits): string`

### Options Classes

[](#options-classes)

#### ParseOptions

[](#parseoptions)

```
new ParseOptions(
    disallowComments: false,    // Reject comments
    allowTrailingComma: false,  // Allow trailing commas
    allowEmptyContent: false    // Allow empty input
)
```

#### FormattingOptions

[](#formattingoptions)

```
new FormattingOptions(
    insertSpaces: true,         // Use spaces vs tabs
    tabSize: 2,                 // Indent size
    insertFinalNewline: false,  // Add newline at EOF
    eol: "\n",                  // Line ending
    keepLines: false            // Preserve line breaks
)
```

#### ModificationOptions

[](#modificationoptions)

```
new ModificationOptions(
    formattingOptions: $formattingOptions,
    isArrayInsertion: false,    // Insert vs replace in arrays
    getInsertionIndex: null     // Custom property ordering
)
```

Error Handling
--------------

[](#error-handling)

The parser is fault-tolerant and continues on errors:

```
$json = '{"invalid": true,}'; // Trailing comma
$errors = [];
$data = JsoncParser::parse($json, $errors);

foreach ($errors as $error) {
    echo "Error code: {$error->error->value}\n";
    echo "At offset: {$error->offset}\n";
    echo "Length: {$error->length}\n";
}
```

Examples
--------

[](#examples)

See the [examples](examples/) directory for complete working examples:

- [basic\_parsing.php](examples/basic_parsing.php) - Parsing, scanning, and basic operations
- [visitor\_pattern.php](examples/visitor_pattern.php) - Using the visitor pattern
- [modification.php](examples/modification.php) - Modifying and formatting JSON

Differences from JavaScript Version
-----------------------------------

[](#differences-from-javascript-version)

1. **Deletion marker**: PHP doesn't distinguish `null` from `undefined`, so we use `RemoveMarker::instance()` to indicate deletion in `modify()` operations
2. **Return type**: Visitor methods return `bool|null` instead of `void` for consistency with PHP's type system
3. **Naming**: Uses PSR-12 style (e.g., `getNodeValue` instead of `getNodeValue`)

Performance
-----------

[](#performance)

The library includes performance optimizations:

- **String interning**: Caches commonly used strings (spaces, line breaks)
- **Lazy evaluation**: Only parses what's needed
- **Efficient scanning**: Character-by-character with minimal allocations

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

[](#requirements)

- PHP 8.4 or higher
- ext-mbstring (for UTF-8 support)

Testing
-------

[](#testing)

```
# Run tests
composer test

# Run with coverage
composer test-coverage

# Code style
composer format

# Static analysis
composer stan
```

Credits
-------

[](#credits)

This is a PHP port of Microsoft's [node-jsonc-parser](https://github.com/microsoft/node-jsonc-parser), licensed under the MIT License.

License
-------

[](#license)

MIT License - see [LICENSE.md](LICENSE.md) for details.

Contributing
------------

[](#contributing)

Contributions are welcome! Please ensure:

- All tests pass (`composer test`)
- Code follows PSR-12 (`composer format`)
- PHPStan passes (`composer stan`)

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance79

Regular maintenance activity

Popularity17

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 92.3% 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

Every ~6 days

Total

2

Last Release

112d ago

### Community

Maintainers

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

---

Top Contributors

[![ragulka](https://avatars.githubusercontent.com/u/593267?v=4)](https://github.com/ragulka "ragulka (12 commits)")[![maxrice](https://avatars.githubusercontent.com/u/1579862?v=4)](https://github.com/maxrice "maxrice (1 commits)")

---

Tags

jsonparsercommentsscannerjsoncjson-with-comments

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/kestrelwp-php-jsonc-parser/health.svg)

```
[![Health](https://phpackages.com/badges/kestrelwp-php-jsonc-parser/health.svg)](https://phpackages.com/packages/kestrelwp-php-jsonc-parser)
```

###  Alternatives

[salsify/json-streaming-parser

A streaming parser for JSON in PHP.

7766.7M15](/packages/salsify-json-streaming-parser)[cerbero/json-parser

Zero-dependencies pull parser to read large JSON from any source in a memory-efficient way.

803474.6k5](/packages/cerbero-json-parser)[laktak/hjson

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

86233.7k12](/packages/laktak-hjson)[pcrov/jsonreader

JSON Pull Parser

1451.2M5](/packages/pcrov-jsonreader)[bcncommerce/json-stream

A bundle of tools to work with JSON in PHP

642.2M3](/packages/bcncommerce-json-stream)[sbsaga/toon

🧠 TOON for Laravel — a compact, human-readable, and token-efficient data format for AI prompts &amp; LLM contexts. Perfect for ChatGPT, Gemini, Claude, Mistral, and OpenAI integrations (JSON ⇄ TOON).

6115.6k](/packages/sbsaga-toon)

PHPackages © 2026

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