boundwize/jsonrecast

Editable JSON AST with visitor traversal and formatting-preserving printing.

Maintainers

Package info

github.com/boundwize/jsonrecast

pkg:composer/boundwize/jsonrecast

Transparency log

Fund package maintenance!

samsonasik

Statistics

Installs: 102 752

Dependents: 1

Suggesters: 0

Stars: 3

Open Issues: 0


README

JsonRecast Logo

Editable JSON AST with visitor traversal and formatting-preserving printing.

Latest Version ci build Documentation Code Coverage PHPStan Downloads

Windows macOS Linux

Edit JSON content without noisy diffs

  • Update JSON content programmatically and keep the original indentation, spacing, and key order intact.
  • Transform documents with visitors, inspired by nikic/PHP-Parser, with path awareness built in.
  • The printed output differs from the input only where you made changes; nothing else is reformatted.

Installation

composer require boundwize/jsonrecast

Example

Say we want to bump a dependency, add a new one, and remove an entry in composer.json. With JsonRecast, a single visitor does all three:

Demo of JsonRecast bumping a dependency, adding a new one, and removing an entry in composer.json while preserving the original formatting, including non-standard alignment

<?php

use Boundwize\JsonRecast\JsonRecast;
use Boundwize\JsonRecast\Node\NodeJson;
use Boundwize\JsonRecast\Node\ObjectItemNode;
use Boundwize\JsonRecast\Node\ObjectNode;
use Boundwize\JsonRecast\Node\StringNode;
use Boundwize\JsonRecast\NodePath\NodeJsonPath;
use Boundwize\JsonRecast\NodeVisitor\NodeJsonVisitor;
use Boundwize\JsonRecast\NodeVisitor\NodeJsonVisitorAbstract;

$document = JsonRecast::parse(file_get_contents('composer.json'));

$result = JsonRecast::traverse($document, new class extends NodeJsonVisitorAbstract {
    public function enterNode(NodeJson $node, NodeJsonPath $path): null|NodeJson|int
    {
        // ~ bump monolog to ^3.6
        if ($node instanceof ObjectItemNode && $path->matches(['require']) && $node->key->value === 'monolog/monolog') {
            $node->value = new StringNode('^3.6');

            return $node;
        }

        // + add guzzle under "require"
        if ($node instanceof ObjectNode && $path->matches(['require'])) {
            $node->set('guzzlehttp/guzzle', new StringNode('^7.8'));

            return $node;
        }

        // − drop the root "minimum-stability" entry
        if ($node instanceof ObjectItemNode && $path->isRoot() && $node->key->value === 'minimum-stability') {
            return NodeJsonVisitor::REMOVE_NODE;
        }

        return null;
    }
});

// update the file with original formatting preserved
file_put_contents('composer.json', JsonRecast::print($result));

Anything the visitor didn't touch keeps its original indentation, key order, and alignment.

Documentation

Documentation is available online, with source files kept in this repository: