Repository: BenSampo/laravel-enum (php)

Issue:
`enum:annotate` command breaks existing docblock descriptions
## Problem

The `enum:annotate` command breaks existing docblock descriptions. For example, when the command is executed for an enum like the following,

```php
/**
 * This is a test enum with multiple line comments.
 *
 * Test enum with multiple line comments. Test enum
 * with multiple line comments. Test enum with multiple line comments.
 *
 * Test enum with multiple line comments.
 *
 * @method static static A()
 * @method static static B()
 * @method static static C()
 * @extends Enum<int>
 */
final class EnumWithMultipleLineComments extends Enum
{
    const A = 1;
    const B = 2;
    const C = 3;
}
```

I expect docblock to remain the same, but as shown below, line breaks are lost from the description and the formatting is broken.

```php
/**
 * This is a test enum with multiple line comments.
 *
 * Test enum with multiple line comments. Test enum with multiple line comments. Test enum with multiple line comments. Test enum with multiple line comments.
 *
 * @method static static A()
 * @method static static B()
 * @method static static C()
 * @extends Enum<int>
 */
final class EnumWithMultipleLineComments extends Enum
{
    const A = 1;
    const B = 2;
    const C = 3;
}
```

## Survey

I have tried to determine the cause of the above behavior. As a result, I found that the laminas-code on which the [docblock generation process](https://github.com/BenSampo/laravel-enum/blob/master/src/Commands/EnumAnnotateCommand.php#L149-L158) depends is causing the problem. For more information, please refer to the following Issue I submitted.

https://github.com/laminas/laminas-code/issues/177

I reported it as a bug, but it will probably never be fixed. This is because fixing it would be a breaking change. Therefore, to fix the `enum:annotate` problem, we would have to rewrite the logic above so that it does not depend on laminas-code.

Pull request:
Fix `enum:annotate` command issue
- [x] Added or updated tests
- [x] Added or updated the [README.md](../README.md)
- [ ] Detailed changes in the [CHANGELOG.md](../CHANGELOG.md) unreleased section

**Related Issue/Intent**

<!-- Link to related issues this PR resolves, e.g. "Resolves #236",
or a description of what this PR is trying to achieve. -->

**Changes**

Fixes #310

**Breaking changes**

<!-- If there are any breaking changes, list them here. -->


Patch:
diff --git a/src/Commands/EnumAnnotateCommand.php b/src/Commands/EnumAnnotateCommand.php
index c696648..0acdcd8 100644
--- a/src/Commands/EnumAnnotateCommand.php
+++ b/src/Commands/EnumAnnotateCommand.php
@@ -149,14 +149,7 @@ class EnumAnnotateCommand extends Command
             $originalDocBlock = DocBlockGenerator::fromReflection(
                 new DocBlockReflection(ltrim($reflectionClass->getDocComment()))
             );
-
-            if ($originalDocBlock->getShortDescription()) {
-                $docBlock->setShortDescription($originalDocBlock->getShortDescription());
-            }
-
-            if ($originalDocBlock->getLongDescription()) {
-                $docBlock->setLongDescription($originalDocBlock->getLongDescription());
-            }
+            $docBlock->setLongDescription($this->getDocblockWithoutTags($reflectionClass));
         }
 
         $docBlock->setTags($this->getDocblockTags(
@@ -167,6 +160,18 @@ class EnumAnnotateCommand extends Command
         return $docBlock;
     }
 
+    /**
+     * @param  \ReflectionClass<\BenSampo\Enum\Enum<mixed>> $reflectionClass
+     */
+    protected function getDocblockWithoutTags(ReflectionClass $reflectionClass): string
+    {
+        // Get full docblock contents as string
+        $docBlockContents = (new DocBlockReflection($reflectionClass))->getContents();
+
+        // Remove all tags from the above
+        return trim(preg_replace('/@.*$/m', '', $docBlockContents));
+    }
+
     /**
      * @param  \ReflectionClass<\BenSampo\Enum\Enum<mixed>> $reflectionClass
      * @return array<\Laminas\Code\Generator\DocBlock\Tag\TagInterface>


Test patch:
diff --git a/tests/ArtisanCommandsTest.php b/tests/ArtisanCommandsTest.php
index 12b2145..0371099 100644
--- a/tests/ArtisanCommandsTest.php
+++ b/tests/ArtisanCommandsTest.php
@@ -2,6 +2,10 @@
 
 namespace BenSampo\Enum\Tests;
 
+use BenSampo\Enum\Tests\Enums\EnumWithMultipleLineComments;
+use BenSampo\Enum\Tests\Enums\EnumWithMultipleLineCommentsWithoutBlankLines;
+use BenSampo\Enum\Tests\Enums\EnumWithSingleLineComment;
+use BenSampo\Enum\Tests\Enums\EnumWithSingleLineCommentWithoutBlankLine;
 use BenSampo\Enum\Tests\Enums\ManyLongConstantNames;
 use Illuminate\Filesystem\Filesystem;
 use Illuminate\Contracts\Console\Kernel as ConsoleKernel;
@@ -95,4 +99,28 @@ final class ArtisanCommandsTest extends ApplicationTestCase
         $newClass = $filesystem->get(__DIR__ . '/Enums/ManyLongConstantNames.php');
         $this->assertSame($original, $newClass);
     }
+
+    public function test_annotate_enum_with_multiple_line_comments_with_blank_lines(): void
+    {
+        $filesystem = $this->app->make(Filesystem::class);
+        assert($filesystem instanceof Filesystem);
+
+        $original = $filesystem->get(__DIR__ . '/Enums/EnumWithMultipleLineComments.php');
+        $this->artisan('enum:annotate', ['class' => EnumWithMultipleLineComments::class])->assertExitCode(0);
+
+        $newClass = $filesystem->get(__DIR__ . '/Enums/EnumWithMultipleLineComments.php');
+        $this->assertSame($original, $newClass);
+    }
+
+    public function test_annotate_enum_with_single_line_comment_with_blank_line(): void
+    {
+        $filesystem = $this->app->make(Filesystem::class);
+        assert($filesystem instanceof Filesystem);
+
+        $original = $filesystem->get(__DIR__ . '/Enums/EnumWithSingleLineComment.php');
+        $this->artisan('enum:annotate', ['class' => EnumWithSingleLineComment::class])->assertExitCode(0);
+
+        $newClass = $filesystem->get(__DIR__ . '/Enums/EnumWithSingleLineComment.php');
+        $this->assertSame($original, $newClass);
+    }
 }
diff --git a/tests/Enums/EnumWithMultipleLineComments.php b/tests/Enums/EnumWithMultipleLineComments.php
new file mode 100644
index 0000000..532aa20
--- /dev/null
+++ b/tests/Enums/EnumWithMultipleLineComments.php
@@ -0,0 +1,25 @@
+<?php declare(strict_types=1);
+
+namespace BenSampo\Enum\Tests\Enums;
+
+use BenSampo\Enum\Enum;
+
+/**
+ * This is a test enum with multiple line comments.
+ *
+ * Test enum with multiple line comments. Test enum
+ * with multiple line comments. Test enum with multiple line comments.
+ *
+ * Test enum with multiple line comments.
+ *
+ * @method static static A()
+ * @method static static B()
+ * @method static static C()
+ * @extends Enum<int>
+ */
+final class EnumWithMultipleLineComments extends Enum
+{
+    const A = 1;
+    const B = 2;
+    const C = 3;
+}
diff --git a/tests/Enums/EnumWithSingleLineComment.php b/tests/Enums/EnumWithSingleLineComment.php
new file mode 100644
index 0000000..f088525
--- /dev/null
+++ b/tests/Enums/EnumWithSingleLineComment.php
@@ -0,0 +1,20 @@
+<?php declare(strict_types=1);
+
+namespace BenSampo\Enum\Tests\Enums;
+
+use BenSampo\Enum\Enum;
+
+/**
+ * This is a test enum with single line comment.
+ *
+ * @method static static A()
+ * @method static static B()
+ * @method static static C()
+ * @extends Enum<int>
+ */
+final class EnumWithSingleLineComment extends Enum
+{
+    const A = 1;
+    const B = 2;
+    const C = 3;
+}