mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-30 06:33:31 +00:00
Various doc parser fixes (#6125)
This commit is contained in:
parent
22d35689bf
commit
5bde10c181
|
@ -0,0 +1,3 @@
|
||||||
|
/**
|
||||||
|
* @foor a,
|
||||||
|
*/
|
|
@ -38,7 +38,7 @@ final class ArrayParserTest extends AbstractKernelTestCase
|
||||||
{
|
{
|
||||||
$betterTokenIterator = $this->tokenIteratorFactory->create($docContent);
|
$betterTokenIterator = $this->tokenIteratorFactory->create($docContent);
|
||||||
|
|
||||||
$array = $this->arrayParser->parserArray($betterTokenIterator);
|
$array = $this->arrayParser->parseCurlyArray($betterTokenIterator);
|
||||||
$this->assertSame($expectedArray, $array);
|
$this->assertSame($expectedArray, $array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\BetterPhpDocParser\PhpDocParser\TagValueNodeReprint\Fixture;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Rector\Tests\BetterPhpDocParser\PhpDocParser\TagValueNodeReprint\Source\Embeddable;
|
||||||
|
|
||||||
|
final class AnEntityWithAnEmbedded
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Embedded(class="Embeddable"),
|
||||||
|
*/
|
||||||
|
private $embedded;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
-----
|
||||||
|
PhpParser\Node\Stmt\Property
|
||||||
|
-----
|
||||||
|
Doctrine\ORM\Mapping\Embedded
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\BetterPhpDocParser\PhpDocParser\TagValueNodeReprint\Fixture;
|
||||||
|
|
||||||
|
use Annotation\NotFoundErrorResponse;
|
||||||
|
use Annotation\OpenApi;
|
||||||
|
|
||||||
|
final class AnEntityWithAnEmbedded
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @NotFoundErrorResponse( "collection" ) ,
|
||||||
|
*
|
||||||
|
* @OpenApi("
|
||||||
|
* summary: Delete collection
|
||||||
|
* ")
|
||||||
|
*/
|
||||||
|
private $embedded;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
-----
|
||||||
|
PhpParser\Node\Stmt\Property
|
||||||
|
-----
|
||||||
|
Annotation\NotFoundErrorResponse
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\BetterPhpDocParser\PhpDocParser\TagValueNodeReprint\Fixture;
|
||||||
|
|
||||||
|
use Annotation\NotFoundErrorResponse;
|
||||||
|
use Annotation\OpenApi;
|
||||||
|
|
||||||
|
final class AnEntityWithAnEmbeddedWithoutSpaces
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @NotFoundErrorResponse("collection"),
|
||||||
|
*
|
||||||
|
* @OpenApi("
|
||||||
|
* summary: Delete collection
|
||||||
|
* ")
|
||||||
|
*/
|
||||||
|
private $embedded;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
-----
|
||||||
|
PhpParser\Node\Stmt\Property
|
||||||
|
-----
|
||||||
|
Annotation\NotFoundErrorResponse
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\BetterPhpDocParser\PhpDocParser\TagValueNodeReprint\Fixture;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Swagger\Annotations as SWG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Long running task to track progress.
|
||||||
|
*
|
||||||
|
* @ORM\Entity(repositoryClass="Application\Api\Admin\Repository\AdminTaskRepository")
|
||||||
|
* @ORM\Table(
|
||||||
|
* name="admin_task",
|
||||||
|
* options={"collate": "utf8_bin", "charset": "utf8"},
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @SWG\Definition(required={"id", "created", "modified", "status", "progress", "completed"})
|
||||||
|
*/
|
||||||
|
final class Mixture
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
-----
|
||||||
|
PhpParser\Node\Stmt\Class_
|
||||||
|
-----
|
||||||
|
Swagger\Annotations\Definition
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\BetterPhpDocParser\PhpDocParser\TagValueNodeReprint\Fixture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Api\ApiResource(
|
||||||
|
* normalizationContext={"groups"={"default"}}
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
final class QuotedKeysAndValues
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
-----
|
||||||
|
PhpParser\Node\Stmt\Class_
|
||||||
|
-----
|
||||||
|
Api\ApiResource
|
|
@ -9,6 +9,7 @@ use PhpParser\Node;
|
||||||
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
||||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
|
||||||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
|
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
|
||||||
|
use PHPStan\PhpDocParser\Lexer\Lexer;
|
||||||
use Rector\BetterPhpDocParser\Attributes\AttributeMirrorer;
|
use Rector\BetterPhpDocParser\Attributes\AttributeMirrorer;
|
||||||
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
|
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
|
||||||
use Rector\BetterPhpDocParser\PhpDoc\SpacelessPhpDocTagNode;
|
use Rector\BetterPhpDocParser\PhpDoc\SpacelessPhpDocTagNode;
|
||||||
|
@ -21,12 +22,6 @@ use Rector\Core\Exception\ShouldNotHappenException;
|
||||||
|
|
||||||
final class DoctrineAnnotationDecorator
|
final class DoctrineAnnotationDecorator
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @see https://regex101.com/r/jHF5D9/1
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private const OPEN_ANNOTATION_SUFFIX_REGEX = '#(\{|\,)$#';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var CurrentNodeProvider
|
* @var CurrentNodeProvider
|
||||||
*/
|
*/
|
||||||
|
@ -76,6 +71,91 @@ final class DoctrineAnnotationDecorator
|
||||||
// merge split doctrine nested tags
|
// merge split doctrine nested tags
|
||||||
$this->mergeNestedDoctrineAnnotations($phpDocNode);
|
$this->mergeNestedDoctrineAnnotations($phpDocNode);
|
||||||
|
|
||||||
|
$this->transformGenericTagValueNodesToDoctrineAnnotationTagValueNodes($phpDocNode, $currentPhpNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join token iterator with all the following nodes if nested
|
||||||
|
*/
|
||||||
|
private function mergeNestedDoctrineAnnotations(PhpDocNode $phpDocNode): void
|
||||||
|
{
|
||||||
|
$removedKeys = [];
|
||||||
|
|
||||||
|
foreach ($phpDocNode->children as $key => $phpDocChildNode) {
|
||||||
|
if (in_array($key, $removedKeys, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $phpDocChildNode instanceof PhpDocTagNode) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $phpDocChildNode->value instanceof GenericTagValueNode) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$genericTagValueNode = $phpDocChildNode->value;
|
||||||
|
|
||||||
|
while (isset($phpDocNode->children[$key])) {
|
||||||
|
++$key;
|
||||||
|
|
||||||
|
// no more next nodes
|
||||||
|
if (! isset($phpDocNode->children[$key])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nextPhpDocChildNode = $phpDocNode->children[$key];
|
||||||
|
if (! $nextPhpDocChildNode instanceof PhpDocTagNode) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $nextPhpDocChildNode->value instanceof GenericTagValueNode) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isClosedContent($genericTagValueNode->value)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$composedContent = $genericTagValueNode->value . PHP_EOL . $nextPhpDocChildNode->name . $nextPhpDocChildNode->value;
|
||||||
|
$genericTagValueNode->value = $composedContent;
|
||||||
|
|
||||||
|
/** @var StartAndEnd $currentStartAndEnd */
|
||||||
|
$currentStartAndEnd = $phpDocChildNode->getAttribute(PhpDocAttributeKey::START_AND_END);
|
||||||
|
|
||||||
|
/** @var StartAndEnd $nextStartAndEnd */
|
||||||
|
$nextStartAndEnd = $nextPhpDocChildNode->getAttribute(PhpDocAttributeKey::START_AND_END);
|
||||||
|
|
||||||
|
$startAndEnd = new StartAndEnd($currentStartAndEnd->getStart(), $nextStartAndEnd->getEnd());
|
||||||
|
$phpDocChildNode->setAttribute(PhpDocAttributeKey::START_AND_END, $startAndEnd);
|
||||||
|
|
||||||
|
$currentChildValueNode = $phpDocNode->children[$key];
|
||||||
|
if (! $currentChildValueNode instanceof PhpDocTagNode) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentGenericTagValueNode = $currentChildValueNode->value;
|
||||||
|
if (! $currentGenericTagValueNode instanceof GenericTagValueNode) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$removedKeys[] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (array_keys($phpDocNode->children) as $key) {
|
||||||
|
if (! in_array($key, $removedKeys, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($phpDocNode->children[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function transformGenericTagValueNodesToDoctrineAnnotationTagValueNodes(
|
||||||
|
PhpDocNode $phpDocNode,
|
||||||
|
Node $currentPhpNode
|
||||||
|
): void {
|
||||||
foreach ($phpDocNode->children as $key => $phpDocChildNode) {
|
foreach ($phpDocNode->children as $key => $phpDocChildNode) {
|
||||||
if (! $phpDocChildNode instanceof PhpDocTagNode) {
|
if (! $phpDocChildNode instanceof PhpDocTagNode) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -111,6 +191,7 @@ final class DoctrineAnnotationDecorator
|
||||||
$values,
|
$values,
|
||||||
SilentKeyMap::CLASS_NAMES_TO_SILENT_KEYS[$fullyQualifiedAnnotationClass] ?? null
|
SilentKeyMap::CLASS_NAMES_TO_SILENT_KEYS[$fullyQualifiedAnnotationClass] ?? null
|
||||||
);
|
);
|
||||||
|
|
||||||
$doctrineAnnotationTagValueNode->setAttribute(PhpDocAttributeKey::START_AND_END, $formerStartEnd);
|
$doctrineAnnotationTagValueNode->setAttribute(PhpDocAttributeKey::START_AND_END, $formerStartEnd);
|
||||||
|
|
||||||
$spacelessPhpDocTagNode = new SpacelessPhpDocTagNode(
|
$spacelessPhpDocTagNode = new SpacelessPhpDocTagNode(
|
||||||
|
@ -124,76 +205,36 @@ final class DoctrineAnnotationDecorator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join token iterator with all the following nodes if nested
|
* This is closed block, e.g. {( ... )},
|
||||||
|
* false on: {( ... )
|
||||||
*/
|
*/
|
||||||
private function mergeNestedDoctrineAnnotations(PhpDocNode $phpDocNode): void
|
private function isClosedContent(string $composedContent): bool
|
||||||
{
|
{
|
||||||
$removedKeys = [];
|
$composedTokenIterator = $this->tokenIteratorFactory->create($composedContent);
|
||||||
|
$tokenCount = $composedTokenIterator->count();
|
||||||
|
|
||||||
foreach ($phpDocNode->children as $key => $phpDocChildNode) {
|
$openBracketCount = 0;
|
||||||
if (in_array($key, $removedKeys, true)) {
|
$closeBracketCount = 0;
|
||||||
continue;
|
|
||||||
|
do {
|
||||||
|
if ($composedTokenIterator->isCurrentTokenTypes([
|
||||||
|
Lexer::TOKEN_OPEN_CURLY_BRACKET,
|
||||||
|
Lexer::TOKEN_OPEN_PARENTHESES,
|
||||||
|
]) || Strings::contains($composedTokenIterator->currentTokenValue(), '(')) {
|
||||||
|
++$openBracketCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $phpDocChildNode instanceof PhpDocTagNode) {
|
if ($composedTokenIterator->isCurrentTokenTypes([
|
||||||
continue;
|
Lexer::TOKEN_CLOSE_CURLY_BRACKET,
|
||||||
|
Lexer::TOKEN_CLOSE_PARENTHESES,
|
||||||
|
// sometimes it gets mixed int ")
|
||||||
|
]) || Strings::contains($composedTokenIterator->currentTokenValue(), ')')) {
|
||||||
|
++$closeBracketCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $phpDocChildNode->value instanceof GenericTagValueNode) {
|
$composedTokenIterator->next();
|
||||||
continue;
|
} while ($composedTokenIterator->currentPosition() < ($tokenCount - 1));
|
||||||
}
|
|
||||||
|
|
||||||
$genericTagValueNode = $phpDocChildNode->value;
|
return $openBracketCount === $closeBracketCount;
|
||||||
|
|
||||||
/** @var GenericTagValueNode $currentGenericTagValueNode */
|
|
||||||
$currentGenericTagValueNode = $genericTagValueNode;
|
|
||||||
|
|
||||||
while (Strings::match($currentGenericTagValueNode->value, self::OPEN_ANNOTATION_SUFFIX_REGEX)) {
|
|
||||||
$nextPhpDocChildNode = $phpDocNode->children[$key + 1];
|
|
||||||
if (! $nextPhpDocChildNode instanceof PhpDocTagNode) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $nextPhpDocChildNode->value instanceof GenericTagValueNode) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$genericTagValueNode->value .= PHP_EOL . $nextPhpDocChildNode->name . $nextPhpDocChildNode->value;
|
|
||||||
|
|
||||||
/** @var StartAndEnd $currentStartAndEnd */
|
|
||||||
$currentStartAndEnd = $phpDocChildNode->getAttribute(PhpDocAttributeKey::START_AND_END);
|
|
||||||
|
|
||||||
/** @var StartAndEnd $nextStartAndEnd */
|
|
||||||
$nextStartAndEnd = $nextPhpDocChildNode->getAttribute(PhpDocAttributeKey::START_AND_END);
|
|
||||||
|
|
||||||
$startAndEnd = new StartAndEnd($currentStartAndEnd->getStart(), $nextStartAndEnd->getEnd());
|
|
||||||
$phpDocChildNode->setAttribute(PhpDocAttributeKey::START_AND_END, $startAndEnd);
|
|
||||||
|
|
||||||
++$key;
|
|
||||||
if (! isset($phpDocNode->children[$key])) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentChildValueNode = $phpDocNode->children[$key];
|
|
||||||
if (! $currentChildValueNode instanceof PhpDocTagNode) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentGenericTagValueNode = $currentChildValueNode->value;
|
|
||||||
if (! $currentGenericTagValueNode instanceof GenericTagValueNode) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$removedKeys[] = $key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (array_keys($phpDocNode->children) as $key) {
|
|
||||||
if (! in_array($key, $removedKeys, true)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($phpDocNode->children[$key]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ final class StaticDoctrineAnnotationParser
|
||||||
private function parseValue(BetterTokenIterator $tokenIterator)
|
private function parseValue(BetterTokenIterator $tokenIterator)
|
||||||
{
|
{
|
||||||
if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) {
|
if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) {
|
||||||
$items = $this->arrayParser->parserArray($tokenIterator);
|
$items = $this->arrayParser->parseCurlyArray($tokenIterator);
|
||||||
return new CurlyListNode($items);
|
return new CurlyListNode($items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,15 @@ final class ArrayParser
|
||||||
* Mimics https://github.com/doctrine/annotations/blob/c66f06b7c83e9a2a7523351a9d5a4b55f885e574/lib/Doctrine/Common/Annotations/DocParser.php#L1305-L1352
|
* Mimics https://github.com/doctrine/annotations/blob/c66f06b7c83e9a2a7523351a9d5a4b55f885e574/lib/Doctrine/Common/Annotations/DocParser.php#L1305-L1352
|
||||||
* @return mixed[]
|
* @return mixed[]
|
||||||
*/
|
*/
|
||||||
public function parserArray(BetterTokenIterator $tokenIterator): array
|
public function parseCurlyArray(BetterTokenIterator $tokenIterator): array
|
||||||
{
|
{
|
||||||
$values = [];
|
$values = [];
|
||||||
|
|
||||||
|
// nothing
|
||||||
|
if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$tokenIterator->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);
|
$tokenIterator->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);
|
||||||
|
|
||||||
// If the array is empty, stop parsing and return.
|
// If the array is empty, stop parsing and return.
|
||||||
|
|
|
@ -33,6 +33,11 @@ final class PlainValueParser
|
||||||
*/
|
*/
|
||||||
private $currentNodeProvider;
|
private $currentNodeProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ArrayParser
|
||||||
|
*/
|
||||||
|
private $arrayParser;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ClassAnnotationMatcher $classAnnotationMatcher,
|
ClassAnnotationMatcher $classAnnotationMatcher,
|
||||||
CurrentNodeProvider $currentNodeProvider
|
CurrentNodeProvider $currentNodeProvider
|
||||||
|
@ -44,9 +49,12 @@ final class PlainValueParser
|
||||||
/**
|
/**
|
||||||
* @required
|
* @required
|
||||||
*/
|
*/
|
||||||
public function autowirePlainValueParser(StaticDoctrineAnnotationParser $staticDoctrineAnnotationParser): void
|
public function autowirePlainValueParser(
|
||||||
{
|
StaticDoctrineAnnotationParser $staticDoctrineAnnotationParser,
|
||||||
|
ArrayParser $arrayParser
|
||||||
|
): void {
|
||||||
$this->staticDoctrineAnnotationParser = $staticDoctrineAnnotationParser;
|
$this->staticDoctrineAnnotationParser = $staticDoctrineAnnotationParser;
|
||||||
|
$this->arrayParser = $arrayParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,6 +70,11 @@ final class PlainValueParser
|
||||||
}
|
}
|
||||||
|
|
||||||
// consume the token
|
// consume the token
|
||||||
|
$isOpenCurlyArray = $tokenIterator->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);
|
||||||
|
if ($isOpenCurlyArray) {
|
||||||
|
return $this->arrayParser->parseCurlyArray($tokenIterator);
|
||||||
|
}
|
||||||
|
|
||||||
$tokenIterator->next();
|
$tokenIterator->next();
|
||||||
|
|
||||||
// normalize value
|
// normalize value
|
||||||
|
@ -86,27 +99,34 @@ final class PlainValueParser
|
||||||
|
|
||||||
// nested entity!
|
// nested entity!
|
||||||
if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
if ($tokenIterator->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
|
||||||
// @todo
|
return $this->parseNestedDoctrineAnnotationTagValueNode($currentTokenValue, $tokenIterator);
|
||||||
$annotationShortName = $currentTokenValue;
|
|
||||||
$values = $this->staticDoctrineAnnotationParser->resolveAnnotationMethodCall($tokenIterator);
|
|
||||||
|
|
||||||
$currentNode = $this->currentNodeProvider->getNode();
|
|
||||||
if (! $currentNode instanceof Node) {
|
|
||||||
throw new ShouldNotHappenException();
|
|
||||||
}
|
|
||||||
|
|
||||||
$fullyQualifiedAnnotationClass = $this->classAnnotationMatcher->resolveTagFullyQualifiedName(
|
|
||||||
$annotationShortName,
|
|
||||||
$currentNode
|
|
||||||
);
|
|
||||||
|
|
||||||
// keep the last ")"
|
|
||||||
$tokenIterator->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
|
||||||
$tokenIterator->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
|
|
||||||
|
|
||||||
return new DoctrineAnnotationTagValueNode($fullyQualifiedAnnotationClass, $annotationShortName, $values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $currentTokenValue;
|
return $currentTokenValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function parseNestedDoctrineAnnotationTagValueNode(
|
||||||
|
string $currentTokenValue,
|
||||||
|
BetterTokenIterator $tokenIterator
|
||||||
|
): DoctrineAnnotationTagValueNode {
|
||||||
|
// @todo
|
||||||
|
$annotationShortName = $currentTokenValue;
|
||||||
|
$values = $this->staticDoctrineAnnotationParser->resolveAnnotationMethodCall($tokenIterator);
|
||||||
|
|
||||||
|
$currentNode = $this->currentNodeProvider->getNode();
|
||||||
|
if (! $currentNode instanceof Node) {
|
||||||
|
throw new ShouldNotHappenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fullyQualifiedAnnotationClass = $this->classAnnotationMatcher->resolveTagFullyQualifiedName(
|
||||||
|
$annotationShortName,
|
||||||
|
$currentNode
|
||||||
|
);
|
||||||
|
|
||||||
|
// keep the last ")"
|
||||||
|
$tokenIterator->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
|
||||||
|
$tokenIterator->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
|
||||||
|
|
||||||
|
return new DoctrineAnnotationTagValueNode($fullyQualifiedAnnotationClass, $annotationShortName, $values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,20 @@ final class BetterTokenIterator extends TokenIterator
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int[] $tokenTypes
|
||||||
|
*/
|
||||||
|
public function isCurrentTokenTypes(array $tokenTypes): bool
|
||||||
|
{
|
||||||
|
foreach ($tokenTypes as $tokenType) {
|
||||||
|
if ($this->isCurrentTokenType($tokenType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function isTokenTypeOnPosition(int $tokenType, int $position): bool
|
public function isTokenTypeOnPosition(int $tokenType, int $position): bool
|
||||||
{
|
{
|
||||||
$tokens = $this->getTokens();
|
$tokens = $this->getTokens();
|
||||||
|
@ -112,17 +126,15 @@ final class BetterTokenIterator extends TokenIterator
|
||||||
|
|
||||||
public function nextTokenType(): ?int
|
public function nextTokenType(): ?int
|
||||||
{
|
{
|
||||||
$this->pushSavePoint();
|
|
||||||
|
|
||||||
$tokens = $this->getTokens();
|
$tokens = $this->getTokens();
|
||||||
$index = $this->privatesAccessor->getPrivateProperty($this, self::INDEX);
|
|
||||||
|
|
||||||
// does next token exist?
|
// does next token exist?
|
||||||
$nextIndex = $index + 1;
|
$nextIndex = $this->currentPosition() + 1;
|
||||||
if (! isset($tokens[$nextIndex])) {
|
if (! isset($tokens[$nextIndex])) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->pushSavePoint();
|
||||||
$this->next();
|
$this->next();
|
||||||
$nextTokenType = $this->currentTokenType();
|
$nextTokenType = $this->currentTokenType();
|
||||||
$this->rollback();
|
$this->rollback();
|
||||||
|
|
|
@ -39,6 +39,10 @@ final class CurlyListNode extends AbstractValuesAwareNode
|
||||||
return 'true';
|
return 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
return implode(', ', $value);
|
||||||
|
}
|
||||||
|
|
||||||
return (string) $value;
|
return (string) $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,16 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||||
*/
|
*/
|
||||||
final class DispatchStringToObjectRector extends AbstractRector
|
final class DispatchStringToObjectRector extends AbstractRector
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private const STMTS = 'stmts';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private const NAME = 'name';
|
||||||
|
|
||||||
public function getRuleDefinition(): RuleDefinition
|
public function getRuleDefinition(): RuleDefinition
|
||||||
{
|
{
|
||||||
return new RuleDefinition(
|
return new RuleDefinition(
|
||||||
|
@ -119,7 +129,7 @@ CODE_SAMPLE
|
||||||
|
|
||||||
return new New_(new Class_(null, [
|
return new New_(new Class_(null, [
|
||||||
'implements' => $implements,
|
'implements' => $implements,
|
||||||
'stmts' => $this->createAnonymousEventClassBody(),
|
self::STMTS => $this->createAnonymousEventClassBody(),
|
||||||
]), [new Arg($expr)]);
|
]), [new Arg($expr)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,16 +139,16 @@ CODE_SAMPLE
|
||||||
private function createAnonymousEventClassBody(): array
|
private function createAnonymousEventClassBody(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
new Property(Class_::MODIFIER_PRIVATE, [new PropertyProperty('name')]),
|
new Property(Class_::MODIFIER_PRIVATE, [new PropertyProperty(self::NAME)]),
|
||||||
new ClassMethod('__construct', [
|
new ClassMethod('__construct', [
|
||||||
'flags' => Class_::MODIFIER_PUBLIC,
|
'flags' => Class_::MODIFIER_PUBLIC,
|
||||||
'params' => $this->createConstructParams(),
|
'params' => $this->createConstructParams(),
|
||||||
'stmts' => [new Expression($this->createConstructAssign())],
|
self::STMTS => [new Expression($this->createConstructAssign())],
|
||||||
]),
|
]),
|
||||||
new ClassMethod('eventName', [
|
new ClassMethod('eventName', [
|
||||||
'flags' => Class_::MODIFIER_PUBLIC,
|
'flags' => Class_::MODIFIER_PUBLIC,
|
||||||
'returnType' => 'string',
|
'returnType' => 'string',
|
||||||
'stmts' => [new Return_(new Variable('this->name'))],
|
self::STMTS => [new Return_(new Variable('this->name'))],
|
||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -148,13 +158,11 @@ CODE_SAMPLE
|
||||||
*/
|
*/
|
||||||
private function createConstructParams(): array
|
private function createConstructParams(): array
|
||||||
{
|
{
|
||||||
return [
|
return [new Param(new Variable(self::NAME), null, 'string')];
|
||||||
new Param(new Variable('name'), null, 'string')
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createConstructAssign(): Assign
|
private function createConstructAssign(): Assign
|
||||||
{
|
{
|
||||||
return new Assign(new Variable('this->name'), new Variable('name'));
|
return new Assign(new Variable('this->name'), new Variable(self::NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user