Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- Add `EndpointConfig::introspectionConfig()` to pass options to `Introspection::getIntrospectionQuery()`, defaulting to `includeDeprecated: true`

## v1.1.2

### Fixed
Expand Down
12 changes: 12 additions & 0 deletions src/EndpointConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ public function errorsAreClientSafe(): bool
return false;
}

/**
* Options passed to GraphQL\Type\Introspection::getIntrospectionQuery.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

graphql-php defines a type alias IntrospectionOptions for this. Let's @phpstan-import-type this and use it here to define the type precisely.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. How can I do that? I tried including it but phpstan complains and it can't seem to reference the type and tries to reference it using the current namespace:

image

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type imports have to go in the class PhpDoc.

*
* @return array<string, mixed>
*/
public function introspectionConfig(): array
{
return [
'includeDeprecated' => true,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just stick with the defaults?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can make this function return ?array, with the default implemenation being return null.

];
Comment on lines +62 to +71
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

webonyx graphql-php Introspection getIntrospectionQuery options parameters

💡 Result:

webonyx/graphql-php does not expose a GraphQL\Utils\Introspection::getIntrospectionQuery() (like graphql-js does). In practice, with graphql-php you send an introspection query string (often copied from graphql-js’s getIntrospectionQuery() output) and adjust the query text yourself.

If what you’re looking for are the options/parameters that getIntrospectionQuery() supports in the reference implementations, they are commonly:

  • descriptions: bool (default true)
  • specifiedByUrl: bool (default false)
  • directiveIsRepeatable: bool (default false)
  • schemaDescription: bool (default false)
  • inputValueDeprecation: bool (default false)
  • oneOf: bool (exists in newer GraphQL versions; default false)
  • typeRefFragmentDepth: int (lets you control the TypeRef fragment nesting depth) [3]

These options are documented in GraphQL-core (Python) [1], and the GraphQL JS API docs list the same option names (including oneOf) [2].


🏁 Script executed:

# Find usage of introspectionConfig in the codebase
rg -A 5 -B 5 "introspectionConfig" --type php

# Check the current EndpointConfig.php implementation
fd "EndpointConfig.php" -x cat -n {}

Repository: spawnia/sailor

Length of output: 8500


🏁 Script executed:

# Search for how Introspection is imported and used in the codebase
rg "Introspection" src/ tests/ -B 2 -A 2 --type php | head -40

# Try to find if there's vendor or any reference to graphql-php Introspection signature
rg "getIntrospectionQuery" -B 5 -A 10 --type php

Repository: spawnia/sailor

Length of output: 3766


🌐 Web query:

graphql-php Introspection::getIntrospectionQuery options signature webonyx

💡 Result:

In webonyx/graphql-php the method is:

public static function getIntrospectionQuery(array $options = []): string

$options is an associative array with these supported keys (and defaults) used by array_merge([...], $options) inside the method: descriptions (default true), directiveIsRepeatable (default false), schemaDescription (default false), typeIsOneOf (default false). Passing true enables the corresponding fields in the generated introspection query (description, isRepeatable, schema description, and input object isOneOf). [1]

(For reference, WPGraphQL calls it as \GraphQL\Type\Introspection::getIntrospectionQuery().) [2]

Sources: [1] [2]


🏁 Script executed:

# Check composer.json or any version constraint for graphql-php
fd "composer.json" -x cat {}

# Look for any documentation or comments about the Introspection options
rg "directiveIsRepeatable|includeDeprecated|descriptions" --type php -B 3 -A 3

Repository: spawnia/sailor

Length of output: 8673


Narrow introspection options type to align with GraphQL API.

The introspectionConfig() return type array<string, mixed> is overly broad and passes untypes options to Introspection::getIntrospectionQuery(). The type should constrain to the supported options shape.

According to webonyx/graphql-php's API, getIntrospectionQuery() accepts: descriptions (bool), schemaDescription (bool), and typeIsOneOf (bool). The current code also sets 'includeDeprecated' => true in the base config. Additionally, directiveIsRepeatable is programmatically injected in Introspector::fetchIntrospectionResult() before passing to the method, so it should not appear in the return type of introspectionConfig() itself.

🔧 Suggested docblock refinement
-     * `@return` array<string, mixed>
+     * `@return` array{
+     *   includeDeprecated?: bool,
+     *   descriptions?: bool,
+     *   schemaDescription?: bool,
+     *   typeIsOneOf?: bool
+     * }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Options passed to GraphQL\Type\Introspection::getIntrospectionQuery.
*
* @return array<string, mixed>
*/
public function introspectionConfig(): array
{
return [
'includeDeprecated' => true,
];
/**
* Options passed to GraphQL\Type\Introspection::getIntrospectionQuery.
*
* `@return` array{
* includeDeprecated?: bool,
* descriptions?: bool,
* schemaDescription?: bool,
* typeIsOneOf?: bool
* }
*/
public function introspectionConfig(): array
{
return [
'includeDeprecated' => true,
];
}
🤖 Prompt for AI Agents
In `@src/EndpointConfig.php` around lines 62 - 71, The introspectionConfig()
method currently returns a too-broad array<string,mixed>; narrow its
docblock/return type to reflect the exact options accepted by
GraphQL\Type\Introspection::getIntrospectionQuery() (descriptions: bool,
schemaDescription: bool, typeIsOneOf: bool) and keep includeDeprecated => true
in the returned array, but do not include directiveIsRepeatable (since
Introspector::fetchIntrospectionResult() injects that). Update the PHPDoc and
the method signature/return annotation to a more specific shape (e.g.,
array{descriptions?:bool,schemaDescription?:bool,typeIsOneOf?:bool,includeDeprecated?:bool})
and ensure introspectionConfig() returns only those keys.

}

/**
* Return a map from type names to a TypeConfig describing how to deal with them.
*
Expand Down
7 changes: 4 additions & 3 deletions src/Introspector.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@

protected function fetchIntrospectionResult(Client $client, bool $directiveIsRepeatable): Response
{
$options = $this->endpointConfig->introspectionConfig();
$options['directiveIsRepeatable'] = $directiveIsRepeatable;
Comment on lines 50 to +53
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems weird to me to override this option ad-hoc when EndpointConfig defines it. How about we give full control?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we do a retry with the directiveIsRepeatable false if the first call fails with false so trying to respect the method call
https://github.com/spawnia/sailor/blob/master/src/Introspector.php#L32

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just do a single try when the endpoint has an explicit configuration (non-null, default being null). When customizing, users should know what they are doing and where to look when things go wrong. For other cases, we can preserve the current fallback behavior.


$response = $client->request(
Introspection::getIntrospectionQuery([
'directiveIsRepeatable' => $directiveIsRepeatable,
])
Introspection::getIntrospectionQuery($options)

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array{descriptions?: bool, directiveIsRepeatable?: bool, schemaDescription?: bool, typeIsOneOf?: bool}, non-empty-array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array<string, bool>, array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array<string, bool>, array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array<string, bool>, array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array{descriptions?: bool, directiveIsRepeatable?: bool, schemaDescription?: bool, typeIsOneOf?: bool}, non-empty-array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array<string, bool>, array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array{descriptions?: bool, directiveIsRepeatable?: bool, schemaDescription?: bool, typeIsOneOf?: bool}, non-empty-array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array{descriptions?: bool, directiveIsRepeatable?: bool, schemaDescription?: bool, typeIsOneOf?: bool}, non-empty-array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array{descriptions?: bool, directiveIsRepeatable?: bool, schemaDescription?: bool, typeIsOneOf?: bool}, non-empty-array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array<string, bool>, array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array{descriptions?: bool, directiveIsRepeatable?: bool, schemaDescription?: bool, typeIsOneOf?: bool}, non-empty-array<string, mixed> given.

Check failure on line 56 in src/Introspector.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Parameter #1 $options of static method GraphQL\Type\Introspection::getIntrospectionQuery() expects array{descriptions?: bool, directiveIsRepeatable?: bool, schemaDescription?: bool, typeIsOneOf?: bool}, non-empty-array<string, mixed> given.
);

if (isset($response->errors)) {
Expand Down
112 changes: 109 additions & 3 deletions tests/Unit/IntrospectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@

GRAPHQL;

public const SCHEMA_WITH_DEPRECATED = /* @lang GraphQL */ <<<'GRAPHQL'
type Query {
oldField: String @deprecated(reason: "Use newField")
newField: String
}

GRAPHQL;

public const PATH = __DIR__ . '/schema.graphql';

/**
Expand All @@ -55,6 +63,42 @@
->introspect();
}

public function testIncludesDeprecationsByDefault(): void
{
$introspector = $this->makeIntrospector(static function (): Response {
return self::introspectionWithDeprecatedMock(true);
});

$introspector->introspect();

self::assertFileExists(self::PATH);
$schema = file_get_contents(self::PATH);
self::assertStringContainsString('@deprecated', $schema);
self::assertStringContainsString('Use newField', $schema);

unlink(self::PATH);
}

public function testCanDisableDeprecations(): void
{
$introspector = $this->makeIntrospector(
static function (): Response {
return self::introspectionWithDeprecatedMock(false);
},
['includeDeprecated' => false]
);

$introspector->introspect();

self::assertFileExists(self::PATH);
$schema = file_get_contents(self::PATH);
self::assertStringNotContainsString('@deprecated', $schema);
self::assertStringNotContainsString('oldField', $schema);
self::assertStringContainsString('newField', $schema);

unlink(self::PATH);
}

/** @return iterable<array{Request}> */
public static function validRequests(): iterable
{
Expand Down Expand Up @@ -88,15 +132,19 @@
}

/** @param Request $request */
private function makeIntrospector(callable $request): Introspector
private function makeIntrospector(callable $request, ?array $introspectionConfig = null): Introspector

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 135 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Method Spawnia\Sailor\Tests\Unit\IntrospectorTest::makeIntrospector() has parameter $introspectionConfig with no value type specified in iterable type array.
{
$endpointConfig = new class($request) extends EndpointConfig {
$endpointConfig = new class($request, $introspectionConfig) extends EndpointConfig {
/** @var callable */
private $request;

public function __construct(callable $request)
/** @var array<string, mixed>|null */
private ?array $introspectionConfig;

public function __construct(callable $request, ?array $introspectionConfig)

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Method Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Method class@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Method class@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Method class@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Method Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Method class@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Method Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Method Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Method Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Method class@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Method Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.

Check failure on line 144 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Method Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::__construct() has parameter $introspectionConfig with no value type specified in iterable type array.
{
$this->request = $request;
$this->introspectionConfig = $introspectionConfig;

Check failure on line 147 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Property Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::$introspectionConfig (array<string, mixed>|null) does not accept array|null.

Check failure on line 147 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Property Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::$introspectionConfig (array<string, mixed>|null) does not accept array|null.

Check failure on line 147 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Property Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::$introspectionConfig (array<string, mixed>|null) does not accept array|null.

Check failure on line 147 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Property Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::$introspectionConfig (array<string, mixed>|null) does not accept array|null.

Check failure on line 147 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Property Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::$introspectionConfig (array<string, mixed>|null) does not accept array|null.

Check failure on line 147 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Property Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::$introspectionConfig (array<string, mixed>|null) does not accept array|null.

Check failure on line 147 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Property Spawnia\Sailor\EndpointConfig@anonymous/tests/Unit/IntrospectorTest.php:137::$introspectionConfig (array<string, mixed>|null) does not accept array|null.
}

public function makeClient(): Client
Expand All @@ -123,6 +171,11 @@
{
return new DirectoryFinder('bar');
}

public function introspectionConfig(): array
{
return $this->introspectionConfig ?? parent::introspectionConfig();
}
};

return new Introspector($endpointConfig, 'foo', 'bar');
Expand All @@ -140,6 +193,59 @@
return $response;
}

public static function introspectionWithDeprecatedMock(bool $includeDeprecated): Response
{
$schema = BuildSchema::build(self::SCHEMA_WITH_DEPRECATED);
$introspection = Introspection::fromSchema($schema);
if (! $includeDeprecated) {
$introspection = self::stripDeprecations($introspection);

Check failure on line 201 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

Check failure on line 201 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

Check failure on line 201 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

Check failure on line 201 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

Check failure on line 201 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.
}

$response = new Response();
// @phpstan-ignore-next-line We know an associative array converts to a stdClass
$response->data = Json::assocToStdClass($introspection);

return $response;
}
Comment on lines +196 to +209
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard or assert the introspection payload type before filtering.

Line 196-203: PHPStan flags Introspection::fromSchema() as possibly nullable, which then flows into stripDeprecations(). Add an assertion or guard to keep the type array<string, mixed> before passing it along.

✅ Suggested guard
         $schema = BuildSchema::build(self::SCHEMA_WITH_DEPRECATED);
         $introspection = Introspection::fromSchema($schema);
+        if (! is_array($introspection)) {
+            throw new \RuntimeException('Unexpected introspection payload type.');
+        }
         if (! $includeDeprecated) {
             $introspection = self::stripDeprecations($introspection);
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public static function introspectionWithDeprecatedMock(bool $includeDeprecated): Response
{
$schema = BuildSchema::build(self::SCHEMA_WITH_DEPRECATED);
$introspection = Introspection::fromSchema($schema);
if (! $includeDeprecated) {
$introspection = self::stripDeprecations($introspection);
}
$response = new Response();
// @phpstan-ignore-next-line We know an associative array converts to a stdClass
$response->data = Json::assocToStdClass($introspection);
return $response;
}
public static function introspectionWithDeprecatedMock(bool $includeDeprecated): Response
{
$schema = BuildSchema::build(self::SCHEMA_WITH_DEPRECATED);
$introspection = Introspection::fromSchema($schema);
if (! is_array($introspection)) {
throw new \RuntimeException('Unexpected introspection payload type.');
}
if (! $includeDeprecated) {
$introspection = self::stripDeprecations($introspection);
}
$response = new Response();
// `@phpstan-ignore-next-line` We know an associative array converts to a stdClass
$response->data = Json::assocToStdClass($introspection);
return $response;
}
🧰 Tools
🪛 GitHub Check: static-code-analysis (7.4, lowest)

[failure] 201-201:
Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

🪛 GitHub Check: static-code-analysis (8, lowest)

[failure] 201-201:
Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

🪛 GitHub Check: static-code-analysis (8.3, lowest)

[failure] 201-201:
Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

🪛 GitHub Check: static-code-analysis (8.4, lowest)

[failure] 201-201:
Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

🪛 GitHub Check: static-code-analysis (8.5, lowest)

[failure] 201-201:
Parameter #1 $introspection of static method Spawnia\Sailor\Tests\Unit\IntrospectorTest::stripDeprecations() expects array<string, mixed>, array<string, array>|null given.

🤖 Prompt for AI Agents
In `@tests/Unit/IntrospectorTest.php` around lines 196 - 209,
Introspection::fromSchema() can return null, so before calling
stripDeprecations() in introspectionWithDeprecatedMock you must guard/assert the
payload is a non-null array<string,mixed>; add a runtime check (e.g., if
($introspection === null) throw) or an is_array() guard and then a
phpstan-friendly docblock like /** `@var` array<string,mixed> $introspection */ so
stripDeprecations($introspection) is passed a strongly-typed array and static
analysis no longer reports a nullable type.


/**
* @param array<string, mixed> $introspection
*
* @return array<string, mixed>
*/
private static function stripDeprecations(array $introspection): array
{
if (! isset($introspection['__schema']['types']) || ! is_array($introspection['__schema']['types'])) {

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Cannot access offset 'types' on mixed.

Check failure on line 218 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Cannot access offset 'types' on mixed.
return $introspection;
}

foreach ($introspection['__schema']['types'] as &$type) {
if (isset($type['fields']) && is_array($type['fields'])) {

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Cannot access offset 'fields' on mixed.

Check failure on line 223 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Cannot access offset 'fields' on mixed.
$type['fields'] = array_values(array_filter($type['fields'], static function (array $field): bool {

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 224 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.
return empty($field['isDeprecated']);

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Construct empty() is not allowed. Use more strict comparison.

Check failure on line 225 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Construct empty() is not allowed. Use more strict comparison.
}));

foreach ($type['fields'] as &$field) {
if (isset($field['args']) && is_array($field['args'])) {

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Cannot access offset 'args' on mixed.

Check failure on line 229 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Cannot access offset 'args' on mixed.
$field['args'] = array_values(array_filter($field['args'], static function (array $arg): bool {

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (7.4, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.4, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.1, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.2, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.5, lowest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.

Check failure on line 230 in tests/Unit/IntrospectorTest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis (8.3, highest)

Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.
return empty($arg['isDeprecated']);
}));
}
}
unset($field);
}

if (isset($type['enumValues']) && is_array($type['enumValues'])) {
$type['enumValues'] = array_values(array_filter($type['enumValues'], static function (array $enumValue): bool {
return empty($enumValue['isDeprecated']);
}));
}
}
unset($type);

return $introspection;
}
Comment on lines +211 to +247
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make deprecation filtering type‑safe and avoid empty().

Line 218-243: PHPStan reports mixed‑offset access and empty() usage. Add is_array checks and strict boolean checks to keep analysis happy and prevent unexpected shapes.

🔧 Suggested type‑safe filtering
-        foreach ($introspection['__schema']['types'] as &$type) {
-            if (isset($type['fields']) && is_array($type['fields'])) {
-                $type['fields'] = array_values(array_filter($type['fields'], static function (array $field): bool {
-                    return empty($field['isDeprecated']);
-                }));
+        foreach ($introspection['__schema']['types'] as &$type) {
+            if (! is_array($type)) {
+                continue;
+            }
+            if (isset($type['fields']) && is_array($type['fields'])) {
+                $type['fields'] = array_values(array_filter($type['fields'], static function ($field): bool {
+                    return is_array($field)
+                        && (($field['isDeprecated'] ?? false) === false);
+                }));
 
                 foreach ($type['fields'] as &$field) {
-                    if (isset($field['args']) && is_array($field['args'])) {
-                        $field['args'] = array_values(array_filter($field['args'], static function (array $arg): bool {
-                            return empty($arg['isDeprecated']);
-                        }));
+                    if (! is_array($field)) {
+                        continue;
+                    }
+                    if (isset($field['args']) && is_array($field['args'])) {
+                        $field['args'] = array_values(array_filter($field['args'], static function ($arg): bool {
+                            return is_array($arg)
+                                && (($arg['isDeprecated'] ?? false) === false);
+                        }));
                     }
                 }
                 unset($field);
             }
 
             if (isset($type['enumValues']) && is_array($type['enumValues'])) {
-                $type['enumValues'] = array_values(array_filter($type['enumValues'], static function (array $enumValue): bool {
-                    return empty($enumValue['isDeprecated']);
-                }));
+                $type['enumValues'] = array_values(array_filter($type['enumValues'], static function ($enumValue): bool {
+                    return is_array($enumValue)
+                        && (($enumValue['isDeprecated'] ?? false) === false);
+                }));
             }
         }
🧰 Tools
🪛 GitHub Check: static-code-analysis (7.4, highest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (7.4, lowest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8, highest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8, lowest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8.1, highest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8.2, highest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8.3, highest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8.3, lowest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8.4, highest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8.4, lowest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8.5, highest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🪛 GitHub Check: static-code-analysis (8.5, lowest)

[failure] 230-230:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 229-229:
Cannot access offset 'args' on mixed.


[failure] 225-225:
Construct empty() is not allowed. Use more strict comparison.


[failure] 224-224:
Parameter #2 $callback of function array_filter expects (callable(mixed): bool)|null, Closure(array): bool given.


[failure] 223-223:
Cannot access offset 'fields' on mixed.


[failure] 218-218:
Cannot access offset 'types' on mixed.

🤖 Prompt for AI Agents
In `@tests/Unit/IntrospectorTest.php` around lines 211 - 247, stripDeprecations
uses mixed-offset access and empty(); make the filters type-safe by first
ensuring each element is an array and then checking isDeprecated explicitly
(avoid empty()). Update the callbacks in stripDeprecations (the filters for
$type['fields'], inner $field['args'], and $type['enumValues']) to accept mixed,
return false when the item is not an array, and otherwise return
!(isset($item['isDeprecated']) && $item['isDeprecated'] === true); also add
explicit is_array checks before iterating ($type['fields'], $field['args'],
$type['enumValues']) so no offsets are accessed on non-arrays (the function name
to change is stripDeprecations and the variables to update are $type, $field,
$arg, $enumValue).


private static function responseWithErrorsMock(): Response
{
$response = new Response();
Expand Down