Your IP : 216.73.216.182


Current Path : /home/e/o/l/eolienneia/www/templates/yootheme/vendor/yootheme/graphql/src/
Upload File :
Current File : /home/e/o/l/eolienneia/www/templates/yootheme/vendor/yootheme/graphql/src/SchemaPrinter.php

<?php

namespace YOOtheme\GraphQL;

use YOOtheme\GraphQL\Error\Error;
use YOOtheme\GraphQL\Language\Printer;
use YOOtheme\GraphQL\Type\Definition\Directive;
use YOOtheme\GraphQL\Type\Definition\EnumType;
use YOOtheme\GraphQL\Type\Definition\InputObjectType;
use YOOtheme\GraphQL\Type\Definition\InterfaceType;
use YOOtheme\GraphQL\Type\Definition\ObjectType;
use YOOtheme\GraphQL\Type\Definition\ScalarType;
use YOOtheme\GraphQL\Type\Definition\Type;
use YOOtheme\GraphQL\Type\Definition\UnionType;
use YOOtheme\GraphQL\Type\Introspection;
use YOOtheme\GraphQL\Type\Schema;
use YOOtheme\GraphQL\Utils\AST;
use YOOtheme\GraphQL\Utils\Utils;

/**
 * Given an instance of Schema, prints it in GraphQL type language.
 */
class SchemaPrinter
{
    /**
     * Accepts options as a second argument:.
     *
     *    - commentDescriptions:
     *        Provide true to use preceding comments as the description.
     *
     * @api
     *
     * @param Schema $schema
     * @param array  $options
     *
     * @return string
     */
    public static function doPrint(Schema $schema, array $options = [])
    {
        return self::printFilteredSchema(
            $schema,
            function ($type) {
                return !Directive::isSpecifiedDirective($type);
            },
            function ($type) {
                return !Type::isBuiltInType($type);
            },
            $options + compact('schema')
        );
    }

    /**
     * @api
     *
     * @param Schema $schema
     * @param array  $options
     *
     * @return string
     */
    public static function printIntrosepctionSchema(Schema $schema, array $options = [])
    {
        return self::printFilteredSchema(
            $schema,
            [Directive::class, 'isSpecifiedDirective'],
            [Introspection::class, 'isIntrospectionType'],
            $options + compact('schema')
        );
    }

    private static function printFilteredSchema(
        Schema $schema,
        $directiveFilter,
        $typeFilter,
        $options
    ) {
        $directives = array_filter($schema->getDirectives(), function ($directive) use (
            $directiveFilter
        ) {
            return $directiveFilter($directive);
        });
        $types = $schema->getTypeMap();
        ksort($types);
        $types = array_filter($types, $typeFilter);

        return implode(
            "\n\n",
            array_filter(
                array_merge(
                    [self::printSchemaDefinition($schema)],
                    array_map(function ($directive) use ($options) {
                        return self::printDirective($directive, $options);
                    }, $directives),
                    array_map(function ($type) use ($options) {
                        return self::printType($type, $options);
                    }, $types)
                )
            )
        ) . "\n";
    }

    private static function printSchemaDefinition(Schema $schema)
    {
        if (self::isSchemaOfCommonNames($schema)) {
            return;
        }

        $operationTypes = [];

        $queryType = $schema->getQueryType();
        if ($queryType) {
            $operationTypes[] = "  query: {$queryType->name}";
        }

        $mutationType = $schema->getMutationType();
        if ($mutationType) {
            $operationTypes[] = "  mutation: {$mutationType->name}";
        }

        $subscriptionType = $schema->getSubscriptionType();
        if ($subscriptionType) {
            $operationTypes[] = "  subscription: {$subscriptionType->name}";
        }

        return "schema {\n" . implode("\n", $operationTypes) . "\n}";
    }

    /**
     * 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:.
     *
     *   schema {
     *     query: Query
     *     mutation: Mutation
     *   }
     *
     * When using this naming convention, the schema description can be omitted.
     *
     * @param Schema $schema
     * @return bool
     */
    private static function isSchemaOfCommonNames(Schema $schema)
    {
        $queryType = $schema->getQueryType();
        if ($queryType && $queryType->name !== 'Query') {
            return false;
        }

        $mutationType = $schema->getMutationType();
        if ($mutationType && $mutationType->name !== 'Mutation') {
            return false;
        }

        $subscriptionType = $schema->getSubscriptionType();
        if ($subscriptionType && $subscriptionType->name !== 'Subscription') {
            return false;
        }

        return true;
    }

