diff --git a/composer.json b/composer.json index eea4bcb..6407c9c 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,13 @@ "wiz-develop/php-cs-fixer-config": "^8.3", "phpstan/phpstan": "^1.12", "phpunit/php-code-coverage": "^11.0", - "phpunit/phpunit": "^11.3" + "phpunit/phpunit": "^11.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan-strict-rules": "^1.6" + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true + } } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index 9bb7c57..4d6c792 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1d15f7c07e1b7c6eea1e820050a7f08d", + "content-hash": "c783ccd266bcfdefe449f2944d204246", "packages": [], "packages-dev": [ { @@ -744,6 +744,54 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, { "name": "phpstan/phpstan", "version": "1.12.3", @@ -802,6 +850,55 @@ ], "time": "2024-09-09T08:10:35+00:00" }, + { + "name": "phpstan/phpstan-strict-rules", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-strict-rules.git", + "reference": "363f921dd8441777d4fc137deb99beb486c77df1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/363f921dd8441777d4fc137deb99beb486c77df1", + "reference": "363f921dd8441777d4fc137deb99beb486c77df1", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.11" + }, + "require-dev": { + "nikic/php-parser": "^4.13.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extra strict and opinionated rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.0" + }, + "time": "2024-04-20T06:37:51+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "11.0.6", @@ -4205,12 +4302,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": ">=8.3" }, - "platform-dev": [], + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 753f54a..7f229a6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -4,5 +4,6 @@ parameters: level: max paths: - src + - tests typeAliases: BasicTypes: 'int|string|bool|null|float|array|iterable|callable|resource|object' diff --git a/src/Option.php b/src/Option.php index 61365b8..68047b1 100644 --- a/src/Option.php +++ b/src/Option.php @@ -103,7 +103,7 @@ public function and(self $right): self; * @param Closure(T): Option $right * @return Option */ - public function andThen(Closure $right): self; + public function andThen(Closure $right): self; /** @phpstan-ignore method.childParameterType */ /** * @see https://doc.rust-lang.org/std/option/enum.Option.html#method.or diff --git a/src/Option/None.php b/src/Option/None.php index ac8425c..7780f5f 100644 --- a/src/Option/None.php +++ b/src/Option/None.php @@ -33,6 +33,9 @@ public static function unit(mixed $value): self /** * @return $this */ + /** + * @phpstan-ignore method.childParameterType + */ #[Override] public function andThen(Closure $right): self { diff --git a/src/Option/Some.php b/src/Option/Some.php index 94b12fa..4170dcc 100644 --- a/src/Option/Some.php +++ b/src/Option/Some.php @@ -41,6 +41,9 @@ public static function unit(mixed $value): self * @param Closure(T): Option $right * @return Option */ + /** + * @phpstan-ignore method.childParameterType + */ #[Override] public function andThen(Closure $right): Option { diff --git a/src/Result.php b/src/Result.php index 886452b..0cf5999 100644 --- a/src/Result.php +++ b/src/Result.php @@ -117,7 +117,7 @@ public function and(self $right): self; * @param Closure(T): Result $right * @return (F is BasicTypes ? Result : Result) */ - public function andThen(Closure $right): self; + public function andThen(Closure $right): self; /** @phpstan-ignore method.childParameterType */ /** * @see https://doc.rust-lang.org/std/result/enum.Result.html#method.or diff --git a/src/Result/Err.php b/src/Result/Err.php index d578c4d..35bed4a 100644 --- a/src/Result/Err.php +++ b/src/Result/Err.php @@ -42,7 +42,7 @@ public static function unit(mixed $value): self } /** - * @return $this + * @phpstan-ignore method.childParameterType, missingType.generics */ #[Override] public function andThen(Closure $right): self diff --git a/src/Result/Ok.php b/src/Result/Ok.php index edc38f1..fd3ff57 100644 --- a/src/Result/Ok.php +++ b/src/Result/Ok.php @@ -46,9 +46,13 @@ public static function unit(mixed $value): self * @param Closure(T) :Result $right * @return Result */ + /** + * @phpstan-ignore method.childParameterType + */ #[Override] public function andThen(Closure $right): Result { + // @phpstan-ignore return.type return $right($this->value); } diff --git a/src/Result/functions.php b/src/Result/functions.php index 9ac05e0..a2b4e18 100644 --- a/src/Result/functions.php +++ b/src/Result/functions.php @@ -92,15 +92,18 @@ function transpose(Result $result): Option } /** - * @return Result> + * @template T + * @template E + * @param (Result|Result) ...$results + * @return Result> */ -/** @phpstan-ignore-next-line */ -function combine(Result ...$results): Result +function combine(Result ...$results): Result // @phpstan-ignore-line { $errs = array_filter($results, static fn (Result $result) => $result->isErr()); if (count($errs) > 0) { + // @phpstan-ignore return.type return Result\err(array_values(array_map(static fn (Result $result) => $result->unwrapErr(), $errs))); } - return Result\ok(true); + return Result\ok(); } diff --git a/tests/Provider/OptionProvider.php b/tests/Provider/OptionProvider.php index 0ab00a1..cee2ef4 100644 --- a/tests/Provider/OptionProvider.php +++ b/tests/Provider/OptionProvider.php @@ -11,6 +11,9 @@ trait OptionProvider /** * @return iterable, mixed, mixed}> */ + /** + * @phpstan-ignore missingType.iterableValue + */ public static function fromValueMatrix(): iterable { $o = (object)[]; diff --git a/tests/Unit/MonadTest.php b/tests/Unit/MonadTestAbstract.php similarity index 97% rename from tests/Unit/MonadTest.php rename to tests/Unit/MonadTestAbstract.php index 8928f5e..06cc9f2 100644 --- a/tests/Unit/MonadTest.php +++ b/tests/Unit/MonadTestAbstract.php @@ -23,7 +23,7 @@ /** * @template TMonad of Monad */ -abstract class MonadTest extends TestCase +abstract class MonadTestAbstract extends TestCase { /** * @return iterable}> @@ -100,8 +100,7 @@ private function get_caller_type(array $backtrace): ?ReflectionNamedType $ref_class = new ReflectionClass($backtrace['class']); $ref_method = $ref_class->getMethod($backtrace['function']); $ref_type = $ref_method->getReturnType(); - - } elseif ($function = ($backtrace['function'] ?? null)) { + } elseif ($function = ($backtrace['function'] ?? null)) {/** @phpstan-ignore elseif.condNotBoolean */ $ref_function = new ReflectionFunction($function); $ref_type = $ref_function->getReturnType(); } diff --git a/tests/Unit/Option/InterfaceTest.php b/tests/Unit/Option/InterfaceTest.php index a8cacfd..e3fdbae 100644 --- a/tests/Unit/Option/InterfaceTest.php +++ b/tests/Unit/Option/InterfaceTest.php @@ -28,7 +28,6 @@ public function instanceOfOption(): void public function instanceOfNone(): void { Assert::assertInstanceOf(Option\None::class, Option\none()); - // @phpstan-ignore-next-line Assert::assertNotInstanceOf(Option\None::class, Option\some(null)); } @@ -36,7 +35,6 @@ public function instanceOfNone(): void #[TestDox('instanceOfSome test')] public function instanceOfSome(): void { - // @phpstan-ignore-next-line Assert::assertNotInstanceOf(Option\Some::class, Option\none()); Assert::assertInstanceOf(Option\Some::class, Option\some(null)); } diff --git a/tests/Unit/Option/OrThrowTest.php b/tests/Unit/Option/OrThrowTest.php index 7e502e7..7e72a2d 100644 --- a/tests/Unit/Option/OrThrowTest.php +++ b/tests/Unit/Option/OrThrowTest.php @@ -10,6 +10,7 @@ use PHPUnit\Framework\Attributes\TestDox; use RuntimeException; use WizDevelop\PhpMonad\Option; +use WizDevelop\PhpMonad\Tests\Assert; use WizDevelop\PhpMonad\Tests\TestCase; #[TestDox('Option - OrThrow メソッドのテスト')] @@ -27,9 +28,9 @@ public function someReturnsItself(): void $result = $some->orThrow($exception); - $this->assertSame($some, $result); - $this->assertTrue($result->isSome()); - $this->assertSame(42, $result->unwrap()); + Assert::assertSame($some, $result); + Assert::assertTrue($result->isSome()); + Assert::assertSame(42, $result->unwrap()); } #[Test] diff --git a/tests/Unit/Option/TransposeTest.php b/tests/Unit/Option/TransposeTest.php index 884545c..21882c8 100644 --- a/tests/Unit/Option/TransposeTest.php +++ b/tests/Unit/Option/TransposeTest.php @@ -9,6 +9,7 @@ use PHPUnit\Framework\Attributes\TestDox; use WizDevelop\PhpMonad\Option; use WizDevelop\PhpMonad\Result; +use WizDevelop\PhpMonad\Tests\Assert; use WizDevelop\PhpMonad\Tests\TestCase; #[TestDox('Option - transpose関数のテスト')] @@ -24,9 +25,9 @@ public function transposeSomeOk(): void /** @phpstan-ignore-next-line */ $result = Option\transpose($option); - $this->assertTrue($result->isOk()); - $this->assertTrue($result->unwrap()->isSome()); - $this->assertSame(42, $result->unwrap()->unwrap()); + Assert::assertTrue($result->isOk()); + Assert::assertTrue($result->unwrap()->isSome()); + Assert::assertSame(42, $result->unwrap()->unwrap()); } #[Test] @@ -38,8 +39,8 @@ public function transposeSomeErr(): void /** @phpstan-ignore-next-line */ $result = Option\transpose($option); - $this->assertTrue($result->isErr()); - $this->assertSame('error', $result->unwrapErr()); + Assert::assertTrue($result->isErr()); + Assert::assertSame('error', $result->unwrapErr()); } #[Test] @@ -51,7 +52,7 @@ public function transposeNone(): void /** @phpstan-ignore-next-line */ $result = Option\transpose($option); - $this->assertTrue($result->isOk()); - $this->assertTrue($result->unwrap()->isNone()); + Assert::assertTrue($result->isOk()); + Assert::assertTrue($result->unwrap()->isNone()); } } diff --git a/tests/Unit/Option/UnwrapOrThrowTest.php b/tests/Unit/Option/UnwrapOrThrowTest.php index 845de7c..e14a460 100644 --- a/tests/Unit/Option/UnwrapOrThrowTest.php +++ b/tests/Unit/Option/UnwrapOrThrowTest.php @@ -11,6 +11,7 @@ use PHPUnit\Framework\TestCase; use RuntimeException; use WizDevelop\PhpMonad\Option; +use WizDevelop\PhpMonad\Tests\Assert; use function WizDevelop\PhpMonad\Option\none; use function WizDevelop\PhpMonad\Option\some; @@ -27,7 +28,7 @@ public function some値の場合は値を返す(): void $option = some($value); $exception = new Exception('This exception should not be thrown'); - $this->assertSame($value, $option->unwrapOrThrow($exception)); + Assert::assertSame($value, $option->unwrapOrThrow($exception)); } #[Test] diff --git a/tests/Unit/OptionTest.php b/tests/Unit/OptionTest.php index 78def6a..d73fa22 100644 --- a/tests/Unit/OptionTest.php +++ b/tests/Unit/OptionTest.php @@ -6,15 +6,18 @@ use Override; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\TestDox; +use WizDevelop\PhpMonad\Monad; use WizDevelop\PhpMonad\Option; /** - * @extends MonadTest