Completed
Push — master ( 93ccd7...3b27ab )
by Vladimir
27s queued 13s
created

SchemaExtender::extend()   F

Complexity

Conditions 32
Paths 738

Size

Total Lines 139
Code Lines 91

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 87
CRAP Score 32.0015

Importance

Changes 0
Metric Value
eloc 91
dl 0
loc 139
ccs 87
cts 88
cp 0.9886
rs 0.3638
c 0
b 0
f 0
cc 32
nc 738
nop 3
crap 32.0015

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Utils;
6
7
use GraphQL\Error\Error;
8
use GraphQL\Language\AST\DirectiveDefinitionNode;
9
use GraphQL\Language\AST\DocumentNode;
10
use GraphQL\Language\AST\EnumTypeExtensionNode;
11
use GraphQL\Language\AST\InputObjectTypeExtensionNode;
12
use GraphQL\Language\AST\InterfaceTypeExtensionNode;
13
use GraphQL\Language\AST\Node;
14
use GraphQL\Language\AST\ObjectTypeExtensionNode;
15
use GraphQL\Language\AST\SchemaDefinitionNode;
16
use GraphQL\Language\AST\SchemaTypeExtensionNode;
17
use GraphQL\Language\AST\TypeDefinitionNode;
18
use GraphQL\Language\AST\TypeExtensionNode;
19
use GraphQL\Language\AST\UnionTypeExtensionNode;
20
use GraphQL\Type\Definition\CustomScalarType;
21
use GraphQL\Type\Definition\Directive;
22
use GraphQL\Type\Definition\EnumType;
23
use GraphQL\Type\Definition\EnumValueDefinition;
24
use GraphQL\Type\Definition\FieldArgument;
25
use GraphQL\Type\Definition\InputObjectType;
26
use GraphQL\Type\Definition\InterfaceType;
27
use GraphQL\Type\Definition\ListOfType;
28
use GraphQL\Type\Definition\NamedType;
29
use GraphQL\Type\Definition\NonNull;
30
use GraphQL\Type\Definition\ObjectType;
31
use GraphQL\Type\Definition\Type;
32
use GraphQL\Type\Definition\UnionType;
33
use GraphQL\Type\Introspection;
34
use GraphQL\Type\Schema;
35
use GraphQL\Validator\DocumentValidator;
36
use function array_keys;
37
use function array_map;
38
use function array_merge;
39
use function array_values;
40
use function count;
41
42
class SchemaExtender
43
{
44
    const SCHEMA_EXTENSION = 'SchemaExtension';
45
46
    /** @var Type[] */
47
    protected static $extendTypeCache;
48
49
    /** @var mixed[] */
50
    protected static $typeExtensionsMap;
51
52
    /** @var ASTDefinitionBuilder */
53
    protected static $astBuilder;
54
55
    /**
56
     * @return TypeExtensionNode[]|null
57
     */
58 49
    protected static function getExtensionASTNodes(NamedType $type) : ?array
59
    {
60 49
        if (! $type instanceof Type) {
61
            return null;
62
        }
63
64 49
        $name = $type->name;
65 49
        if ($type->extensionASTNodes !== null) {
66 49
            if (isset(static::$typeExtensionsMap[$name])) {
67 19
                return array_merge($type->extensionASTNodes, static::$typeExtensionsMap[$name]);
68
            }
69
70 47
            return $type->extensionASTNodes;
71
        }
72
73 43
        return static::$typeExtensionsMap[$name] ?? null;
74
    }
75
76
    /**
77
     * @throws Error
78
     */
79 29
    protected static function checkExtensionNode(Type $type, Node $node) : void
80
    {
81
        switch (true) {
82 29
            case $node instanceof ObjectTypeExtensionNode:
83 20
                if (! ($type instanceof ObjectType)) {
84 1
                    throw new Error(
85 1
                        'Cannot extend non-object type "' . $type->name . '".',
86 1
                        [$node]
87
                    );
88
                }
89 19
                break;
90 15
            case $node instanceof InterfaceTypeExtensionNode:
91 7
                if (! ($type instanceof InterfaceType)) {
92 1
                    throw new Error(
93 1
                        'Cannot extend non-interface type "' . $type->name . '".',
94 1
                        [$node]
95
                    );
96
                }
97 6
                break;
98 12
            case $node instanceof EnumTypeExtensionNode:
99 6
                if (! ($type instanceof EnumType)) {
100 1
                    throw new Error(
101 1
                        'Cannot extend non-enum type "' . $type->name . '".',
102 1
                        [$node]
103
                    );
104
                }
105 5
                break;
106 9
            case $node instanceof UnionTypeExtensionNode:
107 6
                if (! ($type instanceof UnionType)) {
108 1
                    throw new Error(
109 1
                        'Cannot extend non-union type "' . $type->name . '".',
110 1
                        [$node]
111
                    );
112
                }
113 5
                break;
114 7
            case $node instanceof InputObjectTypeExtensionNode:
115 6
                if (! ($type instanceof InputObjectType)) {
116 1
                    throw new Error(
117 1
                        'Cannot extend non-input object type "' . $type->name . '".',
118 1
                        [$node]
119
                    );
120
                }
121 5
                break;
122
        }
123 28
    }
124
125 42
    protected static function extendCustomScalarType(CustomScalarType $type) : CustomScalarType
126
    {
127 42
        return new CustomScalarType([
128 42
            'name' => $type->name,
129 42
            'description' => $type->description,
130 42
            'astNode' => $type->astNode,
131 42
            'serialize' => $type->config['serialize'] ?? null,
132 42
            'parseValue' => $type->config['parseValue'] ?? null,
133 42
            'parseLiteral' => $type->config['parseLiteral'] ?? null,
134 42
            'extensionASTNodes' => static::getExtensionASTNodes($type),
135
        ]);
136
    }
137
138 42
    protected static function extendUnionType(UnionType $type) : UnionType
139
    {
140 42
        return new UnionType([
141 42
            'name' => $type->name,
142 42
            'description' => $type->description,
143
            'types' => static function () use ($type) {
144 41
                return static::extendPossibleTypes($type);
145 42
            },
146 42
            'astNode' => $type->astNode,
147 42
            'resolveType' => $type->config['resolveType'] ?? null,
148 42
            'extensionASTNodes' => static::getExtensionASTNodes($type),
149
        ]);
150
    }
151
152 42
    protected static function extendEnumType(EnumType $type) : EnumType
153
    {
154 42
        return new EnumType([
155 42
            'name' => $type->name,
156 42
            'description' => $type->description,
157 42
            'values' => static::extendValueMap($type),
158 41
            'astNode' => $type->astNode,
159 41
            'extensionASTNodes' => static::getExtensionASTNodes($type),
160
        ]);
161
    }
162
163 42
    protected static function extendInputObjectType(InputObjectType $type) : InputObjectType
164
    {
165 42
        return new InputObjectType([
166 42
            'name' => $type->name,
167 42
            'description' => $type->description,
168
            'fields' => static function () use ($type) {
169 42
                return static::extendInputFieldMap($type);
170 42
            },
171 42
            'astNode' => $type->astNode,
172 42
            'extensionASTNodes' => static::getExtensionASTNodes($type),
173
        ]);
174
    }
175
176
    /**
177
     * @return mixed[]
178
     */
179 42
    protected static function extendInputFieldMap(InputObjectType $type) : array
180
    {
181 42
        $newFieldMap = [];
182 42
        $oldFieldMap = $type->getFields();
183 42
        foreach ($oldFieldMap as $fieldName => $field) {
184 42
            $newFieldMap[$fieldName] = [
185 42
                'description' => $field->description,
186 42
                'type' => static::extendType($field->type),
187 42
                'astNode' => $field->astNode,
188
            ];
189
190 42
            if (! $field->defaultValueExists()) {
191 42
                continue;
192
            }
193
194
            $newFieldMap[$fieldName]['defaultValue'] = $field->defaultValue;
195
        }
196
197 42
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
198 42
        if ($extensions !== null) {
199 5
            foreach ($extensions as $extension) {
200 5
                foreach ($extension->fields as $field) {
201 5
                    $fieldName = $field->name->value;
202 5
                    if (isset($oldFieldMap[$fieldName])) {
203 1
                        throw new Error('Field "' . $type->name . '.' . $fieldName . '" already exists in the schema. It cannot also be defined in this type extension.', [$field]);
204
                    }
205
206 4
                    $newFieldMap[$fieldName] = static::$astBuilder->buildInputField($field);
207
                }
208
            }
209
        }
210
211 42
        return $newFieldMap;
212
    }
213
214
    /**
215
     * @return mixed[]
216
     */
217 42
    protected static function extendValueMap(EnumType $type) : array
218
    {
219 42
        $newValueMap = [];
220
        /** @var EnumValueDefinition[] $oldValueMap */
221 42
        $oldValueMap = [];
222 42
        foreach ($type->getValues() as $value) {
223 42
            $oldValueMap[$value->name] = $value;
224
        }
225
226 42
        foreach ($oldValueMap as $key => $value) {
227 42
            $newValueMap[$key] = [
228 42
                'name' => $value->name,
229 42
                'description' => $value->description,
230 42
                'value' => $value->value,
231 42
                'deprecationReason' => $value->deprecationReason,
232 42
                'astNode' => $value->astNode,
233
            ];
234
        }
235
236 42
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
237 42
        if ($extensions !== null) {
238 5
            foreach ($extensions as $extension) {
239 5
                foreach ($extension->values as $value) {
240 5
                    $valueName = $value->name->value;
241 5
                    if (isset($oldValueMap[$valueName])) {
242 1
                        throw new Error('Enum value "' . $type->name . '.' . $valueName . '" already exists in the schema. It cannot also be defined in this type extension.', [$value]);
243
                    }
244 4
                    $newValueMap[$valueName] = static::$astBuilder->buildEnumValue($value);
245
                }
246
            }
247
        }
248
249 41
        return $newValueMap;
250
    }
251
252
    /**
253
     * @return ObjectType[]
254
     */
255 41
    protected static function extendPossibleTypes(UnionType $type) : array
256
    {
257
        $possibleTypes = array_map(static function ($type) {
258 41
            return static::extendNamedType($type);
259 41
        }, $type->getTypes());
260
261 41
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
262 41
        if ($extensions !== null) {
263 5
            foreach ($extensions as $extension) {
264 5
                foreach ($extension->types as $namedType) {
265 5
                    $possibleTypes[] = static::$astBuilder->buildType($namedType);
266
                }
267
            }
268
        }
269
270 41
        return $possibleTypes;
271
    }
272
273
    /**
274
     * @return InterfaceType[]
275
     */
276 45
    protected static function extendImplementedInterfaces(ObjectType $type) : array
277
    {
278
        $interfaces = array_map(static function (InterfaceType $interfaceType) {
279 42
            return static::extendNamedType($interfaceType);
280 45
        }, $type->getInterfaces());
281
282 45
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
283 45
        if ($extensions !== null) {
284
            /** @var ObjectTypeExtensionNode $extension */
285 19
            foreach ($extensions as $extension) {
286 19
                foreach ($extension->interfaces as $namedType) {
287 19
                    $interfaces[] = static::$astBuilder->buildType($namedType);
288
                }
289
            }
290
        }
291
292 45
        return $interfaces;
293
    }
294
295 46
    protected static function extendType($typeDef)
296
    {
297 46
        if ($typeDef instanceof ListOfType) {
298 42
            return Type::listOf(static::extendType($typeDef->ofType));
299
        }
300
301 46
        if ($typeDef instanceof NonNull) {
302 45
            return Type::nonNull(static::extendType($typeDef->getWrappedType()));
0 ignored issues
show
Bug introduced by
It seems like static::extendType($typeDef->getWrappedType()) can also be of type GraphQL\Type\Definition\NonNull and GraphQL\Type\Definition\Type; however, parameter $wrappedType of GraphQL\Type\Definition\Type::nonNull() does only seem to accept GraphQL\Type\Definition\NullableType, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

302
            return Type::nonNull(/** @scrutinizer ignore-type */ static::extendType($typeDef->getWrappedType()));
Loading history...
303
        }
304
305 46
        return static::extendNamedType($typeDef);
306
    }
307
308
    /**
309
     * @param FieldArgument[] $args
310
     *
311
     * @return mixed[]
312
     */
313 45
    protected static function extendArgs(array $args) : array
314
    {
315 45
        return Utils::keyValMap(
316 45
            $args,
317
            static function (FieldArgument $arg) {
318 45
                return $arg->name;
319 45
            },
320
            static function (FieldArgument $arg) {
321
                $def = [
322 45
                    'type'        => static::extendType($arg->getType()),
323 45
                    'description' => $arg->description,
324 45
                    'astNode'     => $arg->astNode,
325
                ];
326
327 45
                if ($arg->defaultValueExists()) {
328 44
                    $def['defaultValue'] = $arg->defaultValue;
329
                }
330
331 45
                return $def;
332 45
            }
333
        );
334
    }
335
336
    /**
337
     * @param InterfaceType|ObjectType $type
338
     *
339
     * @return mixed[]
340
     *
341
     * @throws Error
342
     */
343 45
    protected static function extendFieldMap($type) : array
344
    {
345 45
        $newFieldMap = [];
346 45
        $oldFieldMap = $type->getFields();
347
348 45
        foreach (array_keys($oldFieldMap) as $fieldName) {
349 45
            $field = $oldFieldMap[$fieldName];
350
351 45
            $newFieldMap[$fieldName] = [
352 45
                'name' => $fieldName,
353 45
                'description' => $field->description,
354 45
                'deprecationReason' => $field->deprecationReason,
355 45
                'type' => static::extendType($field->getType()),
356 45
                'args' => static::extendArgs($field->args),
357 45
                'astNode' => $field->astNode,
358 45
                'resolve' => $field->resolveFn,
359
            ];
360
        }
361
362 45
        $extensions = static::$typeExtensionsMap[$type->name] ?? null;
363 45
        if ($extensions !== null) {
364 21
            foreach ($extensions as $extension) {
365 21
                foreach ($extension->fields as $field) {
366 21
                    $fieldName = $field->name->value;
367 21
                    if (isset($oldFieldMap[$fieldName])) {
368 1
                        throw new Error('Field "' . $type->name . '.' . $fieldName . '" already exists in the schema. It cannot also be defined in this type extension.', [$field]);
369
                    }
370
371 20
                    $newFieldMap[$fieldName] = static::$astBuilder->buildField($field);
372
                }
373
            }
374
        }
375
376 45
        return $newFieldMap;
377
    }
378
379 49
    protected static function extendObjectType(ObjectType $type) : ObjectType
380
    {
381 49
        return new ObjectType([
382 49
            'name' => $type->name,
383 49
            'description' => $type->description,
384
            'interfaces' => static function () use ($type) {
385 45
                return static::extendImplementedInterfaces($type);
386 49
            },
387
            'fields' => static function () use ($type) {
388 45
                return static::extendFieldMap($type);
389 49
            },
390 49
            'astNode' => $type->astNode,
391 49
            'extensionASTNodes' => static::getExtensionASTNodes($type),
392 49
            'isTypeOf' => $type->config['isTypeOf'] ?? null,
393
        ]);
394
    }
395
396 43
    protected static function extendInterfaceType(InterfaceType $type) : InterfaceType
397
    {
398 43
        return new InterfaceType([
399 43
            'name' => $type->name,
400 43
            'description' => $type->description,
401
            'fields' => static function () use ($type) {
402 42
                return static::extendFieldMap($type);
403 43
            },
404 43
            'astNode' => $type->astNode,
405 43
            'extensionASTNodes' => static::getExtensionASTNodes($type),
406 43
            'resolveType' => $type->config['resolveType'] ?? null,
407
        ]);
408
    }
409
410 49
    protected static function isSpecifiedScalarType(Type $type) : bool
411
    {
412 49
        return $type instanceof NamedType &&
413
            (
414 49
                $type->name === Type::STRING ||
415 49
                $type->name === Type::INT ||
416 49
                $type->name === Type::FLOAT ||
417 49
                $type->name === Type::BOOLEAN ||
418 49
                $type->name === Type::ID
419
            );
420
    }
421
422 49
    protected static function extendNamedType(Type $type)
423
    {
424 49
        if (Introspection::isIntrospectionType($type) || static::isSpecifiedScalarType($type)) {
425 46
            return $type;
426
        }
427
428 49
        $name = $type->name;
429 49
        if (! isset(static::$extendTypeCache[$name])) {
430 49
            if ($type instanceof CustomScalarType) {
431 42
                static::$extendTypeCache[$name] = static::extendCustomScalarType($type);
432 49
            } elseif ($type instanceof ObjectType) {
433 49
                static::$extendTypeCache[$name] = static::extendObjectType($type);
434 43
            } elseif ($type instanceof InterfaceType) {
435 43
                static::$extendTypeCache[$name] = static::extendInterfaceType($type);
436 43
            } elseif ($type instanceof UnionType) {
437 42
                static::$extendTypeCache[$name] = static::extendUnionType($type);
438 43
            } elseif ($type instanceof EnumType) {
439 42
                static::$extendTypeCache[$name] = static::extendEnumType($type);
440 42
            } elseif ($type instanceof InputObjectType) {
441 42
                static::$extendTypeCache[$name] = static::extendInputObjectType($type);
442
            }
443
        }
444
445 49
        return static::$extendTypeCache[$name];
446
    }
447
448
    /**
449
     * @return mixed|null
450
     */
451 49
    protected static function extendMaybeNamedType(?NamedType $type = null)
452
    {
453 49
        if ($type !== null) {
454 48
            return static::extendNamedType($type);
455
        }
456
457 48
        return null;
458
    }
459
460
    /**
461
     * @param DirectiveDefinitionNode[] $directiveDefinitions
462
     *
463
     * @return Directive[]
464
     */
465 45
    protected static function getMergedDirectives(Schema $schema, array $directiveDefinitions) : array
466
    {
467
        $existingDirectives = array_map(static function (Directive $directive) {
468 45
            return static::extendDirective($directive);
469 45
        }, $schema->getDirectives());
470
471 45
        Utils::invariant(count($existingDirectives) > 0, 'schema must have default directives');
472
473 45
        return array_merge(
474 45
            $existingDirectives,
475
            array_map(static function (DirectiveDefinitionNode $directive) {
476 6
                return static::$astBuilder->buildDirective($directive);
477 45
            }, $directiveDefinitions)
478
        );
479
    }
480
481 45
    protected static function extendDirective(Directive $directive) : Directive
482
    {
483 45
        return new Directive([
484 45
            'name' => $directive->name,
485 45
            'description' => $directive->description,
486 45
            'locations' => $directive->locations,
487 45
            'args' => static::extendArgs($directive->args),
488 45
            'astNode' => $directive->astNode,
489
        ]);
490
    }
491
492
    /**
493
     * @param mixed[]|null $options
494
     */
495 55
    public static function extend(Schema $schema, DocumentNode $documentAST, ?array $options = null) : Schema
496
    {
497 55
        if ($options === null || ! (isset($options['assumeValid']) || isset($options['assumeValidSDL']))) {
498 54
            DocumentValidator::assertValidSDLExtension($documentAST, $schema);
499
        }
500
501 54
        $typeDefinitionMap         = [];
502 54
        static::$typeExtensionsMap = [];
503 54
        $directiveDefinitions      = [];
504
        /** @var SchemaDefinitionNode|null $schemaDef */
505 54
        $schemaDef = null;
506
        /** @var SchemaTypeExtensionNode[] $schemaExtensions */
507 54
        $schemaExtensions = [];
508
509 54
        $definitionsCount = count($documentAST->definitions);
510 54
        for ($i = 0; $i < $definitionsCount; $i++) {
511
512
            /** @var Node $def */
513 54
            $def = $documentAST->definitions[$i];
514
515 54
            if ($def instanceof SchemaDefinitionNode) {
516 1
                $schemaDef = $def;
517 53
            } elseif ($def instanceof SchemaTypeExtensionNode) {
518 8
                $schemaExtensions[] = $def;
519 52
            } elseif ($def instanceof TypeDefinitionNode) {
520 20
                $typeName = isset($def->name) ? $def->name->value : null;
521
522
                try {
523 20
                    $type = $schema->getType($typeName);
524 1
                } catch (Error $error) {
525 1
                    $type = null;
526
                }
527
528 20
                if ($type) {
529 1
                    throw new Error('Type "' . $typeName . '" already exists in the schema. It cannot also be defined in this type definition.', [$def]);
530
                }
531 19
                $typeDefinitionMap[$typeName] = $def;
532 37
            } elseif ($def instanceof TypeExtensionNode) {
533 30
                $extendedTypeName = isset($def->name) ? $def->name->value : null;
534 30
                $existingType     = $schema->getType($extendedTypeName);
535 30
                if ($existingType === null) {
536 1
                    throw new Error('Cannot extend type "' . $extendedTypeName . '" because it does not exist in the existing schema.', [$def]);
537
                }
538
539 29
                static::checkExtensionNode($existingType, $def);
540
541 28
                $existingTypeExtensions                       = static::$typeExtensionsMap[$extendedTypeName] ?? null;
542 28
                static::$typeExtensionsMap[$extendedTypeName] = $existingTypeExtensions !== null ? array_merge($existingTypeExtensions, [$def]) : [$def];
543 8
            } elseif ($def instanceof DirectiveDefinitionNode) {
544 7
                $directiveName     = $def->name->value;
545 7
                $existingDirective = $schema->getDirective($directiveName);
546 7
                if ($existingDirective !== null) {
547 2
                    throw new Error('Directive "' . $directiveName . '" already exists in the schema. It cannot be redefined.', [$def]);
548
                }
549 6
                $directiveDefinitions[] = $def;
550
            }
551
        }
552
553 50
        if (count(static::$typeExtensionsMap) === 0 &&
554 50
            count($typeDefinitionMap) === 0 &&
555 50
            count($directiveDefinitions) === 0 &&
556 50
            count($schemaExtensions) === 0 &&
557 50
            $schemaDef === null
558
        ) {
559 1
            return $schema;
560
        }
561
562 49
        static::$astBuilder = new ASTDefinitionBuilder(
563 49
            $typeDefinitionMap,
564 49
            $options,
565
            static function (string $typeName) use ($schema) {
566
                /** @var NamedType $existingType */
567 10
                $existingType = $schema->getType($typeName);
568 10
                if ($existingType !== null) {
569 9
                    return static::extendNamedType($existingType);
570
                }
571
572 1
                throw new Error('Unknown type: "' . $typeName . '". Ensure that this type exists either in the original schema, or is added in a type definition.', [$typeName]);
573 49
            }
574
        );
575
576 49
        static::$extendTypeCache = [];
577
578
        $operationTypes = [
579 49
            'query' => static::extendMaybeNamedType($schema->getQueryType()),
580 49
            'mutation' => static::extendMaybeNamedType($schema->getMutationType()),
581 49
            'subscription' => static::extendMaybeNamedType($schema->getSubscriptionType()),
582
        ];
583
584 49
        if ($schemaDef) {
585 1
            foreach ($schemaDef->operationTypes as $operationType) {
586 1
                $operation = $operationType->operation;
587 1
                $type      = $operationType->type;
588
589 1
                if (isset($operationTypes[$operation])) {
590
                    throw new Error('Must provide only one ' . $operation . ' type in schema.');
591
                }
592
593 1
                $operationTypes[$operation] = static::$astBuilder->buildType($type);
594
            }
595
        }
596
597 49
        foreach ($schemaExtensions as $schemaExtension) {
598 8
            if (! $schemaExtension->operationTypes) {
599 2
                continue;
600
            }
601
602 7
            foreach ($schemaExtension->operationTypes as $operationType) {
603 7
                $operation = $operationType->operation;
604 7
                if (isset($operationTypes[$operation])) {
605 3
                    throw new Error('Must provide only one ' . $operation . ' type in schema.');
606
                }
607 6
                $operationTypes[$operation] = static::$astBuilder->buildType($operationType->type);
608
            }
609
        }
610
611 46
        $schemaExtensionASTNodes = count($schemaExtensions) > 0
612 5
            ? ($schema->extensionASTNodes
613 1
                ? array_merge($schema->extensionASTNodes, $schemaExtensions)
614 5
                : $schemaExtensions)
615 46
            : $schema->extensionASTNodes;
616
617 46
        $types = array_merge(
618
            array_map(static function ($type) {
619 46
                return static::extendType($type);
620 46
            }, array_values($schema->getTypeMap())),
621
            array_map(static function ($type) {
622 16
                return static::$astBuilder->buildType($type);
623 45
            }, array_values($typeDefinitionMap))
624
        );
625
626 45
        return new Schema([
627 45
            'query' => $operationTypes['query'],
628 45
            'mutation' => $operationTypes['mutation'],
629 45
            'subscription' => $operationTypes['subscription'],
630 45
            'types' => $types,
631 45
            'directives' => static::getMergedDirectives($schema, $directiveDefinitions),
632 45
            'astNode' => $schema->getAstNode(),
633 45
            'extensionASTNodes' => $schemaExtensionASTNodes,
634
        ]);
635
    }
636
}
637