    public static function printType(Type $type, array $options = [])
    {
        if ($type instanceof ScalarType) {
            return self::printScalar($type, $options);
        }
        if ($type instanceof ObjectType) {
            return self::printObject($type, $options);
        }
        if ($type instanceof InterfaceType) {
            return self::printInterface($type, $options);
        }
        if ($type instanceof UnionType) {
            return self::printUnion($type, $options);
        }
        if ($type instanceof EnumType) {
            return self::printEnum($type, $options);
        }
        if ($type instanceof InputObjectType) {
            return self::printInputObject($type, $options);
        }

        throw new Error('Unknown type: ' . Utils::printSafe($type) . '.');
    }

    private static function printScalar(ScalarType $type, array $options)
    {
        return self::printDescription($options, $type) . "scalar {$type->name}";
    }

    private static function printObject(ObjectType $type, array $options)
    {
        $interfaces = $type->getInterfaces();
        $directives = self::printDirectives($type, $options);
        $implementedInterfaces = !empty($interfaces)
            ? ' implements ' .
                implode(
                    ', ',
                    array_map(function ($i) {
                        return $i->name;
                    }, $interfaces)
                )
            : '';
        return self::printDescription($options, $type) .
            "type {$type->name}$implementedInterfaces$directives {\n" .
            self::printFields($options, $type) .
            "\n" .
            '}';
    }

    private static function printInterface(InterfaceType $type, array $options)
    {
        return self::printDescription($options, $type) .
            "interface {$type->name} {\n" .
            self::printFields($options, $type) .
            "\n" .
            '}';
    }

    private static function printUnion(UnionType $type, array $options)
    {
        return self::printDescription($options, $type) .
            "union {$type->name} = " .
            implode(' | ', $type->getTypes());
    }

    private static function printEnum(EnumType $type, array $options)
    {
        return self::printDescription($options, $type) .
            "enum {$type->name} {\n" .
            self::printEnumValues($type->getValues(), $options) .
            "\n" .
            '}';
    }

    private static function printEnumValues($values, $options)
    {
        return implode(
            "\n",
            array_map(
                function ($value, $i) use ($options) {
                    return self::printDescription($options, $value, '  ', !$i) .
                        '  ' .
                        $value->name .
                        self::printDeprecated($value);
                },
                $values,
                array_keys($values)
            )
        );
    }

    private static function printInputObject(InputObjectType $type, array $options)
    {
        $fields = array_values($type->getFields());
        return self::printDescription($options, $type) .
            "input {$type->name} {\n" .
            implode(
                "\n",
                array_map(
                    function ($f, $i) use ($options) {
                        return self::printDescription($options, $f, '  ', !$i) .
                            '  ' .
                            self::printInputValue($f);
                    },
                    $fields,
                    array_keys($fields)
                )
            ) .
            "\n" .
            '}';
    }

    private static function printFields($options, $type)
    {
        $fields = array_values($type->getFields());
        return implode(
            "\n",
            array_map(
                function ($f, $i) use ($options) {
                    return self::printDescription($options, $f, '  ', !$i) .
                        '  ' .
                        $f->name .
                        self::printArgs($options, $f->args, '  ') .
                        ': ' .
                        (string) $f->getType() .
                        self::printDirectives($f, $options) .
                        self::printDeprecated($f);
                },
                $fields,
                array_keys($fields)
            )
        );
    }

    private static function printArgs($options, $args, $indentation = '')
    {
        if (!$args) {
            return '';
        }

        // If every arg does not have a description, print them on one line.
        if (
            Utils::every($args, function ($arg) {
                return empty($arg->description);
            })
        ) {
            return '(' . implode(', ', array_map('self::printInputValue', $args)) . ')';
        }

        return "(\n" .
            implode(
                "\n",
                array_map(
                    function ($arg, $i) use ($indentation, $options) {
                        return self::printDescription($options, $arg, '  ' . $indentation, !$i) .
                            '  ' .
                            $indentation .
                            self::printInputValue($arg);
                    },
                    $args,
                    array_keys($args)
                )
            ) .
            "\n" .
            $indentation .
            ')';
    }

