diff --git a/UPGRADE.md b/UPGRADE.md index 987b27f01..0b5bc60cb 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -422,7 +422,7 @@ class MyType extends ScalarType { ### Breaking: Descriptions in comments are not used as descriptions by default anymore Descriptions now need to be inside Strings or BlockStrings in order to be picked up as -description. If you want to keep the old behaviour you can supply the option `commentDescriptions` +description. If you want to keep the old behavior you can supply the option `commentDescriptions` to BuildSchema::buildAST(), BuildSchema::build() or Printer::doPrint(). Here is the official way now to define descriptions in the graphQL language: diff --git a/composer.json b/composer.json index ca2723523..4ec80a24e 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "nyholm/psr7": "^1.5", "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "2.1.11", + "phpstan/phpstan": "2.1.15", "phpstan/phpstan-phpunit": "2.0.6", "phpstan/phpstan-strict-rules": "2.0.4", "phpunit/phpunit": "^9.5 || ^10.5.21 || ^11", diff --git a/rector.php b/rector.php index 851d258cd..93cfa0373 100644 --- a/rector.php +++ b/rector.php @@ -19,13 +19,13 @@ Rector\CodeQuality\Rector\ClassMethod\LocallyCalledStaticMethodToNonStaticRector::class, // static methods are fine Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector::class, // Less efficient Rector\CodeQuality\Rector\Switch_\SwitchTrueToIfRector::class, // More expressive in some cases - Rector\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector::class, // Sometimes necessary to prove runtime behaviour matches defined types - Rector\DeadCode\Rector\If_\RemoveDeadInstanceOfRector::class, // Sometimes necessary to prove runtime behaviour matches defined types + Rector\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector::class, // Sometimes necessary to prove runtime behavior matches defined types + Rector\DeadCode\Rector\If_\RemoveDeadInstanceOfRector::class, // Sometimes necessary to prove runtime behavior matches defined types Rector\DeadCode\Rector\Node\RemoveNonExistingVarAnnotationRector::class, // Sometimes false-positive Rector\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector::class, // TODO reintroduce when https://github.com/rectorphp/rector-src/pull/4491 is released Rector\PHPUnit\CodeQuality\Rector\Class_\NarrowUnusedSetUpDefinedPropertyRector::class, // Sometimes nicer for symmetry Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector::class, // Prefer self:: - Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector::class, // imprecise + Rector\PHPUnit\CodeQuality\Rector\Class_\RemoveDataProviderParamKeysRector::class, // Less clear Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertPropertyExistsRector::class, // Uses deprecated PHPUnit methods Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertIssetToSpecificMethodRector::class => [ __DIR__ . '/tests/Utils/MixedStoreTest.php', // Uses keys that are not string or int diff --git a/src/Type/Definition/CustomScalarType.php b/src/Type/Definition/CustomScalarType.php index 64cd887de..80694dca9 100644 --- a/src/Type/Definition/CustomScalarType.php +++ b/src/Type/Definition/CustomScalarType.php @@ -101,19 +101,19 @@ public function assertValid(): void throw new InvariantViolation("{$this->name} must provide \"parseValue\" and \"parseLiteral\" functions, \"serialize\" function, or both."); } - // @phpstan-ignore-next-line not necessary according to types, but can happen during runtime + // @phpstan-ignore-next-line unnecessary according to types, but can happen during runtime if ($hasSerialize && ! is_callable($serialize)) { $notCallable = Utils::printSafe($serialize); throw new InvariantViolation("{$this->name} must provide \"serialize\" as a callable if given, but got: {$notCallable}."); } - // @phpstan-ignore-next-line not necessary according to types, but can happen during runtime + // @phpstan-ignore-next-line unnecessary according to types, but can happen during runtime if ($hasParseValue && ! is_callable($parseValue)) { $notCallable = Utils::printSafe($parseValue); throw new InvariantViolation("{$this->name} must provide \"parseValue\" as a callable if given, but got: {$notCallable}."); } - // @phpstan-ignore-next-line not necessary according to types, but can happen during runtime + // @phpstan-ignore-next-line unnecessary according to types, but can happen during runtime if ($hasParseLiteral && ! is_callable($parseLiteral)) { $notCallable = Utils::printSafe($parseLiteral); throw new InvariantViolation("{$this->name} must provide \"parseLiteral\" as a callable if given, but got: {$notCallable}."); diff --git a/src/Type/Definition/EnumType.php b/src/Type/Definition/EnumType.php index e30fc7b2b..4182a3545 100644 --- a/src/Type/Definition/EnumType.php +++ b/src/Type/Definition/EnumType.php @@ -222,7 +222,7 @@ public function assertValid(): void { Utils::assertValidName($this->name); - $values = $this->config['values'] ?? null; + $values = $this->config['values'] ?? null; // @phpstan-ignore nullCoalesce.initializedProperty (unnecessary according to types, but can happen during runtime) if (! is_iterable($values) && ! is_callable($values)) { $notIterable = Utils::printSafe($values); throw new InvariantViolation("{$this->name} values must be an iterable or callable, got: {$notIterable}"); diff --git a/src/Type/Definition/FieldDefinition.php b/src/Type/Definition/FieldDefinition.php index 02f6ddafb..788dab9f2 100644 --- a/src/Type/Definition/FieldDefinition.php +++ b/src/Type/Definition/FieldDefinition.php @@ -238,7 +238,7 @@ public function assertValid(Type $parentType): void throw new InvariantViolation("{$parentType->name}.{$this->name} field type must be Output Type but got: {$safeType}."); } - // @phpstan-ignore-next-line not necessary according to types, but can happen during runtime + // @phpstan-ignore-next-line unnecessary according to types, but can happen during runtime if ($this->resolveFn !== null && ! is_callable($this->resolveFn)) { $safeResolveFn = Utils::printSafe($this->resolveFn); throw new InvariantViolation("{$parentType->name}.{$this->name} field resolver must be a function if provided, but got: {$safeResolveFn}."); diff --git a/src/Type/Definition/InputObjectType.php b/src/Type/Definition/InputObjectType.php index 3cf82699d..3e9c1ad9e 100644 --- a/src/Type/Definition/InputObjectType.php +++ b/src/Type/Definition/InputObjectType.php @@ -181,7 +181,7 @@ public function assertValid(): void { Utils::assertValidName($this->name); - $fields = $this->config['fields'] ?? null; + $fields = $this->config['fields'] ?? null; // @phpstan-ignore nullCoalesce.initializedProperty (unnecessary according to types, but can happen during runtime) if (is_callable($fields)) { $fields = $fields(); } diff --git a/src/Type/Definition/InterfaceType.php b/src/Type/Definition/InterfaceType.php index d4e42e9b0..3506e9b35 100644 --- a/src/Type/Definition/InterfaceType.php +++ b/src/Type/Definition/InterfaceType.php @@ -85,7 +85,7 @@ public function assertValid(): void Utils::assertValidName($this->name); $resolveType = $this->config['resolveType'] ?? null; - // @phpstan-ignore-next-line not necessary according to types, but can happen during runtime + // @phpstan-ignore-next-line unnecessary according to types, but can happen during runtime if ($resolveType !== null && ! is_callable($resolveType)) { $notCallable = Utils::printSafe($resolveType); throw new InvariantViolation("{$this->name} must provide \"resolveType\" as null or a callable, but got: {$notCallable}."); diff --git a/src/Type/Definition/NamedTypeImplementation.php b/src/Type/Definition/NamedTypeImplementation.php index cb5f65811..f47f9e4d4 100644 --- a/src/Type/Definition/NamedTypeImplementation.php +++ b/src/Type/Definition/NamedTypeImplementation.php @@ -4,9 +4,7 @@ use GraphQL\Error\InvariantViolation; -/** - * @see NamedType - */ +/** @see NamedType */ trait NamedTypeImplementation { public string $name; @@ -21,7 +19,7 @@ public function toString(): string /** @throws InvariantViolation */ protected function inferName(): string { - if (isset($this->name)) { + if (isset($this->name)) { // @phpstan-ignore-line property might be uninitialized return $this->name; } diff --git a/src/Type/Definition/ObjectType.php b/src/Type/Definition/ObjectType.php index 63b7c5d99..cb34bbc56 100644 --- a/src/Type/Definition/ObjectType.php +++ b/src/Type/Definition/ObjectType.php @@ -154,7 +154,7 @@ public function assertValid(): void Utils::assertValidName($this->name); $isTypeOf = $this->config['isTypeOf'] ?? null; - // @phpstan-ignore-next-line not necessary according to types, but can happen during runtime + // @phpstan-ignore-next-line unnecessary according to types, but can happen during runtime if (isset($isTypeOf) && ! is_callable($isTypeOf)) { $notCallable = Utils::printSafe($isTypeOf); throw new InvariantViolation("{$this->name} must provide \"isTypeOf\" as null or a callable, but got: {$notCallable}."); diff --git a/src/Type/Definition/UnionType.php b/src/Type/Definition/UnionType.php index 3b6535bfa..935ac60eb 100644 --- a/src/Type/Definition/UnionType.php +++ b/src/Type/Definition/UnionType.php @@ -89,7 +89,7 @@ public function getTypes(): array if (! isset($this->types)) { $this->types = []; - $types = $this->config['types'] ?? null; + $types = $this->config['types'] ?? null; // @phpstan-ignore nullCoalesce.initializedProperty (unnecessary according to types, but can happen during runtime) if (is_callable($types)) { $types = $types(); } @@ -120,7 +120,7 @@ public function assertValid(): void Utils::assertValidName($this->name); $resolveType = $this->config['resolveType'] ?? null; - // @phpstan-ignore-next-line not necessary according to types, but can happen during runtime + // @phpstan-ignore-next-line unnecessary according to types, but can happen during runtime if (isset($resolveType) && ! is_callable($resolveType)) { $notCallable = Utils::printSafe($resolveType); throw new InvariantViolation("{$this->name} must provide \"resolveType\" as null or a callable, but got: {$notCallable}."); diff --git a/src/Utils/Utils.php b/src/Utils/Utils.php index c171a3fcb..ee122b115 100644 --- a/src/Utils/Utils.php +++ b/src/Utils/Utils.php @@ -116,7 +116,10 @@ public static function chr(int $ord, string $encoding = 'UTF-8'): string return pack('N', $ord); } - return mb_convert_encoding(self::chr($ord, 'UCS-4BE'), $encoding, 'UCS-4BE'); + $converted = mb_convert_encoding(self::chr($ord, 'UCS-4BE'), $encoding, 'UCS-4BE'); + assert(is_string($converted), 'format string is statically known to be correct'); + + return $converted; } /** UTF-8 compatible ord(). */ @@ -128,10 +131,13 @@ public static function ord(string $char, string $encoding = 'UTF-8'): int if ($encoding !== 'UCS-4BE') { $char = mb_convert_encoding($char, 'UCS-4BE', $encoding); + assert(is_string($char), 'format string is statically known to be correct'); } - // @phpstan-ignore-next-line format string is statically known to be correct - return unpack('N', $char)[1]; + $unpacked = unpack('N', $char); + assert(is_array($unpacked), 'format string is statically known to be correct'); + + return $unpacked[1]; } /** Returns UTF-8 char code at given $positing of the $string. */ diff --git a/tests/Language/PrinterTest.php b/tests/Language/PrinterTest.php index 480e24322..526eecb27 100644 --- a/tests/Language/PrinterTest.php +++ b/tests/Language/PrinterTest.php @@ -44,7 +44,7 @@ public function testPrintsMinimalAst(): void /** @see it('produces helpful error messages', () => { */ public function testProducesHelpfulErrorMessages(): void { - self::markTestSkipped('Not necessary because our class based AST makes it impossible to pass bad data.'); + self::markTestSkipped('Unnecessary because our class based AST makes it impossible to pass bad data.'); } /** @see it('correctly prints non-query operations without name', () => { */ diff --git a/tests/TestCaseBase.php b/tests/TestCaseBase.php index e4b0ab162..5da54f382 100644 --- a/tests/TestCaseBase.php +++ b/tests/TestCaseBase.php @@ -9,7 +9,7 @@ abstract class TestCaseBase extends TestCase { /** - * Useful to test code with no observable behaviour other than not crashing. + * Useful to test code with no observable behavior other than not crashing. * * In contrast to PHPUnit's native method, this lets the test case count towards coverage. * diff --git a/tests/Utils/BuildSchemaTest.php b/tests/Utils/BuildSchemaTest.php index 9e068e3c7..b222f88b5 100644 --- a/tests/Utils/BuildSchemaTest.php +++ b/tests/Utils/BuildSchemaTest.php @@ -1212,7 +1212,7 @@ public function testCanBuildInvalidSchema(): void /** @see it('Do not override standard types') */ public function testDoNotOverrideStandardTypes(): void { - // NOTE: not sure it's desired behaviour to just silently ignore override + // NOTE: not sure it's desired behavior to just silently ignore override // attempts so just documenting it here. $schema = BuildSchema::build(' diff --git a/tests/Utils/CoerceInputValueTest.php b/tests/Utils/CoerceInputValueTest.php index 082ce59ef..90ba5e06c 100644 --- a/tests/Utils/CoerceInputValueTest.php +++ b/tests/Utils/CoerceInputValueTest.php @@ -479,7 +479,7 @@ public function testReturnsNestedNullForNestedNullValues(): void * @see it('throw error without path', () => { * @see it('throw error with path', () => { * - * Not necessary because we do not implement the callback variant coerceInputValue. + * Unnecessary because we do not implement the callback variant coerceInputValue. */ /**