Skip to content

AST::fromArray converts DirectiveDefinitionNode->locations from array into NodeList #723

@zimzat

Description

@zimzat

After running AST::fromArray on the output of AST::toArray, the DirectiveDefinitionNode->locations goes from an array to a NodeList. The KnownDirectives usage of DirectiveDefinitionNode->locations expects to work with an array so an error is generated instead.

Warning: array_map(): Expected parameter 2 to be an array, object given

/** @var NameNode[] */
public $locations;

foreach ($node as $key => $value) {
if ($key === 'loc' || $key === 'kind') {
continue;
}
if (is_array($value)) {
if (isset($value[0]) || count($value) === 0) {
$value = new NodeList($value);
} else {
$value = self::fromArray($value);
}
}
$instance->{$key} = $value;
}

foreach ($astDefinition as $def) {
if (! ($def instanceof DirectiveDefinitionNode)) {
continue;
}
$locationsMap[$def->name->value] = array_map(
static function ($name) : string {
return $name->value;
},
$def->locations
);

I'm not sure if the correct fix is to change KnownDirective to use Utils::map, adjust AST::fromArray to ensure it stays as an array, and/or to adjust the creation of DirectiveDefinitionNode to use a NodeList initially.

diffs for exposing the problem and a naive "fix"

The easiest way to expose this problem:

diff --git a/tests/Validator/KnownDirectivesTest.php b/tests/Validator/KnownDirectivesTest.php
index 38c190e..f35e94b 100644
--- a/tests/Validator/KnownDirectivesTest.php
+++ b/tests/Validator/KnownDirectivesTest.php
@@ -5,8 +5,10 @@ declare(strict_types=1);
 namespace GraphQL\Tests\Validator;
 
 use GraphQL\Error\FormattedError;
+use GraphQL\Language\Parser;
 use GraphQL\Language\SourceLocation;
 use GraphQL\Type\Schema;
+use GraphQL\Utils\AST;
 use GraphQL\Utils\BuildSchema;
 use GraphQL\Validator\Rules\KnownDirectives;
 
@@ -17,7 +19,7 @@ class KnownDirectivesTest extends ValidatorTestCase
 
     public function setUp() : void
     {
-        $this->schemaWithSDLDirectives = BuildSchema::build('
+        $this->schemaWithSDLDirectives = BuildSchema::build(AST::fromArray(AST::toArray(Parser::parse('
           directive @onSchema on SCHEMA
           directive @onScalar on SCALAR
           directive @onObject on OBJECT
@@ -29,7 +31,7 @@ class KnownDirectivesTest extends ValidatorTestCase
           directive @onEnumValue on ENUM_VALUE
           directive @onInputObject on INPUT_OBJECT
           directive @onInputFieldDefinition on INPUT_FIELD_DEFINITION
-        ');
+        '))));
     }
 
     private function expectSDLErrors($sdlString, $schema = null, $errors = [])

The easiest immediate "fix" (though having the type change doesn't seem correct?):

diff --git a/src/Validator/Rules/KnownDirectives.php b/src/Validator/Rules/KnownDirectives.php
index 6dbf849..758e861 100644
--- a/src/Validator/Rules/KnownDirectives.php
+++ b/src/Validator/Rules/KnownDirectives.php
@@ -36,6 +36,7 @@ use GraphQL\Language\AST\UnionTypeExtensionNode;
 use GraphQL\Language\AST\VariableDefinitionNode;
 use GraphQL\Language\DirectiveLocation;
 use GraphQL\Type\Definition\Directive;
+use GraphQL\Utils\Utils;
 use GraphQL\Validator\ASTValidationContext;
 use GraphQL\Validator\SDLValidationContext;
 use GraphQL\Validator\ValidationContext;
@@ -76,11 +77,11 @@ class KnownDirectives extends ValidationRule
                 continue;
             }
 
-            $locationsMap[$def->name->value] = array_map(
+            $locationsMap[$def->name->value] = Utils::map(
+                $def->locations,
                 static function ($name) : string {
                     return $name->value;
-                },
-                $def->locations
+                }
             );
         }
 

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions