File: /home/cafsindia/lead_cafsinfotech_in/vendor/webonyx/graphql-php/src/Utils/SchemaPrinter.php
<?php declare(strict_types=1);
namespace GraphQL\Utils;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Error\SerializationError;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Language\BlockString;
use GraphQL\Language\Printer;
use GraphQL\Type\Definition\Argument;
use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\EnumType;
use GraphQL\Type\Definition\EnumValueDefinition;
use GraphQL\Type\Definition\FieldDefinition;
use GraphQL\Type\Definition\ImplementingType;
use GraphQL\Type\Definition\InputObjectField;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\NamedType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ScalarType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\UnionType;
use GraphQL\Type\Introspection;
use GraphQL\Type\Schema;
/**
* Prints the contents of a Schema in schema definition language.
*
* All sorting options sort alphabetically. If not given or `false`, the original schema definition order will be used.
*
* @phpstan-type Options array{
* sortArguments?: bool,
* sortEnumValues?: bool,
* sortFields?: bool,
* sortInputFields?: bool,
* sortTypes?: bool,
* }
*
* @see \GraphQL\Tests\Utils\SchemaPrinterTest
*/
class SchemaPrinter
{
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @api
*
* @throws \JsonException
* @throws Error
* @throws InvariantViolation
* @throws SerializationError
*/
public static function doPrint(Schema $schema, array $options = []): string
{
return static::printFilteredSchema(
$schema,
static fn (Directive $directive): bool => ! Directive::isSpecifiedDirective($directive),
static fn (NamedType $type): bool => ! $type->isBuiltInType(),
$options
);
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @api
*
* @throws \JsonException
* @throws Error
* @throws InvariantViolation
* @throws SerializationError
*/
public static function printIntrospectionSchema(Schema $schema, array $options = []): string
{
return static::printFilteredSchema(
$schema,
[Directive::class, 'isSpecifiedDirective'],
[Introspection::class, 'isIntrospectionType'],
$options
);
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws Error
* @throws InvariantViolation
* @throws SerializationError
*/
public static function printType(Type $type, array $options = []): string
{
if ($type instanceof ScalarType) {
return static::printScalar($type, $options);
}
if ($type instanceof ObjectType) {
return static::printObject($type, $options);
}
if ($type instanceof InterfaceType) {
return static::printInterface($type, $options);
}
if ($type instanceof UnionType) {
return static::printUnion($type, $options);
}
if ($type instanceof EnumType) {
return static::printEnum($type, $options);
}
if ($type instanceof InputObjectType) {
return static::printInputObject($type, $options);
}
$unknownType = Utils::printSafe($type);
throw new Error("Unknown type: {$unknownType}.");
}
/**
* @param callable(Directive $directive): bool $directiveFilter
* @param callable(Type&NamedType $type): bool $typeFilter
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws Error
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printFilteredSchema(Schema $schema, callable $directiveFilter, callable $typeFilter, array $options): string
{
$directives = \array_filter($schema->getDirectives(), $directiveFilter);
$types = \array_filter($schema->getTypeMap(), $typeFilter);
if (isset($options['sortTypes']) && $options['sortTypes']) {
ksort($types);
}
$elements = [static::printSchemaDefinition($schema)];
foreach ($directives as $directive) {
$elements[] = static::printDirective($directive, $options);
}
foreach ($types as $type) {
$elements[] = static::printType($type, $options);
}
return \implode("\n\n", \array_filter($elements)) . "\n";
}
/** @throws InvariantViolation */
protected static function printSchemaDefinition(Schema $schema): ?string
{
$queryType = $schema->getQueryType();
$mutationType = $schema->getMutationType();
$subscriptionType = $schema->getSubscriptionType();
// Special case: When a schema has no root operation types, no valid schema
// definition can be printed.
if ($queryType === null && $mutationType === null && $subscriptionType === null) {
return null;
}
// TODO add condition for schema.description
// Only print a schema definition if there is a description or if it should
// not be omitted because of having default type names.
if (! static::hasDefaultRootOperationTypes($schema)) {
return "schema {\n"
. ($queryType !== null ? " query: {$queryType->name}\n" : '')
. ($mutationType !== null ? " mutation: {$mutationType->name}\n" : '')
. ($subscriptionType !== null ? " subscription: {$subscriptionType->name}\n" : '')
. '}';
}
return null;
}
/**
* GraphQL schema define root types for each type of operation. These types are
* the same as any other type and can be named in any manner, however there is
* a common naming convention:.
*
* ```graphql
* schema {
* query: Query
* mutation: Mutation
* subscription: Subscription
* }
* ```
*
* When using this naming convention, the schema description can be omitted.
* When using this naming convention, the schema description can be omitted so
* long as these names are only used for operation types.
*
* Note however that if any of these default names are used elsewhere in the
* schema but not as a root operation type, the schema definition must still
* be printed to avoid ambiguity.
*
* @throws InvariantViolation
*/
protected static function hasDefaultRootOperationTypes(Schema $schema): bool
{
return $schema->getQueryType() === $schema->getType('Query')
&& $schema->getMutationType() === $schema->getType('Mutation')
&& $schema->getSubscriptionType() === $schema->getType('Subscription');
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printDirective(Directive $directive, array $options): string
{
return static::printDescription($options, $directive)
. 'directive @' . $directive->name
. static::printArgs($options, $directive->args)
. ($directive->isRepeatable ? ' repeatable' : '')
. ' on ' . \implode(' | ', $directive->locations);
}
/**
* @param array<string, bool> $options
* @param (Type&NamedType)|Directive|EnumValueDefinition|Argument|FieldDefinition|InputObjectField $def
*
* @throws \JsonException
*/
protected static function printDescription(array $options, $def, string $indentation = '', bool $firstInBlock = true): string
{
$description = $def->description;
if ($description === null) {
return '';
}
$prefix = $indentation !== '' && ! $firstInBlock
? "\n{$indentation}"
: $indentation;
if (count(Utils::splitLines($description)) === 1) {
$description = \json_encode($description, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
} else {
$description = BlockString::print($description);
$description = $indentation !== ''
? \str_replace("\n", "\n{$indentation}", $description)
: $description;
}
return "{$prefix}{$description}\n";
}
/**
* @param array<string, bool> $options
* @param array<int, Argument> $args
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printArgs(array $options, array $args, string $indentation = ''): string
{
if ($args === []) {
return '';
}
if (isset($options['sortArguments']) && $options['sortArguments']) {
usort($args, static fn (Argument $left, Argument $right): int => $left->name <=> $right->name);
}
$allArgsWithoutDescription = true;
foreach ($args as $arg) {
$description = $arg->description;
if ($description !== null && $description !== '') {
$allArgsWithoutDescription = false;
break;
}
}
if ($allArgsWithoutDescription) {
return '('
. \implode(
', ',
\array_map(
[static::class, 'printInputValue'],
$args
)
)
. ')';
}
$argsStrings = [];
$firstInBlock = true;
$previousHasDescription = false;
foreach ($args as $arg) {
$hasDescription = $arg->description !== null;
if ($previousHasDescription && ! $hasDescription) {
$argsStrings[] = '';
}
$argsStrings[] = static::printDescription($options, $arg, ' ' . $indentation, $firstInBlock)
. ' '
. $indentation
. static::printInputValue($arg);
$firstInBlock = false;
$previousHasDescription = $hasDescription;
}
return "(\n"
. \implode("\n", $argsStrings)
. "\n"
. $indentation
. ')';
}
/**
* @param InputObjectField|Argument $arg
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printInputValue($arg): string
{
$argDecl = "{$arg->name}: {$arg->getType()->toString()}";
if ($arg->defaultValueExists()) {
$defaultValueAST = AST::astFromValue($arg->defaultValue, $arg->getType());
if ($defaultValueAST === null) {
$inconvertibleDefaultValue = Utils::printSafe($arg->defaultValue);
throw new InvariantViolation("Unable to convert defaultValue of argument {$arg->name} into AST: {$inconvertibleDefaultValue}.");
}
$printedDefaultValue = Printer::doPrint($defaultValueAST);
$argDecl .= " = {$printedDefaultValue}";
}
return $argDecl . static::printDeprecated($arg);
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
*/
protected static function printScalar(ScalarType $type, array $options): string
{
return static::printDescription($options, $type)
. "scalar {$type->name}";
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printObject(ObjectType $type, array $options): string
{
return static::printDescription($options, $type)
. "type {$type->name}"
. static::printImplementedInterfaces($type)
. static::printFields($options, $type);
}
/**
* @param array<string, bool> $options
* @param ObjectType|InterfaceType $type
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printFields(array $options, $type): string
{
$fields = [];
$firstInBlock = true;
$previousHasDescription = false;
$fieldDefinitions = $type->getFields();
if (isset($options['sortFields']) && $options['sortFields']) {
ksort($fieldDefinitions);
}
foreach ($fieldDefinitions as $f) {
$hasDescription = $f->description !== null;
if ($previousHasDescription && ! $hasDescription) {
$fields[] = '';
}
$fields[] = static::printDescription($options, $f, ' ', $firstInBlock)
. ' '
. $f->name
. static::printArgs($options, $f->args, ' ')
. ': '
. $f->getType()->toString()
. static::printDeprecated($f);
$firstInBlock = false;
$previousHasDescription = $hasDescription;
}
return static::printBlock($fields);
}
/**
* @param FieldDefinition|EnumValueDefinition|InputObjectField|Argument $deprecation
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printDeprecated($deprecation): string
{
$reason = $deprecation->deprecationReason;
if ($reason === null) {
return '';
}
if ($reason === '' || $reason === Directive::DEFAULT_DEPRECATION_REASON) {
return ' @deprecated';
}
$reasonAST = AST::astFromValue($reason, Type::string());
assert($reasonAST instanceof StringValueNode);
$reasonASTString = Printer::doPrint($reasonAST);
return " @deprecated(reason: {$reasonASTString})";
}
protected static function printImplementedInterfaces(ImplementingType $type): string
{
$interfaces = $type->getInterfaces();
return $interfaces === []
? ''
: ' implements ' . \implode(
' & ',
\array_map(
static fn (InterfaceType $interface): string => $interface->name,
$interfaces
)
);
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printInterface(InterfaceType $type, array $options): string
{
return static::printDescription($options, $type)
. "interface {$type->name}"
. static::printImplementedInterfaces($type)
. static::printFields($options, $type);
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws InvariantViolation
*/
protected static function printUnion(UnionType $type, array $options): string
{
$types = $type->getTypes();
$types = $types === []
? ''
: ' = ' . \implode(' | ', $types);
return static::printDescription($options, $type) . 'union ' . $type->name . $types;
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printEnum(EnumType $type, array $options): string
{
$values = [];
$firstInBlock = true;
$valueDefinitions = $type->getValues();
if (isset($options['sortEnumValues']) && $options['sortEnumValues']) {
usort($valueDefinitions, static fn (EnumValueDefinition $left, EnumValueDefinition $right): int => $left->name <=> $right->name);
}
foreach ($valueDefinitions as $value) {
$values[] = static::printDescription($options, $value, ' ', $firstInBlock)
. ' '
. $value->name
. static::printDeprecated($value);
$firstInBlock = false;
}
return static::printDescription($options, $type)
. "enum {$type->name}"
. static::printBlock($values);
}
/**
* @param array<string, bool> $options
*
* @phpstan-param Options $options
*
* @throws \JsonException
* @throws InvariantViolation
* @throws SerializationError
*/
protected static function printInputObject(InputObjectType $type, array $options): string
{
$fields = [];
$firstInBlock = true;
$fieldDefinitions = $type->getFields();
if (isset($options['sortInputFields']) && $options['sortInputFields']) {
ksort($fieldDefinitions);
}
foreach ($fieldDefinitions as $field) {
$fields[] = static::printDescription($options, $field, ' ', $firstInBlock)
. ' '
. static::printInputValue($field);
$firstInBlock = false;
}
return static::printDescription($options, $type)
. "input {$type->name}"
. static::printBlock($fields);
}
/** @param array<string> $items */
protected static function printBlock(array $items): string
{
return $items === []
? ''
: " {\n" . \implode("\n", $items) . "\n}";
}
}