From 5f1b2b357fe0ad1199844b811165991fbfc42788 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 12:24:40 +0400 Subject: [PATCH 01/22] `SCALAR` support. --- src/Utils/SchemaPrinter.php | 64 ++++++++++++++++++++++++++++++- tests/Utils/SchemaPrinterTest.php | 41 ++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 28c92edba..e2f2b19d6 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -4,7 +4,10 @@ namespace GraphQL\Utils; +use Closure; use GraphQL\Error\Error; +use GraphQL\Language\AST\DirectiveNode; +use GraphQL\Language\AST\ScalarTypeDefinitionNode; use GraphQL\Language\BlockString; use GraphQL\Language\Printer; use GraphQL\Type\Definition\Directive; @@ -30,8 +33,10 @@ use function count; use function explode; use function implode; +use function is_callable; use function ksort; use function mb_strlen; +use function self; use function sprintf; use function str_replace; use function strlen; @@ -39,14 +44,18 @@ /** * Prints the contents of a Schema in schema definition language. * - * @phpstan-type Options array{commentDescriptions?: bool} + * @phpstan-type Options array{commentDescriptions?: bool, printDirectives?: callable(DirectiveNode): bool} * * - commentDescriptions: * Provide true to use preceding comments as the description. * This option is provided to ease adoption and will be removed in v16. + * - printDirectives + * Callable used to determine should be directive printed or not. */ class SchemaPrinter { + protected const LINE_LENGTH = 80; + /** * @param array $options * @phpstan-param Options $options @@ -308,7 +317,9 @@ protected static function printInputValue($arg): string */ protected static function printScalar(ScalarType $type, array $options): string { - return sprintf('%sscalar %s', static::printDescription($options, $type), $type->name); + return static::printDescription($options, $type) . + sprintf('scalar %s', $type->name) . + static::printTypeDirectives($type, $options); } /** @@ -459,4 +470,53 @@ protected static function printBlock(array $items): string ? " {\n" . implode("\n", $items) . "\n}" : ''; } + + /** + * @param array $options + * @phpstan-param Options $options + */ + protected static function printTypeDirectives(Type $type, array $options, string $indentation = ''): string { + // Enabled? + $filter = $options['printDirectives'] ?? null; + + if (!$filter || !is_callable($filter)) { + return ''; + } + + // AST Node available and has directives? + $node = $type->astNode; + + if (!($node instanceof ScalarTypeDefinitionNode)) { + return ''; + } + + // Print + /** @var array $directives */ + $length = 0; + $directives = []; + + foreach ($node->directives as $directive) { + if ($filter($directive)) { + $string = static::printTypeDirective($directive, $options, $indentation); + $length = $length + mb_strlen($string); + $directives[] = $string; + } + } + + // Multiline? + $delimiter = $length > static::LINE_LENGTH ? "\n{$indentation}" : ' '; + $serialized = $delimiter.implode($delimiter, $directives); + + // Return + return $serialized; + } + + /** + * @param array $options + * @phpstan-param Options $options + */ + protected static function printTypeDirective(DirectiveNode $directive, array $options, string $indentation): string + { + return Printer::doPrint($directive); + } } diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index ac29eed9a..72b97968b 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -6,6 +6,7 @@ use Generator; use GraphQL\Language\DirectiveLocation; +use GraphQL\Language\Parser; use GraphQL\Type\Definition\CustomScalarType; use GraphQL\Type\Definition\Directive; use GraphQL\Type\Definition\EnumType; @@ -19,6 +20,8 @@ use GraphQL\Utils\SchemaPrinter; use PHPUnit\Framework\TestCase; +use function str_pad; + class SchemaPrinterTest extends TestCase { private static function assertPrintedSchemaEquals(string $expected, Schema $schema): void @@ -1273,4 +1276,42 @@ enum __TypeKind { GRAPHQL; self::assertEquals($expected, $output); } + + public function testPrintDirectives(): void { + $text = str_pad('a', 80, 'a'); + $schema = /** @lang GraphQL */ << static function(): bool { + return true; + }, + ]); + + self::assertEquals($expected, $actual); + } } From 09c162d48c566c733da3c062033498ca9f52dea2 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 19:37:12 +0400 Subject: [PATCH 02/22] `ENUM_VALUE` support. --- src/Utils/SchemaPrinter.php | 49 +++++++++++++++++++++++++------ tests/Utils/SchemaPrinterTest.php | 27 +++++++++++++++++ 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index e2f2b19d6..cfc466cd7 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -7,6 +7,7 @@ use Closure; use GraphQL\Error\Error; use GraphQL\Language\AST\DirectiveNode; +use GraphQL\Language\AST\EnumValueDefinitionNode; use GraphQL\Language\AST\ScalarTypeDefinitionNode; use GraphQL\Language\BlockString; use GraphQL\Language\Printer; @@ -35,6 +36,7 @@ use function implode; use function is_callable; use function ksort; +use function ltrim; use function mb_strlen; use function self; use function sprintf; @@ -54,7 +56,7 @@ */ class SchemaPrinter { - protected const LINE_LENGTH = 80; + protected const LINE_LENGTH = 70; /** * @param array $options @@ -235,7 +237,7 @@ protected static function printDescription(array $options, $def, string $indenta return static::printDescriptionWithComments($description, $indentation, $firstInBlock); } - $preferMultipleLines = mb_strlen($description) > 70; + $preferMultipleLines = mb_strlen($description) > static::LINE_LENGTH; $blockString = BlockString::print($description, '', $preferMultipleLines); $prefix = $indentation !== '' && ! $firstInBlock ? "\n" . $indentation @@ -427,10 +429,7 @@ protected static function printEnum(EnumType $type, array $options): string $values = $type->getValues(); $values = array_map( static function (EnumValueDefinition $value, int $i) use ($options): string { - return static::printDescription($options, $value, ' ', $i === 0) . - ' ' . - $value->name . - static::printDeprecated($value); + return static::printEnumValue($value, $options, ' ', $i === 0); }, $values, array_keys($values) @@ -441,6 +440,24 @@ static function (EnumValueDefinition $value, int $i) use ($options): string { static::printBlock($values); } + /** + * @param array $options + * @phpstan-param Options $options + */ + protected static function printEnumValue(EnumValueDefinition $type, array $options, string $indentation = '', bool $firstInBlock = false): string + { + $value = static::printDescription($options, $type, $indentation, $firstInBlock) . + ' ' . + $type->name . + static::printTypeDirectives($type, $options, $indentation); + + if (!$firstInBlock && mb_strlen($value) > static::LINE_LENGTH) { + $value = "\n".ltrim($value, "\n"); + } + + return $value; + } + /** * @param array $options * @phpstan-param Options $options @@ -472,21 +489,26 @@ protected static function printBlock(array $items): string } /** + * @param Type|EnumValueDefinition $type * @param array $options * @phpstan-param Options $options */ - protected static function printTypeDirectives(Type $type, array $options, string $indentation = ''): string { + protected static function printTypeDirectives($type, array $options, string $indentation = ''): string { // Enabled? $filter = $options['printDirectives'] ?? null; if (!$filter || !is_callable($filter)) { + if ($type instanceof EnumValueDefinition) { + return static::printDeprecated($type); + } + return ''; } // AST Node available and has directives? $node = $type->astNode; - if (!($node instanceof ScalarTypeDefinitionNode)) { + if (!($node instanceof ScalarTypeDefinitionNode || $node instanceof EnumValueDefinitionNode)) { return ''; } @@ -496,8 +518,17 @@ protected static function printTypeDirectives(Type $type, array $options, string $directives = []; foreach ($node->directives as $directive) { - if ($filter($directive)) { + $string = null; + + if ($directive->name === Directive::DEPRECATED_NAME && ($type instanceof EnumValueDefinition)) { + $string = static::printDeprecated($type); + } elseif ($filter($directive)) { $string = static::printTypeDirective($directive, $options, $indentation); + } else { + // empty + } + + if ($string) { $length = $length + mb_strlen($string); $directives[] = $string; } diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 72b97968b..18b5dfbe5 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1296,10 +1296,37 @@ public function testPrintDirectives(): void { scalar ScalarA @test scalar ScalarB @test(value: "{$text}") + + enum EnumA { + a @test @deprecated + b @test(value: "{$text}") + "{$text}" + c @test + "{$text}" + d @test(value: "{$text}") + } GRAPHQL; $expected = <<<'GRAPHQL' directive @test(value: String) on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION + enum EnumA { + a @test @deprecated + + b + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + + """ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + """ + c @test + + """ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + """ + d + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + } + scalar ScalarA @test scalar ScalarB From 51e8126c8dceea1bfe1d82a2687fe541d4baf2f5 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 19:45:32 +0400 Subject: [PATCH 03/22] `ENUM` support. --- src/Utils/SchemaPrinter.php | 14 ++++++++++---- tests/Utils/SchemaPrinterTest.php | 20 +++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index cfc466cd7..8d0be7373 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -7,6 +7,7 @@ use Closure; use GraphQL\Error\Error; use GraphQL\Language\AST\DirectiveNode; +use GraphQL\Language\AST\EnumTypeDefinitionNode; use GraphQL\Language\AST\EnumValueDefinitionNode; use GraphQL\Language\AST\ScalarTypeDefinitionNode; use GraphQL\Language\BlockString; @@ -437,6 +438,7 @@ static function (EnumValueDefinition $value, int $i) use ($options): string { return static::printDescription($options, $type) . sprintf('enum %s', $type->name) . + static::printTypeDirectives($type, $options) . static::printBlock($values); } @@ -489,7 +491,7 @@ protected static function printBlock(array $items): string } /** - * @param Type|EnumValueDefinition $type + * @param Type|EnumValueDefinition|EnumType $type * @param array $options * @phpstan-param Options $options */ @@ -508,7 +510,7 @@ protected static function printTypeDirectives($type, array $options, string $ind // AST Node available and has directives? $node = $type->astNode; - if (!($node instanceof ScalarTypeDefinitionNode || $node instanceof EnumValueDefinitionNode)) { + if (!($node instanceof ScalarTypeDefinitionNode || $node instanceof EnumValueDefinitionNode || $node instanceof EnumTypeDefinitionNode)) { return ''; } @@ -535,8 +537,12 @@ protected static function printTypeDirectives($type, array $options, string $ind } // Multiline? - $delimiter = $length > static::LINE_LENGTH ? "\n{$indentation}" : ' '; - $serialized = $delimiter.implode($delimiter, $directives); + $serialized = ''; + + if ($directives) { + $delimiter = $length > static::LINE_LENGTH ? "\n{$indentation}" : ' '; + $serialized = $delimiter.implode($delimiter, $directives); + } // Return return $serialized; diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 18b5dfbe5..4bb13ac6e 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1278,7 +1278,7 @@ enum __TypeKind { } public function testPrintDirectives(): void { - $text = str_pad('a', 80, 'a'); + $text = str_pad('a', 80, 'a'); $schema = /** @lang GraphQL */ << Date: Sat, 30 Oct 2021 19:49:32 +0400 Subject: [PATCH 04/22] `INTERFACE` support. --- src/Utils/SchemaPrinter.php | 5 +++-- tests/Utils/SchemaPrinterTest.php | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 8d0be7373..42c955102 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -404,6 +404,7 @@ protected static function printInterface(InterfaceType $type, array $options): s return static::printDescription($options, $type) . sprintf('interface %s', $type->name) . self::printImplementedInterfaces($type) . + static::printTypeDirectives($type, $options) . static::printFields($options, $type); } @@ -491,7 +492,7 @@ protected static function printBlock(array $items): string } /** - * @param Type|EnumValueDefinition|EnumType $type + * @param Type|EnumValueDefinition|EnumType|InterfaceType $type * @param array $options * @phpstan-param Options $options */ @@ -510,7 +511,7 @@ protected static function printTypeDirectives($type, array $options, string $ind // AST Node available and has directives? $node = $type->astNode; - if (!($node instanceof ScalarTypeDefinitionNode || $node instanceof EnumValueDefinitionNode || $node instanceof EnumTypeDefinitionNode)) { + if (!$node) { return ''; } diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 4bb13ac6e..65f1a2946 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1309,6 +1309,14 @@ enum EnumA @test { enum EnumB @test(value: "{$text}") { a } + + interface InterfaceA @test { + a: ID + } + + interface InterfaceB @test(value: "{$text}") { + a: ID + } GRAPHQL; $expected = /** @lang GraphQL */ <<<'GRAPHQL' directive @test(value: String) on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION @@ -1337,6 +1345,15 @@ enum EnumB a } + interface InterfaceA @test { + a: ID + } + + interface InterfaceB + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") { + a: ID + } + scalar ScalarA @test scalar ScalarB From 3cd43670932ce3709745454a639d4485682e74ae Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 20:00:47 +0400 Subject: [PATCH 05/22] `FIELD_DEFINITION` support. --- src/Utils/SchemaPrinter.php | 33 ++++++++++++----- tests/Utils/SchemaPrinterTest.php | 60 +++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 42c955102..2e1a4d796 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -347,13 +347,7 @@ protected static function printFields(array $options, $type): string $fields = array_values($type->getFields()); $fields = array_map( static function (FieldDefinition $f, int $i) use ($options): string { - return static::printDescription($options, $f, ' ', $i === 0) . - ' ' . - $f->name . - static::printArgs($options, $f->args, ' ') . - ': ' . - (string) $f->getType() . - static::printDeprecated($f); + return static::printField($f, $options, ' ', $i === 0); }, $fields, array_keys($fields) @@ -362,6 +356,27 @@ static function (FieldDefinition $f, int $i) use ($options): string { return self::printBlock($fields); } + /** + * @param array $options + * @phpstan-param Options $options + */ + protected static function printField(FieldDefinition $type, array $options, string $indentation = '', bool $firstInBlock = true): string + { + $field = static::printDescription($options, $type, $indentation, $firstInBlock) . + ' ' . + $type->name . + static::printArgs($options, $type->args, ' ') . + ': ' . + (string) $type->getType() . + static::printTypeDirectives($type, $options, $indentation); + + if (!$firstInBlock && mb_strlen($field) > static::LINE_LENGTH) { + $field = "\n".ltrim($field, "\n"); + } + + return $field; + } + /** * @param FieldDefinition|EnumValueDefinition $fieldOrEnumVal */ @@ -492,7 +507,7 @@ protected static function printBlock(array $items): string } /** - * @param Type|EnumValueDefinition|EnumType|InterfaceType $type + * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition $type * @param array $options * @phpstan-param Options $options */ @@ -501,7 +516,7 @@ protected static function printTypeDirectives($type, array $options, string $ind $filter = $options['printDirectives'] ?? null; if (!$filter || !is_callable($filter)) { - if ($type instanceof EnumValueDefinition) { + if ($type instanceof EnumValueDefinition || $type instanceof FieldDefinition) { return static::printDeprecated($type); } diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 65f1a2946..f7f5b9c4d 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1311,12 +1311,30 @@ enum EnumB @test(value: "{$text}") { } interface InterfaceA @test { - a: ID + a: Int @test @deprecated + b: Int @test(value: "{$text}") + "{$text}" + c: Int @test + "{$text}" + d: Int @test(value: "{$text}") @deprecated } interface InterfaceB @test(value: "{$text}") { a: ID } + + type TypeA { + a: Int @test @deprecated + b: Int @test(value: "{$text}") + "{$text}" + c: Int @test + "{$text}" + d: Int @test(value: "{$text}") @deprecated + } + + type TypeB { + a: ID + } GRAPHQL; $expected = /** @lang GraphQL */ <<<'GRAPHQL' directive @test(value: String) on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION @@ -1346,7 +1364,22 @@ enum EnumB } interface InterfaceA @test { - a: ID + a: Int @test @deprecated + + b: Int + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + + """ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + """ + c: Int @test + + """ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + """ + d: Int + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + @deprecated } interface InterfaceB @@ -1359,6 +1392,29 @@ interface InterfaceB scalar ScalarB @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + type TypeA { + a: Int @test @deprecated + + b: Int + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + + """ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + """ + c: Int @test + + """ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + """ + d: Int + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + @deprecated + } + + type TypeB { + a: ID + } + GRAPHQL; $actual = SchemaPrinter::doPrint(BuildSchema::build($schema), [ 'printDirectives' => static function(): bool { From a1898dc5dc0d877dd204ab6da4e4b0ed3587c965 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 20:05:34 +0400 Subject: [PATCH 06/22] `OBJECT` support. --- src/Utils/SchemaPrinter.php | 1 + tests/Utils/SchemaPrinterTest.php | 271 +++++++++++++++--------------- 2 files changed, 137 insertions(+), 135 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 2e1a4d796..3121756fc 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -334,6 +334,7 @@ protected static function printObject(ObjectType $type, array $options): string return static::printDescription($options, $type) . sprintf('type %s', $type->name) . self::printImplementedInterfaces($type) . + static::printTypeDirectives($type, $options) . static::printFields($options, $type); } diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index f7f5b9c4d..3194b8d6b 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1280,142 +1280,143 @@ enum __TypeKind { public function testPrintDirectives(): void { $text = str_pad('a', 80, 'a'); $schema = /** @lang GraphQL */ << static function(): bool { return true; From 7327a77ef14c7c13cc0c43bc0e9a6396744e2bbe Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 20:16:55 +0400 Subject: [PATCH 07/22] `UNION` support. --- src/Utils/SchemaPrinter.php | 13 +++++++++++-- tests/Utils/SchemaPrinterTest.php | 10 ++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 3121756fc..8eddbe901 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -434,8 +434,17 @@ protected static function printUnion(UnionType $type, array $options): string $types = count($types) > 0 ? ' = ' . implode(' | ', $types) : ''; + $directives = static::printTypeDirectives($type, $options, ''); - return static::printDescription($options, $type) . 'union ' . $type->name . $types; + if (mb_strlen($directives) > static::LINE_LENGTH) { + $types = ltrim($types); + $directives .= "\n"; + } + + return static::printDescription($options, $type) . + 'union ' . $type->name . + $directives . + $types; } /** @@ -508,7 +517,7 @@ protected static function printBlock(array $items): string } /** - * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition $type + * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition|UnionType $type * @param array $options * @phpstan-param Options $options */ diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 3194b8d6b..ee65c9479 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1335,6 +1335,10 @@ interface InterfaceB implements InterfaceA @test(value: "{$text}") { type TypeB implements InterfaceB @test(value: "{$text}") { a: ID } + + union UnionA @test = TypeA | TypeB + + union UnionB @test(value: "{$text}") = TypeA | TypeB GRAPHQL; $expected = /** @lang GraphQL */ <<<'GRAPHQL' directive @test(value: String) on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION @@ -1416,6 +1420,12 @@ interface InterfaceB implements InterfaceA a: ID } + union UnionA @test = TypeA | TypeB + + union UnionB + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + = TypeA | TypeB + GRAPHQL; $actual = SchemaPrinter::doPrint(BuildSchema::build($schema), [ 'printDirectives' => static function(): bool { From 7d5eafd36016d32c17a2272a2e8845dfbb4d35d1 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 20:20:01 +0400 Subject: [PATCH 08/22] `INPUT_OBJECT` support. --- src/Utils/SchemaPrinter.php | 3 ++- tests/Utils/SchemaPrinterTest.php | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 8eddbe901..ad63c414a 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -503,6 +503,7 @@ static function ($f, $i) use ($options): string { return static::printDescription($options, $type) . sprintf('input %s', $type->name) . + static::printTypeDirectives($type, $options) . static::printBlock($fields); } @@ -517,7 +518,7 @@ protected static function printBlock(array $items): string } /** - * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition|UnionType $type + * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition|UnionType|InputObjectType $type * @param array $options * @phpstan-param Options $options */ diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index ee65c9479..026e6f2e2 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1339,6 +1339,14 @@ interface InterfaceB implements InterfaceA @test(value: "{$text}") { union UnionA @test = TypeA | TypeB union UnionB @test(value: "{$text}") = TypeA | TypeB + + input InputA @test { + a: Int + } + + input InputB @test(value: "{$text}") { + a: ID + } GRAPHQL; $expected = /** @lang GraphQL */ <<<'GRAPHQL' directive @test(value: String) on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION @@ -1367,6 +1375,15 @@ enum EnumB a } + input InputA @test { + a: Int + } + + input InputB + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") { + a: ID + } + interface InterfaceA @test { a: Int @test @deprecated From fc10a4d86c849469d04a69c16532b1d974eae59a Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 20:25:28 +0400 Subject: [PATCH 09/22] `INPUT_FIELD_DEFINITION` support. --- src/Utils/SchemaPrinter.php | 24 +++++++++++++++++++++--- tests/Utils/SchemaPrinterTest.php | 23 +++++++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index ad63c414a..71755bf41 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -494,8 +494,8 @@ protected static function printInputObject(InputObjectType $type, array $options { $fields = array_values($type->getFields()); $fields = array_map( - static function ($f, $i) use ($options): string { - return static::printDescription($options, $f, ' ', ! $i) . ' ' . static::printInputValue($f); + static function (InputObjectField $f, $i) use ($options): string { + return static::printInputObjectField($f, $options, ' ', ! $i); }, $fields, array_keys($fields) @@ -507,6 +507,24 @@ static function ($f, $i) use ($options): string { static::printBlock($fields); } + /** + * @param array $options + * @phpstan-param Options $options + */ + protected static function printInputObjectField(InputObjectField $type, array $options, string $indentation = '', bool $firstInBlock = true): string + { + $field = static::printDescription($options, $type, $indentation, $firstInBlock) . + ' ' . + static::printInputValue($type) . + static::printTypeDirectives($type, $options, $indentation); + + if (!$firstInBlock && mb_strlen($field) > static::LINE_LENGTH) { + $field = "\n".ltrim($field, "\n"); + } + + return $field; + } + /** * @param array $items */ @@ -518,7 +536,7 @@ protected static function printBlock(array $items): string } /** - * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition|UnionType|InputObjectType $type + * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition|UnionType|InputObjectType|InputObjectField $type * @param array $options * @phpstan-param Options $options */ diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 026e6f2e2..db5041037 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1341,7 +1341,12 @@ interface InterfaceB implements InterfaceA @test(value: "{$text}") { union UnionB @test(value: "{$text}") = TypeA | TypeB input InputA @test { - a: Int + a: Int @test + b: Int @test(value: "{$text}") + "{$text}" + c: Int @test + "{$text}" + d: Int @test(value: "{$text}") } input InputB @test(value: "{$text}") { @@ -1376,7 +1381,21 @@ enum EnumB } input InputA @test { - a: Int + a: Int @test + + b: Int + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + + """ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + """ + c: Int @test + + """ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + """ + d: Int + @test(value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } input InputB From f9220f3a84014283fc5be8e8dfe56f5b16e0882a Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 21:01:01 +0400 Subject: [PATCH 10/22] `ARGUMENT_DEFINITION` support. --- src/Utils/SchemaPrinter.php | 70 ++++++++++++++++++------------- tests/Utils/SchemaPrinterTest.php | 54 +++++++++++++++++++++++- 2 files changed, 94 insertions(+), 30 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 71755bf41..6a3b7cc90 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -268,37 +268,51 @@ protected static function printDescriptionWithComments(string $description, stri */ protected static function printArgs(array $options, array $args, string $indentation = ''): string { + // Empty? if (count($args) === 0) { return ''; } - // If every arg does not have a description, print them on one line. - if ( - Utils::every( - $args, - static function ($arg): bool { - return strlen($arg->description ?? '') === 0; - } - ) - ) { - return '(' . implode(', ', array_map('static::printInputValue', $args)) . ')'; - } - - return sprintf( - "(\n%s\n%s)", - implode( - "\n", - array_map( - static function (FieldArgument $arg, int $i) use ($indentation, $options): string { - return static::printDescription($options, $arg, ' ' . $indentation, $i === 0) . ' ' . $indentation . - static::printInputValue($arg); - }, - $args, - array_keys($args) - ) - ), - $indentation - ); + // Print arguments + $length = 0; + $arguments = []; + $description = false; + + foreach ($args as $i => $arg) { + $value = static::printArg($arg, $options, ' ' . $indentation, $i === 0); + $length = $length + mb_strlen($value); + $description = $description || mb_strlen($arg->description ?? '') > 0; + $arguments[] = $value; + } + + // Multiline? + $serialized = ''; + + if ($length > static::LINE_LENGTH || $description) { + $serialized = "(\n" . implode("\n", $arguments) . "\n{$indentation})"; + } else { + $serialized = '(' . implode(', ', array_map('trim', $arguments)) . ')'; + } + + return $serialized; + } + + /** + * @param array $options + * @phpstan-param Options $options + */ + protected static function printArg(FieldArgument $type, array $options, string $indentation = '', bool $firstInBlock = true): string + { + $field = static::printDescription($options, $type, $indentation, $firstInBlock) . + $indentation . + static::printInputValue($type) . + static::printTypeDirectives($type, $options, $indentation); + + if (!$firstInBlock && mb_strlen($field) > static::LINE_LENGTH) { + $field = "\n".ltrim($field, "\n"); + } + + return $field; } /** @@ -536,7 +550,7 @@ protected static function printBlock(array $items): string } /** - * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition|UnionType|InputObjectType|InputObjectField $type + * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition|UnionType|InputObjectType|InputObjectField|FieldArgument $type * @param array $options * @phpstan-param Options $options */ diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index db5041037..3487cb2f8 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1281,7 +1281,7 @@ public function testPrintDirectives(): void { $text = str_pad('a', 80, 'a'); $schema = /** @lang GraphQL */ << Date: Sat, 30 Oct 2021 21:51:52 +0400 Subject: [PATCH 11/22] Code cleanup. --- src/Utils/SchemaPrinter.php | 42 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 6a3b7cc90..63b6ac31d 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -36,6 +36,7 @@ use function explode; use function implode; use function is_callable; +use function is_string; use function ksort; use function ltrim; use function mb_strlen; @@ -238,7 +239,7 @@ protected static function printDescription(array $options, $def, string $indenta return static::printDescriptionWithComments($description, $indentation, $firstInBlock); } - $preferMultipleLines = mb_strlen($description) > static::LINE_LENGTH; + $preferMultipleLines = static::isMultiline($description); $blockString = BlockString::print($description, '', $preferMultipleLines); $prefix = $indentation !== '' && ! $firstInBlock ? "\n" . $indentation @@ -288,7 +289,7 @@ protected static function printArgs(array $options, array $args, string $indenta // Multiline? $serialized = ''; - if ($length > static::LINE_LENGTH || $description) { + if ($description || static::isMultiline($length)) { $serialized = "(\n" . implode("\n", $arguments) . "\n{$indentation})"; } else { $serialized = '(' . implode(', ', array_map('trim', $arguments)) . ')'; @@ -307,10 +308,7 @@ protected static function printArg(FieldArgument $type, array $options, string $ $indentation . static::printInputValue($type) . static::printTypeDirectives($type, $options, $indentation); - - if (!$firstInBlock && mb_strlen($field) > static::LINE_LENGTH) { - $field = "\n".ltrim($field, "\n"); - } + $field = static::printLine($field, $firstInBlock); return $field; } @@ -384,10 +382,7 @@ protected static function printField(FieldDefinition $type, array $options, stri ': ' . (string) $type->getType() . static::printTypeDirectives($type, $options, $indentation); - - if (!$firstInBlock && mb_strlen($field) > static::LINE_LENGTH) { - $field = "\n".ltrim($field, "\n"); - } + $field = static::printLine($field, $firstInBlock); return $field; } @@ -492,10 +487,7 @@ protected static function printEnumValue(EnumValueDefinition $type, array $optio ' ' . $type->name . static::printTypeDirectives($type, $options, $indentation); - - if (!$firstInBlock && mb_strlen($value) > static::LINE_LENGTH) { - $value = "\n".ltrim($value, "\n"); - } + $value = static::printLine($value, $firstInBlock); return $value; } @@ -531,10 +523,7 @@ protected static function printInputObjectField(InputObjectField $type, array $o ' ' . static::printInputValue($type) . static::printTypeDirectives($type, $options, $indentation); - - if (!$firstInBlock && mb_strlen($field) > static::LINE_LENGTH) { - $field = "\n".ltrim($field, "\n"); - } + $field = static::printLine($field, $firstInBlock); return $field; } @@ -599,7 +588,7 @@ protected static function printTypeDirectives($type, array $options, string $ind $serialized = ''; if ($directives) { - $delimiter = $length > static::LINE_LENGTH ? "\n{$indentation}" : ' '; + $delimiter = static::isMultiline($length) ? "\n{$indentation}" : ' '; $serialized = $delimiter.implode($delimiter, $directives); } @@ -615,4 +604,19 @@ protected static function printTypeDirective(DirectiveNode $directive, array $op { return Printer::doPrint($directive); } + + protected static function printLine(string $string, bool $firstInBlock = true): string { + if (!$firstInBlock && static::isMultiline($string)) { + $string = "\n".ltrim($string, "\n"); + } + + return $string; + } + + /** + * @param string|int $string + */ + protected static function isMultiline($string): bool { + return (is_string($string) ? mb_strlen($string) : $string) > static::LINE_LENGTH; + } } From d521d1bd8754ee9deb4ce0a5ce5a7a6952a80767 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 23:05:10 +0400 Subject: [PATCH 12/22] Refactored how lines combined into block of text. --- src/Utils/SchemaPrinter.php | 85 +++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 63b6ac31d..7de1394f3 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -31,6 +31,7 @@ use function array_filter; use function array_keys; use function array_map; +use function array_sum; use function array_values; use function count; use function explode; @@ -40,6 +41,7 @@ use function ksort; use function ltrim; use function mb_strlen; +use function mb_strpos; use function self; use function sprintf; use function str_replace; @@ -239,7 +241,7 @@ protected static function printDescription(array $options, $def, string $indenta return static::printDescriptionWithComments($description, $indentation, $firstInBlock); } - $preferMultipleLines = static::isMultiline($description); + $preferMultipleLines = static::isLineTooLong($description); $blockString = BlockString::print($description, '', $preferMultipleLines); $prefix = $indentation !== '' && ! $firstInBlock ? "\n" . $indentation @@ -286,16 +288,8 @@ protected static function printArgs(array $options, array $args, string $indenta $arguments[] = $value; } - // Multiline? - $serialized = ''; - - if ($description || static::isMultiline($length)) { - $serialized = "(\n" . implode("\n", $arguments) . "\n{$indentation})"; - } else { - $serialized = '(' . implode(', ', array_map('trim', $arguments)) . ')'; - } - - return $serialized; + // Return + return static::printLines($arguments, '(', ')', $description || static::isLineTooLong($length), $indentation); } /** @@ -304,13 +298,10 @@ protected static function printArgs(array $options, array $args, string $indenta */ protected static function printArg(FieldArgument $type, array $options, string $indentation = '', bool $firstInBlock = true): string { - $field = static::printDescription($options, $type, $indentation, $firstInBlock) . + return static::printDescription($options, $type, $indentation, $firstInBlock) . $indentation . static::printInputValue($type) . static::printTypeDirectives($type, $options, $indentation); - $field = static::printLine($field, $firstInBlock); - - return $field; } /** @@ -375,16 +366,13 @@ static function (FieldDefinition $f, int $i) use ($options): string { */ protected static function printField(FieldDefinition $type, array $options, string $indentation = '', bool $firstInBlock = true): string { - $field = static::printDescription($options, $type, $indentation, $firstInBlock) . + return static::printDescription($options, $type, $indentation, $firstInBlock) . ' ' . $type->name . static::printArgs($options, $type->args, ' ') . ': ' . (string) $type->getType() . static::printTypeDirectives($type, $options, $indentation); - $field = static::printLine($field, $firstInBlock); - - return $field; } /** @@ -483,13 +471,10 @@ static function (EnumValueDefinition $value, int $i) use ($options): string { */ protected static function printEnumValue(EnumValueDefinition $type, array $options, string $indentation = '', bool $firstInBlock = false): string { - $value = static::printDescription($options, $type, $indentation, $firstInBlock) . + return static::printDescription($options, $type, $indentation, $firstInBlock) . ' ' . $type->name . static::printTypeDirectives($type, $options, $indentation); - $value = static::printLine($value, $firstInBlock); - - return $value; } /** @@ -519,13 +504,10 @@ static function (InputObjectField $f, $i) use ($options): string { */ protected static function printInputObjectField(InputObjectField $type, array $options, string $indentation = '', bool $firstInBlock = true): string { - $field = static::printDescription($options, $type, $indentation, $firstInBlock) . + return static::printDescription($options, $type, $indentation, $firstInBlock) . ' ' . static::printInputValue($type) . static::printTypeDirectives($type, $options, $indentation); - $field = static::printLine($field, $firstInBlock); - - return $field; } /** @@ -533,9 +515,7 @@ protected static function printInputObjectField(InputObjectField $type, array $o */ protected static function printBlock(array $items): string { - return count($items) > 0 - ? " {\n" . implode("\n", $items) . "\n}" - : ''; + return static::printLines($items, ' {', '}', true); } /** @@ -588,7 +568,7 @@ protected static function printTypeDirectives($type, array $options, string $ind $serialized = ''; if ($directives) { - $delimiter = static::isMultiline($length) ? "\n{$indentation}" : ' '; + $delimiter = static::isLineTooLong($length) ? "\n{$indentation}" : ' '; $serialized = $delimiter.implode($delimiter, $directives); } @@ -605,18 +585,51 @@ protected static function printTypeDirective(DirectiveNode $directive, array $op return Printer::doPrint($directive); } - protected static function printLine(string $string, bool $firstInBlock = true): string { - if (!$firstInBlock && static::isMultiline($string)) { - $string = "\n".ltrim($string, "\n"); + /** + * @param array $lines + */ + protected static function printLines(array $lines, string $begin, string $end, bool $multiline, string $indentation = ''): string + { + $block = ''; + + if ($lines) { + $multiline = $multiline || static::isLineTooLong(array_sum(array_map('mb_strlen', $lines))); + + if ($multiline) { + $wrapped = false; + + for ($i = 0, $c = count($lines); $i < $c; $i++) { + // If line too long and contains LF we wrap it by empty lines + $line = trim($lines[$i], "\n"); + $wrap = static::isLineTooLong($line) || mb_strpos($line, "\n") !== false; + + if ($i === 0) { + $line = "\n{$line}"; + } + + if (($wrap && $i > 0) || $wrapped) { + $line = "\n{$line}"; + } + + $block .= "{$line}\n"; + $wrapped = $wrap; + } + + $block .= $indentation; + } else { + $block = implode(', ', array_map('trim', $lines)); + } + + $block = $begin.$block.$end; } - return $string; + return $block; } /** * @param string|int $string */ - protected static function isMultiline($string): bool { + protected static function isLineTooLong($string): bool { return (is_string($string) ? mb_strlen($string) : $string) > static::LINE_LENGTH; } } From af9d6c382550c823713288c5172326b51786faec Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 30 Oct 2021 23:30:20 +0400 Subject: [PATCH 13/22] Long directives arguments will be split to multiple lines. --- src/Utils/SchemaPrinter.php | 30 +++++++++-- tests/Utils/SchemaPrinterTest.php | 82 +++++++++++++++++++++++-------- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 7de1394f3..6c7079fd7 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -6,6 +6,7 @@ use Closure; use GraphQL\Error\Error; +use GraphQL\Language\AST\ArgumentNode; use GraphQL\Language\AST\DirectiveNode; use GraphQL\Language\AST\EnumTypeDefinitionNode; use GraphQL\Language\AST\EnumValueDefinitionNode; @@ -582,26 +583,45 @@ protected static function printTypeDirectives($type, array $options, string $ind */ protected static function printTypeDirective(DirectiveNode $directive, array $options, string $indentation): string { - return Printer::doPrint($directive); + $length = 0; + $arguments = []; + + foreach ($directive->arguments as $argument) { + $value = static::printArgument($argument, $options, ' '.$indentation); + $length = $length + mb_strlen($value); + $arguments[] = $value; + } + + return "@{$directive->name->value}" . + static::printLines($arguments, '(', ')', static::isLineTooLong($length), $indentation); + } + + /** + * @param array $options + * @phpstan-param Options $options + */ + protected static function printArgument(ArgumentNode $argument, array $options, string $indentation): string + { + return "{$indentation}{$argument->name->value}: " . Printer::doPrint($argument->value); } /** * @param array $lines */ - protected static function printLines(array $lines, string $begin, string $end, bool $multiline, string $indentation = ''): string + protected static function printLines(array $lines, string $begin, string $end, bool $forceMultiline, string $indentation = ''): string { $block = ''; if ($lines) { - $multiline = $multiline || static::isLineTooLong(array_sum(array_map('mb_strlen', $lines))); + $forceMultiline = $forceMultiline || static::isLineTooLong(array_sum(array_map('mb_strlen', $lines))); - if ($multiline) { + if ($forceMultiline) { $wrapped = false; for ($i = 0, $c = count($lines); $i < $c; $i++) { // If line too long and contains LF we wrap it by empty lines $line = trim($lines[$i], "\n"); - $wrap = static::isLineTooLong($line) || mb_strpos($line, "\n") !== false; + $wrap = mb_strpos($line, "\n") !== false; if ($i === 0) { $line = "\n{$line}"; diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 3487cb2f8..fcbfceae6 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1282,6 +1282,7 @@ public function testPrintDirectives(): void { $schema = /** @lang GraphQL */ << Date: Sat, 30 Oct 2021 23:44:53 +0400 Subject: [PATCH 14/22] Long list passed to directive will be split to multiple lines. --- src/Utils/SchemaPrinter.php | 22 +++++++++++++++++++++- tests/Utils/SchemaPrinterTest.php | 13 +++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 6c7079fd7..48b5015b4 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -10,7 +10,10 @@ use GraphQL\Language\AST\DirectiveNode; use GraphQL\Language\AST\EnumTypeDefinitionNode; use GraphQL\Language\AST\EnumValueDefinitionNode; +use GraphQL\Language\AST\ListValueNode; +use GraphQL\Language\AST\Node; use GraphQL\Language\AST\ScalarTypeDefinitionNode; +use GraphQL\Language\AST\ValueNode; use GraphQL\Language\BlockString; use GraphQL\Language\Printer; use GraphQL\Type\Definition\Directive; @@ -602,7 +605,24 @@ protected static function printTypeDirective(DirectiveNode $directive, array $op */ protected static function printArgument(ArgumentNode $argument, array $options, string $indentation): string { - return "{$indentation}{$argument->name->value}: " . Printer::doPrint($argument->value); + $value = $argument->value; + + if ($value instanceof ListValueNode) { + $length = 0; + $values = []; + + foreach ($value->values as $item) { + $string = ' ' . $indentation . Printer::doPrint($item); + $length = $length + mb_strlen($string); + $values[] = $string; + } + + $value = static::printLines($values, '[', ']', static::isLineTooLong($length), $indentation); + } else { + $value = Printer::doPrint($value); + } + + return "{$indentation}{$argument->name->value}: {$value}"; } /** diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index fcbfceae6..f6de86bdf 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1281,6 +1281,7 @@ public function testPrintDirectives(): void { $text = str_pad('a', 80, 'a'); $schema = /** @lang GraphQL */ << Date: Sat, 30 Oct 2021 23:50:53 +0400 Subject: [PATCH 15/22] phpstan fixes. --- src/Utils/SchemaPrinter.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 48b5015b4..1c0f6676a 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -46,7 +46,6 @@ use function ltrim; use function mb_strlen; use function mb_strpos; -use function self; use function sprintf; use function str_replace; use function strlen; @@ -531,7 +530,7 @@ protected static function printTypeDirectives($type, array $options, string $ind // Enabled? $filter = $options['printDirectives'] ?? null; - if (!$filter || !is_callable($filter)) { + if (!is_callable($filter)) { if ($type instanceof EnumValueDefinition || $type instanceof FieldDefinition) { return static::printDeprecated($type); } @@ -542,12 +541,11 @@ protected static function printTypeDirectives($type, array $options, string $ind // AST Node available and has directives? $node = $type->astNode; - if (!$node) { + if ($node === null) { return ''; } // Print - /** @var array $directives */ $length = 0; $directives = []; @@ -562,7 +560,7 @@ protected static function printTypeDirectives($type, array $options, string $ind // empty } - if ($string) { + if ($string !== null) { $length = $length + mb_strlen($string); $directives[] = $string; } @@ -571,7 +569,7 @@ protected static function printTypeDirectives($type, array $options, string $ind // Multiline? $serialized = ''; - if ($directives) { + if (count($directives) > 0) { $delimiter = static::isLineTooLong($length) ? "\n{$indentation}" : ' '; $serialized = $delimiter.implode($delimiter, $directives); } @@ -632,7 +630,7 @@ protected static function printLines(array $lines, string $begin, string $end, b { $block = ''; - if ($lines) { + if (count($lines) > 0) { $forceMultiline = $forceMultiline || static::isLineTooLong(array_sum(array_map('mb_strlen', $lines))); if ($forceMultiline) { From 7b2c03b382a2d430fd35ca316d33782820ac2fe3 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:34:39 +0400 Subject: [PATCH 16/22] `@deprecated` multiline support. --- src/Utils/SchemaPrinter.php | 60 +++++++++++++++++++++---------- tests/Utils/SchemaPrinterTest.php | 47 ++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 21 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 1c0f6676a..b513c3f35 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -15,6 +15,7 @@ use GraphQL\Language\AST\ScalarTypeDefinitionNode; use GraphQL\Language\AST\ValueNode; use GraphQL\Language\BlockString; +use GraphQL\Language\Parser; use GraphQL\Language\Printer; use GraphQL\Type\Definition\Directive; use GraphQL\Type\Definition\EnumType; @@ -42,6 +43,7 @@ use function implode; use function is_callable; use function is_string; +use function json_encode; use function ksort; use function ltrim; use function mb_strlen; @@ -383,12 +385,12 @@ protected static function printField(FieldDefinition $type, array $options, stri */ protected static function printDeprecated($fieldOrEnumVal): string { - $reason = $fieldOrEnumVal->deprecationReason; + $reason = static::getDeprecatedReason($fieldOrEnumVal); if ($reason === null) { return ''; } - if ($reason === '' || $reason === Directive::DEFAULT_DEPRECATION_REASON) { + if ($reason === '') { return ' @deprecated'; } @@ -529,19 +531,32 @@ protected static function printBlock(array $items): string protected static function printTypeDirectives($type, array $options, string $indentation = ''): string { // Enabled? $filter = $options['printDirectives'] ?? null; + $deprecatable = $type instanceof EnumValueDefinition || $type instanceof FieldDefinition; if (!is_callable($filter)) { - if ($type instanceof EnumValueDefinition || $type instanceof FieldDefinition) { + if ($deprecatable) { return static::printDeprecated($type); } return ''; } - // AST Node available and has directives? + // Collect directives $node = $type->astNode; + $nodeDirectives = []; + + if ($node !== null) { + $nodeDirectives = $node->directives; + } elseif ($deprecatable && $type->deprecationReason !== null) { + // TODO Is there a better way to create directive node? + $name = Directive::DEPRECATED_NAME; + $reason = json_encode(static::getDeprecatedReason($type)); + $nodeDirectives[] = Parser::directive("@{$name}(reason: {$reason})"); + } else { + // empty + } - if ($node === null) { + if (count($nodeDirectives) === 0) { return ''; } @@ -549,21 +564,14 @@ protected static function printTypeDirectives($type, array $options, string $ind $length = 0; $directives = []; - foreach ($node->directives as $directive) { - $string = null; - - if ($directive->name === Directive::DEPRECATED_NAME && ($type instanceof EnumValueDefinition)) { - $string = static::printDeprecated($type); - } elseif ($filter($directive)) { - $string = static::printTypeDirective($directive, $options, $indentation); - } else { - // empty + foreach ($nodeDirectives as $nodeDirective) { + if (!$filter($nodeDirective)) { + continue; } - if ($string !== null) { - $length = $length + mb_strlen($string); - $directives[] = $string; - } + $directive = static::printTypeDirective($nodeDirective, $options, $indentation); + $length = $length + mb_strlen($directive); + $directives[] = $directive; } // Multiline? @@ -637,7 +645,7 @@ protected static function printLines(array $lines, string $begin, string $end, b $wrapped = false; for ($i = 0, $c = count($lines); $i < $c; $i++) { - // If line too long and contains LF we wrap it by empty lines + // If line contains LF we wrap it by empty lines $line = trim($lines[$i], "\n"); $wrap = mb_strpos($line, "\n") !== false; @@ -670,4 +678,18 @@ protected static function printLines(array $lines, string $begin, string $end, b protected static function isLineTooLong($string): bool { return (is_string($string) ? mb_strlen($string) : $string) > static::LINE_LENGTH; } + + /** + * @param FieldDefinition|EnumValueDefinition $fieldOrEnumVal + */ + protected static function getDeprecatedReason($fieldOrEnumVal): ?string + { + $reason = $fieldOrEnumVal->deprecationReason; + + if ($reason === '' || $reason === Directive::DEFAULT_DEPRECATION_REASON) { + $reason = ''; + } + + return $reason; + } } diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index f6de86bdf..bcb071183 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1277,7 +1277,7 @@ enum __TypeKind { self::assertEquals($expected, $output); } - public function testPrintDirectives(): void { + public function testPrintDirectivesAst(): void { $text = str_pad('a', 80, 'a'); $schema = /** @lang GraphQL */ << 'Aaa', + 'values' => [ + 'A' => [ + 'value' => 'AAA', + 'description' => 'AAAAAAAAAAAAA', + 'deprecationReason' => 'deprecated for tests' + ], + 'B' => [ + 'value' => 'AAA', + 'deprecationReason' => $text + ], + ] + ]); + $schema = new Schema(['types' => [$enum]]); + $actual = SchemaPrinter::doPrint($schema, [ + 'printDirectives' => static function(): bool { + return true; + }, + ]); + + self::assertEquals( + <<<'GRAPHQL' + enum Aaa { + """AAAAAAAAAAAAA""" + A @deprecated(reason: "deprecated for tests") + + B + @deprecated( + reason: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ) + } + + GRAPHQL, + $actual + ); + } } From 093c9bc75480fd188ae40dbd3c9bc17f742b98ac Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:50:06 +0400 Subject: [PATCH 17/22] Long list used for input fields or args will be split to multiple lines. --- src/Utils/SchemaPrinter.php | 35 ++++++++++++++++++++++++------- tests/Utils/SchemaPrinterTest.php | 16 ++++++++++---- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index b513c3f35..f5daa27ac 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -7,12 +7,19 @@ use Closure; use GraphQL\Error\Error; use GraphQL\Language\AST\ArgumentNode; +use GraphQL\Language\AST\BooleanValueNode; use GraphQL\Language\AST\DirectiveNode; use GraphQL\Language\AST\EnumTypeDefinitionNode; use GraphQL\Language\AST\EnumValueDefinitionNode; +use GraphQL\Language\AST\EnumValueNode; +use GraphQL\Language\AST\FloatValueNode; +use GraphQL\Language\AST\IntValueNode; use GraphQL\Language\AST\ListValueNode; use GraphQL\Language\AST\Node; +use GraphQL\Language\AST\NullValueNode; +use GraphQL\Language\AST\ObjectValueNode; use GraphQL\Language\AST\ScalarTypeDefinitionNode; +use GraphQL\Language\AST\StringValueNode; use GraphQL\Language\AST\ValueNode; use GraphQL\Language\BlockString; use GraphQL\Language\Parser; @@ -316,7 +323,10 @@ protected static function printInputValue($arg): string { $argDecl = $arg->name . ': ' . (string) $arg->getType(); if ($arg->defaultValueExists()) { - $argDecl .= ' = ' . Printer::doPrint(AST::astFromValue($arg->defaultValue, $arg->getType())); + // TODO Pass `options`. + $value = AST::astFromValue($arg->defaultValue, $arg->getType()); + $indentation = $arg instanceof InputObjectField ? ' ' : ' '; + $argDecl .= ' = ' . static::printValue($value, [], $indentation); } return $argDecl; @@ -611,24 +621,35 @@ protected static function printTypeDirective(DirectiveNode $directive, array $op */ protected static function printArgument(ArgumentNode $argument, array $options, string $indentation): string { - $value = $argument->value; + return "{$indentation}{$argument->name->value}: " . + self::printValue($argument->value, $options, $indentation); + } + + /** + * @param ObjectValueNode|ListValueNode|BooleanValueNode|IntValueNode|FloatValueNode|EnumValueNode|StringValueNode|NullValueNode|null $value + * @param array $options + * @phpstan-param Options $options + */ + protected static function printValue($value, array $options, string $indentation): string + { + $result = ''; if ($value instanceof ListValueNode) { $length = 0; $values = []; foreach ($value->values as $item) { - $string = ' ' . $indentation . Printer::doPrint($item); - $length = $length + mb_strlen($string); + $string = ' '.$indentation.Printer::doPrint($item); + $length = $length + mb_strlen($string); $values[] = $string; } - $value = static::printLines($values, '[', ']', static::isLineTooLong($length), $indentation); + $result = static::printLines($values, '[', ']', static::isLineTooLong($length), $indentation); } else { - $value = Printer::doPrint($value); + $result = Printer::doPrint($value); } - return "{$indentation}{$argument->name->value}: {$value}"; + return $result; } /** diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index bcb071183..907cd2429 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -1352,12 +1352,12 @@ interface InterfaceB implements InterfaceA @test(value: "{$text}") { } input InputB @test(value: "{$text}") { - a: ID + a: [String] = ["{$text}", "{$text}", "{$text}"] } type Query { a(a: String, b: String, c: String): Boolean @test - b("desc" a: String): Boolean @test(value: "{$text}") + b("desc" a: [String] = ["{$text}", "{$text}", "{$text}"]): Boolean @test(value: "{$text}") c(a: String @test(value: "{$text}")): Boolean d( a: String @test @@ -1441,7 +1441,11 @@ enum EnumB @test( value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) { - a: ID + a: [String] = [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ] } interface InterfaceA @test { @@ -1479,7 +1483,11 @@ interface InterfaceB implements InterfaceA b( """desc""" - a: String + a: [String] = [ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ] ): Boolean @test( value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" From c046687f1e80842a49934f2e4a40ad27f3f94cd5 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sun, 31 Oct 2021 11:00:50 +0400 Subject: [PATCH 18/22] Renames. --- src/Utils/SchemaPrinter.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index f5daa27ac..095c595e6 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -301,7 +301,7 @@ protected static function printArgs(array $options, array $args, string $indenta } // Return - return static::printLines($arguments, '(', ')', $description || static::isLineTooLong($length), $indentation); + return static::printChildrenBlock($arguments, '(', ')', $description || static::isLineTooLong($length), $indentation); } /** @@ -448,7 +448,7 @@ protected static function printUnion(UnionType $type, array $options): string : ''; $directives = static::printTypeDirectives($type, $options, ''); - if (mb_strlen($directives) > static::LINE_LENGTH) { + if (static::isLineTooLong($directives)) { $types = ltrim($types); $directives .= "\n"; } @@ -530,7 +530,8 @@ protected static function printInputObjectField(InputObjectField $type, array $o */ protected static function printBlock(array $items): string { - return static::printLines($items, ' {', '}', true); + // TODO Deprecated? + return static::printChildrenBlock($items, ' {', '}', true); } /** @@ -612,7 +613,7 @@ protected static function printTypeDirective(DirectiveNode $directive, array $op } return "@{$directive->name->value}" . - static::printLines($arguments, '(', ')', static::isLineTooLong($length), $indentation); + static::printChildrenBlock($arguments, '(', ')', static::isLineTooLong($length), $indentation); } /** @@ -644,7 +645,7 @@ protected static function printValue($value, array $options, string $indentation $values[] = $string; } - $result = static::printLines($values, '[', ']', static::isLineTooLong($length), $indentation); + $result = static::printChildrenBlock($values, '[', ']', static::isLineTooLong($length), $indentation); } else { $result = Printer::doPrint($value); } @@ -655,7 +656,7 @@ protected static function printValue($value, array $options, string $indentation /** * @param array $lines */ - protected static function printLines(array $lines, string $begin, string $end, bool $forceMultiline, string $indentation = ''): string + protected static function printChildrenBlock(array $lines, string $begin, string $end, bool $forceMultiline, string $indentation = ''): string { $block = ''; From 3d4ceaa5547d915cd6cf21e5925f9a99bab70e9b Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sun, 31 Oct 2021 11:03:42 +0400 Subject: [PATCH 19/22] Code style. --- src/Utils/SchemaPrinter.php | 78 +++++++++++++++---------------- tests/Utils/SchemaPrinterTest.php | 29 ++++++------ 2 files changed, 52 insertions(+), 55 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 095c595e6..f6a95763d 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -4,23 +4,17 @@ namespace GraphQL\Utils; -use Closure; use GraphQL\Error\Error; use GraphQL\Language\AST\ArgumentNode; use GraphQL\Language\AST\BooleanValueNode; use GraphQL\Language\AST\DirectiveNode; -use GraphQL\Language\AST\EnumTypeDefinitionNode; -use GraphQL\Language\AST\EnumValueDefinitionNode; use GraphQL\Language\AST\EnumValueNode; use GraphQL\Language\AST\FloatValueNode; use GraphQL\Language\AST\IntValueNode; use GraphQL\Language\AST\ListValueNode; -use GraphQL\Language\AST\Node; use GraphQL\Language\AST\NullValueNode; use GraphQL\Language\AST\ObjectValueNode; -use GraphQL\Language\AST\ScalarTypeDefinitionNode; use GraphQL\Language\AST\StringValueNode; -use GraphQL\Language\AST\ValueNode; use GraphQL\Language\BlockString; use GraphQL\Language\Parser; use GraphQL\Language\Printer; @@ -57,7 +51,7 @@ use function mb_strpos; use function sprintf; use function str_replace; -use function strlen; +use function trim; /** * Prints the contents of a Schema in schema definition language. @@ -289,13 +283,13 @@ protected static function printArgs(array $options, array $args, string $indenta } // Print arguments - $length = 0; - $arguments = []; + $length = 0; + $arguments = []; $description = false; foreach ($args as $i => $arg) { - $value = static::printArg($arg, $options, ' ' . $indentation, $i === 0); - $length = $length + mb_strlen($value); + $value = static::printArg($arg, $options, ' ' . $indentation, $i === 0); + $length += mb_strlen($value); $description = $description || mb_strlen($arg->description ?? '') > 0; $arguments[] = $value; } @@ -324,9 +318,9 @@ protected static function printInputValue($arg): string $argDecl = $arg->name . ': ' . (string) $arg->getType(); if ($arg->defaultValueExists()) { // TODO Pass `options`. - $value = AST::astFromValue($arg->defaultValue, $arg->getType()); + $value = AST::astFromValue($arg->defaultValue, $arg->getType()); $indentation = $arg instanceof InputObjectField ? ' ' : ' '; - $argDecl .= ' = ' . static::printValue($value, [], $indentation); + $argDecl .= ' = ' . static::printValue($value, [], $indentation); } return $argDecl; @@ -442,14 +436,14 @@ protected static function printInterface(InterfaceType $type, array $options): s */ protected static function printUnion(UnionType $type, array $options): string { - $types = $type->getTypes(); - $types = count($types) > 0 + $types = $type->getTypes(); + $types = count($types) > 0 ? ' = ' . implode(' | ', $types) : ''; $directives = static::printTypeDirectives($type, $options, ''); if (static::isLineTooLong($directives)) { - $types = ltrim($types); + $types = ltrim($types); $directives .= "\n"; } @@ -536,15 +530,16 @@ protected static function printBlock(array $items): string /** * @param Type|EnumValueDefinition|EnumType|InterfaceType|FieldDefinition|UnionType|InputObjectType|InputObjectField|FieldArgument $type - * @param array $options + * @param array $options * @phpstan-param Options $options */ - protected static function printTypeDirectives($type, array $options, string $indentation = ''): string { + protected static function printTypeDirectives($type, array $options, string $indentation = ''): string + { // Enabled? - $filter = $options['printDirectives'] ?? null; + $filter = $options['printDirectives'] ?? null; $deprecatable = $type instanceof EnumValueDefinition || $type instanceof FieldDefinition; - if (!is_callable($filter)) { + if (! is_callable($filter)) { if ($deprecatable) { return static::printDeprecated($type); } @@ -553,18 +548,16 @@ protected static function printTypeDirectives($type, array $options, string $ind } // Collect directives - $node = $type->astNode; + $node = $type->astNode; $nodeDirectives = []; if ($node !== null) { $nodeDirectives = $node->directives; } elseif ($deprecatable && $type->deprecationReason !== null) { // TODO Is there a better way to create directive node? - $name = Directive::DEPRECATED_NAME; - $reason = json_encode(static::getDeprecatedReason($type)); + $name = Directive::DEPRECATED_NAME; + $reason = json_encode(static::getDeprecatedReason($type)); $nodeDirectives[] = Parser::directive("@{$name}(reason: {$reason})"); - } else { - // empty } if (count($nodeDirectives) === 0) { @@ -572,16 +565,16 @@ protected static function printTypeDirectives($type, array $options, string $ind } // Print - $length = 0; + $length = 0; $directives = []; foreach ($nodeDirectives as $nodeDirective) { - if (!$filter($nodeDirective)) { + if (! $filter($nodeDirective)) { continue; } - $directive = static::printTypeDirective($nodeDirective, $options, $indentation); - $length = $length + mb_strlen($directive); + $directive = static::printTypeDirective($nodeDirective, $options, $indentation); + $length += mb_strlen($directive); $directives[] = $directive; } @@ -589,8 +582,10 @@ protected static function printTypeDirectives($type, array $options, string $ind $serialized = ''; if (count($directives) > 0) { - $delimiter = static::isLineTooLong($length) ? "\n{$indentation}" : ' '; - $serialized = $delimiter.implode($delimiter, $directives); + $delimiter = static::isLineTooLong($length) + ? "\n{$indentation}" + : ' '; + $serialized = $delimiter . implode($delimiter, $directives); } // Return @@ -603,12 +598,12 @@ protected static function printTypeDirectives($type, array $options, string $ind */ protected static function printTypeDirective(DirectiveNode $directive, array $options, string $indentation): string { - $length = 0; + $length = 0; $arguments = []; foreach ($directive->arguments as $argument) { - $value = static::printArgument($argument, $options, ' '.$indentation); - $length = $length + mb_strlen($value); + $value = static::printArgument($argument, $options, ' ' . $indentation); + $length += mb_strlen($value); $arguments[] = $value; } @@ -628,7 +623,7 @@ protected static function printArgument(ArgumentNode $argument, array $options, /** * @param ObjectValueNode|ListValueNode|BooleanValueNode|IntValueNode|FloatValueNode|EnumValueNode|StringValueNode|NullValueNode|null $value - * @param array $options + * @param array $options * @phpstan-param Options $options */ protected static function printValue($value, array $options, string $indentation): string @@ -640,8 +635,8 @@ protected static function printValue($value, array $options, string $indentation $values = []; foreach ($value->values as $item) { - $string = ' '.$indentation.Printer::doPrint($item); - $length = $length + mb_strlen($string); + $string = ' ' . $indentation . Printer::doPrint($item); + $length += mb_strlen($string); $values[] = $string; } @@ -679,7 +674,7 @@ protected static function printChildrenBlock(array $lines, string $begin, string $line = "\n{$line}"; } - $block .= "{$line}\n"; + $block .= "{$line}\n"; $wrapped = $wrap; } @@ -688,7 +683,7 @@ protected static function printChildrenBlock(array $lines, string $begin, string $block = implode(', ', array_map('trim', $lines)); } - $block = $begin.$block.$end; + $block = $begin . $block . $end; } return $block; @@ -697,8 +692,9 @@ protected static function printChildrenBlock(array $lines, string $begin, string /** * @param string|int $string */ - protected static function isLineTooLong($string): bool { - return (is_string($string) ? mb_strlen($string) : $string) > static::LINE_LENGTH; + protected static function isLineTooLong($string): bool + { + return (is_string($string) ? mb_strlen($string) : $string) > self::LINE_LENGTH; } /** diff --git a/tests/Utils/SchemaPrinterTest.php b/tests/Utils/SchemaPrinterTest.php index 907cd2429..a9603073e 100644 --- a/tests/Utils/SchemaPrinterTest.php +++ b/tests/Utils/SchemaPrinterTest.php @@ -6,7 +6,6 @@ use Generator; use GraphQL\Language\DirectiveLocation; -use GraphQL\Language\Parser; use GraphQL\Type\Definition\CustomScalarType; use GraphQL\Type\Definition\Directive; use GraphQL\Type\Definition\EnumType; @@ -1277,9 +1276,10 @@ enum __TypeKind { self::assertEquals($expected, $output); } - public function testPrintDirectivesAst(): void { - $text = str_pad('a', 80, 'a'); - $schema = /** @lang GraphQL */ << static function(): bool { + $actual = SchemaPrinter::doPrint(BuildSchema::build($schema), [ + 'printDirectives' => static function (): bool { return true; }, ]); @@ -1588,25 +1588,26 @@ interface InterfaceB implements InterfaceA self::assertEquals($expected, $actual); } - public function testPrintDirectivesDeprecated(): void { - $text = str_pad('a', 80, 'a'); - $enum = new EnumType([ + public function testPrintDirectivesDeprecated(): void + { + $text = str_pad('a', 80, 'a'); + $enum = new EnumType([ 'name' => 'Aaa', 'values' => [ 'A' => [ 'value' => 'AAA', 'description' => 'AAAAAAAAAAAAA', - 'deprecationReason' => 'deprecated for tests' + 'deprecationReason' => 'deprecated for tests', ], 'B' => [ 'value' => 'AAA', - 'deprecationReason' => $text + 'deprecationReason' => $text, ], - ] + ], ]); - $schema = new Schema(['types' => [$enum]]); + $schema = new Schema(['types' => [$enum]]); $actual = SchemaPrinter::doPrint($schema, [ - 'printDirectives' => static function(): bool { + 'printDirectives' => static function (): bool { return true; }, ]); From 2a359c00f3aba63a15113d08b7874a1cd0814dea Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sun, 31 Oct 2021 11:24:11 +0400 Subject: [PATCH 20/22] Tests fixes. --- tests/Utils/BuildSchemaTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Utils/BuildSchemaTest.php b/tests/Utils/BuildSchemaTest.php index 6823d1c72..626e74923 100644 --- a/tests/Utils/BuildSchemaTest.php +++ b/tests/Utils/BuildSchemaTest.php @@ -155,6 +155,7 @@ enum Color { """Not a creative color""" GREEN + BLUE } @@ -187,6 +188,7 @@ enum Color { # Not a creative color GREEN + BLUE } @@ -492,7 +494,7 @@ public function testCanBuildRecursiveUnion(): void { $schema = BuildSchema::build(' union Hello = Hello - + type Query { hello: Hello } @@ -758,7 +760,7 @@ interfaceField: String type TestType implements TestInterface { interfaceField: String } - + scalar TestScalar directive @test(arg: TestScalar) on FIELD From 7c7e24d03c7a2ab93d6666b28776e884f1df738e Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 6 Nov 2021 17:16:02 +0400 Subject: [PATCH 21/22] `SchemaPrinter::printChildrenBlock()` will not detect multiline. --- src/Utils/SchemaPrinter.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index f6a95763d..93322aa22 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -651,14 +651,12 @@ protected static function printValue($value, array $options, string $indentation /** * @param array $lines */ - protected static function printChildrenBlock(array $lines, string $begin, string $end, bool $forceMultiline, string $indentation = ''): string + protected static function printChildrenBlock(array $lines, string $begin, string $end, bool $multiline, string $indentation = ''): string { $block = ''; if (count($lines) > 0) { - $forceMultiline = $forceMultiline || static::isLineTooLong(array_sum(array_map('mb_strlen', $lines))); - - if ($forceMultiline) { + if ($multiline) { $wrapped = false; for ($i = 0, $c = count($lines); $i < $c; $i++) { From 5c51b1b19c16fa2b80d25ce4976c822c47eee5ea Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 20 Nov 2021 17:49:32 +0400 Subject: [PATCH 22/22] Code cleanup. --- src/Utils/SchemaPrinter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Utils/SchemaPrinter.php b/src/Utils/SchemaPrinter.php index 93322aa22..e1e3bd85c 100644 --- a/src/Utils/SchemaPrinter.php +++ b/src/Utils/SchemaPrinter.php @@ -37,7 +37,6 @@ use function array_filter; use function array_keys; use function array_map; -use function array_sum; use function array_values; use function count; use function explode;