PHP-Parser: Pretty printing multi-line arrays

358 views Asked by At

Using nikic/php-parser, I'm trying to read an existing configuration file, find an array node within it, append a new item to this node, then write everything back to the file.
Ideally, this should not modify the rest of the file, including comments and whitespace.

I'm using the approach to formatting-preserving pretty printing outlined in the documentation.

The node visitor roughly looks like the following (truncated for clarity):

$traverser = new NodeTraverser();
$traverser->addVisitor(new class extends Visitor {
    public function leaveNode(Node $node): ?Node
    {
        if ($this->isParentNodeIAmLookingFor($node)) {

            // Check whether the new item exists
            if ($this->nodeAlreadyHasChild($node, $node->value->items)) {
                throw new RuntimeException('Item exists');
            }

            // The structure I'd like to add
            $newChild = new Expr\Array_();
            $newChild->setAttribute( 'kind', Expr\Array_::KIND_SHORT);

            // Adding a new item with my desired key into the target array here
            $node->value->items[] = new Expr\ArrayItem(
                $newChild,
                new Scalar\String_('<<NEWLY_INSERTED_ITEM>>')
            );

            return $node;
        }

        return null;
    }
});

The original configuration file looks roughly like this:

<?php
return [
    'important stuff' => [
        'with multiple lines',
        /* ... */
    ],

    // A comment I'd like to keep
    'items' => [
        'an existing item' => [ /* with stuff */ ],

        # <------ this is where I'd like to add my new item
    ],
];

What PHP-Parser prints out, though:

<?php
return [
    'important stuff' => ['with multiple lines', /* ... */ ],
    // A comment I'd like to keep
    'items' => ['an existing item' => [ /* with stuff */ ], '<<NEWLY_INSERTED_ITEM>>' => []],
];

So it seems like the formatting-preserving pretty printing does actually remove empty lines between all items in the file, even though I did not touch them, and also transforms my existing arrays from multi-line to single-line.
I know the formatting-preserving option is still experimental and incomplete, but from what I've read in the docs, issues and code multi-line arrays should actually be working already, and thus I would have expected the other items to stay the same at least.

Is there a way to force multi-line output for array structures? Anything I've missed? I'm not too deep into AST manipulations yet.

1

There are 1 answers

0
anonymous On

You can add whitespace via the Comment class in a node's attributes. (You can just specify whitespace in the comment text instead of comment characters.) For example, here's inserting a new alternate node

return new Node\Stmt\Property(
        8,
        [new Node\Stmt\PropertyProperty(
            new Node\VarLikeIdentifier($ident),
            static::valueNode($value)
        )],
        ['comments'=>[new Comment("\n")]]
    );