From 03db1ca427101aae3ff5f7c818019a96c5899f52 Mon Sep 17 00:00:00 2001 From: Alexander Pape Date: Tue, 14 Dec 2021 16:11:28 +0100 Subject: [PATCH] Support psalm array syntax --- CHANGELOG.md | 4 ++ src/Parser/PhpDocParser.php | 15 ++++-- tests/Fixtures/ArrayClass.php | 63 ++++++++++++++++++++++ tests/Fixtures/Person.php | 7 +++ tests/Services/ParserServiceArrayTest.php | 49 +++++++++++++++++ tests/{ => Services}/ParserServiceTest.php | 18 ++----- 6 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 tests/Fixtures/ArrayClass.php create mode 100644 tests/Services/ParserServiceArrayTest.php rename tests/{ => Services}/ParserServiceTest.php (89%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6d9399..b5bbe5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Changelog ====== +# 1.1.0 + +- Add support for psalm array syntax as well: `@var array` + # 1.0.0 - Initial Release of the Parser diff --git a/src/Parser/PhpDocParser.php b/src/Parser/PhpDocParser.php index dd68067..f244c5c 100644 --- a/src/Parser/PhpDocParser.php +++ b/src/Parser/PhpDocParser.php @@ -8,11 +8,15 @@ class PhpDocParser public const PROPERTY_TYPE_VARIABLE = 'VARIABLE'; public const PROPERTY_TYPE_METHOD = 'METHOD'; - public function parseDocComment(string $phpDoc, $type = self::PROPERTY_TYPE_VARIABLE, $includeTypeNullable = false): string - { + public function parseDocComment( + string $phpDoc, + $type = self::PROPERTY_TYPE_VARIABLE, + $includeTypeNullable = false + ): string { $varRegex = '/@var\s+(?P[^\s*]+)?/'; $methodRegex = '/@return\s+(?P[^\s*]+)?/'; $typeRegex = '/(?P[^\[\]\s]+)(?P\[\])?/i'; + $psalmTypeRegex = '/array\<(?P[^\s*]+)?\>/i'; if (empty($phpDoc)) { return 'any'; @@ -28,7 +32,12 @@ public function parseDocComment(string $phpDoc, $type = self::PROPERTY_TYPE_VARI foreach ($types as $phpType) { $tsType = $phpType; - if (preg_match($typeRegex, $phpType, $typeMatch)) { + if (preg_match($psalmTypeRegex, $phpType, $typeMatch)) { + $tsType = $this->getTypeEquivalent($typeMatch['psalmType'], $includeTypeNullable); + if ($tsType !== null) { + $tsType .= '[]'; + } + } else if (preg_match($typeRegex, $phpType, $typeMatch)) { $tsType = $this->getTypeEquivalent($typeMatch['type'], $includeTypeNullable); if ($tsType === null) { continue; diff --git a/tests/Fixtures/ArrayClass.php b/tests/Fixtures/ArrayClass.php new file mode 100644 index 0000000..0267c37 --- /dev/null +++ b/tests/Fixtures/ArrayClass.php @@ -0,0 +1,63 @@ + + */ + protected $psalmArrayType; + + /** + * @PTS\VirtualProperty() + * @return bool[] + */ + public function hasSomeValue() + { + return [true]; + } + + /** + * @PTS\VirtualProperty() + */ + public function virtualWithReturnType(): int + { + return 1; + } +} diff --git a/tests/Fixtures/Person.php b/tests/Fixtures/Person.php index 69accfa..11973ca 100644 --- a/tests/Fixtures/Person.php +++ b/tests/Fixtures/Person.php @@ -83,6 +83,13 @@ class Person */ protected $someInterfaceArray; + /** + * This syntax is not correct PHPDoc actually, but anyway used sometimes. + * + * @var array + */ + protected $psalmArrayType; + /** * @PTS\VirtualProperty() * @return bool diff --git a/tests/Services/ParserServiceArrayTest.php b/tests/Services/ParserServiceArrayTest.php new file mode 100644 index 0000000..65ad284 --- /dev/null +++ b/tests/Services/ParserServiceArrayTest.php @@ -0,0 +1,49 @@ +loadFixture(); + + $this->assertStringContainsString('mixed: any;', $content); + $this->assertStringContainsString('mixedArray: any[];', $content); + } + + public function testRespectsTypeScriptTypeAnnotationForArrays() + { + $content = $this->loadFixture(); + + $this->assertStringContainsString('someInterfaceArray: ClassImplementingInterface1[]|ClassImplementingInterface2[];', $content); + } + + public function testPhpDocArraySyntax() + { + $content = $this->loadFixture(); + + $this->assertStringContainsString('classCollection: SomeClass[];', $content); + } + + public function testPsalmArraySyntax() + { + $content = $this->loadFixture(); + + $this->assertStringContainsString('psalmArrayType: number[];', $content); + } + + private function loadFixture(): ?string + { + $fixture = $this->getDefaultFixtureFile(); + return $this->parserService->getInterfaceContent($fixture); + } + + private function getDefaultFixtureFile(): string + { + return __DIR__ . '/../Fixtures/ArrayClass.php'; + } +} diff --git a/tests/ParserServiceTest.php b/tests/Services/ParserServiceTest.php similarity index 89% rename from tests/ParserServiceTest.php rename to tests/Services/ParserServiceTest.php index bbefdbe..8f96328 100644 --- a/tests/ParserServiceTest.php +++ b/tests/Services/ParserServiceTest.php @@ -1,7 +1,8 @@ parserService->getInterfaceContent($fixture); $this->assertNull($content); } - /** - * @test - */ - public function convertsMixedToArray() - { - $fixture = $this->getDefaultFixtureFile(); - $content = $this->parserService->getInterfaceContent($fixture); - - $this->assertStringContainsString('mixed: any;', $content); - $this->assertStringContainsString('mixedArray: any[];', $content); - } /** * @test @@ -159,6 +149,6 @@ private function loadFixture(): ?string private function getDefaultFixtureFile(): string { - return __DIR__ . '/Fixtures/Person.php'; + return __DIR__ . '/../Fixtures/Person.php'; } }