From 3d90c9661e5926a9964298ffc230bd841ca98d14 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sat, 18 Apr 2020 23:14:45 +0200 Subject: [PATCH 1/3] spacing --- .../better-php-doc-parser/src/Printer/WhitespaceDetector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php b/packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php index e02e1e810254..3782e859d82a 100644 --- a/packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php +++ b/packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php @@ -29,7 +29,7 @@ public function detectOldWhitespaces(Node $node, array $tokens, StartEndValueObj --$start; } - for ($i = $start; $i <= $startEndValueObject->getEnd(); ++$i) { + for ($i = $start; $i < $startEndValueObject->getEnd(); ++$i) { /** @var string $tokenValue */ $tokenValue = $tokens[$i][0]; From 307ed647549b0469db6df543fbc1a03f7b1432df Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sat, 18 Apr 2020 23:16:51 +0200 Subject: [PATCH 2/3] more generic spacing --- .../better-php-doc-parser/src/Printer/WhitespaceDetector.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php b/packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php index 3782e859d82a..75875c453e2c 100644 --- a/packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php +++ b/packages/better-php-doc-parser/src/Printer/WhitespaceDetector.php @@ -9,7 +9,7 @@ use PHPStan\PhpDocParser\Ast\Node; use PHPStan\PhpDocParser\Lexer\Lexer; use Rector\BetterPhpDocParser\Contract\Doctrine\DoctrineTagNodeInterface; -use Rector\BetterPhpDocParser\PhpDocNode\Symfony\SymfonyRouteTagValueNode; +use Rector\BetterPhpDocParser\Contract\PhpDocNode\ShortNameAwareTagInterface; use Rector\BetterPhpDocParser\ValueObject\StartEndValueObject; final class WhitespaceDetector @@ -36,7 +36,7 @@ public function detectOldWhitespaces(Node $node, array $tokens, StartEndValueObj if ($tokens[$i][1] === Lexer::TOKEN_HORIZONTAL_WS) { // give back "\s+\*" as well // do not overlap to previous node - if (($node instanceof DoctrineTagNodeInterface || $node instanceof SymfonyRouteTagValueNode) && + if (($node instanceof DoctrineTagNodeInterface || $node instanceof ShortNameAwareTagInterface) && $i - 1 > $start && isset($tokens[$i - 1]) && $tokens[$i - 1][1] === Lexer::TOKEN_PHPDOC_EOL From 99da24ba2cec7a296055b355e41058e366200c38 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sat, 18 Apr 2020 23:23:33 +0200 Subject: [PATCH 3/3] improve constant quoting in name @Route --- .../src/PhpDocNode/AbstractTagValueNode.php | 34 +++++++++++++ .../Symfony/SymfonyRouteTagValueNode.php | 13 +++-- .../Constraints/AssertTypeTagValueNode.php | 48 ++++--------------- .../Fixture/RouteName.php | 17 +++++++ 4 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 packages/better-php-doc-parser/tests/PhpDocParser/SymfonyRouteTagParser/Fixture/RouteName.php diff --git a/packages/better-php-doc-parser/src/PhpDocNode/AbstractTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/AbstractTagValueNode.php index 40eaebc06640..11587f5c4b85 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/AbstractTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/AbstractTagValueNode.php @@ -158,6 +158,40 @@ protected function resolveOriginalContentSpacingAndOrder(?string $originalConten $this->hasClosingBracket = (bool) Strings::match($originalContent, '#\)$#'); } + protected function resolveIsValueQuoted(string $originalContent, $value): bool + { + if ($value === null) { + return false; + } + + if (! is_string($value)) { + return false; + } + + // @see https://regex101.com/r/VgvK8C/3/ + $quotedNamePattern = sprintf('#"%s"#', preg_quote($value, '#')); + + return (bool) Strings::match($originalContent, $quotedNamePattern); + } + + protected function printWithOptionalQuotes(string $name, $value, bool $isQuoted, bool $isExplicit = true): string + { + $content = ''; + if ($isExplicit) { + $content = $name . '='; + } + + if (is_array($value)) { + return $content . $this->printArrayItem($value); + } + + if ($isQuoted) { + return $content . sprintf('"%s"', $value); + } + + return $content . sprintf('%s', $value); + } + /** * @param PhpDocTagValueNode[] $tagValueNodes */ diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Symfony/SymfonyRouteTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Symfony/SymfonyRouteTagValueNode.php index 144b9630134c..0ace8e9a6063 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Symfony/SymfonyRouteTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Symfony/SymfonyRouteTagValueNode.php @@ -74,6 +74,11 @@ final class SymfonyRouteTagValueNode extends AbstractTagValueNode implements Sho */ private $condition; + /** + * @var bool + */ + private $isNameQuoted = true; + /** * @param string[] $localizedPaths * @param string[] $methods @@ -111,13 +116,15 @@ public function __construct( $this->resolveOriginalContentSpacingAndOrder($originalContent); // default value without key - if ($this->shouldAddIimplicitPaths()) { + if ($this->shouldAddImplicitPaths()) { // add path as first item $this->orderedVisibleItems = array_merge(['path'], (array) $this->orderedVisibleItems); } $matches = Strings::match($originalContent, '#requirements={(.*?)(?(=|:))(.*)}#'); $this->requirementsKeyValueSeparator = $matches['separator'] ?? '='; + + $this->isNameQuoted = $this->resolveIsValueQuoted($originalContent, $name); } $this->host = $host; @@ -131,7 +138,7 @@ public function __toString(): string ]; if ($this->name) { - $contentItems['name'] = sprintf('name="%s"', $this->name); + $contentItems['name'] = $this->printWithOptionalQuotes('name', $this->name, $this->isNameQuoted); } if ($this->methods !== []) { @@ -191,7 +198,7 @@ private function createPath(): string return Strings::replace($localizedPaths, '#:#', ': '); } - private function shouldAddIimplicitPaths(): bool + private function shouldAddImplicitPaths(): bool { return ($this->path || $this->localizedPaths) && ! in_array('path', (array) $this->orderedVisibleItems, true); } diff --git a/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertTypeTagValueNode.php b/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertTypeTagValueNode.php index 5b32048097eb..c5c82986a857 100644 --- a/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertTypeTagValueNode.php +++ b/packages/better-php-doc-parser/src/PhpDocNode/Symfony/Validator/Constraints/AssertTypeTagValueNode.php @@ -10,6 +10,8 @@ /** * @see \Rector\BetterPhpDocParser\PhpDocNodeFactory\Symfony\Validator\Constraints\AssertTypePhpDocNodeFactory + * + * @see \Rector\BetterPhpDocParser\Tests\PhpDocParser\SymfonyValidation\AssertTypeTagValueNodeTest */ final class AssertTypeTagValueNode extends AbstractConstraintTagValueNode implements ShortNameAwareTagInterface { @@ -37,7 +39,7 @@ public function __construct(array $groups, ?string $message = null, $type = null if ($originalContent !== null) { $this->isTypeExplicit = (bool) Strings::contains($originalContent, 'type='); - $this->resolveIsQuotedType($originalContent, $type); + $this->isTypeQuoted = $this->resolveIsValueQuoted($originalContent, $type); } $this->resolveOriginalContentSpacingAndOrder($originalContent, 'type'); @@ -50,7 +52,12 @@ public function __toString(): string $contentItems = []; if ($this->type !== null) { - $contentItems['type'] = $this->createType(); + $contentItems['type'] = $this->printWithOptionalQuotes( + 'type', + $this->type, + $this->isTypeQuoted, + $this->isTypeExplicit + ); } $contentItems = $this->appendGroups($contentItems); @@ -63,41 +70,4 @@ public function getShortName(): string { return '@Assert\Type'; } - - /** - * @param string|mixed[]|null $type - */ - private function resolveIsQuotedType(string $originalContent, $type): void - { - if ($type === null) { - return; - } - - if (! is_string($type)) { - return; - } - - // @see https://regex101.com/r/VgvK8C/3/ - $quotedTypePattern = sprintf('#"%s"#', preg_quote($type, '#')); - - $this->isTypeQuoted = (bool) Strings::match($originalContent, $quotedTypePattern); - } - - private function createType(): string - { - $content = ''; - if ($this->isTypeExplicit) { - $content = 'type='; - } - - if ($this->isTypeQuoted && is_string($this->type)) { - return $content . '"' . $this->type . '"'; - } - - if (is_array($this->type)) { - return $content . $this->printArrayItem($this->type); - } - - return $content . $this->type; - } } diff --git a/packages/better-php-doc-parser/tests/PhpDocParser/SymfonyRouteTagParser/Fixture/RouteName.php b/packages/better-php-doc-parser/tests/PhpDocParser/SymfonyRouteTagParser/Fixture/RouteName.php new file mode 100644 index 000000000000..4083d87fe8e8 --- /dev/null +++ b/packages/better-php-doc-parser/tests/PhpDocParser/SymfonyRouteTagParser/Fixture/RouteName.php @@ -0,0 +1,17 @@ +