diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index bf7599a32..64d490ee1 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -184,6 +184,60 @@ jobs: INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }} STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} + mutation-tests-phpstan: + name: "Mutation tests with PHPStan" + + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + dependencies: + - "locked" + php-version: + - "8.4" + operating-system: + - "ubuntu-latest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v4" + + - name: "Install PHP" + uses: "shivammathur/setup-php@2.33.0" + with: + coverage: "xdebug" + php-version: "${{ matrix.php-version }}" + extensions: intl, sodium + ini-values: memory_limit=-1, zend.assertions=1 + + - name: "Install dependencies" + uses: "ramsey/composer-install@3.1.0" + with: + dependency-versions: "${{ matrix.dependencies }}" + + - name: "Install CI dependencies" + uses: "ramsey/composer-install@3.1.0" + with: + dependency-versions: "${{ matrix.dependencies }}" + working-directory: "tools" + custom-cache-suffix: "ci" + + - name: "Warmup PHPStan" + run: "tools/vendor/bin/phpstan analyse --memory-limit=-1" + + - name: "Infection" + run: "tools/vendor/bin/phpstan-mutant-killer-infection-runner --phpstan-config phpstan.neon --log log.txt --threads=$(nproc)" + env: + INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }} + STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} + + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: log.txt + path: log.txt + if-no-files-found: error + compatibility: name: "Test Compatibility" diff --git a/src/Reflection/ReflectionMethod.php b/src/Reflection/ReflectionMethod.php index 9fdd7ed0d..e5005f587 100644 --- a/src/Reflection/ReflectionMethod.php +++ b/src/Reflection/ReflectionMethod.php @@ -307,7 +307,7 @@ public function getModifiers(): int /** @return int-mask-of */ private function computeModifiers(MethodNode|Node\PropertyHook $node): int { - $modifiers = 0; + $modifiers = $node->isFinal() ? CoreReflectionMethod::IS_FINAL : 0; if ($node instanceof MethodNode) { $modifiers += $node->isStatic() ? CoreReflectionMethod::IS_STATIC : 0; @@ -317,8 +317,6 @@ private function computeModifiers(MethodNode|Node\PropertyHook $node): int $modifiers += $node->isAbstract() ? CoreReflectionMethod::IS_ABSTRACT : 0; } - $modifiers += $node->isFinal() ? CoreReflectionMethod::IS_FINAL : 0; - return $modifiers; } diff --git a/src/Reflection/ReflectionObject.php b/src/Reflection/ReflectionObject.php index 9e5168e49..744b4effb 100644 --- a/src/Reflection/ReflectionObject.php +++ b/src/Reflection/ReflectionObject.php @@ -27,7 +27,7 @@ /** @psalm-immutable */ class ReflectionObject extends ReflectionClass { - protected function __construct(private Reflector $reflector, private ReflectionClass $reflectionClass, private object $object) + private function __construct(private Reflector $reflector, private ReflectionClass $reflectionClass, private object $object) { } @@ -117,6 +117,7 @@ private function createPropertyNodeFromRuntimePropertyReflection(CoreReflectionP { $builder = new PropertyNodeBuilder($property->getName()); $builder->setDefault($property->getValue($instance)); + // @infection-ignore-all MethodCallRemoval: The call is not necessary because the property is public by default, it's just for clarity $builder->makePublic(); return $builder->getNode(); diff --git a/src/Reflection/ReflectionProperty.php b/src/Reflection/ReflectionProperty.php index ddcd21190..f2831fd5a 100644 --- a/src/Reflection/ReflectionProperty.php +++ b/src/Reflection/ReflectionProperty.php @@ -598,6 +598,7 @@ public function hasType(): bool public function isVirtual(): bool { + // @infection-ignore-all AssignCoalesce: It's just optimization $this->cachedVirtual ??= $this->createCachedVirtual(); return $this->cachedVirtual; @@ -621,6 +622,7 @@ public function getHook(ReflectionPropertyHookType $hookType): ReflectionMethod| /** @return array{get?: ReflectionMethod, set?: ReflectionMethod} */ public function getHooks(): array { + // @infection-ignore-all AssignCoalesce: It's just optimization $this->cachedHooks ??= $this->createCachedHooks(); return $this->cachedHooks; diff --git a/test/unit/Fixture/PropertyHooks.php b/test/unit/Fixture/PropertyHooks.php index 1619c6588..2eb1af4d8 100644 --- a/test/unit/Fixture/PropertyHooks.php +++ b/test/unit/Fixture/PropertyHooks.php @@ -100,6 +100,45 @@ class GetAndSetPropertyHook extends GetPropertyHook } } +class SetPropertyHook +{ + public string $hook { + set (string $value) { + $this->hook = $value; + } + } +} + +class SetAndGetPropertyHook extends SetPropertyHook +{ + public string $hook { + get { + return 'hook'; + } + } +} + +class BothPropertyHooks +{ + public string $hook { + get { + return 'hook'; + } + set (string $value) { + $this->hook = $value; + } + } +} + +class ExtendedHooks extends BothPropertyHooks +{ + public string $hook { + get { + return 'hook2'; + } + } +} + trait PropertyHookTrait { public string $hook { diff --git a/test/unit/Reflection/ReflectionClassConstantTest.php b/test/unit/Reflection/ReflectionClassConstantTest.php index 2a59e765e..bc758c7cb 100644 --- a/test/unit/Reflection/ReflectionClassConstantTest.php +++ b/test/unit/Reflection/ReflectionClassConstantTest.php @@ -61,25 +61,34 @@ public function testDefaultVisibility(): void { $const = $this->getExampleConstant('MY_CONST_1'); self::assertTrue($const->isPublic()); + self::assertFalse($const->isProtected()); + self::assertFalse($const->isPrivate()); + self::assertFalse($const->isFinal()); } public function testOnlyPublicVisibility(): void { $const = $this->getExampleConstant('MY_CONST_3'); self::assertTrue($const->isPublic()); + self::assertFalse($const->isProtected()); + self::assertFalse($const->isPrivate()); self::assertFalse($const->isFinal()); } public function testOnlyProtectedVisibility(): void { $const = $this->getExampleConstant('MY_CONST_4'); + self::assertFalse($const->isPublic()); self::assertTrue($const->isProtected()); + self::assertFalse($const->isPrivate()); self::assertFalse($const->isFinal()); } public function testPrivateVisibility(): void { $const = $this->getExampleConstant('MY_CONST_5'); + self::assertFalse($const->isPublic()); + self::assertFalse($const->isProtected()); self::assertTrue($const->isPrivate()); self::assertFalse($const->isFinal()); } @@ -94,7 +103,9 @@ public function testPublicFinal(): void public function testProtectedFinal(): void { $const = $this->getExampleConstant('MY_CONST_7'); + self::assertFalse($const->isPublic()); self::assertTrue($const->isProtected()); + self::assertFalse($const->isPrivate()); self::assertTrue($const->isFinal()); } diff --git a/test/unit/Reflection/ReflectionClassTest.php b/test/unit/Reflection/ReflectionClassTest.php index 8471bf59f..c137f5bac 100644 --- a/test/unit/Reflection/ReflectionClassTest.php +++ b/test/unit/Reflection/ReflectionClassTest.php @@ -33,6 +33,7 @@ use Roave\BetterReflection\Reflection\ReflectionClassConstant; use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflection\ReflectionNamedType; +use Roave\BetterReflection\Reflection\ReflectionObject; use Roave\BetterReflection\Reflection\ReflectionParameter; use Roave\BetterReflection\Reflection\ReflectionProperty; use Roave\BetterReflection\Reflection\ReflectionUnionType; @@ -108,6 +109,7 @@ use function uniqid; #[CoversClass(ReflectionClass::class)] +#[CoversClass(ReflectionObject::class)] class ReflectionClassTest extends TestCase { private Locator $astLocator; diff --git a/test/unit/Reflection/ReflectionPropertyTest.php b/test/unit/Reflection/ReflectionPropertyTest.php index d07cc2949..184680267 100644 --- a/test/unit/Reflection/ReflectionPropertyTest.php +++ b/test/unit/Reflection/ReflectionPropertyTest.php @@ -192,10 +192,11 @@ public function testIsReadOnly(): void $notReadOnlyProperty = $classInfo->getProperty('publicProperty'); self::assertFalse($notReadOnlyProperty->isReadOnly()); + self::assertTrue($notReadOnlyProperty->isPublic()); $readOnlyProperty = $classInfo->getProperty('readOnlyProperty'); - self::assertTrue($readOnlyProperty->isPublic()); self::assertTrue($readOnlyProperty->isReadOnly()); + self::assertTrue($readOnlyProperty->isPublic()); } public function testIsFinal(): void @@ -204,6 +205,7 @@ public function testIsFinal(): void $notReadOnlyProperty = $classInfo->getProperty('publicProperty'); self::assertFalse($notReadOnlyProperty->isFinal()); + self::assertTrue($notReadOnlyProperty->isPublic()); $finalPublicProperty = $classInfo->getProperty('finalPublicProperty'); self::assertTrue($finalPublicProperty->isFinal()); @@ -215,6 +217,7 @@ public function testIsNotAbstract(): void $classInfo = $this->reflector->reflectClass(ExampleClass::class); $notAbstractProperty = $classInfo->getProperty('publicProperty'); + self::assertTrue($notAbstractProperty->isPublic()); self::assertFalse($notAbstractProperty->isAbstract()); } @@ -227,6 +230,7 @@ public function testIsReadOnlyInReadOnlyClass(): void $classInfo = $reflector->reflectClass('\\Roave\\BetterReflectionTest\\Fixture\\ReadOnlyClass'); $property = $classInfo->getProperty('property'); + self::assertTrue($property->isPrivate()); self::assertTrue($property->isReadOnly()); } @@ -265,25 +269,32 @@ public function testGetDocCommentReturnsNullWithNoComment(): void self::assertNull($property->getDocComment()); } - /** @return list}> */ + /** @return list}> */ public static function modifierProvider(): array { return [ - ['publicProperty', CoreReflectionProperty::IS_PUBLIC], - ['protectedProperty', CoreReflectionProperty::IS_PROTECTED], - ['privateProperty', CoreReflectionProperty::IS_PRIVATE], - ['publicStaticProperty', CoreReflectionProperty::IS_PUBLIC | CoreReflectionProperty::IS_STATIC], - ['readOnlyProperty', CoreReflectionProperty::IS_PUBLIC | ReflectionPropertyAdapter::IS_READONLY | ReflectionPropertyAdapter::IS_PROTECTED_SET_COMPATIBILITY], - ['finalPublicProperty', CoreReflectionProperty::IS_PUBLIC | ReflectionPropertyAdapter::IS_FINAL_COMPATIBILITY], + [__DIR__ . '/../Fixture/ExampleClass.php', 'Roave\BetterReflectionTest\Fixture\ExampleClass', 'publicProperty', CoreReflectionProperty::IS_PUBLIC], + [__DIR__ . '/../Fixture/ExampleClass.php', 'Roave\BetterReflectionTest\Fixture\ExampleClass', 'protectedProperty', CoreReflectionProperty::IS_PROTECTED], + [__DIR__ . '/../Fixture/ExampleClass.php', 'Roave\BetterReflectionTest\Fixture\ExampleClass', 'privateProperty', CoreReflectionProperty::IS_PRIVATE], + [__DIR__ . '/../Fixture/ExampleClass.php', 'Roave\BetterReflectionTest\Fixture\ExampleClass', 'publicStaticProperty', CoreReflectionProperty::IS_PUBLIC | CoreReflectionProperty::IS_STATIC], + [__DIR__ . '/../Fixture/ExampleClass.php', 'Roave\BetterReflectionTest\Fixture\ExampleClass', 'readOnlyProperty', CoreReflectionProperty::IS_PUBLIC | ReflectionPropertyAdapter::IS_READONLY | ReflectionPropertyAdapter::IS_PROTECTED_SET_COMPATIBILITY], + [__DIR__ . '/../Fixture/ExampleClass.php', 'Roave\BetterReflectionTest\Fixture\ExampleClass', 'finalPublicProperty', CoreReflectionProperty::IS_PUBLIC | ReflectionPropertyAdapter::IS_FINAL_COMPATIBILITY], + [__DIR__ . '/../Fixture/PropertyHooks.php', 'Roave\BetterReflectionTest\Fixture\AbstractPropertyHooks', 'hook', CoreReflectionProperty::IS_PUBLIC | ReflectionPropertyAdapter::IS_ABSTRACT_COMPATIBILITY | ReflectionPropertyAdapter::IS_VIRTUAL_COMPATIBILITY], ]; } - /** @param non-empty-string $propertyName */ + /** + * @param non-empty-string $fileName + * @param class-string $className + * @param non-empty-string $propertyName + */ #[DataProvider('modifierProvider')] - public function testGetModifiers(string $propertyName, int $expectedModifier): void + public function testGetModifiers(string $fileName, string $className, string $propertyName, int $expectedModifier): void { - $classInfo = $this->reflector->reflectClass(ExampleClass::class); - $property = $classInfo->getProperty($propertyName); + $reflector = new DefaultReflector(new SingleFileSourceLocator($fileName, $this->astLocator)); + $classInfo = $reflector->reflectClass($className); + + $property = $classInfo->getProperty($propertyName); self::assertSame($expectedModifier, $property->getModifiers()); } @@ -972,25 +983,29 @@ public function testIsPrivateSet(): void self::assertTrue($protectedPrivateSet->isPrivateSet()); } - /** @return list */ + /** @return list}> */ public static function asymmetricVisibilityImplicitFinalProvider(): array { return [ - ['publicPrivateSetIsFinal', true], - ['protectedPrivateSetIsFinal', true], - ['privatePrivateSetIsNotFinal', false], + ['publicPrivateSetIsFinal', true, ReflectionPropertyAdapter::IS_PUBLIC | ReflectionPropertyAdapter::IS_PRIVATE_SET_COMPATIBILITY | ReflectionPropertyAdapter::IS_FINAL_COMPATIBILITY], + ['protectedPrivateSetIsFinal', true, ReflectionPropertyAdapter::IS_PROTECTED | ReflectionPropertyAdapter::IS_PRIVATE_SET_COMPATIBILITY | ReflectionPropertyAdapter::IS_FINAL_COMPATIBILITY], + ['privatePrivateSetIsNotFinal', false, ReflectionPropertyAdapter::IS_PRIVATE], ]; } - /** @param non-empty-string $propertyName */ + /** + * @param non-empty-string $propertyName + * @param int-mask-of $modifiers + */ #[DataProvider('asymmetricVisibilityImplicitFinalProvider')] - public function testAsymmetricVisibilityImplicitFinal(string $propertyName, bool $isFinal): void + public function testAsymmetricVisibilityImplicitFinal(string $propertyName, bool $isFinal, int $modifiers): void { $reflector = new DefaultReflector(new SingleFileSourceLocator(__DIR__ . '/../Fixture/AsymmetricVisibilityImplicitFinal.php', $this->astLocator)); $classInfo = $reflector->reflectClass('Roave\BetterReflectionTest\Fixture\AsymmetricVisibilityImplicitFinal'); $property = $classInfo->getProperty($propertyName); self::assertSame($isFinal, $property->isFinal()); + self::assertSame($modifiers, $property->getModifiers()); } /** @return list */ @@ -1023,6 +1038,7 @@ public function testIsAbstract(): void $hookProperty = $classInfo->getProperty('hook'); self::assertTrue($hookProperty->isAbstract()); + self::assertTrue($hookProperty->isPublic()); } public function testIsAbstractInInterface(): void @@ -1032,6 +1048,7 @@ public function testIsAbstractInInterface(): void $abstractProperty = $classInfo->getProperty('abstractPropertyFromInterface'); self::assertTrue($abstractProperty->isAbstract()); + self::assertTrue($abstractProperty->isPublic()); } public function testNoHooks(): void @@ -1212,6 +1229,20 @@ public function testExtendingHooks(): void self::assertSame('Roave\BetterReflectionTest\Fixture\GetAndSetPropertyHook', $getAndSetHookProperty->getHook(ReflectionPropertyHookType::Set)->getDeclaringClass()->getName()); } + public function testExtendingHooks2(): void + { + $reflector = new DefaultReflector(new SingleFileSourceLocator(__DIR__ . '/../Fixture/PropertyHooks.php', $this->astLocator)); + + $classInfo = $reflector->reflectClass('Roave\BetterReflectionTest\Fixture\ExtendedHooks'); + + $getAndSetHookProperty = $classInfo->getProperty('hook'); + self::assertCount(2, $getAndSetHookProperty->getHooks()); + self::assertTrue($getAndSetHookProperty->hasHook(ReflectionPropertyHookType::Get)); + self::assertTrue($getAndSetHookProperty->hasHook(ReflectionPropertyHookType::Set)); + self::assertSame('Roave\BetterReflectionTest\Fixture\ExtendedHooks', $getAndSetHookProperty->getHook(ReflectionPropertyHookType::Get)->getDeclaringClass()->getName()); + self::assertSame('Roave\BetterReflectionTest\Fixture\BothPropertyHooks', $getAndSetHookProperty->getHook(ReflectionPropertyHookType::Set)->getDeclaringClass()->getName()); + } + public function testUseHookFromTrait(): void { $reflector = new DefaultReflector(new SingleFileSourceLocator(__DIR__ . '/../Fixture/PropertyHooks.php', $this->astLocator)); diff --git a/tools/composer.json b/tools/composer.json index f74fc302e..7e891ec15 100644 --- a/tools/composer.json +++ b/tools/composer.json @@ -5,7 +5,8 @@ "phpstan/phpstan-phpunit": "^2.0.6", "vimeo/psalm": "^6.11.0", "roave/backward-compatibility-check": "^8.13.0", - "roave/infection-static-analysis-plugin": "^1.37.0" + "roave/infection-static-analysis-plugin": "^1.38.0", + "phpstan/mutant-killer-infection-runner": "1.0.x-dev" }, "config": { "allow-plugins": { @@ -20,5 +21,7 @@ "psr-4": { "Roave\\BetterReflection\\": "../src" } - } + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/tools/composer.lock b/tools/composer.lock index 00c8e5262..a28a190cd 100644 --- a/tools/composer.lock +++ b/tools/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": "ba89c36915dd88eae09b350640150a49", + "content-hash": "e8956028c4f5c7eaf27a79ea3a5908da", "packages": [ { "name": "amphp/amp", @@ -1194,16 +1194,16 @@ }, { "name": "composer/composer", - "version": "2.8.6", + "version": "2.8.9", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "937c775a644bd7d2c3dfbb352747488463a6e673" + "reference": "b4e6bff2db7ce756ddb77ecee958a0f41f42bd9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/937c775a644bd7d2c3dfbb352747488463a6e673", - "reference": "937c775a644bd7d2c3dfbb352747488463a6e673", + "url": "https://api.github.com/repos/composer/composer/zipball/b4e6bff2db7ce756ddb77ecee958a0f41f42bd9d", + "reference": "b4e6bff2db7ce756ddb77ecee958a0f41f42bd9d", "shasum": "" }, "require": { @@ -1214,7 +1214,7 @@ "composer/semver": "^3.3", "composer/spdx-licenses": "^1.5.7", "composer/xdebug-handler": "^2.0.2 || ^3.0.3", - "justinrainbow/json-schema": "^5.3", + "justinrainbow/json-schema": "^6.3.1", "php": "^7.2.5 || ^8.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "react/promise": "^2.11 || ^3.2", @@ -1288,7 +1288,7 @@ "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", "security": "https://github.com/composer/composer/security/policy", - "source": "https://github.com/composer/composer/tree/2.8.6" + "source": "https://github.com/composer/composer/tree/2.8.9" }, "funding": [ { @@ -1304,7 +1304,7 @@ "type": "tidelift" } ], - "time": "2025-02-25T12:03:50+00:00" + "time": "2025-05-13T12:01:37+00:00" }, { "name": "composer/metadata-minifier", @@ -2292,16 +2292,16 @@ }, { "name": "infection/infection", - "version": "0.29.12", + "version": "0.29.14", "source": { "type": "git", "url": "https://github.com/infection/infection.git", - "reference": "dfe9cf6e65545881c7d21343c494cc8a1fdbfb80" + "reference": "feea2a48a8aeedd3a4d2105167b41a46f0e568a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/infection/infection/zipball/dfe9cf6e65545881c7d21343c494cc8a1fdbfb80", - "reference": "dfe9cf6e65545881c7d21343c494cc8a1fdbfb80", + "url": "https://api.github.com/repos/infection/infection/zipball/feea2a48a8aeedd3a4d2105167b41a46f0e568a3", + "reference": "feea2a48a8aeedd3a4d2105167b41a46f0e568a3", "shasum": "" }, "require": { @@ -2317,7 +2317,7 @@ "infection/extension-installer": "^0.1.0", "infection/include-interceptor": "^0.2.5", "infection/mutator": "^0.4", - "justinrainbow/json-schema": "^5.3", + "justinrainbow/json-schema": "^5.3 || ^6.0", "nikic/php-parser": "^5.3", "ondram/ci-detector": "^4.1.0", "php": "^8.2", @@ -2339,16 +2339,16 @@ "require-dev": { "ext-simplexml": "*", "fidry/makefile": "^1.0", - "helmich/phpunit-json-assert": "^3.0", - "phpstan/extension-installer": "^1.1.0", - "phpstan/phpstan": "^1.10.15", - "phpstan/phpstan-phpunit": "^1.0.0", - "phpstan/phpstan-strict-rules": "^1.1.0", - "phpstan/phpstan-webmozart-assert": "^1.0.2", - "phpunit/phpunit": "^10.5", - "rector/rector": "^1.0", - "sidz/phpstan-rules": "^0.4", - "symfony/yaml": "^6.4 || ^7.0" + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpstan/phpstan-webmozart-assert": "^2.0", + "phpunit/phpunit": "^11.5", + "rector/rector": "^2.0", + "sidz/phpstan-rules": "^0.5.1", + "symfony/yaml": "^6.4 || ^7.0", + "thecodingmachine/phpstan-safe-rule": "^1.4" }, "bin": [ "bin/infection" @@ -2404,7 +2404,7 @@ ], "support": { "issues": "https://github.com/infection/infection/issues", - "source": "https://github.com/infection/infection/tree/0.29.12" + "source": "https://github.com/infection/infection/tree/0.29.14" }, "funding": [ { @@ -2416,7 +2416,7 @@ "type": "open_collective" } ], - "time": "2025-02-17T18:25:11+00:00" + "time": "2025-03-02T18:49:12+00:00" }, { "name": "infection/mutator", @@ -2520,30 +2520,40 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.3.0", + "version": "6.4.1", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" + "reference": "35d262c94959571e8736db1e5c9bc36ab94ae900" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", - "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/35d262c94959571e8736db1e5c9bc36ab94ae900", + "reference": "35d262c94959571e8736db1e5c9bc36ab94ae900", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-json": "*", + "marc-mabe/php-enum": "^4.0", + "php": "^7.2 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "friendsofphp/php-cs-fixer": "3.3.0", "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" + "marc-mabe/php-enum-phpstan": "^2.0", + "phpspec/prophecy": "^1.19", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "^8.5" }, "bin": [ "bin/validate-json" ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.x-dev" + } + }, "autoload": { "psr-4": { "JsonSchema\\": "src/JsonSchema/" @@ -2572,16 +2582,16 @@ } ], "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", + "homepage": "https://github.com/jsonrainbow/json-schema", "keywords": [ "json", "schema" ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.4.1" }, - "time": "2024-07-06T21:00:26+00:00" + "time": "2025-04-04T13:08:07+00:00" }, { "name": "kelunik/certificate", @@ -2815,6 +2825,182 @@ ], "time": "2024-12-08T08:18:47+00:00" }, + { + "name": "marc-mabe/php-enum", + "version": "v4.7.1", + "source": { + "type": "git", + "url": "https://github.com/marc-mabe/php-enum.git", + "reference": "7159809e5cfa041dca28e61f7f7ae58063aae8ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/marc-mabe/php-enum/zipball/7159809e5cfa041dca28e61f7f7ae58063aae8ed", + "reference": "7159809e5cfa041dca28e61f7f7ae58063aae8ed", + "shasum": "" + }, + "require": { + "ext-reflection": "*", + "php": "^7.1 | ^8.0" + }, + "require-dev": { + "phpbench/phpbench": "^0.16.10 || ^1.0.4", + "phpstan/phpstan": "^1.3.1", + "phpunit/phpunit": "^7.5.20 | ^8.5.22 | ^9.5.11", + "vimeo/psalm": "^4.17.0 | ^5.26.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-3.x": "3.2-dev", + "dev-master": "4.7-dev" + } + }, + "autoload": { + "psr-4": { + "MabeEnum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Marc Bennewitz", + "email": "dev@mabe.berlin", + "homepage": "https://mabe.berlin/", + "role": "Lead" + } + ], + "description": "Simple and fast implementation of enumerations with native PHP", + "homepage": "https://github.com/marc-mabe/php-enum", + "keywords": [ + "enum", + "enum-map", + "enum-set", + "enumeration", + "enumerator", + "enummap", + "enumset", + "map", + "set", + "type", + "type-hint", + "typehint" + ], + "support": { + "issues": "https://github.com/marc-mabe/php-enum/issues", + "source": "https://github.com/marc-mabe/php-enum/tree/v4.7.1" + }, + "time": "2024-11-28T04:54:44+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.9.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", + "predis/predis": "^1.1 || ^2", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2025-03-24T10:02:05+00:00" + }, { "name": "netresearch/jsonmapper", "version": "v5.0.0", @@ -3301,6 +3487,66 @@ }, "time": "2024-11-09T15:12:26+00:00" }, + { + "name": "phpstan/mutant-killer-infection-runner", + "version": "1.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/phpstan/mutant-killer-infection-runner.git", + "reference": "ba2df97163487ff2f7682cfa648dded3d4a6ca90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/mutant-killer-infection-runner/zipball/ba2df97163487ff2f7682cfa648dded3d4a6ca90", + "reference": "ba2df97163487ff2f7682cfa648dded3d4a6ca90", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "infection/infection": "0.29.14", + "monolog/monolog": "^3.9", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "phpstan/phpstan": "^1.12.27 || ^2.1.17", + "sanmai/later": "^0.1.7" + }, + "conflict": { + "symfony/polyfill-php84": "<1.30.0" + }, + "require-dev": { + "azjezz/psl": "^3.3.0", + "doctrine/coding-standard": "^12.0.0", + "phpunit/phpunit": "^11.5.20" + }, + "default-branch": true, + "bin": [ + "bin/phpstan-mutant-killer-infection-runner" + ], + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\InfectionStaticAnalysis\\": "src/InfectionStaticAnalysis" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + }, + { + "name": "PHPStan s.r.o.", + "email": "biz@phpstan.com" + } + ], + "description": "Static analysis on top of mutation testing - prevents escaped mutants from being invalid according to static analysis", + "support": { + "source": "https://github.com/phpstan/mutant-killer-infection-runner/tree/1.0.x" + }, + "time": "2025-05-21T20:26:47+00:00" + }, { "name": "phpstan/phpdoc-parser", "version": "2.1.0", @@ -3959,34 +4205,35 @@ }, { "name": "roave/infection-static-analysis-plugin", - "version": "1.37.0", + "version": "1.38.x-dev", "source": { "type": "git", "url": "https://github.com/Roave/infection-static-analysis-plugin.git", - "reference": "062af2a493b570346f6cbbae378e1d69bc4194bb" + "reference": "55cac2d20358f24b6dd84ec067fb08d1540f8166" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/infection-static-analysis-plugin/zipball/062af2a493b570346f6cbbae378e1d69bc4194bb", - "reference": "062af2a493b570346f6cbbae378e1d69bc4194bb", + "url": "https://api.github.com/repos/Roave/infection-static-analysis-plugin/zipball/55cac2d20358f24b6dd84ec067fb08d1540f8166", + "reference": "55cac2d20358f24b6dd84ec067fb08d1540f8166", "shasum": "" }, "require": { "composer-runtime-api": "^2.2", - "infection/infection": "0.29.12", + "infection/infection": "0.29.14", "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "sanmai/later": "^0.1.4", - "vimeo/psalm": "^6.8.8" + "sanmai/later": "^0.1.7", + "vimeo/psalm": "^6.11.0" }, "conflict": { "symfony/polyfill-php84": "<1.30.0" }, "require-dev": { - "azjezz/psl": "^3.2", + "azjezz/psl": "^3.3.0", "doctrine/coding-standard": "^12.0.0", - "phpunit/phpunit": "^11.5.10", - "psalm/plugin-phpunit": "^0.19.2" + "phpunit/phpunit": "^11.5.21", + "psalm/plugin-phpunit": "^0.19.5" }, + "default-branch": true, "bin": [ "bin/roave-infection-static-analysis-plugin" ], @@ -4009,9 +4256,9 @@ "description": "Static analysis on top of mutation testing - prevents escaped mutants from being invalid according to static analysis", "support": { "issues": "https://github.com/Roave/infection-static-analysis-plugin/issues", - "source": "https://github.com/Roave/infection-static-analysis-plugin/tree/1.37.0" + "source": "https://github.com/Roave/infection-static-analysis-plugin/tree/1.38.x" }, - "time": "2025-02-27T18:02:45+00:00" + "time": "2025-05-23T00:00:54+00:00" }, { "name": "sanmai/later", @@ -6065,9 +6312,11 @@ ], "packages-dev": [], "aliases": [], - "minimum-stability": "stable", - "stability-flags": {}, - "prefer-stable": false, + "minimum-stability": "dev", + "stability-flags": { + "phpstan/mutant-killer-infection-runner": 20 + }, + "prefer-stable": true, "prefer-lowest": false, "platform": {}, "platform-dev": {},