Skip to content

Commit

Permalink
Extend @feature, @show and @hide to Args, InputFields and Types
Browse files Browse the repository at this point in the history
  • Loading branch information
pyrou committed Nov 20, 2024
1 parent f5e1205 commit d0290cb
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 10 deletions.
67 changes: 57 additions & 10 deletions src/Schema/Directives/HideDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
namespace Nuwave\Lighthouse\Schema\Directives;

use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
use GraphQL\Language\AST\InputValueDefinitionNode;
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use GraphQL\Language\AST\TypeDefinitionNode;
use Illuminate\Container\Container;
use Illuminate\Contracts\Foundation\Application;
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
use Nuwave\Lighthouse\Support\Contracts\ArgManipulator;
use Nuwave\Lighthouse\Support\Contracts\FieldManipulator;
use Nuwave\Lighthouse\Support\Contracts\InputFieldManipulator;
use Nuwave\Lighthouse\Support\Contracts\TypeManipulator;

class HideDirective extends BaseDirective implements FieldManipulator
class HideDirective extends BaseDirective implements ArgManipulator, FieldManipulator, InputFieldManipulator, TypeManipulator
{
protected string $env;

Expand All @@ -36,7 +42,7 @@ public static function definition(): string
Specify which environments must not use this field, e.g. ["production"].
"""
env: [String!]!
) repeatable on FIELD_DEFINITION
) repeatable on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | FIELD_DEFINITION | OBJECT
GRAPHQL;
}

Expand All @@ -48,16 +54,57 @@ protected function shouldHide(): bool

public function manipulateFieldDefinition(DocumentAST &$documentAST, FieldDefinitionNode &$fieldDefinition, ObjectTypeDefinitionNode|InterfaceTypeDefinitionNode &$parentType): void
{
if ($this->shouldHide()) {
$keyToRemove = null;
foreach ($parentType->fields as $key => $value) {
if ($value === $fieldDefinition) {
$keyToRemove = $key;
break;
}
if (! $this->shouldHide()) {
return;
}

foreach ($parentType->fields as $key => $value) {
if ($value === $fieldDefinition) {
unset($parentType->fields[$key]);
break;
}
}
}

public function manipulateTypeDefinition(DocumentAST &$documentAST, TypeDefinitionNode &$typeDefinition): void
{
if (! $this->shouldHide()) {
return;
}

foreach ($documentAST->types as $key => $value) {
if ($value === $typeDefinition) {
unset($documentAST->types[$key]);
break;
}
}
}

public function manipulateInputFieldDefinition(DocumentAST &$documentAST, InputValueDefinitionNode &$inputField, InputObjectTypeDefinitionNode &$parentInput): void
{
if (! $this->shouldHide()) {
return;
}

foreach ($parentInput->fields as $key => $value) {
if ($value === $inputField) {
unset($parentInput->fields[$key]);
break;
}
}
}

unset($parentType->fields[$keyToRemove]);
public function manipulateArgDefinition(DocumentAST &$documentAST, InputValueDefinitionNode &$argDefinition, FieldDefinitionNode &$parentField, ObjectTypeDefinitionNode|InterfaceTypeDefinitionNode &$parentType): void
{
if (! $this->shouldHide()) {
return;
}

foreach ($parentField->arguments as $key => $value) {
if ($value === $argDefinition) {
unset($parentField->arguments[$key]);
break;
}
}
}
}
85 changes: 85 additions & 0 deletions tests/Unit/Schema/Directives/HideDirectiveTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,91 @@ public function testHiddenOnTestingEnv(): void
$this->graphQL($query)->assertGraphQLErrorMessage('Cannot query field "hiddenField" on type "Query". Did you mean "shownField"?');
}

public function testHiddenArgs(): void
{
$this->schema = /** @lang GraphQL */ '
type Query {
field(hiddenArg: String @hide(env: ["testing"])): String! @mock
}
';

$introspectionQuery = /** @lang GraphQL */ '
{
__schema {
queryType {
fields {
args {
name
}
}
}
}
}
';

$this->graphQL($introspectionQuery)
->assertJsonCount(0, 'data.__schema.queryType.fields.0.args');
}

public function testHiddenType(): void
{
$this->schema = /** @lang GraphQL */ '
type Query {
field: String! @mock
}
type HiddenType @hide(env: ["testing"]) {
field: String!
}
';

$introspectionQuery = /** @lang GraphQL */ '
{
__schema {
types {
name
}
}
}
';

$types = $this->graphQL($introspectionQuery)
->json('data.__schema.types.*.name');

$this->assertNotContains('HiddenType', $types);
}

public function testHiddenInputField(): void
{
$this->schema = /** @lang GraphQL */ '
type Query {
field: String! @mock
}
input Input {
hiddenInputField: String! @hide(env: ["testing"])
}
';

$introspectionQuery = /** @lang GraphQL */ '
{
__schema {
types {
name
inputFields {
name
}
}
}
}
';

$types = $this->graphQL($introspectionQuery)->json('data.__schema.types');

$input = array_find($types, fn (array $type): bool => $type['name'] === 'Input');

$this->assertEmpty($input['inputFields']);
}

public function testHiddenWhenManuallySettingEnv(): void
{
$this->schema = /** @lang GraphQL */ '
Expand Down

0 comments on commit d0290cb

Please sign in to comment.