    private static function printInputValue($arg)
    {
        $argDecl = $arg->name . ': ' . (string) $arg->getType();
        if ($arg->defaultValueExists()) {
            $argDecl .=
                ' = ' . Printer::doPrint(AST::astFromValue($arg->defaultValue, $arg->getType()));
        }
        return $argDecl;
    }

    private static function printDirective($directive, $options)
    {
        return self::printDescription($options, $directive) .
            'directive @' .
            $directive->name .
            self::printArgs($options, $directive->args) .
            ' on ' .
            implode(' | ', $directive->locations);
    }

    private static function printDirectives($fieldOrType, $options)
    {
        $directives = [];

        if (isset($fieldOrType->astNode->directives)) {
            foreach ($fieldOrType->astNode->directives as $directive) {
                if (!$options['schema']->getDirective($directive->name->value)) {
                    throw new Error(
                        'Unknown directive: ' . Utils::printSafe($directive->name->value) . '.'
                    );
                }

                $directives[] = Printer::doPrint($directive);
            }
        }

        return $directives ? ' ' . implode(' ', $directives) : '';
    }

    private static function printDeprecated($fieldOrEnumVal)
    {
        $reason = $fieldOrEnumVal->deprecationReason;
        if (empty($reason)) {
            return '';
        }
        if ($reason === Directive::DEFAULT_DEPRECATION_REASON) {
            return ' @deprecated';
        }
        return ' @deprecated(reason: ' .
            Printer::doPrint(AST::astFromValue($reason, Type::string())) .
            ')';
    }

    private static function printDescription(
        $options,
        $def,
        $indentation = '',
        $firstInBlock = true
    ) {
        if (!$def->description) {
            return '';
        }
        $lines = self::descriptionLines($def->description, 120 - strlen($indentation));
        if (isset($options['commentDescriptions'])) {
            return self::printDescriptionWithComments($lines, $indentation, $firstInBlock);
        }

        $description =
            $indentation && !$firstInBlock ? "\n" . $indentation . '"""' : $indentation . '"""';

        // In some circumstances, a single line can be used for the description.
        if (count($lines) === 1 && mb_strlen($lines[0]) < 70 && substr($lines[0], -1) !== '"') {
            return $description . self::escapeQuote($lines[0]) . "\"\"\"\n";
        }

        // Format a multi-line block quote to account for leading space.
        $hasLeadingSpace =
            isset($lines[0]) &&
            (substr($lines[0], 0, 1) === ' ' || substr($lines[0], 0, 1) === '\t');
        if (!$hasLeadingSpace) {
            $description .= "\n";
        }

        $lineLength = count($lines);
        for ($i = 0; $i < $lineLength; $i++) {
            if ($i !== 0 || !$hasLeadingSpace) {
                $description .= $indentation;
            }
            $description .= self::escapeQuote($lines[$i]) . "\n";
        }
        $description .= $indentation . "\"\"\"\n";

        return $description;
    }

    private static function escapeQuote($line)
    {
        return str_replace('"""', '\\"""', $line);
    }

    private static function printDescriptionWithComments($lines, $indentation, $firstInBlock)
    {
        $description = $indentation && !$firstInBlock ? "\n" : '';
        foreach ($lines as $line) {
            if ($line === '') {
                $description .= $indentation . "#\n";
            } else {
                $description .= $indentation . '# ' . $line . "\n";
            }
        }

        return $description;
    }

    private static function descriptionLines($description, $maxLen)
    {
        $lines = [];
        $rawLines = explode("\n", $description);
        foreach ($rawLines as $line) {
            if ($line === '') {
                $lines[] = $line;
            } else {
                // For > 120 character long lines, cut at space boundaries into sublines
                // of ~80 chars.
                $sublines = self::breakLine($line, $maxLen);
                foreach ($sublines as $subline) {
                    $lines[] = $subline;
                }
            }
        }
        return $lines;
    }

    private static function breakLine($line, $maxLen)
    {
        if (strlen($line) < $maxLen + 5) {
            return [$line];
        }
        preg_match_all('/((?: |^).{15,' . ($maxLen - 40) . '}(?= |$))/', $line, $parts);
        $parts = $parts[0];
        return array_map(function ($part) {
            return trim($part);
        }, $parts);
    }
}