Browse Source

feature: [PhpdocAlignFixer] Add support for every tag (#6564)

Vincent Langlet 1 year ago
parent
commit
67db5f6d49

+ 1 - 1
doc/list.rst

@@ -1973,7 +1973,7 @@ List of Available Rules
 
    - | ``tags``
      | The tags that should be aligned.
-     | Allowed values: a subset of ``['method', 'param', 'property', 'property-read', 'property-write', 'return', 'throws', 'type', 'var']``
+     | Allowed types: ``array``
      | Default value: ``['method', 'param', 'property', 'return', 'throws', 'type', 'var']``
    - | ``align``
      | How comments should be aligned.

+ 1 - 1
doc/rules/phpdoc/phpdoc_align.rst

@@ -13,7 +13,7 @@ Configuration
 
 The tags that should be aligned.
 
-Allowed values: a subset of ``['method', 'param', 'property', 'property-read', 'property-write', 'return', 'throws', 'type', 'var']``
+Allowed types: ``array``
 
 Default value: ``['method', 'param', 'property', 'return', 'throws', 'type', 'var']``
 

+ 34 - 29
src/Fixer/Phpdoc/PhpdocAlignFixer.php

@@ -16,10 +16,10 @@ namespace PhpCsFixer\Fixer\Phpdoc;
 
 use PhpCsFixer\AbstractFixer;
 use PhpCsFixer\DocBlock\DocBlock;
+use PhpCsFixer\DocBlock\Line;
 use PhpCsFixer\DocBlock\TypeExpression;
 use PhpCsFixer\Fixer\ConfigurableFixerInterface;
 use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
-use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
 use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
 use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
 use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
@@ -49,16 +49,14 @@ final class PhpdocAlignFixer extends AbstractFixer implements ConfigurableFixerI
      */
     public const ALIGN_VERTICAL = 'vertical';
 
-    private const ALIGNABLE_TAGS = [
+    private const DEFAULT_TAGS = [
+        'method',
         'param',
         'property',
-        'property-read',
-        'property-write',
         'return',
         'throws',
         'type',
         'var',
-        'method',
     ];
 
     private const TAGS_WITH_NAME = [
@@ -66,10 +64,27 @@ final class PhpdocAlignFixer extends AbstractFixer implements ConfigurableFixerI
         'property',
         'property-read',
         'property-write',
+        'phpstan-param',
+        'phpstan-property',
+        'phpstan-property-read',
+        'phpstan-property-write',
+        'phpstan-assert',
+        'phpstan-assert-if-true',
+        'phpstan-assert-if-false',
+        'psalm-param',
+        'psalm-param-out',
+        'psalm-property',
+        'psalm-property-read',
+        'psalm-property-write',
+        'psalm-assert',
+        'psalm-assert-if-true',
+        'psalm-assert-if-false',
     ];
 
     private const TAGS_WITH_METHOD_SIGNATURE = [
         'method',
+        'phpstan-method',
+        'psalm-method',
     ];
 
     /**
@@ -97,10 +112,11 @@ final class PhpdocAlignFixer extends AbstractFixer implements ConfigurableFixerI
         $tagsWithNameToAlign = array_intersect($this->configuration['tags'], self::TAGS_WITH_NAME);
         $tagsWithMethodSignatureToAlign = array_intersect($this->configuration['tags'], self::TAGS_WITH_METHOD_SIGNATURE);
         $tagsWithoutNameToAlign = array_diff($this->configuration['tags'], $tagsWithNameToAlign, $tagsWithMethodSignatureToAlign);
-        $types = [];
 
         $indent = '(?P<indent>(?:\ {2}|\t)*)';
 
+        $types = [];
+
         // e.g. @param <hint> <$var>
         if ([] !== $tagsWithNameToAlign) {
             $types[] = '(?P<tag>'.implode('|', $tagsWithNameToAlign).')\s+(?P<hint>(?:'.TypeExpression::REGEX_TYPES.')?)\s+(?P<var>(?:&|\.{3})?\$\S+)';
@@ -113,7 +129,7 @@ final class PhpdocAlignFixer extends AbstractFixer implements ConfigurableFixerI
 
         // e.g. @method <hint> <signature>
         if ([] !== $tagsWithMethodSignatureToAlign) {
-            $types[] = '(?P<tag3>'.implode('|', $tagsWithMethodSignatureToAlign).')(\s+(?P<static>static))?(\s+(?P<hint3>[^\s(]+)|)\s+(?P<signature>.+\))';
+            $types[] = '(?P<tag3>'.implode('|', $tagsWithMethodSignatureToAlign).')(\s+(?P<static>static))?(\s+(?P<hint3>(?:'.TypeExpression::REGEX_TYPES.')?))\s+(?P<signature>.+\))';
         }
 
         // optional <desc>
@@ -204,16 +220,7 @@ EOF;
         $tags = new FixerOptionBuilder('tags', 'The tags that should be aligned.');
         $tags
             ->setAllowedTypes(['array'])
-            ->setAllowedValues([new AllowedValueSubset(self::ALIGNABLE_TAGS)])
-            ->setDefault([
-                'method',
-                'param',
-                'property',
-                'return',
-                'throws',
-                'type',
-                'var',
-            ])
+            ->setDefault(self::DEFAULT_TAGS)
         ;
 
         $align = new FixerOptionBuilder('align', 'How comments should be aligned.');
@@ -276,7 +283,8 @@ EOF;
             foreach ($items as $j => $item) {
                 if (null === $item['tag']) {
                     if ('@' === $item['desc'][0]) {
-                        $docBlock->getLine($current + $j)->setContent($item['indent'].' * '.$item['desc'].$lineEnding);
+                        $line = $item['indent'].' * '.$item['desc'];
+                        $docBlock->getLine($current + $j)->setContent($line.$lineEnding);
 
                         continue;
                     }
@@ -284,7 +292,7 @@ EOF;
                     $extraIndent = 2;
 
                     if (\in_array($currTag, self::TAGS_WITH_NAME, true) || \in_array($currTag, self::TAGS_WITH_METHOD_SIGNATURE, true)) {
-                        $extraIndent = 3;
+                        $extraIndent += $varMax + 1;
                     }
 
                     if ($hasStatic) {
@@ -295,13 +303,12 @@ EOF;
                         $item['indent']
                         .' *  '
                         .$this->getIndent(
-                            $tagMax + $hintMax + $varMax + $extraIndent,
+                            $tagMax + $hintMax + $extraIndent,
                             $this->getLeftAlignedDescriptionIndent($items, $j)
                         )
-                        .$item['desc']
-                        .$lineEnding;
+                        .$item['desc'];
 
-                    $docBlock->getLine($current + $j)->setContent($line);
+                    $docBlock->getLine($current + $j)->setContent($line.$lineEnding);
 
                     continue;
                 }
@@ -338,16 +345,14 @@ EOF;
                         .$item['var']
                         .(
                             !empty($item['desc'])
-                            ? $this->getIndent($varMax - \strlen($item['var']) + 1).$item['desc'].$lineEnding
-                            : $lineEnding
+                            ? $this->getIndent($varMax - \strlen($item['var']) + 1).$item['desc']
+                            : ''
                         );
                 } elseif (!empty($item['desc'])) {
-                    $line .= $this->getIndent($hintMax - \strlen($item['hint']) + 1).$item['desc'].$lineEnding;
-                } else {
-                    $line .= $lineEnding;
+                    $line .= $this->getIndent($hintMax - \strlen($item['hint']) + 1).$item['desc'];
                 }
 
-                $docBlock->getLine($current + $j)->setContent($line);
+                $docBlock->getLine($current + $j)->setContent($line.$lineEnding);
             }
         }
     }

+ 35 - 0
tests/Fixer/Phpdoc/PhpdocAlignFixerTest.php

@@ -342,8 +342,10 @@ EOF;
     /**
      * @param  EngineInterface $templating
      * @param  mixed           &$reference A parameter passed by reference
+     *                                     Multiline description
      * @throws Bar             description bar
      * @return Foo             description foo
+     *                         multiline description
      */
 
 EOF;
@@ -353,8 +355,10 @@ EOF;
     /**
      * @param EngineInterface       $templating
      * @param  mixed    &$reference     A parameter passed by reference
+     *                                  Multiline description
      * @throws   Bar description bar
      * @return  Foo     description foo
+     *                  multiline description
      */
 
 EOF;
@@ -1557,4 +1561,35 @@ class Foo {}
          */
         EOT];
     }
+
+    public function testFixCustomTags(): void
+    {
+        $this->fixer->configure(['tags' => ['param', 'phpstan-param']]);
+
+        $expected = <<<'EOF'
+<?php
+    /**
+     * @param         EngineInterface $templating
+     * @param         string          $format
+     * @phpstan-param int             $code       An HTTP response status code
+     * @param         bool            $debug
+     * @param         mixed           &$reference A parameter passed by reference
+     */
+
+EOF;
+
+        $input = <<<'EOF'
+<?php
+    /**
+     * @param  EngineInterface $templating
+     * @param string      $format
+     * @phpstan-param  int  $code       An HTTP response status code
+     * @param    bool         $debug
+     * @param  mixed    &$reference     A parameter passed by reference
+     */
+
+EOF;
+
+        $this->doTest($expected, $input);
+    }
 }