diff --git a/phpstan.neon b/phpstan.neon index 7552167..642efd1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,18 +1,11 @@ includes: - - ./vendor/worksome/coding-style/phpstan.neon - +- vendor/worksome/coding-style/phpstan.neon parameters: paths: - - src - - tests - + - src + - tests level: 9 - ignoreErrors: - - '#Call to an undefined method Pest\\Expectation.*#' - - - message: "#Undefined variable: \\$this#" - path: tests/** - - - message: '#^Instanceof between GraphQL\\Language\\AST\\Node and GraphQL\\Language\\AST\\NodeList will always evaluate to false\.$#' - path: src/Inspections/IgnoreByNameSuppressorInspection.php + - '#Call to an undefined method Pest\\Expectation.*#' + - message: "#Undefined variable: \\$this#" + path: tests/** diff --git a/src/Contracts/SuppressorInspection.php b/src/Contracts/SuppressorInspection.php index eaafdc4..2922620 100644 --- a/src/Contracts/SuppressorInspection.php +++ b/src/Contracts/SuppressorInspection.php @@ -5,12 +5,13 @@ namespace Worksome\Graphlint\Contracts; use GraphQL\Language\AST\Node; +use GraphQL\Language\AST\NodeList; use Worksome\Graphlint\Inspections\Inspection; interface SuppressorInspection { /** - * @param Node[] $parents + * @param array> $parents */ public function shouldSuppress(Node $node, array $parents, Inspection $inspection): bool; } diff --git a/src/Inspections/IgnoreByNameSuppressorInspection.php b/src/Inspections/IgnoreByNameSuppressorInspection.php index 1664196..087eb67 100644 --- a/src/Inspections/IgnoreByNameSuppressorInspection.php +++ b/src/Inspections/IgnoreByNameSuppressorInspection.php @@ -5,7 +5,6 @@ namespace Worksome\Graphlint\Inspections; use GraphQL\Language\AST\Node; -use GraphQL\Language\AST\NodeList; use Worksome\Graphlint\Contracts\SuppressorInspection; use Worksome\Graphlint\Utils\NodeNameResolver; @@ -23,27 +22,18 @@ public function __construct( public function shouldSuppress(Node $node, array $parents, Inspection $inspection): bool { - $name = $this->nameResolver->getName($node); - - $parent = end($parents); - if ($parent === false || $parent instanceof NodeList) { - $parentName = null; - } else { - $parentName = $this->nameResolver->getName($parent); - } - - if ($name === null) { - return false; - } - - // Check if name in names - if (in_array($name, $this->names)) { - return true; - } - - // Check if name dotted with parents in names - if (in_array("$parentName.$name", $this->names)) { - return true; + $path = []; + foreach ([...$parents, $node] as $ancestor) { + $name = $this->nameResolver->getName($ancestor); + if ($name === null) { + continue; + } + + $path[] = $name; + $fullName = implode('.', $path); + if (in_array($fullName, $this->names)) { + return true; + } } return false; diff --git a/src/Inspections/MutationFieldArgumentNamedInputInspection.php b/src/Inspections/MutationFieldArgumentNamedInputInspection.php index 0c07637..533b66d 100644 --- a/src/Inspections/MutationFieldArgumentNamedInputInspection.php +++ b/src/Inspections/MutationFieldArgumentNamedInputInspection.php @@ -38,8 +38,8 @@ public function visitObjectTypeDefinition( Collection::make($fields) // Get all arguments of the fields ->flatMap(fn(FieldDefinitionNode $node) => iterator_to_array($node->arguments)) - // Filter down to arguments which are not named `input` - ->filter(fn(InputValueDefinitionNode $node) => $this->nameResolver->getName($node) !== 'input') + // Reject arguments which are named `input` + ->reject(fn(InputValueDefinitionNode $node) => $this->nameResolver->getName($node) === 'input') // Register a problem on each of the arguments ->each(fn(InputValueDefinitionNode $node) => $problemsHolder->registerProblemWithDescription( $node->name, diff --git a/src/Utils/NodeNameResolver.php b/src/Utils/NodeNameResolver.php index 2fbdade..0fb1b81 100644 --- a/src/Utils/NodeNameResolver.php +++ b/src/Utils/NodeNameResolver.php @@ -6,12 +6,16 @@ use GraphQL\Language\AST\NameNode; use GraphQL\Language\AST\Node; +use GraphQL\Language\AST\NodeList; class NodeNameResolver { - public function getName(?Node $node): ?string + /** + * @param Node|NodeList|null $node + */ + public function getName(Node|NodeList|null $node): ?string { - if ($node === null) { + if (! $node instanceof Node) { return null; } diff --git a/src/Visitors/VisitorCollector.php b/src/Visitors/VisitorCollector.php index 15e929c..6565975 100644 --- a/src/Visitors/VisitorCollector.php +++ b/src/Visitors/VisitorCollector.php @@ -15,6 +15,7 @@ use GraphQL\Language\AST\ListTypeNode; use GraphQL\Language\AST\Node; use GraphQL\Language\AST\NodeKind; +use GraphQL\Language\AST\NodeList; use GraphQL\Language\AST\ObjectTypeDefinitionNode; use GraphQL\Language\AST\ScalarTypeDefinitionNode; use GraphQL\Language\AST\UnionTypeDefinitionNode; @@ -144,7 +145,7 @@ private function wrapper( $key, $parent, $path, - $ancestors, + array $ancestors, ) use ( $closure, $affectedInspections, @@ -171,7 +172,7 @@ private function wrapper( } /** - * @param Node[] $parent + * @param array> $parent */ private function shouldSkip(Node $node, array $parent, Inspection $inspection): bool { diff --git a/test-resources/Inspections/IgnoreByNameSuppressorInspectionTest/nullable-list-field.skip.graphql.inc b/test-resources/Inspections/IgnoreByNameSuppressorInspectionTest/nullable-list-field.skip.graphql.inc new file mode 100644 index 0000000..cd52d34 --- /dev/null +++ b/test-resources/Inspections/IgnoreByNameSuppressorInspectionTest/nullable-list-field.skip.graphql.inc @@ -0,0 +1,3 @@ +type User { + alwaysTwoItems: [Int]! +} diff --git a/tests/Feature/Inspections/IgnoreByNameSuppressorInspectionTest.php b/tests/Feature/Inspections/IgnoreByNameSuppressorInspectionTest.php new file mode 100644 index 0000000..bd0d07a --- /dev/null +++ b/tests/Feature/Inspections/IgnoreByNameSuppressorInspectionTest.php @@ -0,0 +1,22 @@ +app->get(NonNullableInsideListInspection::class); + $suppressor = $this->app->get(IgnoreByNameSuppressorInspection::class); + $suppressor->configure('User.alwaysTwoItems'); + + expect($smartFileInfo) + ->toPassInspection($inspection, $suppressor); +})->with(getFixturesForDirectory( + __DIR__ . '/../../../test-resources/Inspections/IgnoreByNameSuppressorInspectionTest' +));