-1

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.

2
  • Not sure of the actual problem, but would a simpler method of read source/replace arbitrary token/write file make this process a lot easier? Commented Dec 16, 2020 at 13:17
  • The actual "problem" is more of the source file than necessary will be modified, causing larger and unrelated changes in version control. I'd not like having tools mess up my config files, and it doesn't exactly instill confidence either... I wanted to avoid using regex search-replace if possible, due to all the edge cases it causes :/ (see relevant CodingHorror) Commented Dec 16, 2020 at 17:57

1 Answer 1

1

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")]]
    );
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.