nikic / PHP-Parser

A PHP parser written in PHP

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Formatting-preserving pretty printing

harikt opened this issue · comments

Hi,

I am trying to add a few comments to below code

<?php
return [
	// Inline comments

	'a' => 'A',

	'b' => [
		'c1' => 'C1', // # b.c1 #
		'c2' => 'C2',
		'c3' => 'C3',
	],

	/**
	 * Multiline comments
	 */

	'g' => [
		'h' => [
			'k1' => 'L1', // # g.h.k1 #
			'k2' => 'L2'
		]
	]
];

so that the modified one will add a few comments as below.

<?php
return [
	// Inline comments

	// # a #
	'a' => 'A',

	// # b #
	'b' => [
		// # b.c1 #
		'c1' => 'C1', // # b.c1 #
		// # b.c2 #
		'c2' => 'C2',
		// # b.c3 #
		'c3' => 'C3',
	],

	/**
	 * Multiline comments
	 */

	// # g #
	'g' => [
		// # g.h #
		'h' => [
			// # g.h.k1 #
			'k1' => 'L1', // # g.h.k1 #
			// # g.h.k2 #
			'k2' => 'L2'
		]
	]
];

The code that run to modify the AST is as

<?php
require __DIR__ . '/vendor/autoload.php';

use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;
use PhpParser\Lexer;
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor;
use PhpParser\NodeVisitorAbstract;

$lexer = new Lexer\Emulative([
	'usedAttributes' => [
		'comments',
		'startLine', 'endLine',
		'startTokenPos', 'endTokenPos',
	],
]);

$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7, $lexer);

$code = file_get_contents(__DIR__ . '/src/Config/Test.php');

$traverser = new NodeTraverser();
// $traverser->addVisitor(new NodeVisitor\CloningVisitor());

$oldStmts = $parser->parse($code);
$oldTokens = $lexer->getTokens();

$newStmts = $traverser->traverse($oldStmts);

$traverser = new NodeTraverser();
$traverser->addVisitor(new class extends NodeVisitorAbstract {

	protected $item_value = '';

	protected $item_values = [];

	public function enterNode(Node $node)
	{
		if ($node instanceof Node\Expr\Array_)
		{
			if ($this->item_value)
			{
				$this->item_values[] = $this->item_value;
			}
		}

		if ($node instanceof Node\Expr\ArrayItem)
		{
			$this->item_value = $node->key->value;
		}

		return $node;
	}

	public function leaveNode(Node $node)
	{
		if ($node instanceof Node\Expr\Array_)
		{
			if ($this->item_values)
			{
				array_pop($this->item_values);
			}
		}

		if ($node instanceof Node\Expr\ArrayItem)
		{
			$key = $node->key->value;
			if ($this->item_values)
			{
				$key = implode('.', $this->item_values) . "." . $node->key->value;
			}
			$comments = $node->getComments();
			$comments[] = new PhpParser\Comment\Doc("// # {$key} #", $node->getStartLine(), $node->getStartFilePos(), $node->getStartTokenPos(), $node->getEndLine(), $node->getEndFilePos(), $node->getEndTokenPos());
			$node->setAttribute('comments', $comments);
		}

		return $node;
	}
});

$newStmts2 = $traverser->traverse($newStmts);

$prettyPrinter = new PrettyPrinter\Standard();
echo $prettyPrinter->printFormatPreserving($newStmts2, $newStmts, $oldTokens);

From the docs it mentions to add NodeVisitor\CloningVisitor. I have tried that also, but the formatting is not as the original.

Below is the output when I have used CloningVisitor .

Screenshot 2023-07-08 at 5 16 17 PM

Below is the output when I comment out CloningVisitor . But the new lines are removed in that case.

Screenshot 2023-07-08 at 5 17 17 PM

I am not sure if this is a bug or is caused by the code I have.

Thank you.