diff --git a/src/Tasks/AnonymousMigrations.php b/src/Tasks/AnonymousMigrations.php index 7275669..006a3df 100644 --- a/src/Tasks/AnonymousMigrations.php +++ b/src/Tasks/AnonymousMigrations.php @@ -2,8 +2,8 @@ namespace Shift\Cli\Tasks; -use Illuminate\Support\Str; use Shift\Cli\Sdk\Contracts\Task; +use Shift\Cli\Sdk\Models\File; use Shift\Cli\Sdk\Traits\FindsFiles; class AnonymousMigrations implements Task @@ -22,6 +22,15 @@ public function perform(): int return 0; } + private function parseClass(string $contents) + { + static $finder; + + $finder ??= new \Shift\Cli\Sdk\Parsers\NikicParser(new \Shift\Cli\Sdk\Parsers\Finders\ClassDefinition()); + + return $finder->parse($contents); + } + private function updateMigrations(): void { foreach ($this->findFilesContaining('/\bclass\s+\S+\s+extends\s+Migration\s/') as $path) { @@ -77,14 +86,22 @@ private function updateStubs(): void private function convertClassDefinition($contents): ?string { + $file = File::fromString($contents); + $class = $this->parseClass($file->contents()); + $found = \preg_match('/^class\s+(\S+)\s+extends\s+Migration(\s+)/m', $contents, $matches); if (! $found) { return null; } + $contents = \substr_replace($contents, + ';', + $class['offset']['end'] + 1, + 0 + ); $contents = \str_replace(\rtrim($matches[0]), 'return new class extends Migration', $contents); $contents = \preg_replace('/\b' . \preg_quote($matches[1], '/') . '::/', 'self::', $contents); - return Str::replaceLast('}', '};', $contents); + return $contents; } } diff --git a/tests/Feature/Tasks/AnonymousMigrationsTest.php b/tests/Feature/Tasks/AnonymousMigrationsTest.php index e069b76..d652a05 100644 --- a/tests/Feature/Tasks/AnonymousMigrationsTest.php +++ b/tests/Feature/Tasks/AnonymousMigrationsTest.php @@ -54,4 +54,18 @@ public function it_converts_migrations_and_stubs() $this->assertFileChanges('tests/fixtures/anonymous-migrations/simple.after.php', 'other/migrations/2014_10_12_000000_create_users_table.php'); $this->assertFileChanges('tests/fixtures/anonymous-migrations/stub.after.php', 'stubs/migration.stub'); } + + #[Test] + public function it_converts_with_comments_beyond_the_class() + { + $this->fakeProject([ + 'database/migrations/2015_10_12_000000_create_users_table.php' => 'tests/fixtures/anonymous-migrations/post-class-comments.php', + ]); + + $result = $this->subject->perform(); + + $this->assertSame(0, $result); + + $this->assertFileChanges('tests/fixtures/anonymous-migrations/post-class-comments.after.php', 'database/migrations/2015_10_12_000000_create_users_table.php'); + } } diff --git a/tests/fixtures/anonymous-migrations/post-class-comments.after.php b/tests/fixtures/anonymous-migrations/post-class-comments.after.php new file mode 100644 index 0000000..6a0ddfc --- /dev/null +++ b/tests/fixtures/anonymous-migrations/post-class-comments.after.php @@ -0,0 +1,36 @@ +integer('runtime')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('videos', function (Blueprint $table) { + $table->dropColumn('runtime'); + }); + } +}; + +/* a closing bracket in a comment here can confuse the parsing +{ id: 1, name: "Doug" } +*/ diff --git a/tests/fixtures/anonymous-migrations/post-class-comments.php b/tests/fixtures/anonymous-migrations/post-class-comments.php new file mode 100644 index 0000000..e6773de --- /dev/null +++ b/tests/fixtures/anonymous-migrations/post-class-comments.php @@ -0,0 +1,36 @@ +integer('runtime')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('videos', function (Blueprint $table) { + $table->dropColumn('runtime'); + }); + } +} + +/* a closing bracket in a comment here can confuse the parsing +{ id: 1, name: "Doug" } +*/