diff --git a/composer.json b/composer.json
index 6145303..9679bbe 100644
--- a/composer.json
+++ b/composer.json
@@ -10,6 +10,7 @@
],
"require": {
"php": "^7.1",
+ "ext-json": "*",
"ext-mbstring": "*"
},
"require-dev": {
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 4be54dd..aba1cb2 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -90,4 +90,11 @@
/>
+
+
+
+
+
+
+
diff --git a/src/Language/AST/ArgumentNode.php b/src/Language/AST/ArgumentNode.php
index 3c942e7..1519429 100644
--- a/src/Language/AST/ArgumentNode.php
+++ b/src/Language/AST/ArgumentNode.php
@@ -1,17 +1,19 @@
start = $start;
- $tmp->end = $end;
+ $tmp->end = $end;
return $tmp;
}
- public function __construct(Token $startToken = null, Token $endToken = null, Source $source = null)
+ public function __construct(?Token $startToken = null, ?Token $endToken = null, ?Source $source = null)
{
$this->startToken = $startToken;
- $this->endToken = $endToken;
- $this->source = $source;
+ $this->endToken = $endToken;
+ $this->source = $source;
- if ($startToken && $endToken) {
- $this->start = $startToken->start;
- $this->end = $endToken->end;
+ if (! $startToken || ! $endToken) {
+ return;
}
+
+ $this->start = $startToken->start;
+ $this->end = $endToken->end;
}
}
diff --git a/src/Language/AST/NameNode.php b/src/Language/AST/NameNode.php
index 7860775..91f6d05 100644
--- a/src/Language/AST/NameNode.php
+++ b/src/Language/AST/NameNode.php
@@ -1,12 +1,15 @@
$arrValue) {
$cloned[$key] = $this->cloneValue($arrValue);
}
- } else if ($value instanceof Node) {
+ } elseif ($value instanceof self) {
$cloned = clone $value;
foreach (get_object_vars($cloned) as $prop => $propValue) {
$cloned->{$prop} = $this->cloneValue($propValue);
@@ -84,34 +88,34 @@ abstract class Node
public function __toString()
{
$tmp = $this->toArray(true);
+
return (string) json_encode($tmp);
}
/**
* @param bool $recursive
- * @return array
+ * @return mixed[]
*/
public function toArray($recursive = false)
{
if ($recursive) {
return $this->recursiveToArray($this);
- } else {
- $tmp = (array) $this;
-
- if ($this->loc) {
- $tmp['loc'] = [
- 'start' => $this->loc->start,
- 'end' => $this->loc->end
- ];
- }
-
- return $tmp;
}
+
+ $tmp = (array) $this;
+
+ if ($this->loc) {
+ $tmp['loc'] = [
+ 'start' => $this->loc->start,
+ 'end' => $this->loc->end,
+ ];
+ }
+
+ return $tmp;
}
/**
- * @param Node $node
- * @return array
+ * @return mixed[]
*/
private function recursiveToArray(Node $node)
{
@@ -122,25 +126,27 @@ abstract class Node
if ($node->loc) {
$result['loc'] = [
'start' => $node->loc->start,
- 'end' => $node->loc->end
+ 'end' => $node->loc->end,
];
}
foreach (get_object_vars($node) as $prop => $propValue) {
- if (isset($result[$prop]))
+ if (isset($result[$prop])) {
continue;
+ }
- if ($propValue === null)
+ if ($propValue === null) {
continue;
+ }
if (is_array($propValue) || $propValue instanceof NodeList) {
$tmp = [];
foreach ($propValue as $tmp1) {
$tmp[] = $tmp1 instanceof Node ? $this->recursiveToArray($tmp1) : (array) $tmp1;
}
- } else if ($propValue instanceof Node) {
+ } elseif ($propValue instanceof Node) {
$tmp = $this->recursiveToArray($propValue);
- } else if (is_scalar($propValue) || null === $propValue) {
+ } elseif (is_scalar($propValue) || $propValue === null) {
$tmp = $propValue;
} else {
$tmp = null;
@@ -148,6 +154,7 @@ abstract class Node
$result[$prop] = $tmp;
}
+
return $result;
}
}
diff --git a/src/Language/AST/NodeKind.php b/src/Language/AST/NodeKind.php
index 1091c6e..d321cdc 100644
--- a/src/Language/AST/NodeKind.php
+++ b/src/Language/AST/NodeKind.php
@@ -1,5 +1,7 @@
NameNode::class,
+ self::NAME => NameNode::class,
// Document
- NodeKind::DOCUMENT => DocumentNode::class,
- NodeKind::OPERATION_DEFINITION => OperationDefinitionNode::class,
- NodeKind::VARIABLE_DEFINITION => VariableDefinitionNode::class,
- NodeKind::VARIABLE => VariableNode::class,
- NodeKind::SELECTION_SET => SelectionSetNode::class,
- NodeKind::FIELD => FieldNode::class,
- NodeKind::ARGUMENT => ArgumentNode::class,
+ self::DOCUMENT => DocumentNode::class,
+ self::OPERATION_DEFINITION => OperationDefinitionNode::class,
+ self::VARIABLE_DEFINITION => VariableDefinitionNode::class,
+ self::VARIABLE => VariableNode::class,
+ self::SELECTION_SET => SelectionSetNode::class,
+ self::FIELD => FieldNode::class,
+ self::ARGUMENT => ArgumentNode::class,
// Fragments
- NodeKind::FRAGMENT_SPREAD => FragmentSpreadNode::class,
- NodeKind::INLINE_FRAGMENT => InlineFragmentNode::class,
- NodeKind::FRAGMENT_DEFINITION => FragmentDefinitionNode::class,
+ self::FRAGMENT_SPREAD => FragmentSpreadNode::class,
+ self::INLINE_FRAGMENT => InlineFragmentNode::class,
+ self::FRAGMENT_DEFINITION => FragmentDefinitionNode::class,
// Values
- NodeKind::INT => IntValueNode::class,
- NodeKind::FLOAT => FloatValueNode::class,
- NodeKind::STRING => StringValueNode::class,
- NodeKind::BOOLEAN => BooleanValueNode::class,
- NodeKind::ENUM => EnumValueNode::class,
- NodeKind::NULL => NullValueNode::class,
- NodeKind::LST => ListValueNode::class,
- NodeKind::OBJECT => ObjectValueNode::class,
- NodeKind::OBJECT_FIELD => ObjectFieldNode::class,
+ self::INT => IntValueNode::class,
+ self::FLOAT => FloatValueNode::class,
+ self::STRING => StringValueNode::class,
+ self::BOOLEAN => BooleanValueNode::class,
+ self::ENUM => EnumValueNode::class,
+ self::NULL => NullValueNode::class,
+ self::LST => ListValueNode::class,
+ self::OBJECT => ObjectValueNode::class,
+ self::OBJECT_FIELD => ObjectFieldNode::class,
// Directives
- NodeKind::DIRECTIVE => DirectiveNode::class,
+ self::DIRECTIVE => DirectiveNode::class,
// Types
- NodeKind::NAMED_TYPE => NamedTypeNode::class,
- NodeKind::LIST_TYPE => ListTypeNode::class,
- NodeKind::NON_NULL_TYPE => NonNullTypeNode::class,
+ self::NAMED_TYPE => NamedTypeNode::class,
+ self::LIST_TYPE => ListTypeNode::class,
+ self::NON_NULL_TYPE => NonNullTypeNode::class,
// Type System Definitions
- NodeKind::SCHEMA_DEFINITION => SchemaDefinitionNode::class,
- NodeKind::OPERATION_TYPE_DEFINITION => OperationTypeDefinitionNode::class,
+ self::SCHEMA_DEFINITION => SchemaDefinitionNode::class,
+ self::OPERATION_TYPE_DEFINITION => OperationTypeDefinitionNode::class,
// Type Definitions
- NodeKind::SCALAR_TYPE_DEFINITION => ScalarTypeDefinitionNode::class,
- NodeKind::OBJECT_TYPE_DEFINITION => ObjectTypeDefinitionNode::class,
- NodeKind::FIELD_DEFINITION => FieldDefinitionNode::class,
- NodeKind::INPUT_VALUE_DEFINITION => InputValueDefinitionNode::class,
- NodeKind::INTERFACE_TYPE_DEFINITION => InterfaceTypeDefinitionNode::class,
- NodeKind::UNION_TYPE_DEFINITION => UnionTypeDefinitionNode::class,
- NodeKind::ENUM_TYPE_DEFINITION => EnumTypeDefinitionNode::class,
- NodeKind::ENUM_VALUE_DEFINITION => EnumValueDefinitionNode::class,
- NodeKind::INPUT_OBJECT_TYPE_DEFINITION =>InputObjectTypeDefinitionNode::class,
+ self::SCALAR_TYPE_DEFINITION => ScalarTypeDefinitionNode::class,
+ self::OBJECT_TYPE_DEFINITION => ObjectTypeDefinitionNode::class,
+ self::FIELD_DEFINITION => FieldDefinitionNode::class,
+ self::INPUT_VALUE_DEFINITION => InputValueDefinitionNode::class,
+ self::INTERFACE_TYPE_DEFINITION => InterfaceTypeDefinitionNode::class,
+ self::UNION_TYPE_DEFINITION => UnionTypeDefinitionNode::class,
+ self::ENUM_TYPE_DEFINITION => EnumTypeDefinitionNode::class,
+ self::ENUM_VALUE_DEFINITION => EnumValueDefinitionNode::class,
+ self::INPUT_OBJECT_TYPE_DEFINITION => InputObjectTypeDefinitionNode::class,
// Type Extensions
- NodeKind::SCALAR_TYPE_EXTENSION => ScalarTypeExtensionNode::class,
- NodeKind::OBJECT_TYPE_EXTENSION => ObjectTypeExtensionNode::class,
- NodeKind::INTERFACE_TYPE_EXTENSION => InterfaceTypeExtensionNode::class,
- NodeKind::UNION_TYPE_EXTENSION => UnionTypeExtensionNode::class,
- NodeKind::ENUM_TYPE_EXTENSION => EnumTypeExtensionNode::class,
- NodeKind::INPUT_OBJECT_TYPE_EXTENSION => InputObjectTypeExtensionNode::class,
+ self::SCALAR_TYPE_EXTENSION => ScalarTypeExtensionNode::class,
+ self::OBJECT_TYPE_EXTENSION => ObjectTypeExtensionNode::class,
+ self::INTERFACE_TYPE_EXTENSION => InterfaceTypeExtensionNode::class,
+ self::UNION_TYPE_EXTENSION => UnionTypeExtensionNode::class,
+ self::ENUM_TYPE_EXTENSION => EnumTypeExtensionNode::class,
+ self::INPUT_OBJECT_TYPE_EXTENSION => InputObjectTypeExtensionNode::class,
// Directive Definitions
- NodeKind::DIRECTIVE_DEFINITION => DirectiveDefinitionNode::class
+ self::DIRECTIVE_DEFINITION => DirectiveDefinitionNode::class,
];
}
diff --git a/src/Language/AST/NodeList.php b/src/Language/AST/NodeList.php
index b0adb81..5028022 100644
--- a/src/Language/AST/NodeList.php
+++ b/src/Language/AST/NodeList.php
@@ -1,22 +1,22 @@
nodes;
}
return new NodeList(array_merge($this->nodes, $list));
diff --git a/src/Language/AST/NonNullTypeNode.php b/src/Language/AST/NonNullTypeNode.php
index e450404..da0ce3d 100644
--- a/src/Language/AST/NonNullTypeNode.php
+++ b/src/Language/AST/NonNullTypeNode.php
@@ -1,12 +1,15 @@
self::QUERY,
self::MUTATION => self::MUTATION,
diff --git a/src/Language/Lexer.php b/src/Language/Lexer.php
index 835b947..223b6f8 100644
--- a/src/Language/Lexer.php
+++ b/src/Language/Lexer.php
@@ -1,9 +1,16 @@
source = $source;
- $this->options = $options;
+ $this->source = $source;
+ $this->options = $options;
$this->lastToken = $startOfFileToken;
- $this->token = $startOfFileToken;
- $this->line = 1;
+ $this->token = $startOfFileToken;
+ $this->line = 1;
$this->lineStart = 0;
- $this->position = $this->byteStreamPosition = 0;
+ $this->position = $this->byteStreamPosition = 0;
}
/**
@@ -93,7 +93,8 @@ class Lexer
public function advance()
{
$this->lastToken = $this->token;
- $token = $this->token = $this->lookahead();
+ $token = $this->token = $this->lookahead();
+
return $token;
}
@@ -105,11 +106,11 @@ class Lexer
$token = $token->next ?: ($token->next = $this->readToken($token));
} while ($token->kind === Token::COMMENT);
}
+
return $token;
}
/**
- * @param Token $prev
* @return Token
* @throws SyntaxError
*/
@@ -121,7 +122,7 @@ class Lexer
$position = $this->position;
$line = $this->line;
- $col = 1 + $position - $this->lineStart;
+ $col = 1 + $position - $this->lineStart;
if ($position >= $bodyLength) {
return new Token(Token::EOF, $bodyLength, $bodyLength, $line, $col, $prev);
@@ -144,6 +145,7 @@ class Lexer
return new Token(Token::BANG, $position, $position + 1, $line, $col, $prev);
case 35: // #
$this->moveStringCursor(-1, -1 * $bytes);
+
return $this->readComment($line, $col, $prev);
case 36: // $
return new Token(Token::DOLLAR, $position, $position + 1, $line, $col, $prev);
@@ -178,30 +180,82 @@ class Lexer
case 125: // }
return new Token(Token::BRACE_R, $position, $position + 1, $line, $col, $prev);
// A-Z
- case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72:
- case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80:
- case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88:
- case 89: case 90:
- // _
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+ case 73:
+ case 74:
+ case 75:
+ case 76:
+ case 77:
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ case 85:
+ case 86:
+ case 87:
+ case 88:
+ case 89:
+ case 90:
+ // _
case 95:
- // a-z
- case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104:
- case 105: case 106: case 107: case 108: case 109: case 110: case 111:
- case 112: case 113: case 114: case 115: case 116: case 117: case 118:
- case 119: case 120: case 121: case 122:
+ // a-z
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ case 108:
+ case 109:
+ case 110:
+ case 111:
+ case 112:
+ case 113:
+ case 114:
+ case 115:
+ case 116:
+ case 117:
+ case 118:
+ case 119:
+ case 120:
+ case 121:
+ case 122:
return $this->moveStringCursor(-1, -1 * $bytes)
->readName($line, $col, $prev);
// -
case 45:
- // 0-9
- case 48: case 49: case 50: case 51: case 52:
- case 53: case 54: case 55: case 56: case 57:
+ // 0-9
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
return $this->moveStringCursor(-1, -1 * $bytes)
->readNumber($line, $col, $prev);
// "
case 34:
- list(,$nextCode) = $this->readChar();
- list(,$nextNextCode) = $this->moveStringCursor(1, 1)->readChar();
+ list(, $nextCode) = $this->readChar();
+ list(, $nextNextCode) = $this->moveStringCursor(1, 1)->readChar();
if ($nextCode === 34 && $nextNextCode === 34) {
return $this->moveStringCursor(-2, (-1 * $bytes) - 1)
@@ -213,7 +267,7 @@ class Lexer
}
$errMessage = $code === 39
- ? "Unexpected single quote character ('), did you mean to use ". 'a double quote (")?'
+ ? "Unexpected single quote character ('), did you mean to use " . 'a double quote (")?'
: 'Cannot parse the unexpected character ' . Utils::printCharCode($code) . '.';
throw new SyntaxError(
@@ -230,24 +284,24 @@ class Lexer
*
* @param int $line
* @param int $col
- * @param Token $prev
* @return Token
*/
private function readName($line, $col, Token $prev)
{
- $value = '';
- $start = $this->position;
+ $value = '';
+ $start = $this->position;
list ($char, $code) = $this->readChar();
while ($code && (
- $code === 95 || // _
- $code >= 48 && $code <= 57 || // 0-9
- $code >= 65 && $code <= 90 || // A-Z
- $code >= 97 && $code <= 122 // a-z
- )) {
- $value .= $char;
+ $code === 95 || // _
+ $code >= 48 && $code <= 57 || // 0-9
+ $code >= 65 && $code <= 90 || // A-Z
+ $code >= 97 && $code <= 122 // a-z
+ )) {
+ $value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
}
+
return new Token(
Token::NAME,
$start,
@@ -268,33 +322,36 @@ class Lexer
*
* @param int $line
* @param int $col
- * @param Token $prev
* @return Token
* @throws SyntaxError
*/
private function readNumber($line, $col, Token $prev)
{
- $value = '';
- $start = $this->position;
+ $value = '';
+ $start = $this->position;
list ($char, $code) = $this->readChar();
$isFloat = false;
if ($code === 45) { // -
- $value .= $char;
+ $value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
}
// guard against leading zero's
if ($code === 48) { // 0
- $value .= $char;
+ $value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
if ($code >= 48 && $code <= 57) {
- throw new SyntaxError($this->source, $this->position, "Invalid number, unexpected digit after 0: " . Utils::printCharCode($code));
+ throw new SyntaxError(
+ $this->source,
+ $this->position,
+ 'Invalid number, unexpected digit after 0: ' . Utils::printCharCode($code)
+ );
}
} else {
- $value .= $this->readDigits();
+ $value .= $this->readDigits();
list ($char, $code) = $this->readChar();
}
@@ -302,14 +359,14 @@ class Lexer
$isFloat = true;
$this->moveStringCursor(1, 1);
- $value .= $char;
- $value .= $this->readDigits();
+ $value .= $char;
+ $value .= $this->readDigits();
list ($char, $code) = $this->readChar();
}
if ($code === 69 || $code === 101) { // E e
- $isFloat = true;
- $value .= $char;
+ $isFloat = true;
+ $value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
if ($code === 43 || $code === 45) { // + -
@@ -341,7 +398,7 @@ class Lexer
$value = '';
do {
- $value .= $char;
+ $value .= $char;
list ($char, $code) = $this->moveStringCursor(1, 1)->readChar();
} while ($code >= 48 && $code <= 57); // 0 - 9
@@ -362,7 +419,6 @@ class Lexer
/**
* @param int $line
* @param int $col
- * @param Token $prev
* @return Token
* @throws SyntaxError
*/
@@ -371,13 +427,12 @@ class Lexer
$start = $this->position;
// Skip leading quote and read first string char:
- list ($char, $code, $bytes) = $this->moveStringCursor(1, 1)->readChar();
+ [$char, $code, $bytes] = $this->moveStringCursor(1, 1)->readChar();
$chunk = '';
$value = '';
- while (
- $code !== null &&
+ while ($code !== null &&
// not LineTerminator
$code !== 10 && $code !== 13
) {
@@ -403,22 +458,38 @@ class Lexer
$this->moveStringCursor(1, $bytes);
if ($code === 92) { // \
- $value .= $chunk;
+ $value .= $chunk;
list (, $code) = $this->readChar(true);
switch ($code) {
- case 34: $value .= '"'; break;
- case 47: $value .= '/'; break;
- case 92: $value .= '\\'; break;
- case 98: $value .= chr(8); break; // \b (backspace)
- case 102: $value .= "\f"; break;
- case 110: $value .= "\n"; break;
- case 114: $value .= "\r"; break;
- case 116: $value .= "\t"; break;
+ case 34:
+ $value .= '"';
+ break;
+ case 47:
+ $value .= '/';
+ break;
+ case 92:
+ $value .= '\\';
+ break;
+ case 98:
+ $value .= chr(8);
+ break; // \b (backspace)
+ case 102:
+ $value .= "\f";
+ break;
+ case 110:
+ $value .= "\n";
+ break;
+ case 114:
+ $value .= "\r";
+ break;
+ case 116:
+ $value .= "\t";
+ break;
case 117:
- $position = $this->position;
+ $position = $this->position;
list ($hex) = $this->readChars(4, true);
- if (!preg_match('/[0-9a-fA-F]{4}/', $hex)) {
+ if (! preg_match('/[0-9a-fA-F]{4}/', $hex)) {
throw new SyntaxError(
$this->source,
$position - 1,
@@ -470,8 +541,8 @@ class Lexer
// Closing Triple-Quote (""")
if ($code === 34) {
// Move 2 quotes
- list(,$nextCode) = $this->moveStringCursor(1, 1)->readChar();
- list(,$nextNextCode) = $this->moveStringCursor(1, 1)->readChar();
+ list(, $nextCode) = $this->moveStringCursor(1, 1)->readChar();
+ list(, $nextNextCode) = $this->moveStringCursor(1, 1)->readChar();
if ($nextCode === 34 && $nextNextCode === 34) {
$value .= $chunk;
@@ -496,9 +567,9 @@ class Lexer
$this->assertValidBlockStringCharacterCode($code, $this->position);
$this->moveStringCursor(1, $bytes);
- list(,$nextCode) = $this->readChar();
- list(,$nextNextCode) = $this->moveStringCursor(1, 1)->readChar();
- list(,$nextNextNextCode) = $this->moveStringCursor(1, 1)->readChar();
+ list(, $nextCode) = $this->readChar();
+ list(, $nextNextCode) = $this->moveStringCursor(1, 1)->readChar();
+ list(, $nextNextNextCode) = $this->moveStringCursor(1, 1)->readChar();
// Escape Triple-Quote (\""")
if ($code === 92 &&
@@ -508,7 +579,7 @@ class Lexer
) {
$this->moveStringCursor(1, 1);
$value .= $chunk . '"""';
- $chunk = '';
+ $chunk = '';
} else {
$this->moveStringCursor(-2, -2);
$chunk .= $char;
@@ -561,11 +632,11 @@ class Lexer
// tab | space | comma | BOM
if ($code === 9 || $code === 32 || $code === 44 || $code === 0xFEFF) {
$this->moveStringCursor(1, $bytes);
- } else if ($code === 10) { // new line
+ } elseif ($code === 10) { // new line
$this->moveStringCursor(1, $bytes);
$this->line++;
$this->lineStart = $this->position;
- } else if ($code === 13) { // carriage return
+ } elseif ($code === 13) { // carriage return
list(, $nextCode, $nextBytes) = $this->moveStringCursor(1, $bytes)->readChar();
if ($nextCode === 10) { // lf after cr
@@ -584,9 +655,8 @@ class Lexer
*
* #[\u0009\u0020-\uFFFF]*
*
- * @param $line
- * @param $col
- * @param Token $prev
+ * @param int $line
+ * @param int $col
* @return Token
*/
private function readComment($line, $col, Token $prev)
@@ -597,11 +667,10 @@ class Lexer
do {
list ($char, $code, $bytes) = $this->moveStringCursor(1, $bytes)->readChar();
- $value .= $char;
- } while (
- $code &&
- // SourceCharacter but not LineTerminator
- ($code > 0x001F || $code === 0x0009)
+ $value .= $char;
+ } while ($code &&
+ // SourceCharacter but not LineTerminator
+ ($code > 0x001F || $code === 0x0009)
);
return new Token(
@@ -619,8 +688,8 @@ class Lexer
* Reads next UTF8Character from the byte stream, starting from $byteStreamPosition.
*
* @param bool $advance
- * @param int $byteStreamPosition
- * @return array
+ * @param int $byteStreamPosition
+ * @return (string|int)[]
*/
private function readChar($advance = false, $byteStreamPosition = null)
{
@@ -628,9 +697,9 @@ class Lexer
$byteStreamPosition = $this->byteStreamPosition;
}
- $code = null;
- $utf8char = '';
- $bytes = 0;
+ $code = null;
+ $utf8char = '';
+ $bytes = 0;
$positionOffset = 0;
if (isset($this->source->body[$byteStreamPosition])) {
@@ -638,7 +707,7 @@ class Lexer
if ($ord < 128) {
$bytes = 1;
- } else if ($ord < 224) {
+ } elseif ($ord < 224) {
$bytes = 2;
} elseif ($ord < 240) {
$bytes = 3;
@@ -651,7 +720,7 @@ class Lexer
$utf8char .= $this->source->body[$pos];
}
$positionOffset = 1;
- $code = $bytes === 1 ? $ord : Utils::ord($utf8char);
+ $code = $bytes === 1 ? $ord : Utils::ord($utf8char);
}
if ($advance) {
@@ -664,40 +733,42 @@ class Lexer
/**
* Reads next $numberOfChars UTF8 characters from the byte stream, starting from $byteStreamPosition.
*
- * @param $numberOfChars
+ * @param int $charCount
* @param bool $advance
* @param null $byteStreamPosition
- * @return array
+ * @return (string|int)[]
*/
- private function readChars($numberOfChars, $advance = false, $byteStreamPosition = null)
+ private function readChars($charCount, $advance = false, $byteStreamPosition = null)
{
- $result = '';
+ $result = '';
$totalBytes = 0;
$byteOffset = $byteStreamPosition ?: $this->byteStreamPosition;
- for ($i = 0; $i < $numberOfChars; $i++) {
+ for ($i = 0; $i < $charCount; $i++) {
list ($char, $code, $bytes) = $this->readChar(false, $byteOffset);
- $totalBytes += $bytes;
- $byteOffset += $bytes;
- $result .= $char;
+ $totalBytes += $bytes;
+ $byteOffset += $bytes;
+ $result .= $char;
}
if ($advance) {
- $this->moveStringCursor($numberOfChars, $totalBytes);
+ $this->moveStringCursor($charCount, $totalBytes);
}
+
return [$result, $totalBytes];
}
/**
* Moves internal string cursor position
*
- * @param $positionOffset
- * @param $byteStreamOffset
+ * @param int $positionOffset
+ * @param int $byteStreamOffset
* @return self
*/
private function moveStringCursor($positionOffset, $byteStreamOffset)
{
- $this->position += $positionOffset;
+ $this->position += $positionOffset;
$this->byteStreamPosition += $byteStreamOffset;
+
return $this;
}
}
diff --git a/src/Language/Parser.php b/src/Language/Parser.php
index b920583..6f0ce0a 100644
--- a/src/Language/Parser.php
+++ b/src/Language/Parser.php
@@ -1,38 +1,43 @@
parseDocument();
}
@@ -121,16 +127,17 @@ class Parser
*
* @api
* @param Source|string $source
- * @param array $options
+ * @param bool[] $options
* @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|ListValueNode|ObjectValueNode|StringValueNode|VariableNode
*/
public static function parseValue($source, array $options = [])
{
$sourceObj = $source instanceof Source ? $source : new Source($source);
- $parser = new Parser($sourceObj, $options);
+ $parser = new Parser($sourceObj, $options);
$parser->expect(Token::SOF);
$value = $parser->parseValueLiteral(false);
$parser->expect(Token::EOF);
+
return $value;
}
@@ -146,30 +153,28 @@ class Parser
*
* @api
* @param Source|string $source
- * @param array $options
+ * @param bool[] $options
* @return ListTypeNode|NameNode|NonNullTypeNode
*/
public static function parseType($source, array $options = [])
{
$sourceObj = $source instanceof Source ? $source : new Source($source);
- $parser = new Parser($sourceObj, $options);
+ $parser = new Parser($sourceObj, $options);
$parser->expect(Token::SOF);
$type = $parser->parseTypeReference();
$parser->expect(Token::EOF);
+
return $type;
}
- /**
- * @var Lexer
- */
+ /** @var Lexer */
private $lexer;
/**
- * Parser constructor.
- * @param Source $source
- * @param array $options
+ *
+ * @param bool[] $options
*/
- function __construct(Source $source, array $options = [])
+ public function __construct(Source $source, array $options = [])
{
$this->lexer = new Lexer($source, $options);
}
@@ -178,24 +183,24 @@ class Parser
* Returns a location object, used to identify the place in
* the source that created a given parsed object.
*
- * @param Token $startToken
* @return Location|null
*/
- function loc(Token $startToken)
+ private function loc(Token $startToken)
{
if (empty($this->lexer->options['noLocation'])) {
return new Location($startToken, $this->lexer->lastToken, $this->lexer->source);
}
+
return null;
}
/**
* Determines if the next token is of a given kind
*
- * @param $kind
+ * @param string $kind
* @return bool
*/
- function peek($kind)
+ private function peek($kind)
{
return $this->lexer->token->kind === $kind;
}
@@ -204,16 +209,17 @@ class Parser
* If the next token is of the given kind, return true after advancing
* the parser. Otherwise, do not change the parser state and return false.
*
- * @param $kind
+ * @param string $kind
* @return bool
*/
- function skip($kind)
+ private function skip($kind)
{
$match = $this->lexer->token->kind === $kind;
if ($match) {
$this->lexer->advance();
}
+
return $match;
}
@@ -224,19 +230,20 @@ class Parser
* @return Token
* @throws SyntaxError
*/
- function expect($kind)
+ private function expect($kind)
{
$token = $this->lexer->token;
if ($token->kind === $kind) {
$this->lexer->advance();
+
return $token;
}
throw new SyntaxError(
$this->lexer->source,
$token->start,
- "Expected $kind, found " . $token->getDescription()
+ sprintf('Expected %s, found %s', $kind, $token->getDescription())
);
}
@@ -249,12 +256,13 @@ class Parser
* @return Token
* @throws SyntaxError
*/
- function expectKeyword($value)
+ private function expectKeyword($value)
{
$token = $this->lexer->token;
if ($token->kind === Token::NAME && $token->value === $value) {
$this->lexer->advance();
+
return $token;
}
throw new SyntaxError(
@@ -265,13 +273,13 @@ class Parser
}
/**
- * @param Token|null $atToken
* @return SyntaxError
*/
- function unexpected(Token $atToken = null)
+ private function unexpected(?Token $atToken = null)
{
$token = $atToken ?: $this->lexer->token;
- return new SyntaxError($this->lexer->source, $token->start, "Unexpected " . $token->getDescription());
+
+ return new SyntaxError($this->lexer->source, $token->start, 'Unexpected ' . $token->getDescription());
}
/**
@@ -280,20 +288,21 @@ class Parser
* and ends with a lex token of closeKind. Advances the parser
* to the next lex token after the closing token.
*
- * @param int $openKind
+ * @param string $openKind
* @param callable $parseFn
- * @param int $closeKind
+ * @param string $closeKind
* @return NodeList
* @throws SyntaxError
*/
- function any($openKind, $parseFn, $closeKind)
+ private function any($openKind, $parseFn, $closeKind)
{
$this->expect($openKind);
$nodes = [];
- while (!$this->skip($closeKind)) {
+ while (! $this->skip($closeKind)) {
$nodes[] = $parseFn($this);
}
+
return new NodeList($nodes);
}
@@ -303,20 +312,21 @@ class Parser
* and ends with a lex token of closeKind. Advances the parser
* to the next lex token after the closing token.
*
- * @param $openKind
- * @param $parseFn
- * @param $closeKind
+ * @param string $openKind
+ * @param callable $parseFn
+ * @param string $closeKind
* @return NodeList
* @throws SyntaxError
*/
- function many($openKind, $parseFn, $closeKind)
+ private function many($openKind, $parseFn, $closeKind)
{
$this->expect($openKind);
$nodes = [$parseFn($this)];
- while (!$this->skip($closeKind)) {
+ while (! $this->skip($closeKind)) {
$nodes[] = $parseFn($this);
}
+
return new NodeList($nodes);
}
@@ -326,13 +336,13 @@ class Parser
* @return NameNode
* @throws SyntaxError
*/
- function parseName()
+ private function parseName()
{
$token = $this->expect(Token::NAME);
return new NameNode([
'value' => $token->value,
- 'loc' => $this->loc($token)
+ 'loc' => $this->loc($token),
]);
}
@@ -342,7 +352,7 @@ class Parser
* @return DocumentNode
* @throws SyntaxError
*/
- function parseDocument()
+ private function parseDocument()
{
$start = $this->lexer->token;
$this->expect(Token::SOF);
@@ -350,11 +360,11 @@ class Parser
$definitions = [];
do {
$definitions[] = $this->parseDefinition();
- } while (!$this->skip(Token::EOF));
+ } while (! $this->skip(Token::EOF));
return new DocumentNode([
'definitions' => new NodeList($definitions),
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -362,7 +372,7 @@ class Parser
* @return ExecutableDefinitionNode|TypeSystemDefinitionNode
* @throws SyntaxError
*/
- function parseDefinition()
+ private function parseDefinition()
{
if ($this->peek(Token::NAME)) {
switch ($this->lexer->token->value) {
@@ -385,9 +395,9 @@ class Parser
// Note: The schema definition language is an experimental addition.
return $this->parseTypeSystemDefinition();
}
- } else if ($this->peek(Token::BRACE_L)) {
+ } elseif ($this->peek(Token::BRACE_L)) {
return $this->parseExecutableDefinition();
- } else if ($this->peekDescription()) {
+ } elseif ($this->peekDescription()) {
// Note: The schema definition language is an experimental addition.
return $this->parseTypeSystemDefinition();
}
@@ -399,7 +409,7 @@ class Parser
* @return ExecutableDefinitionNode
* @throws SyntaxError
*/
- function parseExecutableDefinition()
+ private function parseExecutableDefinition()
{
if ($this->peek(Token::NAME)) {
switch ($this->lexer->token->value) {
@@ -411,7 +421,7 @@ class Parser
case 'fragment':
return $this->parseFragmentDefinition();
}
- } else if ($this->peek(Token::BRACE_L)) {
+ } elseif ($this->peek(Token::BRACE_L)) {
return $this->parseOperationDefinition();
}
@@ -424,17 +434,17 @@ class Parser
* @return OperationDefinitionNode
* @throws SyntaxError
*/
- function parseOperationDefinition()
+ private function parseOperationDefinition()
{
$start = $this->lexer->token;
if ($this->peek(Token::BRACE_L)) {
return new OperationDefinitionNode([
- 'operation' => 'query',
- 'name' => null,
+ 'operation' => 'query',
+ 'name' => null,
'variableDefinitions' => new NodeList([]),
- 'directives' => new NodeList([]),
- 'selectionSet' => $this->parseSelectionSet(),
- 'loc' => $this->loc($start)
+ 'directives' => new NodeList([]),
+ 'selectionSet' => $this->parseSelectionSet(),
+ 'loc' => $this->loc($start),
]);
}
@@ -446,12 +456,12 @@ class Parser
}
return new OperationDefinitionNode([
- 'operation' => $operation,
- 'name' => $name,
+ 'operation' => $operation,
+ 'name' => $name,
'variableDefinitions' => $this->parseVariableDefinitions(),
- 'directives' => $this->parseDirectives(false),
- 'selectionSet' => $this->parseSelectionSet(),
- 'loc' => $this->loc($start)
+ 'directives' => $this->parseDirectives(false),
+ 'selectionSet' => $this->parseSelectionSet(),
+ 'loc' => $this->loc($start),
]);
}
@@ -459,13 +469,16 @@ class Parser
* @return string
* @throws SyntaxError
*/
- function parseOperationType()
+ private function parseOperationType()
{
$operationToken = $this->expect(Token::NAME);
switch ($operationToken->value) {
- case 'query': return 'query';
- case 'mutation': return 'mutation';
- case 'subscription': return 'subscription';
+ case 'query':
+ return 'query';
+ case 'mutation':
+ return 'mutation';
+ case 'subscription':
+ return 'subscription';
}
throw $this->unexpected($operationToken);
@@ -474,12 +487,14 @@ class Parser
/**
* @return VariableDefinitionNode[]|NodeList
*/
- function parseVariableDefinitions()
+ private function parseVariableDefinitions()
{
return $this->peek(Token::PAREN_L) ?
$this->many(
Token::PAREN_L,
- [$this, 'parseVariableDefinition'],
+ function () {
+ return $this->parseVariableDefinition();
+ },
Token::PAREN_R
) :
new NodeList([]);
@@ -489,20 +504,20 @@ class Parser
* @return VariableDefinitionNode
* @throws SyntaxError
*/
- function parseVariableDefinition()
+ private function parseVariableDefinition()
{
$start = $this->lexer->token;
- $var = $this->parseVariable();
+ $var = $this->parseVariable();
$this->expect(Token::COLON);
$type = $this->parseTypeReference();
return new VariableDefinitionNode([
- 'variable' => $var,
- 'type' => $type,
+ 'variable' => $var,
+ 'type' => $type,
'defaultValue' =>
($this->skip(Token::EQUALS) ? $this->parseValueLiteral(true) : null),
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -510,27 +525,36 @@ class Parser
* @return VariableNode
* @throws SyntaxError
*/
- function parseVariable()
+ private function parseVariable()
{
$start = $this->lexer->token;
$this->expect(Token::DOLLAR);
return new VariableNode([
'name' => $this->parseName(),
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
/**
* @return SelectionSetNode
*/
- function parseSelectionSet()
+ private function parseSelectionSet()
{
$start = $this->lexer->token;
- return new SelectionSetNode([
- 'selections' => $this->many(Token::BRACE_L, [$this, 'parseSelection'], Token::BRACE_R),
- 'loc' => $this->loc($start)
- ]);
+
+ return new SelectionSetNode(
+ [
+ 'selections' => $this->many(
+ Token::BRACE_L,
+ function () {
+ return $this->parseSelection();
+ },
+ Token::BRACE_R
+ ),
+ 'loc' => $this->loc($start),
+ ]
+ );
}
/**
@@ -541,7 +565,7 @@ class Parser
*
* @return mixed
*/
- function parseSelection()
+ private function parseSelection()
{
return $this->peek(Token::SPREAD) ?
$this->parseFragment() :
@@ -552,26 +576,26 @@ class Parser
* @return FieldNode
* @throws SyntaxError
*/
- function parseField()
+ private function parseField()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$nameOrAlias = $this->parseName();
if ($this->skip(Token::COLON)) {
$alias = $nameOrAlias;
- $name = $this->parseName();
+ $name = $this->parseName();
} else {
$alias = null;
- $name = $nameOrAlias;
+ $name = $nameOrAlias;
}
return new FieldNode([
- 'alias' => $alias,
- 'name' => $name,
- 'arguments' => $this->parseArguments(false),
- 'directives' => $this->parseDirectives(false),
+ 'alias' => $alias,
+ 'name' => $name,
+ 'arguments' => $this->parseArguments(false),
+ 'directives' => $this->parseDirectives(false),
'selectionSet' => $this->peek(Token::BRACE_L) ? $this->parseSelectionSet() : null,
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -580,11 +604,18 @@ class Parser
* @return ArgumentNode[]|NodeList
* @throws SyntaxError
*/
- function parseArguments($isConst)
+ private function parseArguments($isConst)
{
- $item = $isConst ? 'parseConstArgument' : 'parseArgument';
+ $parseFn = $isConst ?
+ function () {
+ return $this->parseConstArgument();
+ } :
+ function () {
+ return $this->parseArgument();
+ };
+
return $this->peek(Token::PAREN_L) ?
- $this->many(Token::PAREN_L, [$this, $item], Token::PAREN_R) :
+ $this->many(Token::PAREN_L, $parseFn, Token::PAREN_R) :
new NodeList([]);
}
@@ -592,18 +623,18 @@ class Parser
* @return ArgumentNode
* @throws SyntaxError
*/
- function parseArgument()
+ private function parseArgument()
{
$start = $this->lexer->token;
- $name = $this->parseName();
+ $name = $this->parseName();
$this->expect(Token::COLON);
$value = $this->parseValueLiteral(false);
return new ArgumentNode([
- 'name' => $name,
+ 'name' => $name,
'value' => $value,
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -611,18 +642,18 @@ class Parser
* @return ArgumentNode
* @throws SyntaxError
*/
- function parseConstArgument()
+ private function parseConstArgument()
{
$start = $this->lexer->token;
- $name = $this->parseName();
+ $name = $this->parseName();
$this->expect(Token::COLON);
$value = $this->parseConstValue();
return new ArgumentNode([
- 'name' => $name,
+ 'name' => $name,
'value' => $value,
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -632,16 +663,16 @@ class Parser
* @return FragmentSpreadNode|InlineFragmentNode
* @throws SyntaxError
*/
- function parseFragment()
+ private function parseFragment()
{
$start = $this->lexer->token;
$this->expect(Token::SPREAD);
if ($this->peek(Token::NAME) && $this->lexer->token->value !== 'on') {
return new FragmentSpreadNode([
- 'name' => $this->parseFragmentName(),
+ 'name' => $this->parseFragmentName(),
'directives' => $this->parseDirectives(false),
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -653,9 +684,9 @@ class Parser
return new InlineFragmentNode([
'typeCondition' => $typeCondition,
- 'directives' => $this->parseDirectives(false),
- 'selectionSet' => $this->parseSelectionSet(),
- 'loc' => $this->loc($start)
+ 'directives' => $this->parseDirectives(false),
+ 'selectionSet' => $this->parseSelectionSet(),
+ 'loc' => $this->loc($start),
]);
}
@@ -663,7 +694,7 @@ class Parser
* @return FragmentDefinitionNode
* @throws SyntaxError
*/
- function parseFragmentDefinition()
+ private function parseFragmentDefinition()
{
$start = $this->lexer->token;
$this->expectKeyword('fragment');
@@ -679,13 +710,14 @@ class Parser
}
$this->expectKeyword('on');
$typeCondition = $this->parseNamedType();
+
return new FragmentDefinitionNode([
- 'name' => $name,
+ 'name' => $name,
'variableDefinitions' => $variableDefinitions,
- 'typeCondition' => $typeCondition,
- 'directives' => $this->parseDirectives(false),
- 'selectionSet' => $this->parseSelectionSet(),
- 'loc' => $this->loc($start)
+ 'typeCondition' => $typeCondition,
+ 'directives' => $this->parseDirectives(false),
+ 'selectionSet' => $this->parseSelectionSet(),
+ 'loc' => $this->loc($start),
]);
}
@@ -693,11 +725,12 @@ class Parser
* @return NameNode
* @throws SyntaxError
*/
- function parseFragmentName()
+ private function parseFragmentName()
{
if ($this->lexer->token->value === 'on') {
throw $this->unexpected();
}
+
return $this->parseName();
}
@@ -721,11 +754,11 @@ class Parser
*
* EnumValue : Name but not `true`, `false` or `null`
*
- * @param $isConst
+ * @param bool $isConst
* @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|StringValueNode|VariableNode|ListValueNode|ObjectValueNode|NullValueNode
* @throws SyntaxError
*/
- function parseValueLiteral($isConst)
+ private function parseValueLiteral($isConst)
{
$token = $this->lexer->token;
switch ($token->kind) {
@@ -735,15 +768,17 @@ class Parser
return $this->parseObject($isConst);
case Token::INT:
$this->lexer->advance();
+
return new IntValueNode([
'value' => $token->value,
- 'loc' => $this->loc($token)
+ 'loc' => $this->loc($token),
]);
case Token::FLOAT:
$this->lexer->advance();
+
return new FloatValueNode([
'value' => $token->value,
- 'loc' => $this->loc($token)
+ 'loc' => $this->loc($token),
]);
case Token::STRING:
case Token::BLOCK_STRING:
@@ -751,26 +786,29 @@ class Parser
case Token::NAME:
if ($token->value === 'true' || $token->value === 'false') {
$this->lexer->advance();
+
return new BooleanValueNode([
'value' => $token->value === 'true',
- 'loc' => $this->loc($token)
+ 'loc' => $this->loc($token),
]);
- } else if ($token->value === 'null') {
+ } elseif ($token->value === 'null') {
$this->lexer->advance();
+
return new NullValueNode([
- 'loc' => $this->loc($token)
+ 'loc' => $this->loc($token),
]);
} else {
$this->lexer->advance();
+
return new EnumValueNode([
'value' => $token->value,
- 'loc' => $this->loc($token)
+ 'loc' => $this->loc($token),
]);
}
break;
case Token::DOLLAR:
- if (!$isConst) {
+ if (! $isConst) {
return $this->parseVariable();
}
break;
@@ -781,14 +819,15 @@ class Parser
/**
* @return StringValueNode
*/
- function parseStringLiteral() {
+ private function parseStringLiteral()
+ {
$token = $this->lexer->token;
$this->lexer->advance();
return new StringValueNode([
'value' => $token->value,
'block' => $token->kind === Token::BLOCK_STRING,
- 'loc' => $this->loc($token)
+ 'loc' => $this->loc($token),
]);
}
@@ -796,7 +835,7 @@ class Parser
* @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|StringValueNode|VariableNode
* @throws SyntaxError
*/
- function parseConstValue()
+ private function parseConstValue()
{
return $this->parseValueLiteral(true);
}
@@ -804,7 +843,7 @@ class Parser
/**
* @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|ListValueNode|ObjectValueNode|StringValueNode|VariableNode
*/
- function parseVariableValue()
+ private function parseVariableValue()
{
return $this->parseValueLiteral(false);
}
@@ -813,49 +852,57 @@ class Parser
* @param bool $isConst
* @return ListValueNode
*/
- function parseArray($isConst)
+ private function parseArray($isConst)
{
- $start = $this->lexer->token;
- $item = $isConst ? 'parseConstValue' : 'parseVariableValue';
- return new ListValueNode([
- 'values' => $this->any(Token::BRACKET_L, [$this, $item], Token::BRACKET_R),
- 'loc' => $this->loc($start)
- ]);
+ $start = $this->lexer->token;
+ $parseFn = $isConst ? function () {
+ return $this->parseConstValue();
+ } : function () {
+ return $this->parseVariableValue();
+ };
+
+ return new ListValueNode(
+ [
+ 'values' => $this->any(Token::BRACKET_L, $parseFn, Token::BRACKET_R),
+ 'loc' => $this->loc($start),
+ ]
+ );
}
/**
- * @param $isConst
+ * @param bool $isConst
* @return ObjectValueNode
*/
- function parseObject($isConst)
+ private function parseObject($isConst)
{
$start = $this->lexer->token;
$this->expect(Token::BRACE_L);
$fields = [];
- while (!$this->skip(Token::BRACE_R)) {
+ while (! $this->skip(Token::BRACE_R)) {
$fields[] = $this->parseObjectField($isConst);
}
+
return new ObjectValueNode([
'fields' => new NodeList($fields),
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
/**
- * @param $isConst
+ * @param bool $isConst
* @return ObjectFieldNode
*/
- function parseObjectField($isConst)
+ private function parseObjectField($isConst)
{
$start = $this->lexer->token;
- $name = $this->parseName();
+ $name = $this->parseName();
$this->expect(Token::COLON);
return new ObjectFieldNode([
- 'name' => $name,
+ 'name' => $name,
'value' => $this->parseValueLiteral($isConst),
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -866,12 +913,13 @@ class Parser
* @return DirectiveNode[]|NodeList
* @throws SyntaxError
*/
- function parseDirectives($isConst)
+ private function parseDirectives($isConst)
{
$directives = [];
while ($this->peek(Token::AT)) {
$directives[] = $this->parseDirective($isConst);
}
+
return new NodeList($directives);
}
@@ -880,14 +928,15 @@ class Parser
* @return DirectiveNode
* @throws SyntaxError
*/
- function parseDirective($isConst)
+ private function parseDirective($isConst)
{
$start = $this->lexer->token;
$this->expect(Token::AT);
+
return new DirectiveNode([
- 'name' => $this->parseName(),
+ 'name' => $this->parseName(),
'arguments' => $this->parseArguments($isConst),
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -899,7 +948,7 @@ class Parser
* @return ListTypeNode|NameNode|NonNullTypeNode
* @throws SyntaxError
*/
- function parseTypeReference()
+ private function parseTypeReference()
{
$start = $this->lexer->token;
@@ -908,7 +957,7 @@ class Parser
$this->expect(Token::BRACKET_R);
$type = new ListTypeNode([
'type' => $type,
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
} else {
$type = $this->parseNamedType();
@@ -916,20 +965,20 @@ class Parser
if ($this->skip(Token::BANG)) {
return new NonNullTypeNode([
'type' => $type,
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
-
}
+
return $type;
}
- function parseNamedType()
+ private function parseNamedType()
{
$start = $this->lexer->token;
return new NamedTypeNode([
'name' => $this->parseName(),
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -953,7 +1002,7 @@ class Parser
* @return TypeSystemDefinitionNode
* @throws SyntaxError
*/
- function parseTypeSystemDefinition()
+ private function parseTypeSystemDefinition()
{
// Many definitions begin with a description and require a lookahead.
$keywordToken = $this->peekDescription()
@@ -962,15 +1011,24 @@ class Parser
if ($keywordToken->kind === Token::NAME) {
switch ($keywordToken->value) {
- case 'schema': return $this->parseSchemaDefinition();
- case 'scalar': return $this->parseScalarTypeDefinition();
- case 'type': return $this->parseObjectTypeDefinition();
- case 'interface': return $this->parseInterfaceTypeDefinition();
- case 'union': return $this->parseUnionTypeDefinition();
- case 'enum': return $this->parseEnumTypeDefinition();
- case 'input': return $this->parseInputObjectTypeDefinition();
- case 'extend': return $this->parseTypeExtension();
- case 'directive': return $this->parseDirectiveDefinition();
+ case 'schema':
+ return $this->parseSchemaDefinition();
+ case 'scalar':
+ return $this->parseScalarTypeDefinition();
+ case 'type':
+ return $this->parseObjectTypeDefinition();
+ case 'interface':
+ return $this->parseInterfaceTypeDefinition();
+ case 'union':
+ return $this->parseUnionTypeDefinition();
+ case 'enum':
+ return $this->parseEnumTypeDefinition();
+ case 'input':
+ return $this->parseInputObjectTypeDefinition();
+ case 'extend':
+ return $this->parseTypeExtension();
+ case 'directive':
+ return $this->parseDirectiveDefinition();
}
}
@@ -980,14 +1038,16 @@ class Parser
/**
* @return bool
*/
- function peekDescription() {
+ private function peekDescription()
+ {
return $this->peek(Token::STRING) || $this->peek(Token::BLOCK_STRING);
}
/**
* @return StringValueNode|null
*/
- function parseDescription() {
+ private function parseDescription()
+ {
if ($this->peekDescription()) {
return $this->parseStringLiteral();
}
@@ -997,7 +1057,7 @@ class Parser
* @return SchemaDefinitionNode
* @throws SyntaxError
*/
- function parseSchemaDefinition()
+ private function parseSchemaDefinition()
{
$start = $this->lexer->token;
$this->expectKeyword('schema');
@@ -1005,14 +1065,16 @@ class Parser
$operationTypes = $this->many(
Token::BRACE_L,
- [$this, 'parseOperationTypeDefinition'],
+ function () {
+ return $this->parseOperationTypeDefinition();
+ },
Token::BRACE_R
);
return new SchemaDefinitionNode([
- 'directives' => $directives,
+ 'directives' => $directives,
'operationTypes' => $operationTypes,
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -1020,17 +1082,17 @@ class Parser
* @return OperationTypeDefinitionNode
* @throws SyntaxError
*/
- function parseOperationTypeDefinition()
+ private function parseOperationTypeDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$operation = $this->parseOperationType();
$this->expect(Token::COLON);
$type = $this->parseNamedType();
return new OperationTypeDefinitionNode([
'operation' => $operation,
- 'type' => $type,
- 'loc' => $this->loc($start)
+ 'type' => $type,
+ 'loc' => $this->loc($start),
]);
}
@@ -1038,19 +1100,19 @@ class Parser
* @return ScalarTypeDefinitionNode
* @throws SyntaxError
*/
- function parseScalarTypeDefinition()
+ private function parseScalarTypeDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
$this->expectKeyword('scalar');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
return new ScalarTypeDefinitionNode([
- 'name' => $name,
- 'directives' => $directives,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'directives' => $directives,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1058,23 +1120,23 @@ class Parser
* @return ObjectTypeDefinitionNode
* @throws SyntaxError
*/
- function parseObjectTypeDefinition()
+ private function parseObjectTypeDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
$this->expectKeyword('type');
- $name = $this->parseName();
+ $name = $this->parseName();
$interfaces = $this->parseImplementsInterfaces();
$directives = $this->parseDirectives(true);
- $fields = $this->parseFieldsDefinition();
+ $fields = $this->parseFieldsDefinition();
return new ObjectTypeDefinitionNode([
- 'name' => $name,
- 'interfaces' => $interfaces,
- 'directives' => $directives,
- 'fields' => $fields,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'interfaces' => $interfaces,
+ 'directives' => $directives,
+ 'fields' => $fields,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1085,7 +1147,7 @@ class Parser
*
* @return NamedTypeNode[]
*/
- function parseImplementsInterfaces()
+ private function parseImplementsInterfaces()
{
$types = [];
if ($this->lexer->token->value === 'implements') {
@@ -1094,12 +1156,12 @@ class Parser
$this->skip(Token::AMP);
do {
$types[] = $this->parseNamedType();
- } while (
- $this->skip(Token::AMP) ||
- // Legacy support for the SDL?
- (!empty($this->lexer->options['allowLegacySDLImplementsInterfaces']) && $this->peek(Token::NAME))
+ } while ($this->skip(Token::AMP) ||
+ // Legacy support for the SDL?
+ (! empty($this->lexer->options['allowLegacySDLImplementsInterfaces']) && $this->peek(Token::NAME))
);
}
+
return $types;
}
@@ -1107,22 +1169,25 @@ class Parser
* @return FieldDefinitionNode[]|NodeList
* @throws SyntaxError
*/
- function parseFieldsDefinition()
+ private function parseFieldsDefinition()
{
// Legacy support for the SDL?
- if (
- !empty($this->lexer->options['allowLegacySDLEmptyFields']) &&
+ if (! empty($this->lexer->options['allowLegacySDLEmptyFields']) &&
$this->peek(Token::BRACE_L) &&
$this->lexer->lookahead()->kind === Token::BRACE_R
) {
$this->lexer->advance();
$this->lexer->advance();
+
return [];
}
+
return $this->peek(Token::BRACE_L)
? $this->many(
Token::BRACE_L,
- [$this, 'parseFieldDefinition'],
+ function () {
+ return $this->parseFieldDefinition();
+ },
Token::BRACE_R
)
: new NodeList([]);
@@ -1132,23 +1197,23 @@ class Parser
* @return FieldDefinitionNode
* @throws SyntaxError
*/
- function parseFieldDefinition()
+ private function parseFieldDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
- $name = $this->parseName();
- $args = $this->parseArgumentDefs();
+ $name = $this->parseName();
+ $args = $this->parseArgumentDefs();
$this->expect(Token::COLON);
- $type = $this->parseTypeReference();
+ $type = $this->parseTypeReference();
$directives = $this->parseDirectives(true);
return new FieldDefinitionNode([
- 'name' => $name,
- 'arguments' => $args,
- 'type' => $type,
- 'directives' => $directives,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'arguments' => $args,
+ 'type' => $type,
+ 'directives' => $directives,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1156,37 +1221,45 @@ class Parser
* @return InputValueDefinitionNode[]|NodeList
* @throws SyntaxError
*/
- function parseArgumentDefs()
+ private function parseArgumentDefs()
{
- if (!$this->peek(Token::PAREN_L)) {
+ if (! $this->peek(Token::PAREN_L)) {
return new NodeList([]);
}
- return $this->many(Token::PAREN_L, [$this, 'parseInputValueDef'], Token::PAREN_R);
+
+ return $this->many(
+ Token::PAREN_L,
+ function () {
+ return $this->parseInputValueDef();
+ },
+ Token::PAREN_R
+ );
}
/**
* @return InputValueDefinitionNode
* @throws SyntaxError
*/
- function parseInputValueDef()
+ private function parseInputValueDef()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
- $name = $this->parseName();
+ $name = $this->parseName();
$this->expect(Token::COLON);
- $type = $this->parseTypeReference();
+ $type = $this->parseTypeReference();
$defaultValue = null;
if ($this->skip(Token::EQUALS)) {
$defaultValue = $this->parseConstValue();
}
$directives = $this->parseDirectives(true);
+
return new InputValueDefinitionNode([
- 'name' => $name,
- 'type' => $type,
+ 'name' => $name,
+ 'type' => $type,
'defaultValue' => $defaultValue,
- 'directives' => $directives,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'directives' => $directives,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1194,21 +1267,21 @@ class Parser
* @return InterfaceTypeDefinitionNode
* @throws SyntaxError
*/
- function parseInterfaceTypeDefinition()
+ private function parseInterfaceTypeDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
$this->expectKeyword('interface');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
- $fields = $this->parseFieldsDefinition();
+ $fields = $this->parseFieldsDefinition();
return new InterfaceTypeDefinitionNode([
- 'name' => $name,
- 'directives' => $directives,
- 'fields' => $fields,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'directives' => $directives,
+ 'fields' => $fields,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1219,21 +1292,21 @@ class Parser
* @return UnionTypeDefinitionNode
* @throws SyntaxError
*/
- function parseUnionTypeDefinition()
+ private function parseUnionTypeDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
$this->expectKeyword('union');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
- $types = $this->parseUnionMemberTypes();
+ $types = $this->parseUnionMemberTypes();
return new UnionTypeDefinitionNode([
- 'name' => $name,
- 'directives' => $directives,
- 'types' => $types,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'directives' => $directives,
+ 'types' => $types,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1244,7 +1317,7 @@ class Parser
*
* @return NamedTypeNode[]
*/
- function parseUnionMemberTypes()
+ private function parseUnionMemberTypes()
{
$types = [];
if ($this->skip(Token::EQUALS)) {
@@ -1254,6 +1327,7 @@ class Parser
$types[] = $this->parseNamedType();
} while ($this->skip(Token::PIPE));
}
+
return $types;
}
@@ -1261,21 +1335,21 @@ class Parser
* @return EnumTypeDefinitionNode
* @throws SyntaxError
*/
- function parseEnumTypeDefinition()
+ private function parseEnumTypeDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
$this->expectKeyword('enum');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
- $values = $this->parseEnumValuesDefinition();
+ $values = $this->parseEnumValuesDefinition();
return new EnumTypeDefinitionNode([
- 'name' => $name,
- 'directives' => $directives,
- 'values' => $values,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'directives' => $directives,
+ 'values' => $values,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1283,14 +1357,16 @@ class Parser
* @return EnumValueDefinitionNode[]|NodeList
* @throws SyntaxError
*/
- function parseEnumValuesDefinition()
+ private function parseEnumValuesDefinition()
{
return $this->peek(Token::BRACE_L)
? $this->many(
Token::BRACE_L,
- [$this, 'parseEnumValueDefinition'],
+ function () {
+ return $this->parseEnumValueDefinition();
+ },
Token::BRACE_R
- )
+ )
: new NodeList([]);
}
@@ -1298,18 +1374,18 @@ class Parser
* @return EnumValueDefinitionNode
* @throws SyntaxError
*/
- function parseEnumValueDefinition()
+ private function parseEnumValueDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
- $name = $this->parseName();
- $directives = $this->parseDirectives(true);
+ $name = $this->parseName();
+ $directives = $this->parseDirectives(true);
return new EnumValueDefinitionNode([
- 'name' => $name,
- 'directives' => $directives,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'directives' => $directives,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1317,21 +1393,21 @@ class Parser
* @return InputObjectTypeDefinitionNode
* @throws SyntaxError
*/
- function parseInputObjectTypeDefinition()
+ private function parseInputObjectTypeDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
$this->expectKeyword('input');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
- $fields = $this->parseInputFieldsDefinition();
+ $fields = $this->parseInputFieldsDefinition();
return new InputObjectTypeDefinitionNode([
- 'name' => $name,
- 'directives' => $directives,
- 'fields' => $fields,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'directives' => $directives,
+ 'fields' => $fields,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1339,11 +1415,14 @@ class Parser
* @return InputValueDefinitionNode[]|NodeList
* @throws SyntaxError
*/
- function parseInputFieldsDefinition() {
+ private function parseInputFieldsDefinition()
+ {
return $this->peek(Token::BRACE_L)
? $this->many(
Token::BRACE_L,
- [$this, 'parseInputValueDef'],
+ function () {
+ return $this->parseInputValueDef();
+ },
Token::BRACE_R
)
: new NodeList([]);
@@ -1361,7 +1440,7 @@ class Parser
* @return TypeExtensionNode
* @throws SyntaxError
*/
- function parseTypeExtension()
+ private function parseTypeExtension()
{
$keywordToken = $this->lexer->lookahead();
@@ -1389,20 +1468,21 @@ class Parser
* @return ScalarTypeExtensionNode
* @throws SyntaxError
*/
- function parseScalarTypeExtension() {
+ private function parseScalarTypeExtension()
+ {
$start = $this->lexer->token;
$this->expectKeyword('extend');
$this->expectKeyword('scalar');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
if (count($directives) === 0) {
throw $this->unexpected();
}
return new ScalarTypeExtensionNode([
- 'name' => $name,
+ 'name' => $name,
'directives' => $directives,
- 'loc' => $this->loc($start)
+ 'loc' => $this->loc($start),
]);
}
@@ -1410,17 +1490,17 @@ class Parser
* @return ObjectTypeExtensionNode
* @throws SyntaxError
*/
- function parseObjectTypeExtension() {
+ private function parseObjectTypeExtension()
+ {
$start = $this->lexer->token;
$this->expectKeyword('extend');
$this->expectKeyword('type');
- $name = $this->parseName();
+ $name = $this->parseName();
$interfaces = $this->parseImplementsInterfaces();
$directives = $this->parseDirectives(true);
- $fields = $this->parseFieldsDefinition();
+ $fields = $this->parseFieldsDefinition();
- if (
- !$interfaces &&
+ if (count($interfaces) === 0 &&
count($directives) === 0 &&
count($fields) === 0
) {
@@ -1428,11 +1508,11 @@ class Parser
}
return new ObjectTypeExtensionNode([
- 'name' => $name,
+ 'name' => $name,
'interfaces' => $interfaces,
'directives' => $directives,
- 'fields' => $fields,
- 'loc' => $this->loc($start)
+ 'fields' => $fields,
+ 'loc' => $this->loc($start),
]);
}
@@ -1440,25 +1520,25 @@ class Parser
* @return InterfaceTypeExtensionNode
* @throws SyntaxError
*/
- function parseInterfaceTypeExtension() {
+ private function parseInterfaceTypeExtension()
+ {
$start = $this->lexer->token;
$this->expectKeyword('extend');
$this->expectKeyword('interface');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
- $fields = $this->parseFieldsDefinition();
- if (
- count($directives) === 0 &&
+ $fields = $this->parseFieldsDefinition();
+ if (count($directives) === 0 &&
count($fields) === 0
) {
throw $this->unexpected();
}
return new InterfaceTypeExtensionNode([
- 'name' => $name,
+ 'name' => $name,
'directives' => $directives,
- 'fields' => $fields,
- 'loc' => $this->loc($start)
+ 'fields' => $fields,
+ 'loc' => $this->loc($start),
]);
}
@@ -1470,25 +1550,25 @@ class Parser
* @return UnionTypeExtensionNode
* @throws SyntaxError
*/
- function parseUnionTypeExtension() {
+ private function parseUnionTypeExtension()
+ {
$start = $this->lexer->token;
$this->expectKeyword('extend');
$this->expectKeyword('union');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
- $types = $this->parseUnionMemberTypes();
- if (
- count($directives) === 0 &&
- !$types
+ $types = $this->parseUnionMemberTypes();
+ if (count($directives) === 0 &&
+ ! $types
) {
throw $this->unexpected();
}
return new UnionTypeExtensionNode([
- 'name' => $name,
+ 'name' => $name,
'directives' => $directives,
- 'types' => $types,
- 'loc' => $this->loc($start)
+ 'types' => $types,
+ 'loc' => $this->loc($start),
]);
}
@@ -1496,25 +1576,25 @@ class Parser
* @return EnumTypeExtensionNode
* @throws SyntaxError
*/
- function parseEnumTypeExtension() {
+ private function parseEnumTypeExtension()
+ {
$start = $this->lexer->token;
$this->expectKeyword('extend');
$this->expectKeyword('enum');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
- $values = $this->parseEnumValuesDefinition();
- if (
- count($directives) === 0 &&
+ $values = $this->parseEnumValuesDefinition();
+ if (count($directives) === 0 &&
count($values) === 0
) {
throw $this->unexpected();
}
return new EnumTypeExtensionNode([
- 'name' => $name,
+ 'name' => $name,
'directives' => $directives,
- 'values' => $values,
- 'loc' => $this->loc($start)
+ 'values' => $values,
+ 'loc' => $this->loc($start),
]);
}
@@ -1522,25 +1602,25 @@ class Parser
* @return InputObjectTypeExtensionNode
* @throws SyntaxError
*/
- function parseInputObjectTypeExtension() {
+ private function parseInputObjectTypeExtension()
+ {
$start = $this->lexer->token;
$this->expectKeyword('extend');
$this->expectKeyword('input');
- $name = $this->parseName();
+ $name = $this->parseName();
$directives = $this->parseDirectives(true);
- $fields = $this->parseInputFieldsDefinition();
- if (
- count($directives) === 0 &&
+ $fields = $this->parseInputFieldsDefinition();
+ if (count($directives) === 0 &&
count($fields) === 0
) {
throw $this->unexpected();
}
return new InputObjectTypeExtensionNode([
- 'name' => $name,
+ 'name' => $name,
'directives' => $directives,
- 'fields' => $fields,
- 'loc' => $this->loc($start)
+ 'fields' => $fields,
+ 'loc' => $this->loc($start),
]);
}
@@ -1551,9 +1631,9 @@ class Parser
* @return DirectiveDefinitionNode
* @throws SyntaxError
*/
- function parseDirectiveDefinition()
+ private function parseDirectiveDefinition()
{
- $start = $this->lexer->token;
+ $start = $this->lexer->token;
$description = $this->parseDescription();
$this->expectKeyword('directive');
$this->expect(Token::AT);
@@ -1563,11 +1643,11 @@ class Parser
$locations = $this->parseDirectiveLocations();
return new DirectiveDefinitionNode([
- 'name' => $name,
- 'arguments' => $args,
- 'locations' => $locations,
- 'loc' => $this->loc($start),
- 'description' => $description
+ 'name' => $name,
+ 'arguments' => $args,
+ 'locations' => $locations,
+ 'loc' => $this->loc($start),
+ 'description' => $description,
]);
}
@@ -1575,7 +1655,7 @@ class Parser
* @return NameNode[]
* @throws SyntaxError
*/
- function parseDirectiveLocations()
+ private function parseDirectiveLocations()
{
// Optional leading pipe
$this->skip(Token::PIPE);
@@ -1583,6 +1663,7 @@ class Parser
do {
$locations[] = $this->parseDirectiveLocation();
} while ($this->skip(Token::PIPE));
+
return $locations;
}
@@ -1590,10 +1671,10 @@ class Parser
* @return NameNode
* @throws SyntaxError
*/
- function parseDirectiveLocation()
+ private function parseDirectiveLocation()
{
$start = $this->lexer->token;
- $name = $this->parseName();
+ $name = $this->parseName();
if (DirectiveLocation::has($name->value)) {
return $name;
}
diff --git a/src/Language/Printer.php b/src/Language/Printer.php
index 49ea385..3c9873f 100644
--- a/src/Language/Printer.php
+++ b/src/Language/Printer.php
@@ -1,29 +1,32 @@
printAST($ast);
}
protected function __construct()
- {}
+ {
+ }
public function printAST($ast)
{
- return Visitor::visit($ast, [
- 'leave' => [
- NodeKind::NAME => function(Node $node) {
- return '' . $node->value;
- },
- NodeKind::VARIABLE => function($node) {
- return '$' . $node->name;
- },
- NodeKind::DOCUMENT => function(DocumentNode $node) {
- return $this->join($node->definitions, "\n\n") . "\n";
- },
- NodeKind::OPERATION_DEFINITION => function(OperationDefinitionNode $node) {
- $op = $node->operation;
- $name = $node->name;
- $varDefs = $this->wrap('(', $this->join($node->variableDefinitions, ', '), ')');
- $directives = $this->join($node->directives, ' ');
- $selectionSet = $node->selectionSet;
- // Anonymous queries with no directives or variable definitions can use
- // the query short form.
- return !$name && !$directives && !$varDefs && $op === 'query'
- ? $selectionSet
- : $this->join([$op, $this->join([$name, $varDefs]), $directives, $selectionSet], ' ');
- },
- NodeKind::VARIABLE_DEFINITION => function(VariableDefinitionNode $node) {
- return $node->variable . ': ' . $node->type . $this->wrap(' = ', $node->defaultValue);
- },
- NodeKind::SELECTION_SET => function(SelectionSetNode $node) {
- return $this->block($node->selections);
- },
- NodeKind::FIELD => function(FieldNode $node) {
- return $this->join([
- $this->wrap('', $node->alias, ': ') . $node->name . $this->wrap('(', $this->join($node->arguments, ', '), ')'),
- $this->join($node->directives, ' '),
- $node->selectionSet
- ], ' ');
- },
- NodeKind::ARGUMENT => function(ArgumentNode $node) {
- return $node->name . ': ' . $node->value;
- },
+ return Visitor::visit(
+ $ast,
+ [
+ 'leave' => [
+ NodeKind::NAME => function (Node $node) {
+ return '' . $node->value;
+ },
- // Fragments
- NodeKind::FRAGMENT_SPREAD => function(FragmentSpreadNode $node) {
- return '...' . $node->name . $this->wrap(' ', $this->join($node->directives, ' '));
- },
- NodeKind::INLINE_FRAGMENT => function(InlineFragmentNode $node) {
- return $this->join([
- "...",
- $this->wrap('on ', $node->typeCondition),
- $this->join($node->directives, ' '),
- $node->selectionSet
- ], ' ');
- },
- NodeKind::FRAGMENT_DEFINITION => function(FragmentDefinitionNode $node) {
- // Note: fragment variable definitions are experimental and may be changed
- // or removed in the future.
- return "fragment {$node->name}"
- . $this->wrap('(', $this->join($node->variableDefinitions, ', '), ')')
- . " on {$node->typeCondition} "
- . $this->wrap('', $this->join($node->directives, ' '), ' ')
- . $node->selectionSet;
- },
+ NodeKind::VARIABLE => function ($node) {
+ return '$' . $node->name;
+ },
- // Value
- NodeKind::INT => function(IntValueNode $node) {
- return $node->value;
- },
- NodeKind::FLOAT => function(FloatValueNode $node) {
- return $node->value;
- },
- NodeKind::STRING => function(StringValueNode $node, $key) {
- if ($node->block) {
- return $this->printBlockString($node->value, $key === 'description');
- }
- return json_encode($node->value);
- },
- NodeKind::BOOLEAN => function(BooleanValueNode $node) {
- return $node->value ? 'true' : 'false';
- },
- NodeKind::NULL => function(NullValueNode $node) {
- return 'null';
- },
- NodeKind::ENUM => function(EnumValueNode $node) {
- return $node->value;
- },
- NodeKind::LST => function(ListValueNode $node) {
- return '[' . $this->join($node->values, ', ') . ']';
- },
- NodeKind::OBJECT => function(ObjectValueNode $node) {
- return '{' . $this->join($node->fields, ', ') . '}';
- },
- NodeKind::OBJECT_FIELD => function(ObjectFieldNode $node) {
- return $node->name . ': ' . $node->value;
- },
+ NodeKind::DOCUMENT => function (DocumentNode $node) {
+ return $this->join($node->definitions, "\n\n") . "\n";
+ },
- // DirectiveNode
- NodeKind::DIRECTIVE => function(DirectiveNode $node) {
- return '@' . $node->name . $this->wrap('(', $this->join($node->arguments, ', '), ')');
- },
+ NodeKind::OPERATION_DEFINITION => function (OperationDefinitionNode $node) {
+ $op = $node->operation;
+ $name = $node->name;
+ $varDefs = $this->wrap('(', $this->join($node->variableDefinitions, ', '), ')');
+ $directives = $this->join($node->directives, ' ');
+ $selectionSet = $node->selectionSet;
+ // Anonymous queries with no directives or variable definitions can use
+ // the query short form.
+ return ! $name && ! $directives && ! $varDefs && $op === 'query'
+ ? $selectionSet
+ : $this->join([$op, $this->join([$name, $varDefs]), $directives, $selectionSet], ' ');
+ },
- // Type
- NodeKind::NAMED_TYPE => function(NamedTypeNode $node) {
- return $node->name;
- },
- NodeKind::LIST_TYPE => function(ListTypeNode $node) {
- return '[' . $node->type . ']';
- },
- NodeKind::NON_NULL_TYPE => function(NonNullTypeNode $node) {
- return $node->type . '!';
- },
+ NodeKind::VARIABLE_DEFINITION => function (VariableDefinitionNode $node) {
+ return $node->variable . ': ' . $node->type . $this->wrap(' = ', $node->defaultValue);
+ },
- // Type System Definitions
- NodeKind::SCHEMA_DEFINITION => function(SchemaDefinitionNode $def) {
- return $this->join([
- 'schema',
- $this->join($def->directives, ' '),
- $this->block($def->operationTypes)
- ], ' ');
- },
- NodeKind::OPERATION_TYPE_DEFINITION => function(OperationTypeDefinitionNode $def) {
- return $def->operation . ': ' . $def->type;
- },
+ NodeKind::SELECTION_SET => function (SelectionSetNode $node) {
+ return $this->block($node->selections);
+ },
- NodeKind::SCALAR_TYPE_DEFINITION => $this->addDescription(function(ScalarTypeDefinitionNode $def) {
- return $this->join(['scalar', $def->name, $this->join($def->directives, ' ')], ' ');
- }),
- NodeKind::OBJECT_TYPE_DEFINITION => $this->addDescription(function(ObjectTypeDefinitionNode $def) {
- return $this->join([
- 'type',
- $def->name,
- $this->wrap('implements ', $this->join($def->interfaces, ' & ')),
- $this->join($def->directives, ' '),
- $this->block($def->fields)
- ], ' ');
- }),
- NodeKind::FIELD_DEFINITION => $this->addDescription(function(FieldDefinitionNode $def) {
- return $def->name
- . $this->wrap('(', $this->join($def->arguments, ', '), ')')
- . ': ' . $def->type
- . $this->wrap(' ', $this->join($def->directives, ' '));
- }),
- NodeKind::INPUT_VALUE_DEFINITION => $this->addDescription(function(InputValueDefinitionNode $def) {
- return $this->join([
- $def->name . ': ' . $def->type,
- $this->wrap('= ', $def->defaultValue),
- $this->join($def->directives, ' ')
- ], ' ');
- }),
- NodeKind::INTERFACE_TYPE_DEFINITION => $this->addDescription(function(InterfaceTypeDefinitionNode $def) {
- return $this->join([
- 'interface',
- $def->name,
- $this->join($def->directives, ' '),
- $this->block($def->fields)
- ], ' ');
- }),
- NodeKind::UNION_TYPE_DEFINITION => $this->addDescription(function(UnionTypeDefinitionNode $def) {
- return $this->join([
- 'union',
- $def->name,
- $this->join($def->directives, ' '),
- $def->types
- ? '= ' . $this->join($def->types, ' | ')
- : ''
- ], ' ');
- }),
- NodeKind::ENUM_TYPE_DEFINITION => $this->addDescription(function(EnumTypeDefinitionNode $def) {
- return $this->join([
- 'enum',
- $def->name,
- $this->join($def->directives, ' '),
- $this->block($def->values)
- ], ' ');
- }),
- NodeKind::ENUM_VALUE_DEFINITION => $this->addDescription(function(EnumValueDefinitionNode $def) {
- return $this->join([$def->name, $this->join($def->directives, ' ')], ' ');
- }),
- NodeKind::INPUT_OBJECT_TYPE_DEFINITION => $this->addDescription(function(InputObjectTypeDefinitionNode $def) {
- return $this->join([
- 'input',
- $def->name,
- $this->join($def->directives, ' '),
- $this->block($def->fields)
- ], ' ');
- }),
- NodeKind::SCALAR_TYPE_EXTENSION => function(ScalarTypeExtensionNode $def) {
- return $this->join([
- 'extend scalar',
- $def->name,
- $this->join($def->directives, ' '),
- ], ' ');
- },
- NodeKind::OBJECT_TYPE_EXTENSION => function(ObjectTypeExtensionNode $def) {
- return $this->join([
- 'extend type',
- $def->name,
- $this->wrap('implements ', $this->join($def->interfaces, ' & ')),
- $this->join($def->directives, ' '),
- $this->block($def->fields),
- ], ' ');
- },
- NodeKind::INTERFACE_TYPE_EXTENSION => function(InterfaceTypeExtensionNode $def) {
- return $this->join([
- 'extend interface',
- $def->name,
- $this->join($def->directives, ' '),
- $this->block($def->fields),
- ], ' ');
- },
- NodeKind::UNION_TYPE_EXTENSION => function(UnionTypeExtensionNode $def) {
- return $this->join([
- 'extend union',
- $def->name,
- $this->join($def->directives, ' '),
- $def->types
- ? '= ' . $this->join($def->types, ' | ')
- : ''
- ], ' ');
- },
- NodeKind::ENUM_TYPE_EXTENSION => function(EnumTypeExtensionNode $def) {
- return $this->join([
- 'extend enum',
- $def->name,
- $this->join($def->directives, ' '),
- $this->block($def->values),
- ], ' ');
- },
- NodeKind::INPUT_OBJECT_TYPE_EXTENSION => function(InputObjectTypeExtensionNode $def) {
- return $this->join([
- 'extend input',
- $def->name,
- $this->join($def->directives, ' '),
- $this->block($def->fields),
- ], ' ');
- },
- NodeKind::DIRECTIVE_DEFINITION => $this->addDescription(function(DirectiveDefinitionNode $def) {
- return 'directive @'
- . $def->name
- . $this->wrap('(', $this->join($def->arguments, ', '), ')')
- . ' on ' . $this->join($def->locations, ' | ');
- })
+ NodeKind::FIELD => function (FieldNode $node) {
+ return $this->join(
+ [
+ $this->wrap('', $node->alias, ': ') . $node->name . $this->wrap(
+ '(',
+ $this->join($node->arguments, ', '),
+ ')'
+ ),
+ $this->join($node->directives, ' '),
+ $node->selectionSet,
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::ARGUMENT => function (ArgumentNode $node) {
+ return $node->name . ': ' . $node->value;
+ },
+
+ NodeKind::FRAGMENT_SPREAD => function (FragmentSpreadNode $node) {
+ return '...' . $node->name . $this->wrap(' ', $this->join($node->directives, ' '));
+ },
+
+ NodeKind::INLINE_FRAGMENT => function (InlineFragmentNode $node) {
+ return $this->join(
+ [
+ '...',
+ $this->wrap('on ', $node->typeCondition),
+ $this->join($node->directives, ' '),
+ $node->selectionSet,
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::FRAGMENT_DEFINITION => function (FragmentDefinitionNode $node) {
+ // Note: fragment variable definitions are experimental and may be changed or removed in the future.
+ return sprintf('fragment %s', $node->name)
+ . $this->wrap('(', $this->join($node->variableDefinitions, ', '), ')')
+ . sprintf(' on %s ', $node->typeCondition)
+ . $this->wrap('', $this->join($node->directives, ' '), ' ')
+ . $node->selectionSet;
+ },
+
+ NodeKind::INT => function (IntValueNode $node) {
+ return $node->value;
+ },
+
+ NodeKind::FLOAT => function (FloatValueNode $node) {
+ return $node->value;
+ },
+
+ NodeKind::STRING => function (StringValueNode $node, $key) {
+ if ($node->block) {
+ return $this->printBlockString($node->value, $key === 'description');
+ }
+
+ return json_encode($node->value);
+ },
+
+ NodeKind::BOOLEAN => function (BooleanValueNode $node) {
+ return $node->value ? 'true' : 'false';
+ },
+
+ NodeKind::NULL => function (NullValueNode $node) {
+ return 'null';
+ },
+
+ NodeKind::ENUM => function (EnumValueNode $node) {
+ return $node->value;
+ },
+
+ NodeKind::LST => function (ListValueNode $node) {
+ return '[' . $this->join($node->values, ', ') . ']';
+ },
+
+ NodeKind::OBJECT => function (ObjectValueNode $node) {
+ return '{' . $this->join($node->fields, ', ') . '}';
+ },
+
+ NodeKind::OBJECT_FIELD => function (ObjectFieldNode $node) {
+ return $node->name . ': ' . $node->value;
+ },
+
+ NodeKind::DIRECTIVE => function (DirectiveNode $node) {
+ return '@' . $node->name . $this->wrap('(', $this->join($node->arguments, ', '), ')');
+ },
+
+ NodeKind::NAMED_TYPE => function (NamedTypeNode $node) {
+ return $node->name;
+ },
+
+ NodeKind::LIST_TYPE => function (ListTypeNode $node) {
+ return '[' . $node->type . ']';
+ },
+
+ NodeKind::NON_NULL_TYPE => function (NonNullTypeNode $node) {
+ return $node->type . '!';
+ },
+
+ NodeKind::SCHEMA_DEFINITION => function (SchemaDefinitionNode $def) {
+ return $this->join(
+ [
+ 'schema',
+ $this->join($def->directives, ' '),
+ $this->block($def->operationTypes),
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::OPERATION_TYPE_DEFINITION => function (OperationTypeDefinitionNode $def) {
+ return $def->operation . ': ' . $def->type;
+ },
+
+ NodeKind::SCALAR_TYPE_DEFINITION => $this->addDescription(function (ScalarTypeDefinitionNode $def) {
+ return $this->join(['scalar', $def->name, $this->join($def->directives, ' ')], ' ');
+ }),
+
+ NodeKind::OBJECT_TYPE_DEFINITION => $this->addDescription(function (ObjectTypeDefinitionNode $def) {
+ return $this->join(
+ [
+ 'type',
+ $def->name,
+ $this->wrap('implements ', $this->join($def->interfaces, ' & ')),
+ $this->join($def->directives, ' '),
+ $this->block($def->fields),
+ ],
+ ' '
+ );
+ }),
+
+ NodeKind::FIELD_DEFINITION => $this->addDescription(function (FieldDefinitionNode $def) {
+ return $def->name
+ . $this->wrap('(', $this->join($def->arguments, ', '), ')')
+ . ': ' . $def->type
+ . $this->wrap(' ', $this->join($def->directives, ' '));
+ }),
+
+ NodeKind::INPUT_VALUE_DEFINITION => $this->addDescription(function (InputValueDefinitionNode $def) {
+ return $this->join(
+ [
+ $def->name . ': ' . $def->type,
+ $this->wrap('= ', $def->defaultValue),
+ $this->join($def->directives, ' '),
+ ],
+ ' '
+ );
+ }),
+
+ NodeKind::INTERFACE_TYPE_DEFINITION => $this->addDescription(
+ function (InterfaceTypeDefinitionNode $def) {
+ return $this->join(
+ [
+ 'interface',
+ $def->name,
+ $this->join($def->directives, ' '),
+ $this->block($def->fields),
+ ],
+ ' '
+ );
+ }
+ ),
+
+ NodeKind::UNION_TYPE_DEFINITION => $this->addDescription(function (UnionTypeDefinitionNode $def) {
+ return $this->join(
+ [
+ 'union',
+ $def->name,
+ $this->join($def->directives, ' '),
+ $def->types
+ ? '= ' . $this->join($def->types, ' | ')
+ : '',
+ ],
+ ' '
+ );
+ }),
+
+ NodeKind::ENUM_TYPE_DEFINITION => $this->addDescription(function (EnumTypeDefinitionNode $def) {
+ return $this->join(
+ [
+ 'enum',
+ $def->name,
+ $this->join($def->directives, ' '),
+ $this->block($def->values),
+ ],
+ ' '
+ );
+ }),
+
+ NodeKind::ENUM_VALUE_DEFINITION => $this->addDescription(function (EnumValueDefinitionNode $def) {
+ return $this->join([$def->name, $this->join($def->directives, ' ')], ' ');
+ }),
+
+ NodeKind::INPUT_OBJECT_TYPE_DEFINITION => $this->addDescription(function (
+ InputObjectTypeDefinitionNode $def
+ ) {
+ return $this->join(
+ [
+ 'input',
+ $def->name,
+ $this->join($def->directives, ' '),
+ $this->block($def->fields),
+ ],
+ ' '
+ );
+ }),
+
+ NodeKind::SCALAR_TYPE_EXTENSION => function (ScalarTypeExtensionNode $def) {
+ return $this->join(
+ [
+ 'extend scalar',
+ $def->name,
+ $this->join($def->directives, ' '),
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::OBJECT_TYPE_EXTENSION => function (ObjectTypeExtensionNode $def) {
+ return $this->join(
+ [
+ 'extend type',
+ $def->name,
+ $this->wrap('implements ', $this->join($def->interfaces, ' & ')),
+ $this->join($def->directives, ' '),
+ $this->block($def->fields),
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::INTERFACE_TYPE_EXTENSION => function (InterfaceTypeExtensionNode $def) {
+ return $this->join(
+ [
+ 'extend interface',
+ $def->name,
+ $this->join($def->directives, ' '),
+ $this->block($def->fields),
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::UNION_TYPE_EXTENSION => function (UnionTypeExtensionNode $def) {
+ return $this->join(
+ [
+ 'extend union',
+ $def->name,
+ $this->join($def->directives, ' '),
+ $def->types
+ ? '= ' . $this->join($def->types, ' | ')
+ : '',
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::ENUM_TYPE_EXTENSION => function (EnumTypeExtensionNode $def) {
+ return $this->join(
+ [
+ 'extend enum',
+ $def->name,
+ $this->join($def->directives, ' '),
+ $this->block($def->values),
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::INPUT_OBJECT_TYPE_EXTENSION => function (InputObjectTypeExtensionNode $def) {
+ return $this->join(
+ [
+ 'extend input',
+ $def->name,
+ $this->join($def->directives, ' '),
+ $this->block($def->fields),
+ ],
+ ' '
+ );
+ },
+
+ NodeKind::DIRECTIVE_DEFINITION => $this->addDescription(function (DirectiveDefinitionNode $def) {
+ return 'directive @'
+ . $def->name
+ . $this->wrap('(', $this->join($def->arguments, ', '), ')')
+ . ' on ' . $this->join($def->locations, ' | ');
+ }),
+ ],
]
- ]);
+ );
}
public function addDescription(\Closure $cb)
@@ -371,7 +469,9 @@ class Printer
$separator,
Utils::filter(
$maybeArray,
- function($x) { return !!$x;}
+ function ($x) {
+ return ! ! $x;
+ }
)
)
: '';
@@ -382,8 +482,10 @@ class Printer
* trailing blank line. However, if a block string starts with whitespace and is
* a single-line, adding a leading blank line would strip that whitespace.
*/
- private function printBlockString($value, $isDescription) {
+ private function printBlockString($value, $isDescription)
+ {
$escaped = str_replace('"""', '\\"""', $value);
+
return (($value[0] === ' ' || $value[0] === "\t") && strpos($value, "\n") === false)
? ('"""' . preg_replace('/"$/', "\"\n", $escaped) . '"""')
: ("\"\"\"\n" . ($isDescription ? $escaped : $this->indent($escaped)) . "\n\"\"\"");
diff --git a/src/Language/Source.php b/src/Language/Source.php
index 899d450..1beb8bc 100644
--- a/src/Language/Source.php
+++ b/src/Language/Source.php
@@ -1,36 +1,33 @@
body = $body;
- $this->length = mb_strlen($body, 'UTF-8');
- $this->name = $name ?: 'GraphQL request';
+ $this->body = $body;
+ $this->length = mb_strlen($body, 'UTF-8');
+ $this->name = $name ?: 'GraphQL request';
$this->locationOffset = $location ?: new SourceLocation(1, 1);
Utils::invariant(
@@ -66,21 +62,22 @@ class Source
}
/**
- * @param $position
+ * @param int $position
* @return SourceLocation
*/
public function getLocation($position)
{
- $line = 1;
+ $line = 1;
$column = $position + 1;
- $utfChars = json_decode('"\u2028\u2029"');
- $lineRegexp = '/\r\n|[\n\r'.$utfChars.']/su';
- $matches = [];
+ $utfChars = json_decode('"\u2028\u2029"');
+ $lineRegexp = '/\r\n|[\n\r' . $utfChars . ']/su';
+ $matches = [];
preg_match_all($lineRegexp, mb_substr($this->body, 0, $position, 'UTF-8'), $matches, PREG_OFFSET_CAPTURE);
foreach ($matches[0] as $index => $match) {
$line += 1;
+
$column = $position + 1 - ($match[1] + mb_strlen($match[0], 'UTF-8'));
}
diff --git a/src/Language/SourceLocation.php b/src/Language/SourceLocation.php
index d09363b..2c406ca 100644
--- a/src/Language/SourceLocation.php
+++ b/src/Language/SourceLocation.php
@@ -1,30 +1,40 @@
line = $line;
+ $this->line = $line;
$this->column = $col;
}
/**
- * @return array
+ * @return int[]
*/
public function toArray()
{
return [
- 'line' => $this->line,
- 'column' => $this->column
+ 'line' => $this->line,
+ 'column' => $this->column,
];
}
/**
- * @return array
+ * @return int[]
*/
public function toSerializableArray()
{
@@ -32,13 +42,9 @@ class SourceLocation implements \JsonSerializable
}
/**
- * Specify data which should be serialized to JSON
- * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
- * @return mixed data which can be serialized by json_encode,
- * which is a value of any type other than a resource.
- * @since 5.4.0
+ * @return int[]
*/
- function jsonSerialize()
+ public function jsonSerialize()
{
return $this->toSerializableArray();
}
diff --git a/src/Language/Token.php b/src/Language/Token.php
index 880cb0d..a1c966c 100644
--- a/src/Language/Token.php
+++ b/src/Language/Token.php
@@ -1,4 +1,7 @@
';
- const EOF = '';
- const BANG = '!';
- const DOLLAR = '$';
- const AMP = '&';
- const PAREN_L = '(';
- const PAREN_R = ')';
- const SPREAD = '...';
- const COLON = ':';
- const EQUALS = '=';
- const AT = '@';
- const BRACKET_L = '[';
- const BRACKET_R = ']';
- const BRACE_L = '{';
- const PIPE = '|';
- const BRACE_R = '}';
- const NAME = 'Name';
- const INT = 'Int';
- const FLOAT = 'Float';
- const STRING = 'String';
+ const SOF = '';
+ const EOF = '';
+ const BANG = '!';
+ const DOLLAR = '$';
+ const AMP = '&';
+ const PAREN_L = '(';
+ const PAREN_R = ')';
+ const SPREAD = '...';
+ const COLON = ':';
+ const EQUALS = '=';
+ const AT = '@';
+ const BRACKET_L = '[';
+ const BRACKET_R = ']';
+ const BRACE_L = '{';
+ const PIPE = '|';
+ const BRACE_R = '}';
+ const NAME = 'Name';
+ const INT = 'Int';
+ const FLOAT = 'Float';
+ const STRING = 'String';
const BLOCK_STRING = 'BlockString';
- const COMMENT = 'Comment';
+ const COMMENT = 'Comment';
/**
* The kind of Token (see one of constants above).
@@ -66,9 +69,7 @@ class Token
*/
public $column;
- /**
- * @var string|null
- */
+ /** @var string|null */
public $value;
/**
@@ -80,31 +81,28 @@ class Token
*/
public $prev;
- /**
- * @var Token
- */
+ /** @var Token */
public $next;
/**
- * Token constructor.
- * @param $kind
- * @param $start
- * @param $end
- * @param $line
- * @param $column
- * @param Token $previous
- * @param null $value
+ *
+ * @param string $kind
+ * @param int $start
+ * @param int $end
+ * @param int $line
+ * @param int $column
+ * @param mixed|null $value
*/
- public function __construct($kind, $start, $end, $line, $column, Token $previous = null, $value = null)
+ public function __construct($kind, $start, $end, $line, $column, ?Token $previous = null, $value = null)
{
- $this->kind = $kind;
- $this->start = (int) $start;
- $this->end = (int) $end;
- $this->line = (int) $line;
- $this->column = (int) $column;
- $this->prev = $previous;
- $this->next = null;
- $this->value = $value;
+ $this->kind = $kind;
+ $this->start = $start;
+ $this->end = $end;
+ $this->line = $line;
+ $this->column = $column;
+ $this->prev = $previous;
+ $this->next = null;
+ $this->value = $value;
}
/**
@@ -112,19 +110,19 @@ class Token
*/
public function getDescription()
{
- return $this->kind . ($this->value ? ' "' . $this->value . '"' : '');
+ return $this->kind . ($this->value ? ' "' . $this->value . '"' : '');
}
/**
- * @return array
+ * @return (string|int|null)[]
*/
public function toArray()
{
return [
- 'kind' => $this->kind,
- 'value' => $this->value,
- 'line' => $this->line,
- 'column' => $this->column
+ 'kind' => $this->kind,
+ 'value' => $this->value,
+ 'line' => $this->line,
+ 'column' => $this->column,
];
}
}
diff --git a/src/Language/Visitor.php b/src/Language/Visitor.php
index ab20d1e..e266f0f 100644
--- a/src/Language/Visitor.php
+++ b/src/Language/Visitor.php
@@ -1,19 +1,24 @@
[],
- NodeKind::DOCUMENT => ['definitions'],
+ NodeKind::NAME => [],
+ NodeKind::DOCUMENT => ['definitions'],
NodeKind::OPERATION_DEFINITION => ['name', 'variableDefinitions', 'directives', 'selectionSet'],
- NodeKind::VARIABLE_DEFINITION => ['variable', 'type', 'defaultValue'],
- NodeKind::VARIABLE => ['name'],
- NodeKind::SELECTION_SET => ['selections'],
- NodeKind::FIELD => ['alias', 'name', 'arguments', 'directives', 'selectionSet'],
- NodeKind::ARGUMENT => ['name', 'value'],
- NodeKind::FRAGMENT_SPREAD => ['name', 'directives'],
- NodeKind::INLINE_FRAGMENT => ['typeCondition', 'directives', 'selectionSet'],
- NodeKind::FRAGMENT_DEFINITION => [
+ NodeKind::VARIABLE_DEFINITION => ['variable', 'type', 'defaultValue'],
+ NodeKind::VARIABLE => ['name'],
+ NodeKind::SELECTION_SET => ['selections'],
+ NodeKind::FIELD => ['alias', 'name', 'arguments', 'directives', 'selectionSet'],
+ NodeKind::ARGUMENT => ['name', 'value'],
+ NodeKind::FRAGMENT_SPREAD => ['name', 'directives'],
+ NodeKind::INLINE_FRAGMENT => ['typeCondition', 'directives', 'selectionSet'],
+ NodeKind::FRAGMENT_DEFINITION => [
'name',
// Note: fragment variable definitions are experimental and may be changed
// or removed in the future.
'variableDefinitions',
'typeCondition',
'directives',
- 'selectionSet'
+ 'selectionSet',
],
- NodeKind::INT => [],
- NodeKind::FLOAT => [],
- NodeKind::STRING => [],
- NodeKind::BOOLEAN => [],
- NodeKind::NULL => [],
- NodeKind::ENUM => [],
- NodeKind::LST => ['values'],
- NodeKind::OBJECT => ['fields'],
- NodeKind::OBJECT_FIELD => ['name', 'value'],
- NodeKind::DIRECTIVE => ['name', 'arguments'],
- NodeKind::NAMED_TYPE => ['name'],
- NodeKind::LIST_TYPE => ['type'],
+ NodeKind::INT => [],
+ NodeKind::FLOAT => [],
+ NodeKind::STRING => [],
+ NodeKind::BOOLEAN => [],
+ NodeKind::NULL => [],
+ NodeKind::ENUM => [],
+ NodeKind::LST => ['values'],
+ NodeKind::OBJECT => ['fields'],
+ NodeKind::OBJECT_FIELD => ['name', 'value'],
+ NodeKind::DIRECTIVE => ['name', 'arguments'],
+ NodeKind::NAMED_TYPE => ['name'],
+ NodeKind::LIST_TYPE => ['type'],
NodeKind::NON_NULL_TYPE => ['type'],
- NodeKind::SCHEMA_DEFINITION => ['directives', 'operationTypes'],
- NodeKind::OPERATION_TYPE_DEFINITION => ['type'],
- NodeKind::SCALAR_TYPE_DEFINITION => ['description', 'name', 'directives'],
- NodeKind::OBJECT_TYPE_DEFINITION => ['description', 'name', 'interfaces', 'directives', 'fields'],
- NodeKind::FIELD_DEFINITION => ['description', 'name', 'arguments', 'type', 'directives'],
- NodeKind::INPUT_VALUE_DEFINITION => ['description', 'name', 'type', 'defaultValue', 'directives'],
- NodeKind::INTERFACE_TYPE_DEFINITION => ['description', 'name', 'directives', 'fields'],
- NodeKind::UNION_TYPE_DEFINITION => ['description', 'name', 'directives', 'types'],
- NodeKind::ENUM_TYPE_DEFINITION => ['description', 'name', 'directives', 'values'],
- NodeKind::ENUM_VALUE_DEFINITION => ['description', 'name', 'directives'],
+ NodeKind::SCHEMA_DEFINITION => ['directives', 'operationTypes'],
+ NodeKind::OPERATION_TYPE_DEFINITION => ['type'],
+ NodeKind::SCALAR_TYPE_DEFINITION => ['description', 'name', 'directives'],
+ NodeKind::OBJECT_TYPE_DEFINITION => ['description', 'name', 'interfaces', 'directives', 'fields'],
+ NodeKind::FIELD_DEFINITION => ['description', 'name', 'arguments', 'type', 'directives'],
+ NodeKind::INPUT_VALUE_DEFINITION => ['description', 'name', 'type', 'defaultValue', 'directives'],
+ NodeKind::INTERFACE_TYPE_DEFINITION => ['description', 'name', 'directives', 'fields'],
+ NodeKind::UNION_TYPE_DEFINITION => ['description', 'name', 'directives', 'types'],
+ NodeKind::ENUM_TYPE_DEFINITION => ['description', 'name', 'directives', 'values'],
+ NodeKind::ENUM_VALUE_DEFINITION => ['description', 'name', 'directives'],
NodeKind::INPUT_OBJECT_TYPE_DEFINITION => ['description', 'name', 'directives', 'fields'],
- NodeKind::SCALAR_TYPE_EXTENSION => ['name', 'directives'],
- NodeKind::OBJECT_TYPE_EXTENSION => ['name', 'interfaces', 'directives', 'fields'],
- NodeKind::INTERFACE_TYPE_EXTENSION => ['name', 'directives', 'fields'],
- NodeKind::UNION_TYPE_EXTENSION => ['name', 'directives', 'types'],
- NodeKind::ENUM_TYPE_EXTENSION => ['name', 'directives', 'values'],
+ NodeKind::SCALAR_TYPE_EXTENSION => ['name', 'directives'],
+ NodeKind::OBJECT_TYPE_EXTENSION => ['name', 'interfaces', 'directives', 'fields'],
+ NodeKind::INTERFACE_TYPE_EXTENSION => ['name', 'directives', 'fields'],
+ NodeKind::UNION_TYPE_EXTENSION => ['name', 'directives', 'types'],
+ NodeKind::ENUM_TYPE_EXTENSION => ['name', 'directives', 'values'],
NodeKind::INPUT_OBJECT_TYPE_EXTENSION => ['name', 'directives', 'fields'],
- NodeKind::DIRECTIVE_DEFINITION => ['description', 'name', 'arguments', 'locations']
+ NodeKind::DIRECTIVE_DEFINITION => ['description', 'name', 'arguments', 'locations'],
];
/**
* Visit the AST (see class description for details)
*
* @api
- * @param Node $root
- * @param array $visitor
- * @param array $keyMap
+ * @param Node|ArrayObject|stdClass $root
+ * @param callable[] $visitor
+ * @param mixed[]|null $keyMap
* @return Node|mixed
* @throws \Exception
*/
@@ -175,28 +181,28 @@ class Visitor
{
$visitorKeys = $keyMap ?: self::$visitorKeys;
- $stack = null;
- $inArray = $root instanceof NodeList || is_array($root);
- $keys = [$root];
- $index = -1;
- $edits = [];
- $parent = null;
- $path = [];
+ $stack = null;
+ $inArray = $root instanceof NodeList || is_array($root);
+ $keys = [$root];
+ $index = -1;
+ $edits = [];
+ $parent = null;
+ $path = [];
$ancestors = [];
- $newRoot = $root;
+ $newRoot = $root;
$UNDEFINED = null;
do {
$index++;
$isLeaving = $index === count($keys);
- $key = null;
- $node = null;
- $isEdited = $isLeaving && count($edits) !== 0;
+ $key = null;
+ $node = null;
+ $isEdited = $isLeaving && count($edits) !== 0;
if ($isLeaving) {
- $key = !$ancestors ? $UNDEFINED : $path[count($path) - 1];
- $node = $parent;
+ $key = ! $ancestors ? $UNDEFINED : $path[count($path) - 1];
+ $node = $parent;
$parent = array_pop($ancestors);
if ($isEdited) {
@@ -210,7 +216,7 @@ class Visitor
}
$editOffset = 0;
for ($ii = 0; $ii < count($edits); $ii++) {
- $editKey = $edits[$ii][0];
+ $editKey = $edits[$ii][0];
$editValue = $edits[$ii][1];
if ($inArray) {
@@ -232,13 +238,13 @@ class Visitor
}
}
}
- $index = $stack['index'];
- $keys = $stack['keys'];
- $edits = $stack['edits'];
+ $index = $stack['index'];
+ $keys = $stack['keys'];
+ $edits = $stack['edits'];
$inArray = $stack['inArray'];
- $stack = $stack['prev'];
+ $stack = $stack['prev'];
} else {
- $key = $parent ? ($inArray ? $index : $keys[$index]) : $UNDEFINED;
+ $key = $parent ? ($inArray ? $index : $keys[$index]) : $UNDEFINED;
$node = $parent ? (($parent instanceof NodeList || is_array($parent)) ? $parent[$key] : $parent->{$key}) : $newRoot;
if ($node === null || $node === $UNDEFINED) {
continue;
@@ -249,8 +255,8 @@ class Visitor
}
$result = null;
- if (!$node instanceof NodeList && !is_array($node)) {
- if (!($node instanceof Node)) {
+ if (! $node instanceof NodeList && ! is_array($node)) {
+ if (! ($node instanceof Node)) {
throw new \Exception('Invalid AST Node: ' . json_encode($node));
}
@@ -264,7 +270,7 @@ class Visitor
if ($result->doBreak) {
break;
}
- if (!$isLeaving && $result->doContinue) {
+ if (! $isLeaving && $result->doContinue) {
array_pop($path);
continue;
}
@@ -276,13 +282,13 @@ class Visitor
}
$edits[] = [$key, $editValue];
- if (!$isLeaving) {
- if ($editValue instanceof Node) {
- $node = $editValue;
- } else {
+ if (! $isLeaving) {
+ if (! ($editValue instanceof Node)) {
array_pop($path);
continue;
}
+
+ $node = $editValue;
}
}
}
@@ -295,16 +301,16 @@ class Visitor
if ($isLeaving) {
array_pop($path);
} else {
- $stack = [
+ $stack = [
'inArray' => $inArray,
- 'index' => $index,
- 'keys' => $keys,
- 'edits' => $edits,
- 'prev' => $stack
+ 'index' => $index,
+ 'keys' => $keys,
+ 'edits' => $edits,
+ 'prev' => $stack,
];
$inArray = $node instanceof NodeList || is_array($node);
- $keys = ($inArray ? $node : $visitorKeys[$node->kind]) ?: [];
+ $keys = ($inArray ? $node : $visitorKeys[$node->kind]) ?: [];
$index = -1;
$edits = [];
if ($parent) {
@@ -312,7 +318,6 @@ class Visitor
}
$parent = $node;
}
-
} while ($stack);
if (count($edits) !== 0) {
@@ -330,8 +335,9 @@ class Visitor
*/
public static function stop()
{
- $r = new VisitorOperation();
+ $r = new VisitorOperation();
$r->doBreak = true;
+
return $r;
}
@@ -343,8 +349,9 @@ class Visitor
*/
public static function skipNode()
{
- $r = new VisitorOperation();
+ $r = new VisitorOperation();
$r->doContinue = true;
+
return $r;
}
@@ -356,66 +363,79 @@ class Visitor
*/
public static function removeNode()
{
- $r = new VisitorOperation();
+ $r = new VisitorOperation();
$r->removeNode = true;
+
return $r;
}
/**
- * @param $visitors
- * @return array
+ * @param callable[][] $visitors
+ * @return callable[][]
*/
- static function visitInParallel($visitors)
+ public static function visitInParallel($visitors)
{
$visitorsCount = count($visitors);
- $skipping = new \SplFixedArray($visitorsCount);
+ $skipping = new \SplFixedArray($visitorsCount);
return [
- 'enter' => function ($node) use ($visitors, $skipping, $visitorsCount) {
+ 'enter' => function (Node $node) use ($visitors, $skipping, $visitorsCount) {
for ($i = 0; $i < $visitorsCount; $i++) {
- if (empty($skipping[$i])) {
- $fn = self::getVisitFn($visitors[$i], $node->kind, /* isLeaving */ false);
+ if (! empty($skipping[$i])) {
+ continue;
+ }
- if ($fn) {
- $result = call_user_func_array($fn, func_get_args());
+ $fn = self::getVisitFn(
+ $visitors[$i],
+ $node->kind, /* isLeaving */
+ false
+ );
- if ($result instanceof VisitorOperation) {
- if ($result->doContinue) {
- $skipping[$i] = $node;
- } else if ($result->doBreak) {
- $skipping[$i] = $result;
- } else if ($result->removeNode) {
- return $result;
- }
- } else if ($result !== null) {
- return $result;
- }
+ if (! $fn) {
+ continue;
+ }
+
+ $result = call_user_func_array($fn, func_get_args());
+
+ if ($result instanceof VisitorOperation) {
+ if ($result->doContinue) {
+ $skipping[$i] = $node;
+ } elseif ($result->doBreak) {
+ $skipping[$i] = $result;
+ } elseif ($result->removeNode) {
+ return $result;
}
+ } elseif ($result !== null) {
+ return $result;
}
}
},
- 'leave' => function ($node) use ($visitors, $skipping, $visitorsCount) {
+ 'leave' => function (Node $node) use ($visitors, $skipping, $visitorsCount) {
for ($i = 0; $i < $visitorsCount; $i++) {
if (empty($skipping[$i])) {
- $fn = self::getVisitFn($visitors[$i], $node->kind, /* isLeaving */ true);
+ $fn = self::getVisitFn(
+ $visitors[$i],
+ $node->kind, /* isLeaving */
+ true
+ );
if ($fn) {
$result = call_user_func_array($fn, func_get_args());
if ($result instanceof VisitorOperation) {
if ($result->doBreak) {
$skipping[$i] = $result;
- } else if ($result->removeNode) {
+ } elseif ($result->removeNode) {
return $result;
}
- } else if ($result !== null) {
+ } elseif ($result !== null) {
return $result;
}
}
- } else if ($skipping[$i] === $node) {
+ } elseif ($skipping[$i] === $node) {
$skipping[$i] = null;
}
}
- }
+ },
];
}
@@ -423,10 +443,10 @@ class Visitor
* Creates a new visitor instance which maintains a provided TypeInfo instance
* along with visiting visitor.
*/
- static function visitWithTypeInfo(TypeInfo $typeInfo, $visitor)
+ public static function visitWithTypeInfo(TypeInfo $typeInfo, $visitor)
{
return [
- 'enter' => function ($node) use ($typeInfo, $visitor) {
+ 'enter' => function (Node $node) use ($typeInfo, $visitor) {
$typeInfo->enter($node);
$fn = self::getVisitFn($visitor, $node->kind, false);
@@ -438,52 +458,58 @@ class Visitor
$typeInfo->enter($result);
}
}
+
return $result;
}
+
return null;
},
- 'leave' => function ($node) use ($typeInfo, $visitor) {
- $fn = self::getVisitFn($visitor, $node->kind, true);
+ 'leave' => function (Node $node) use ($typeInfo, $visitor) {
+ $fn = self::getVisitFn($visitor, $node->kind, true);
$result = $fn ? call_user_func_array($fn, func_get_args()) : null;
$typeInfo->leave($node);
+
return $result;
- }
+ },
];
}
/**
- * @param $visitor
- * @param $kind
- * @param $isLeaving
- * @return null
+ * @param callable[]|null $visitor
+ * @param string $kind
+ * @param bool $isLeaving
+ * @return callable|null
*/
public static function getVisitFn($visitor, $kind, $isLeaving)
{
- if (!$visitor) {
+ if ($visitor === null) {
return null;
}
- $kindVisitor = isset($visitor[$kind]) ? $visitor[$kind] : null;
- if (!$isLeaving && is_callable($kindVisitor)) {
+ $kindVisitor = $visitor[$kind] ?? null;
+
+ if (! $isLeaving && is_callable($kindVisitor)) {
// { Kind() {} }
return $kindVisitor;
}
if (is_array($kindVisitor)) {
if ($isLeaving) {
- $kindSpecificVisitor = isset($kindVisitor['leave']) ? $kindVisitor['leave'] : null;
+ $kindSpecificVisitor = $kindVisitor['leave'] ?? null;
} else {
- $kindSpecificVisitor = isset($kindVisitor['enter']) ? $kindVisitor['enter'] : null;
+ $kindSpecificVisitor = $kindVisitor['enter'] ?? null;
}
if ($kindSpecificVisitor && is_callable($kindSpecificVisitor)) {
// { Kind: { enter() {}, leave() {} } }
return $kindSpecificVisitor;
}
+
return null;
}
$visitor += ['leave' => null, 'enter' => null];
+
$specificVisitor = $isLeaving ? $visitor['leave'] : $visitor['enter'];
if ($specificVisitor) {
@@ -491,13 +517,14 @@ class Visitor
// { enter() {}, leave() {} }
return $specificVisitor;
}
- $specificKindVisitor = isset($specificVisitor[$kind]) ? $specificVisitor[$kind] : null;
+ $specificKindVisitor = $specificVisitor[$kind] ?? null;
if (is_callable($specificKindVisitor)) {
// { enter: { Kind() {} }, leave: { Kind() {} } }
return $specificKindVisitor;
}
}
+
return null;
}
}
diff --git a/src/Language/VisitorOperation.php b/src/Language/VisitorOperation.php
new file mode 100644
index 0000000..2316261
--- /dev/null
+++ b/src/Language/VisitorOperation.php
@@ -0,0 +1,17 @@
+loc = Location::create($node['loc']['start'], $node['loc']['end']);
}
-
foreach ($node as $key => $value) {
- if ('loc' === $key || 'kind' === $key) {
- continue ;
+ if ($key === 'loc' || $key === 'kind') {
+ continue;
}
if (is_array($value)) {
if (isset($value[0]) || empty($value)) {
@@ -92,6 +110,7 @@ class AST
}
$instance->{$key} = $value;
}
+
return $instance;
}
@@ -99,8 +118,7 @@ class AST
* Convert AST node to serializable array
*
* @api
- * @param Node $node
- * @return array
+ * @return mixed[]
*/
public static function toArray(Node $node)
{
@@ -126,17 +144,17 @@ class AST
* | null | NullValue |
*
* @api
- * @param $value
- * @param InputType $type
+ * @param Type|mixed|null $value
* @return ObjectValueNode|ListValueNode|BooleanValueNode|IntValueNode|FloatValueNode|EnumValueNode|StringValueNode|NullValueNode
*/
- static function astFromValue($value, InputType $type)
+ public static function astFromValue($value, InputType $type)
{
if ($type instanceof NonNull) {
$astValue = self::astFromValue($value, $type->getWrappedType());
if ($astValue instanceof NullValueNode) {
return null;
}
+
return $astValue;
}
@@ -152,56 +170,65 @@ class AST
$valuesNodes = [];
foreach ($value as $item) {
$itemNode = self::astFromValue($item, $itemType);
- if ($itemNode) {
- $valuesNodes[] = $itemNode;
+ if (! $itemNode) {
+ continue;
}
+
+ $valuesNodes[] = $itemNode;
}
+
return new ListValueNode(['values' => $valuesNodes]);
}
+
return self::astFromValue($value, $itemType);
}
// Populate the fields of the input object by creating ASTs from each value
// in the PHP object according to the fields in the input type.
if ($type instanceof InputObjectType) {
- $isArray = is_array($value);
+ $isArray = is_array($value);
$isArrayLike = $isArray || $value instanceof \ArrayAccess;
- if ($value === null || (!$isArrayLike && !is_object($value))) {
+ if ($value === null || (! $isArrayLike && ! is_object($value))) {
return null;
}
- $fields = $type->getFields();
+ $fields = $type->getFields();
$fieldNodes = [];
foreach ($fields as $fieldName => $field) {
if ($isArrayLike) {
- $fieldValue = isset($value[$fieldName]) ? $value[$fieldName] : null;
+ $fieldValue = $value[$fieldName] ?? null;
} else {
- $fieldValue = isset($value->{$fieldName}) ? $value->{$fieldName} : null;
+ $fieldValue = $value->{$fieldName} ?? null;
}
// Have to check additionally if key exists, since we differentiate between
// "no key" and "value is null":
- if (null !== $fieldValue) {
+ if ($fieldValue !== null) {
$fieldExists = true;
- } else if ($isArray) {
+ } elseif ($isArray) {
$fieldExists = array_key_exists($fieldName, $value);
- } else if ($isArrayLike) {
+ } elseif ($isArrayLike) {
/** @var \ArrayAccess $value */
$fieldExists = $value->offsetExists($fieldName);
} else {
$fieldExists = property_exists($value, $fieldName);
}
- if ($fieldExists) {
- $fieldNode = self::astFromValue($fieldValue, $field->getType());
-
- if ($fieldNode) {
- $fieldNodes[] = new ObjectFieldNode([
- 'name' => new NameNode(['value' => $fieldName]),
- 'value' => $fieldNode
- ]);
- }
+ if (! $fieldExists) {
+ continue;
}
+
+ $fieldNode = self::astFromValue($fieldValue, $field->getType());
+
+ if (! $fieldNode) {
+ continue;
+ }
+
+ $fieldNodes[] = new ObjectFieldNode([
+ 'name' => new NameNode(['value' => $fieldName]),
+ 'value' => $fieldNode,
+ ]);
}
+
return new ObjectValueNode(['fields' => $fieldNodes]);
}
@@ -230,9 +257,12 @@ class AST
return new IntValueNode(['value' => $serialized]);
}
if (is_float($serialized)) {
+ // int cast with == used for performance reasons
+ // @codingStandardsIgnoreLine
if ((int) $serialized == $serialized) {
return new IntValueNode(['value' => $serialized]);
}
+
return new FloatValueNode(['value' => $serialized]);
}
if (is_string($serialized)) {
@@ -250,7 +280,7 @@ class AST
// Use json_encode, which uses the same string encoding as GraphQL,
// then remove the quotes.
return new StringValueNode([
- 'value' => substr(json_encode($serialized), 1, -1)
+ 'value' => substr(json_encode($serialized), 1, -1),
]);
}
@@ -280,17 +310,16 @@ class AST
* | Null Value | null |
*
* @api
- * @param $valueNode
- * @param InputType $type
- * @param mixed[]|null $variables
- * @return array|null|\stdClass
+ * @param ValueNode|null $valueNode
+ * @param mixed[]|null $variables
+ * @return mixed[]|null|\stdClass
* @throws \Exception
*/
public static function valueFromAST($valueNode, InputType $type, $variables = null)
{
$undefined = Utils::undefined();
- if (!$valueNode) {
+ if ($valueNode === null) {
// When there is no AST, then there is also no value.
// Importantly, this is different from returning the GraphQL null value.
return $undefined;
@@ -301,6 +330,7 @@ class AST
// Invalid: intentionally return no value.
return $undefined;
}
+
return self::valueFromAST($valueNode, $type->getWrappedType(), $variables);
}
@@ -312,7 +342,7 @@ class AST
if ($valueNode instanceof VariableNode) {
$variableName = $valueNode->name->value;
- if (!$variables || !array_key_exists($variableName, $variables)) {
+ if (! $variables || ! array_key_exists($variableName, $variables)) {
// No valid return value.
return $undefined;
}
@@ -327,7 +357,7 @@ class AST
if ($valueNode instanceof ListValueNode) {
$coercedValues = [];
- $itemNodes = $valueNode->values;
+ $itemNodes = $valueNode->values;
foreach ($itemNodes as $itemNode) {
if (self::isMissingVariable($itemNode, $variables)) {
// If an array contains a missing variable, it is either coerced to
@@ -346,6 +376,7 @@ class AST
$coercedValues[] = $itemValue;
}
}
+
return $coercedValues;
}
$coercedValue = self::valueFromAST($valueNode, $itemType, $variables);
@@ -353,31 +384,37 @@ class AST
// Invalid: intentionally return no value.
return $undefined;
}
+
return [$coercedValue];
}
if ($type instanceof InputObjectType) {
- if (!$valueNode instanceof ObjectValueNode) {
+ if (! $valueNode instanceof ObjectValueNode) {
// Invalid: intentionally return no value.
return $undefined;
}
$coercedObj = [];
- $fields = $type->getFields();
- $fieldNodes = Utils::keyMap($valueNode->fields, function($field) {return $field->name->value;});
+ $fields = $type->getFields();
+ $fieldNodes = Utils::keyMap(
+ $valueNode->fields,
+ function ($field) {
+ return $field->name->value;
+ }
+ );
foreach ($fields as $field) {
/** @var ValueNode $fieldNode */
$fieldName = $field->name;
- $fieldNode = isset($fieldNodes[$fieldName]) ? $fieldNodes[$fieldName] : null;
+ $fieldNode = $fieldNodes[$fieldName] ?? null;
- if (!$fieldNode || self::isMissingVariable($fieldNode->value, $variables)) {
+ if (! $fieldNode || self::isMissingVariable($fieldNode->value, $variables)) {
if ($field->defaultValueExists()) {
$coercedObj[$fieldName] = $field->defaultValue;
- } else if ($field->getType() instanceof NonNull) {
+ } elseif ($field->getType() instanceof NonNull) {
// Invalid: intentionally return no value.
return $undefined;
}
- continue ;
+ continue;
}
$fieldValue = self::valueFromAST($fieldNode ? $fieldNode->value : null, $field->getType(), $variables);
@@ -388,15 +425,16 @@ class AST
}
$coercedObj[$fieldName] = $fieldValue;
}
+
return $coercedObj;
}
if ($type instanceof EnumType) {
- if (!$valueNode instanceof EnumValueNode) {
+ if (! $valueNode instanceof EnumValueNode) {
return $undefined;
}
$enumValue = $type->getValue($valueNode->value);
- if (!$enumValue) {
+ if (! $enumValue) {
return $undefined;
}
@@ -436,12 +474,13 @@ class AST
* | Null | null |
*
* @api
- * @param Node $valueNode
- * @param array|null $variables
+ * @param Node $valueNode
+ * @param mixed[]|null $variables
* @return mixed
* @throws \Exception
*/
- public static function valueFromASTUntyped($valueNode, array $variables = null) {
+ public static function valueFromASTUntyped($valueNode, ?array $variables = null)
+ {
switch (true) {
case $valueNode instanceof NullValueNode:
return null;
@@ -455,24 +494,29 @@ class AST
return $valueNode->value;
case $valueNode instanceof ListValueNode:
return array_map(
- function($node) use ($variables) {
+ function ($node) use ($variables) {
return self::valueFromASTUntyped($node, $variables);
},
iterator_to_array($valueNode->values)
);
case $valueNode instanceof ObjectValueNode:
- return array_combine(
- array_map(
- function($field) { return $field->name->value; },
- iterator_to_array($valueNode->fields)
- ),
- array_map(
- function($field) use ($variables) { return self::valueFromASTUntyped($field->value, $variables); },
- iterator_to_array($valueNode->fields)
- )
- );
+ return array_combine(
+ array_map(
+ function ($field) {
+ return $field->name->value;
+ },
+ iterator_to_array($valueNode->fields)
+ ),
+ array_map(
+ function ($field) use ($variables) {
+ return self::valueFromASTUntyped($field->value, $variables);
+ },
+ iterator_to_array($valueNode->fields)
+ )
+ );
case $valueNode instanceof VariableNode:
$variableName = $valueNode->name->value;
+
return ($variables && isset($variables[$variableName]))
? $variables[$variableName]
: null;
@@ -485,7 +529,6 @@ class AST
* Returns type definition for given AST Type node
*
* @api
- * @param Schema $schema
* @param NamedTypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode
* @return Type|null
* @throws \Exception
@@ -494,10 +537,12 @@ class AST
{
if ($inputTypeNode instanceof ListTypeNode) {
$innerType = self::typeFromAST($schema, $inputTypeNode->type);
+
return $innerType ? new ListOfType($innerType) : null;
}
if ($inputTypeNode instanceof NonNullTypeNode) {
$innerType = self::typeFromAST($schema, $inputTypeNode->type);
+
return $innerType ? new NonNull($innerType) : null;
}
if ($inputTypeNode instanceof NamedTypeNode) {
@@ -510,21 +555,20 @@ class AST
/**
* Returns true if the provided valueNode is a variable which is not defined
* in the set of variables.
- * @param $valueNode
- * @param $variables
+ * @param ValueNode $valueNode
+ * @param mixed[] $variables
* @return bool
*/
private static function isMissingVariable($valueNode, $variables)
{
return $valueNode instanceof VariableNode &&
- (!$variables || !array_key_exists($valueNode->name->value, $variables));
+ (count($variables) === 0 || ! array_key_exists($valueNode->name->value, $variables));
}
/**
* Returns operation type ("query", "mutation" or "subscription") given a document and operation name
*
* @api
- * @param DocumentNode $document
* @param string $operationName
* @return bool
*/
@@ -532,13 +576,16 @@ class AST
{
if ($document->definitions) {
foreach ($document->definitions as $def) {
- if ($def instanceof OperationDefinitionNode) {
- if (!$operationName || (isset($def->name->value) && $def->name->value === $operationName)) {
- return $def->operation;
- }
+ if (! ($def instanceof OperationDefinitionNode)) {
+ continue;
+ }
+
+ if (! $operationName || (isset($def->name->value) && $def->name->value === $operationName)) {
+ return $def->operation;
}
}
}
+
return false;
}
}
diff --git a/src/Utils/ASTDefinitionBuilder.php b/src/Utils/ASTDefinitionBuilder.php
index 36c8ec8..8ca7d16 100644
--- a/src/Utils/ASTDefinitionBuilder.php
+++ b/src/Utils/ASTDefinitionBuilder.php
@@ -1,16 +1,21 @@
typeDefintionsMap = $typeDefintionsMap;
+ /**
+ * @param Node[] $typeDefintionsMap
+ * @param bool[] $options
+ */
+ public function __construct(
+ array $typeDefintionsMap,
+ $options,
+ callable $resolveType,
+ ?callable $typeConfigDecorator = null
+ ) {
+ $this->typeDefintionsMap = $typeDefintionsMap;
$this->typeConfigDecorator = $typeConfigDecorator;
- $this->options = $options;
- $this->resolveType = $resolveType;
+ $this->options = $options;
+ $this->resolveType = $resolveType;
$this->cache = Type::getAllBuiltInTypes();
}
/**
- * @param Type $innerType
* @param TypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode
* @return Type
*/
private function buildWrappedType(Type $innerType, TypeNode $inputTypeNode)
{
- if ($inputTypeNode->kind == NodeKind::LIST_TYPE) {
+ if ($inputTypeNode->kind === NodeKind::LIST_TYPE) {
return Type::listOf($this->buildWrappedType($innerType, $inputTypeNode->type));
}
- if ($inputTypeNode->kind == NodeKind::NON_NULL_TYPE) {
+ if ($inputTypeNode->kind === NodeKind::NON_NULL_TYPE) {
$wrappedType = $this->buildWrappedType($innerType, $inputTypeNode->type);
+
return Type::nonNull(NonNull::assertNullableType($wrappedType));
}
+
return $innerType;
}
@@ -95,37 +103,29 @@ class ASTDefinitionBuilder
while ($namedType->kind === NodeKind::LIST_TYPE || $namedType->kind === NodeKind::NON_NULL_TYPE) {
$namedType = $namedType->type;
}
+
return $namedType;
}
/**
- * @param string $typeName
+ * @param string $typeName
* @param NamedTypeNode|null $typeNode
* @return Type
* @throws Error
*/
- private function internalBuildType($typeName, $typeNode = null) {
- if (!isset($this->cache[$typeName])) {
+ private function internalBuildType($typeName, $typeNode = null)
+ {
+ if (! isset($this->cache[$typeName])) {
if (isset($this->typeDefintionsMap[$typeName])) {
$type = $this->makeSchemaDef($this->typeDefintionsMap[$typeName]);
if ($this->typeConfigDecorator) {
$fn = $this->typeConfigDecorator;
try {
$config = $fn($type->config, $this->typeDefintionsMap[$typeName], $this->typeDefintionsMap);
- } catch (\Exception $e) {
- throw new Error(
- "Type config decorator passed to " . (static::class) . " threw an error " .
- "when building $typeName type: {$e->getMessage()}",
- null,
- null,
- null,
- null,
- $e
- );
} catch (\Throwable $e) {
throw new Error(
- "Type config decorator passed to " . (static::class) . " threw an error " .
- "when building $typeName type: {$e->getMessage()}",
+ sprintf('Type config decorator passed to %s threw an error ', static::class) .
+ sprintf('when building %s type: %s', $typeName, $e->getMessage()),
null,
null,
null,
@@ -133,17 +133,20 @@ class ASTDefinitionBuilder
$e
);
}
- if (!is_array($config) || isset($config[0])) {
+ if (! is_array($config) || isset($config[0])) {
throw new Error(
- "Type config decorator passed to " . (static::class) . " is expected to return an array, but got " .
- Utils::getVariableType($config)
+ sprintf(
+ 'Type config decorator passed to %s is expected to return an array, but got %s',
+ static::class,
+ Utils::getVariableType($config)
+ )
);
}
$type = $this->makeSchemaDefFromConfig($this->typeDefintionsMap[$typeName], $config);
}
$this->cache[$typeName] = $type;
} else {
- $fn = $this->resolveType;
+ $fn = $this->resolveType;
$this->cache[$typeName] = $fn($typeName, $typeNode);
}
}
@@ -166,26 +169,29 @@ class ASTDefinitionBuilder
}
/**
- * @param TypeNode $typeNode
* @return Type|InputType
* @throws Error
*/
private function internalBuildWrappedType(TypeNode $typeNode)
{
$typeDef = $this->buildType($this->getNamedTypeNode($typeNode));
+
return $this->buildWrappedType($typeDef, $typeNode);
}
public function buildDirective(DirectiveDefinitionNode $directiveNode)
{
return new Directive([
- 'name' => $directiveNode->name->value,
+ 'name' => $directiveNode->name->value,
'description' => $this->getDescription($directiveNode),
- 'locations' => Utils::map($directiveNode->locations, function ($node) {
- return $node->value;
- }),
- 'args' => $directiveNode->arguments ? FieldArgument::createMap($this->makeInputValues($directiveNode->arguments)) : null,
- 'astNode' => $directiveNode,
+ 'locations' => Utils::map(
+ $directiveNode->locations,
+ function ($node) {
+ return $node->value;
+ }
+ ),
+ 'args' => $directiveNode->arguments ? FieldArgument::createMap($this->makeInputValues($directiveNode->arguments)) : null,
+ 'astNode' => $directiveNode,
]);
}
@@ -195,17 +201,22 @@ class ASTDefinitionBuilder
// Note: While this could make assertions to get the correctly typed
// value, that would throw immediately while type system validation
// with validateSchema() will produce more actionable results.
- 'type' => $this->internalBuildWrappedType($field->type),
- 'description' => $this->getDescription($field),
- 'args' => $field->arguments ? $this->makeInputValues($field->arguments) : null,
+ 'type' => $this->internalBuildWrappedType($field->type),
+ 'description' => $this->getDescription($field),
+ 'args' => $field->arguments ? $this->makeInputValues($field->arguments) : null,
'deprecationReason' => $this->getDeprecationReason($field),
- 'astNode' => $field,
+ 'astNode' => $field,
];
}
+ /**
+ * @param ObjectTypeDefinitionNode|InterfaceTypeDefinitionNode|EnumTypeDefinitionNode|ScalarTypeDefinitionNode|InputObjectTypeDefinitionNode|UnionTypeDefinitionNode $def
+ * @return CustomScalarType|EnumType|InputObjectType|InterfaceType|ObjectType|UnionType
+ * @throws Error
+ */
private function makeSchemaDef($def)
{
- if (!$def) {
+ if (! $def) {
throw new Error('def must be defined.');
}
switch ($def->kind) {
@@ -222,13 +233,19 @@ class ASTDefinitionBuilder
case NodeKind::INPUT_OBJECT_TYPE_DEFINITION:
return $this->makeInputObjectDef($def);
default:
- throw new Error("Type kind of {$def->kind} not supported.");
+ throw new Error(sprintf('Type kind of %s not supported.', $def->kind));
}
}
+ /**
+ * @param ObjectTypeDefinitionNode|InterfaceTypeDefinitionNode|EnumTypeExtensionNode|ScalarTypeDefinitionNode|InputObjectTypeDefinitionNode $def
+ * @param mixed[] $config
+ * @return CustomScalarType|EnumType|InputObjectType|InterfaceType|ObjectType|UnionType
+ * @throws Error
+ */
private function makeSchemaDefFromConfig($def, array $config)
{
- if (!$def) {
+ if (! $def) {
throw new Error('def must be defined.');
}
switch ($def->kind) {
@@ -245,23 +262,24 @@ class ASTDefinitionBuilder
case NodeKind::INPUT_OBJECT_TYPE_DEFINITION:
return new InputObjectType($config);
default:
- throw new Error("Type kind of {$def->kind} not supported.");
+ throw new Error(sprintf('Type kind of %s not supported.', $def->kind));
}
}
private function makeTypeDef(ObjectTypeDefinitionNode $def)
{
$typeName = $def->name->value;
+
return new ObjectType([
- 'name' => $typeName,
+ 'name' => $typeName,
'description' => $this->getDescription($def),
- 'fields' => function () use ($def) {
+ 'fields' => function () use ($def) {
return $this->makeFieldDefMap($def);
},
- 'interfaces' => function () use ($def) {
+ 'interfaces' => function () use ($def) {
return $this->makeImplementedInterfaces($def);
},
- 'astNode' => $def
+ 'astNode' => $def,
]);
}
@@ -286,10 +304,14 @@ class ASTDefinitionBuilder
// Note: While this could make early assertions to get the correctly
// typed values, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
- return Utils::map($def->interfaces, function ($iface) {
- return $this->buildType($iface);
- });
+ return Utils::map(
+ $def->interfaces,
+ function ($iface) {
+ return $this->buildType($iface);
+ }
+ );
}
+
return null;
}
@@ -304,16 +326,17 @@ class ASTDefinitionBuilder
// Note: While this could make assertions to get the correctly typed
// value, that would throw immediately while type system validation
// with validateSchema() will produce more actionable results.
- $type = $this->internalBuildWrappedType($value->type);
+ $type = $this->internalBuildWrappedType($value->type);
$config = [
- 'name' => $value->name->value,
- 'type' => $type,
+ 'name' => $value->name->value,
+ 'type' => $type,
'description' => $this->getDescription($value),
- 'astNode' => $value
+ 'astNode' => $value,
];
if (isset($value->defaultValue)) {
$config['defaultValue'] = AST::valueFromAST($value->defaultValue, $type);
}
+
return $config;
}
);
@@ -322,22 +345,23 @@ class ASTDefinitionBuilder
private function makeInterfaceDef(InterfaceTypeDefinitionNode $def)
{
$typeName = $def->name->value;
+
return new InterfaceType([
- 'name' => $typeName,
+ 'name' => $typeName,
'description' => $this->getDescription($def),
- 'fields' => function () use ($def) {
+ 'fields' => function () use ($def) {
return $this->makeFieldDefMap($def);
},
- 'astNode' => $def
+ 'astNode' => $def,
]);
}
private function makeEnumDef(EnumTypeDefinitionNode $def)
{
return new EnumType([
- 'name' => $def->name->value,
+ 'name' => $def->name->value,
'description' => $this->getDescription($def),
- 'values' => $def->values
+ 'values' => $def->values
? Utils::keyValMap(
$def->values,
function ($enumValue) {
@@ -345,41 +369,44 @@ class ASTDefinitionBuilder
},
function ($enumValue) {
return [
- 'description' => $this->getDescription($enumValue),
+ 'description' => $this->getDescription($enumValue),
'deprecationReason' => $this->getDeprecationReason($enumValue),
- 'astNode' => $enumValue
+ 'astNode' => $enumValue,
];
}
)
: [],
- 'astNode' => $def,
+ 'astNode' => $def,
]);
}
private function makeUnionDef(UnionTypeDefinitionNode $def)
{
return new UnionType([
- 'name' => $def->name->value,
+ 'name' => $def->name->value,
'description' => $this->getDescription($def),
// Note: While this could make assertions to get the correctly typed
// values below, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
- 'types' => $def->types
- ? Utils::map($def->types, function ($typeNode) {
- return $this->buildType($typeNode);
- }):
+ 'types' => $def->types
+ ? Utils::map(
+ $def->types,
+ function ($typeNode) {
+ return $this->buildType($typeNode);
+ }
+ ) :
[],
- 'astNode' => $def,
+ 'astNode' => $def,
]);
}
private function makeScalarDef(ScalarTypeDefinitionNode $def)
{
return new CustomScalarType([
- 'name' => $def->name->value,
+ 'name' => $def->name->value,
'description' => $this->getDescription($def),
- 'astNode' => $def,
- 'serialize' => function($value) {
+ 'astNode' => $def,
+ 'serialize' => function ($value) {
return $value;
},
]);
@@ -388,14 +415,14 @@ class ASTDefinitionBuilder
private function makeInputObjectDef(InputObjectTypeDefinitionNode $def)
{
return new InputObjectType([
- 'name' => $def->name->value,
+ 'name' => $def->name->value,
'description' => $this->getDescription($def),
- 'fields' => function () use ($def) {
+ 'fields' => function () use ($def) {
return $def->fields
? $this->makeInputValues($def->fields)
: [];
},
- 'astNode' => $def,
+ 'astNode' => $def,
]);
}
@@ -409,7 +436,8 @@ class ASTDefinitionBuilder
private function getDeprecationReason($node)
{
$deprecated = Values::getDirectiveValues(Directive::deprecatedDirective(), $node);
- return isset($deprecated['reason']) ? $deprecated['reason'] : null;
+
+ return $deprecated['reason'] ?? null;
}
/**
@@ -433,21 +461,20 @@ class ASTDefinitionBuilder
private function getLeadingCommentBlock($node)
{
$loc = $node->loc;
- if (!$loc || !$loc->startToken) {
+ if (! $loc || ! $loc->startToken) {
return null;
}
$comments = [];
- $token = $loc->startToken->prev;
- while (
- $token &&
+ $token = $loc->startToken->prev;
+ while ($token &&
$token->kind === Token::COMMENT &&
$token->next && $token->prev &&
$token->line + 1 === $token->next->line &&
$token->line !== $token->prev->line
) {
- $value = $token->value;
+ $value = $token->value;
$comments[] = $value;
- $token = $token->prev;
+ $token = $token->prev;
}
return implode("\n", array_reverse($comments));
diff --git a/src/Utils/BlockString.php b/src/Utils/BlockString.php
index eac943d..5bc40e4 100644
--- a/src/Utils/BlockString.php
+++ b/src/Utils/BlockString.php
@@ -53,9 +53,9 @@ class BlockString {
private static function leadingWhitespace($str) {
$i = 0;
while ($i < mb_strlen($str) && ($str[$i] === ' ' || $str[$i] === '\t')) {
- $i++;
+ $i++;
}
return $i;
}
-}
\ No newline at end of file
+}
diff --git a/src/Validator/Rules/KnownArgumentNames.php b/src/Validator/Rules/KnownArgumentNames.php
index bbe3a2f..05a52ef 100644
--- a/src/Validator/Rules/KnownArgumentNames.php
+++ b/src/Validator/Rules/KnownArgumentNames.php
@@ -6,7 +6,9 @@ namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\ArgumentNode;
+use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
+use GraphQL\Language\AST\NodeList;
use GraphQL\Utils\Utils;
use GraphQL\Validator\ValidationContext;
use function array_map;
@@ -25,6 +27,7 @@ class KnownArgumentNames extends ValidationRule
{
return [
NodeKind::ARGUMENT => function (ArgumentNode $node, $key, $parent, $path, $ancestors) use ($context) {
+ /** @var NodeList|Node[] $ancestors */
$argDef = $context->getArgument();
if ($argDef !== null) {
return;
diff --git a/src/Validator/Rules/LoneAnonymousOperation.php b/src/Validator/Rules/LoneAnonymousOperation.php
index 631b6a8..06730f7 100644
--- a/src/Validator/Rules/LoneAnonymousOperation.php
+++ b/src/Validator/Rules/LoneAnonymousOperation.php
@@ -6,6 +6,7 @@ namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\DocumentNode;
+use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\OperationDefinitionNode;
use GraphQL\Utils\Utils;
@@ -28,7 +29,7 @@ class LoneAnonymousOperation extends ValidationRule
NodeKind::DOCUMENT => function (DocumentNode $node) use (&$operationCount) {
$tmp = Utils::filter(
$node->definitions,
- function ($definition) {
+ function (Node $definition) {
return $definition->kind === NodeKind::OPERATION_DEFINITION;
}
);
diff --git a/src/Validator/Rules/QuerySecurityRule.php b/src/Validator/Rules/QuerySecurityRule.php
index ab97fed..810a4d0 100644
--- a/src/Validator/Rules/QuerySecurityRule.php
+++ b/src/Validator/Rules/QuerySecurityRule.php
@@ -111,7 +111,7 @@ abstract class QuerySecurityRule extends ValidationRule
$_astAndDefs = $astAndDefs ?: new \ArrayObject();
foreach ($selectionSet->selections as $selection) {
- switch ($selection->getKind()) {
+ switch ($selection->kind) {
case NodeKind::FIELD:
/** @var FieldNode $selection */
$fieldName = $selection->name->value;
diff --git a/src/Validator/ValidationContext.php b/src/Validator/ValidationContext.php
index a9c4e4b..d8a834e 100644
--- a/src/Validator/ValidationContext.php
+++ b/src/Validator/ValidationContext.php
@@ -11,6 +11,7 @@ use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\HasSelectionSet;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\OperationDefinitionNode;
+use GraphQL\Language\AST\SelectionSetNode;
use GraphQL\Language\AST\VariableNode;
use GraphQL\Language\Visitor;
use GraphQL\Type\Definition\FieldDefinition;
@@ -191,6 +192,7 @@ class ValidationContext
$spreads = $this->fragmentSpreads[$node] ?? null;
if (! $spreads) {
$spreads = [];
+ /** @var SelectionSetNode[] $setsToVisit */
$setsToVisit = [$node->selectionSet];
while (! empty($setsToVisit)) {
$set = array_pop($setsToVisit);
diff --git a/tests/Language/VisitorTest.php b/tests/Language/VisitorTest.php
index 4ed2805..fd7bb20 100644
--- a/tests/Language/VisitorTest.php
+++ b/tests/Language/VisitorTest.php
@@ -1,4 +1,7 @@
toArray()) : $parent;
+ $parentArray = $parent && ! is_array($parent) ? ($parent instanceof NodeList ? iterator_to_array($parent) : $parent->toArray()) : $parent;
$this->assertInstanceOf(Node::class, $node);
$this->assertContains($node->kind, array_keys(NodeKind::$classMap));
$isRoot = $key === null;
if ($isRoot) {
- if (!$isEdited) {
+ if (! $isEdited) {
$this->assertEquals($ast, $node);
}
$this->assertEquals(null, $parent);
@@ -60,14 +71,16 @@ class VisitorTest extends ValidatorTestCase
$this->assertInternalType('array', $ancestors);
$this->assertCount(count($path) - 1, $ancestors);
- if (!$isEdited) {
- $this->assertEquals($node, $parentArray[$key]);
- $this->assertEquals($node, $this->getNodeByPath($ast, $path));
- $ancestorsLength = count($ancestors);
- for ($i = 0; $i < $ancestorsLength; ++$i) {
- $ancestorPath = array_slice($path, 0, $i);
- $this->assertEquals($ancestors[$i], $this->getNodeByPath($ast, $ancestorPath));
- }
+ if ($isEdited) {
+ return;
+ }
+
+ $this->assertEquals($node, $parentArray[$key]);
+ $this->assertEquals($node, $this->getNodeByPath($ast, $path));
+ $ancestorsLength = count($ancestors);
+ for ($i = 0; $i < $ancestorsLength; ++$i) {
+ $ancestorPath = array_slice($path, 0, $i);
+ $this->assertEquals($ancestors[$i], $this->getNodeByPath($ast, $ancestorPath));
}
}
@@ -104,94 +117,84 @@ class VisitorTest extends ValidatorTestCase
$this->assertEquals($expected, $visited);
}
- /**
- * @it allows editing a node both on enter and on leave
- */
public function testAllowsEditingNodeOnEnterAndOnLeave()
{
$ast = Parser::parse('{ a, b, c { a, b, c } }', [ 'noLocation' => true ]);
$selectionSet = null;
- $editedAst = Visitor::visit($ast, [
+ $editedAst = Visitor::visit($ast, [
NodeKind::OPERATION_DEFINITION => [
- 'enter' => function(OperationDefinitionNode $node) use (&$selectionSet, $ast) {
+ 'enter' => function (OperationDefinitionNode $node) use (&$selectionSet, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
$selectionSet = $node->selectionSet;
- $newNode = clone $node;
+ $newNode = clone $node;
$newNode->selectionSet = new SelectionSetNode([
- 'selections' => []
+ 'selections' => [],
]);
- $newNode->didEnter = true;
+ $newNode->didEnter = true;
return $newNode;
},
- 'leave' => function(OperationDefinitionNode $node) use (&$selectionSet, $ast) {
+ 'leave' => function (OperationDefinitionNode $node) use (&$selectionSet, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args(), true);
- $newNode = clone $node;
+ $newNode = clone $node;
$newNode->selectionSet = $selectionSet;
- $newNode->didLeave = true;
+ $newNode->didLeave = true;
return $newNode;
- }
- ]
+ },
+ ],
]);
$this->assertNotEquals($ast, $editedAst);
- $expected = $ast->cloneDeep();
+ $expected = $ast->cloneDeep();
$expected->definitions[0]->didEnter = true;
$expected->definitions[0]->didLeave = true;
$this->assertEquals($expected, $editedAst);
}
- /**
- * @it allows editing the root node on enter and on leave
- */
public function testAllowsEditingRootNodeOnEnterAndLeave()
{
- $ast = Parser::parse('{ a, b, c { a, b, c } }', [ 'noLocation' => true ]);
+ $ast = Parser::parse('{ a, b, c { a, b, c } }', [ 'noLocation' => true ]);
$definitions = $ast->definitions;
$editedAst = Visitor::visit($ast, [
NodeKind::DOCUMENT => [
'enter' => function (DocumentNode $node) use ($ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $tmp = clone $node;
+ $tmp = clone $node;
$tmp->definitions = [];
- $tmp->didEnter = true;
+ $tmp->didEnter = true;
return $tmp;
},
- 'leave' => function(DocumentNode $node) use ($definitions, $ast) {
+ 'leave' => function (DocumentNode $node) use ($definitions, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args(), true);
- $tmp = clone $node;
$node->definitions = $definitions;
- $node->didLeave = true;
- }
- ]
+ $node->didLeave = true;
+ },
+ ],
]);
$this->assertNotEquals($ast, $editedAst);
- $tmp = $ast->cloneDeep();
+ $tmp = $ast->cloneDeep();
$tmp->didEnter = true;
$tmp->didLeave = true;
$this->assertEquals($tmp, $editedAst);
}
- /**
- * @it allows for editing on enter
- */
public function testAllowsForEditingOnEnter()
{
- $ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
+ $ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
$editedAst = Visitor::visit($ast, [
- 'enter' => function($node) use ($ast) {
+ 'enter' => function ($node) use ($ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
if ($node instanceof FieldNode && $node->name->value === 'b') {
return Visitor::removeNode();
}
- }
+ },
]);
$this->assertEquals(
@@ -204,19 +207,16 @@ class VisitorTest extends ValidatorTestCase
);
}
- /**
- * @it allows for editing on leave
- */
public function testAllowsForEditingOnLeave()
{
- $ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
+ $ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
$editedAst = Visitor::visit($ast, [
- 'leave' => function($node) use ($ast) {
+ 'leave' => function ($node) use ($ast) {
$this->checkVisitorFnArgs($ast, func_get_args(), true);
if ($node instanceof FieldNode && $node->name->value === 'b') {
return Visitor::removeNode();
}
- }
+ },
]);
$this->assertEquals(
@@ -230,60 +230,54 @@ class VisitorTest extends ValidatorTestCase
);
}
- /**
- * @it visits edited node
- */
public function testVisitsEditedNode()
{
- $addedField = new FieldNode(array(
- 'name' => new NameNode(array(
- 'value' => '__typename'
- ))
- ));
+ $addedField = new FieldNode([
+ 'name' => new NameNode(['value' => '__typename']),
+ ]);
$didVisitAddedField = false;
$ast = Parser::parse('{ a { x } }', ['noLocation' => true]);
Visitor::visit($ast, [
- 'enter' => function($node) use ($addedField, &$didVisitAddedField, $ast) {
+ 'enter' => function ($node) use ($addedField, &$didVisitAddedField, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args(), true);
if ($node instanceof FieldNode && $node->name->value === 'a') {
return new FieldNode([
- 'selectionSet' => new SelectionSetNode(array(
- 'selections' => NodeList::create([$addedField])->merge($node->selectionSet->selections)
- ))
+ 'selectionSet' => new SelectionSetNode([
+ 'selections' => NodeList::create([$addedField])->merge($node->selectionSet->selections),
+ ]),
]);
}
- if ($node === $addedField) {
- $didVisitAddedField = true;
+ if ($node !== $addedField) {
+ return;
}
- }
+
+ $didVisitAddedField = true;
+ },
]);
$this->assertTrue($didVisitAddedField);
}
- /**
- * @it allows skipping a sub-tree
- */
public function testAllowsSkippingASubTree()
{
$visited = [];
- $ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
+ $ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
Visitor::visit($ast, [
- 'enter' => function(Node $node) use (&$visited, $ast) {
+ 'enter' => function (Node $node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['enter', $node->kind, $node->value ?? null];
if ($node instanceof FieldNode && $node->name->value === 'b') {
return Visitor::skipNode();
}
},
'leave' => function (Node $node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
- }
+ $visited[] = ['leave', $node->kind, $node->value ?? null];
+ },
]);
$expected = [
@@ -301,32 +295,29 @@ class VisitorTest extends ValidatorTestCase
[ 'leave', 'Field', null ],
[ 'leave', 'SelectionSet', null ],
[ 'leave', 'OperationDefinition', null ],
- [ 'leave', 'Document', null ]
+ [ 'leave', 'Document', null ],
];
$this->assertEquals($expected, $visited);
}
- /**
- * @it allows early exit while visiting
- */
public function testAllowsEarlyExitWhileVisiting()
{
$visited = [];
- $ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
+ $ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
Visitor::visit($ast, [
- 'enter' => function(Node $node) use (&$visited, $ast) {
+ 'enter' => function (Node $node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['enter', $node->kind, $node->value ?? null];
if ($node instanceof NameNode && $node->value === 'x') {
return Visitor::stop();
}
},
- 'leave' => function(Node $node) use (&$visited, $ast) {
+ 'leave' => function (Node $node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
- }
+ $visited[] = ['leave', $node->kind, $node->value ?? null];
+ },
]);
$expected = [
@@ -342,33 +333,30 @@ class VisitorTest extends ValidatorTestCase
[ 'leave', 'Name', 'b' ],
[ 'enter', 'SelectionSet', null ],
[ 'enter', 'Field', null ],
- [ 'enter', 'Name', 'x' ]
+ [ 'enter', 'Name', 'x' ],
];
$this->assertEquals($expected, $visited);
}
- /**
- * @it allows early exit while leaving
- */
public function testAllowsEarlyExitWhileLeaving()
{
$visited = [];
$ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
Visitor::visit($ast, [
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['enter', $node->kind, $node->value ?? null];
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['leave', $node->kind, $node->value ?? null];
if ($node->kind === NodeKind::NAME && $node->value === 'x') {
return Visitor::stop();
}
- }
+ },
]);
$this->assertEquals($visited, [
@@ -385,33 +373,30 @@ class VisitorTest extends ValidatorTestCase
[ 'enter', 'SelectionSet', null ],
[ 'enter', 'Field', null ],
[ 'enter', 'Name', 'x' ],
- [ 'leave', 'Name', 'x' ]
+ [ 'leave', 'Name', 'x' ],
]);
}
- /**
- * @it allows a named functions visitor API
- */
public function testAllowsANamedFunctionsVisitorAPI()
{
$visited = [];
- $ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
+ $ast = Parser::parse('{ a, b { x }, c }', ['noLocation' => true]);
Visitor::visit($ast, [
- NodeKind::NAME => function(NameNode $node) use (&$visited, $ast) {
+ NodeKind::NAME => function (NameNode $node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
$visited[] = ['enter', $node->kind, $node->value];
},
NodeKind::SELECTION_SET => [
- 'enter' => function(SelectionSetNode $node) use (&$visited, $ast) {
+ 'enter' => function (SelectionSetNode $node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
$visited[] = ['enter', $node->kind, null];
},
- 'leave' => function(SelectionSetNode $node) use (&$visited, $ast) {
+ 'leave' => function (SelectionSetNode $node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
$visited[] = ['leave', $node->kind, null];
- }
- ]
+ },
+ ],
]);
$expected = [
@@ -428,12 +413,9 @@ class VisitorTest extends ValidatorTestCase
$this->assertEquals($expected, $visited);
}
- /**
- * @it Experimental: visits variables defined in fragments
- */
public function testExperimentalVisitsVariablesDefinedInFragments()
{
- $ast = Parser::parse(
+ $ast = Parser::parse(
'fragment a($v: Boolean = false) on t { f }',
[
'noLocation' => true,
@@ -443,13 +425,13 @@ class VisitorTest extends ValidatorTestCase
$visited = [];
Visitor::visit($ast, [
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['enter', $node->kind, $node->value ?? null];
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['leave', $node->kind, $node->value ?? null];
},
]);
@@ -487,26 +469,23 @@ class VisitorTest extends ValidatorTestCase
$this->assertEquals($expected, $visited);
}
- /**
- * @it visits kitchen sink
- */
public function testVisitsKitchenSink()
{
$kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
- $ast = Parser::parse($kitchenSink);
+ $ast = Parser::parse($kitchenSink);
$visited = [];
Visitor::visit($ast, [
- 'enter' => function(Node $node, $key, $parent) use (&$visited, $ast) {
+ 'enter' => function (Node $node, $key, $parent) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $r = ['enter', $node->kind, $key, $parent instanceof Node ? $parent->kind : null];
+ $r = ['enter', $node->kind, $key, $parent instanceof Node ? $parent->kind : null];
$visited[] = $r;
},
- 'leave' => function(Node $node, $key, $parent) use (&$visited, $ast) {
+ 'leave' => function (Node $node, $key, $parent) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $r = ['leave', $node->kind, $key, $parent instanceof Node ? $parent->kind : null];
+ $r = ['leave', $node->kind, $key, $parent instanceof Node ? $parent->kind : null];
$visited[] = $r;
- }
+ },
]);
$expected = [
@@ -819,17 +798,15 @@ class VisitorTest extends ValidatorTestCase
[ 'leave', 'Field', 1, null ],
[ 'leave', 'SelectionSet', 'selectionSet', 'OperationDefinition' ],
[ 'leave', 'OperationDefinition', 4, null ],
- [ 'leave', 'Document', null, null ]
+ [ 'leave', 'Document', null, null ],
];
$this->assertEquals($expected, $visited);
}
- // Describe: visitInParallel
- // Note: nearly identical to the above test of the same test but using visitInParallel.
-
/**
- * @it allows skipping a sub-tree
+ * Describe: visitInParallel
+ * Note: nearly identical to the above test of the same test but using visitInParallel.
*/
public function testAllowsSkippingSubTree()
{
@@ -838,20 +815,20 @@ class VisitorTest extends ValidatorTestCase
$ast = Parser::parse('{ a, b { x }, c }');
Visitor::visit($ast, Visitor::visitInParallel([
[
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = [ 'enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = [ 'enter', $node->kind, $node->value ?? null];
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
return Visitor::skipNode();
}
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
- }
- ]
+ $visited[] = ['leave', $node->kind, $node->value ?? null];
+ },
+ ],
]));
$this->assertEquals([
@@ -873,9 +850,6 @@ class VisitorTest extends ValidatorTestCase
], $visited);
}
- /**
- * @it allows skipping different sub-trees
- */
public function testAllowsSkippingDifferentSubTrees()
{
$visited = [];
@@ -883,31 +857,31 @@ class VisitorTest extends ValidatorTestCase
$ast = Parser::parse('{ a { x }, b { y} }');
Visitor::visit($ast, Visitor::visitInParallel([
[
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['no-a', 'enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['no-a', 'enter', $node->kind, $node->value ?? null];
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'a') {
return Visitor::skipNode();
}
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = [ 'no-a', 'leave', $node->kind, isset($node->value) ? $node->value : null ];
- }
+ $visited[] = [ 'no-a', 'leave', $node->kind, $node->value ?? null ];
+ },
],
[
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['no-b', 'enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['no-b', 'enter', $node->kind, $node->value ?? null];
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
return Visitor::skipNode();
}
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['no-b', 'leave', $node->kind, isset($node->value) ? $node->value : null];
- }
- ]
+ $visited[] = ['no-b', 'leave', $node->kind, $node->value ?? null];
+ },
+ ],
]));
$this->assertEquals([
@@ -948,28 +922,26 @@ class VisitorTest extends ValidatorTestCase
], $visited);
}
- /**
- * @it allows early exit while visiting
- */
public function testAllowsEarlyExitWhileVisiting2()
{
$visited = [];
$ast = Parser::parse('{ a, b { x }, c }');
Visitor::visit($ast, Visitor::visitInParallel([ [
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $value = isset($node->value) ? $node->value : null;
+ $value = $node->value ?? null;
$visited[] = ['enter', $node->kind, $value];
if ($node->kind === 'Name' && $value === 'x') {
return Visitor::stop();
}
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
- }
- ] ]));
+ $visited[] = ['leave', $node->kind, $node->value ?? null];
+ },
+ ],
+ ]));
$this->assertEquals([
[ 'enter', 'Document', null ],
@@ -984,13 +956,10 @@ class VisitorTest extends ValidatorTestCase
[ 'leave', 'Name', 'b' ],
[ 'enter', 'SelectionSet', null ],
[ 'enter', 'Field', null ],
- [ 'enter', 'Name', 'x' ]
+ [ 'enter', 'Name', 'x' ],
], $visited);
}
- /**
- * @it allows early exit from different points
- */
public function testAllowsEarlyExitFromDifferentPoints()
{
$visited = [];
@@ -998,32 +967,32 @@ class VisitorTest extends ValidatorTestCase
$ast = Parser::parse('{ a { y }, b { x } }');
Visitor::visit($ast, Visitor::visitInParallel([
[
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $value = isset($node->value) ? $node->value : null;
+ $value = $node->value ?? null;
$visited[] = ['break-a', 'enter', $node->kind, $value];
if ($node->kind === 'Name' && $value === 'a') {
return Visitor::stop();
}
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = [ 'break-a', 'leave', $node->kind, isset($node->value) ? $node->value : null ];
- }
+ $visited[] = [ 'break-a', 'leave', $node->kind, $node->value ?? null ];
+ },
],
[
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $value = isset($node->value) ? $node->value : null;
+ $value = $node->value ?? null;
$visited[] = ['break-b', 'enter', $node->kind, $value];
if ($node->kind === 'Name' && $value === 'b') {
return Visitor::stop();
}
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['break-b', 'leave', $node->kind, isset($node->value) ? $node->value : null];
- }
+ $visited[] = ['break-b', 'leave', $node->kind, $node->value ?? null];
+ },
],
]));
@@ -1047,32 +1016,30 @@ class VisitorTest extends ValidatorTestCase
[ 'break-b', 'leave', 'SelectionSet', null ],
[ 'break-b', 'leave', 'Field', null ],
[ 'break-b', 'enter', 'Field', null ],
- [ 'break-b', 'enter', 'Name', 'b' ]
+ [ 'break-b', 'enter', 'Name', 'b' ],
], $visited);
}
- /**
- * @it allows early exit while leaving
- */
public function testAllowsEarlyExitWhileLeaving2()
{
$visited = [];
$ast = Parser::parse('{ a, b { x }, c }');
Visitor::visit($ast, Visitor::visitInParallel([ [
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['enter', $node->kind, $node->value ?? null];
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $value = isset($node->value) ? $node->value : null;
+ $value = $node->value ?? null;
$visited[] = ['leave', $node->kind, $value];
if ($node->kind === 'Name' && $value === 'x') {
return Visitor::stop();
}
- }
- ] ]));
+ },
+ ],
+ ]));
$this->assertEquals([
[ 'enter', 'Document', null ],
@@ -1088,13 +1055,10 @@ class VisitorTest extends ValidatorTestCase
[ 'enter', 'SelectionSet', null ],
[ 'enter', 'Field', null ],
[ 'enter', 'Name', 'x' ],
- [ 'leave', 'Name', 'x' ]
+ [ 'leave', 'Name', 'x' ],
], $visited);
}
- /**
- * @it allows early exit from leaving different points
- */
public function testAllowsEarlyExitFromLeavingDifferentPoints()
{
$visited = [];
@@ -1102,30 +1066,30 @@ class VisitorTest extends ValidatorTestCase
$ast = Parser::parse('{ a { y }, b { x } }');
Visitor::visit($ast, Visitor::visitInParallel([
[
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['break-a', 'enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['break-a', 'enter', $node->kind, $node->value ?? null];
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['break-a', 'leave', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['break-a', 'leave', $node->kind, $node->value ?? null];
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'a') {
return Visitor::stop();
}
- }
+ },
],
[
- 'enter' => function($node) use (&$visited, $ast) {
+ 'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['break-b', 'enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['break-b', 'enter', $node->kind, $node->value ?? null];
},
- 'leave' => function($node) use (&$visited, $ast) {
+ 'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['break-b', 'leave', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['break-b', 'leave', $node->kind, $node->value ?? null];
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
return Visitor::stop();
}
- }
+ },
],
]));
@@ -1165,18 +1129,15 @@ class VisitorTest extends ValidatorTestCase
[ 'break-b', 'leave', 'Name', 'x' ],
[ 'break-b', 'leave', 'Field', null ],
[ 'break-b', 'leave', 'SelectionSet', null ],
- [ 'break-b', 'leave', 'Field', null ]
+ [ 'break-b', 'leave', 'Field', null ],
], $visited);
}
- /**
- * @it allows for editing on enter
- */
public function testAllowsForEditingOnEnter2()
{
$visited = [];
- $ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
+ $ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
$editedAst = Visitor::visit($ast, Visitor::visitInParallel([
[
'enter' => function ($node) use (&$visited, $ast) {
@@ -1184,17 +1145,17 @@ class VisitorTest extends ValidatorTestCase
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
return Visitor::removeNode();
}
- }
+ },
],
[
'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['enter', $node->kind, $node->value ?? null];
},
'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args(), true);
- $visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
- }
+ $visited[] = ['leave', $node->kind, $node->value ?? null];
+ },
],
]));
@@ -1232,18 +1193,15 @@ class VisitorTest extends ValidatorTestCase
['leave', 'Field', null],
['leave', 'SelectionSet', null],
['leave', 'OperationDefinition', null],
- ['leave', 'Document', null]
+ ['leave', 'Document', null],
], $visited);
}
- /**
- * @it allows for editing on leave
- */
public function testAllowsForEditingOnLeave2()
{
$visited = [];
- $ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
+ $ast = Parser::parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);
$editedAst = Visitor::visit($ast, Visitor::visitInParallel([
[
'leave' => function ($node) use (&$visited, $ast) {
@@ -1251,17 +1209,17 @@ class VisitorTest extends ValidatorTestCase
if ($node->kind === 'Field' && isset($node->name->value) && $node->name->value === 'b') {
return Visitor::removeNode();
}
- }
+ },
],
[
'enter' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
- $visited[] = ['enter', $node->kind, isset($node->value) ? $node->value : null];
+ $visited[] = ['enter', $node->kind, $node->value ?? null];
},
'leave' => function ($node) use (&$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args(), true);
- $visited[] = ['leave', $node->kind, isset($node->value) ? $node->value : null];
- }
+ $visited[] = ['leave', $node->kind, $node->value ?? null];
+ },
],
]));
@@ -1305,14 +1263,13 @@ class VisitorTest extends ValidatorTestCase
['leave', 'Field', null],
['leave', 'SelectionSet', null],
['leave', 'OperationDefinition', null],
- ['leave', 'Document', null]
+ ['leave', 'Document', null],
], $visited);
}
- // Describe: visitWithTypeInfo
/**
- * @it maintains type info during visit
+ * Describe: visitWithTypeInfo
*/
public function testMaintainsTypeInfoDuringVisit()
{
@@ -1325,31 +1282,31 @@ class VisitorTest extends ValidatorTestCase
'enter' => function ($node) use ($typeInfo, &$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
$parentType = $typeInfo->getParentType();
- $type = $typeInfo->getType();
- $inputType = $typeInfo->getInputType();
- $visited[] = [
+ $type = $typeInfo->getType();
+ $inputType = $typeInfo->getInputType();
+ $visited[] = [
'enter',
$node->kind,
$node->kind === 'Name' ? $node->value : null,
- $parentType ? (string)$parentType : null,
- $type ? (string)$type : null,
- $inputType ? (string)$inputType : null
+ $parentType ? (string) $parentType : null,
+ $type ? (string) $type : null,
+ $inputType ? (string) $inputType : null,
];
},
'leave' => function ($node) use ($typeInfo, &$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args());
$parentType = $typeInfo->getParentType();
- $type = $typeInfo->getType();
- $inputType = $typeInfo->getInputType();
- $visited[] = [
+ $type = $typeInfo->getType();
+ $inputType = $typeInfo->getInputType();
+ $visited[] = [
'leave',
$node->kind,
$node->kind === 'Name' ? $node->value : null,
- $parentType ? (string)$parentType : null,
- $type ? (string)$type : null,
- $inputType ? (string)$inputType : null
+ $parentType ? (string) $parentType : null,
+ $type ? (string) $type : null,
+ $inputType ? (string) $inputType : null,
];
- }
+ },
]));
$this->assertEquals([
@@ -1392,40 +1349,36 @@ class VisitorTest extends ValidatorTestCase
['leave', 'Field', null, 'QueryRoot', 'Human', null],
['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
['leave', 'OperationDefinition', null, null, 'QueryRoot', null],
- ['leave', 'Document', null, null, null, null]
+ ['leave', 'Document', null, null, null, null],
], $visited);
}
- /**
- * @it maintains type info during edit
- */
public function testMaintainsTypeInfoDuringEdit()
{
- $visited = [];
+ $visited = [];
$typeInfo = new TypeInfo(ValidatorTestCase::getTestSchema());
- $ast = Parser::parse(
+ $ast = Parser::parse(
'{ human(id: 4) { name, pets }, alien }'
);
$editedAst = Visitor::visit($ast, Visitor::visitWithTypeInfo($typeInfo, [
'enter' => function ($node) use ($typeInfo, &$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args(), true);
$parentType = $typeInfo->getParentType();
- $type = $typeInfo->getType();
- $inputType = $typeInfo->getInputType();
- $visited[] = [
+ $type = $typeInfo->getType();
+ $inputType = $typeInfo->getInputType();
+ $visited[] = [
'enter',
$node->kind,
$node->kind === 'Name' ? $node->value : null,
- $parentType ? (string)$parentType : null,
- $type ? (string)$type : null,
- $inputType ? (string)$inputType : null
+ $parentType ? (string) $parentType : null,
+ $type ? (string) $type : null,
+ $inputType ? (string) $inputType : null,
];
// Make a query valid by adding missing selection sets.
- if (
- $node->kind === 'Field' &&
- !$node->selectionSet &&
+ if ($node->kind === 'Field' &&
+ ! $node->selectionSet &&
Type::isCompositeType(Type::getNamedType($type))
) {
return new FieldNode([
@@ -1435,29 +1388,28 @@ class VisitorTest extends ValidatorTestCase
'directives' => $node->directives,
'selectionSet' => new SelectionSetNode([
'kind' => 'SelectionSet',
- 'selections' => [
- new FieldNode([
- 'name' => new NameNode(['value' => '__typename'])
- ])
- ]
- ])
+ 'selections' => [new FieldNode([
+ 'name' => new NameNode(['value' => '__typename']),
+ ]),
+ ],
+ ]),
]);
}
},
'leave' => function ($node) use ($typeInfo, &$visited, $ast) {
$this->checkVisitorFnArgs($ast, func_get_args(), true);
$parentType = $typeInfo->getParentType();
- $type = $typeInfo->getType();
- $inputType = $typeInfo->getInputType();
- $visited[] = [
+ $type = $typeInfo->getType();
+ $inputType = $typeInfo->getInputType();
+ $visited[] = [
'leave',
$node->kind,
$node->kind === 'Name' ? $node->value : null,
- $parentType ? (string)$parentType : null,
- $type ? (string)$type : null,
- $inputType ? (string)$inputType : null
+ $parentType ? (string) $parentType : null,
+ $type ? (string) $type : null,
+ $inputType ? (string) $inputType : null,
];
- }
+ },
]));
$this->assertEquals(Printer::doPrint(Parser::parse(
@@ -1510,7 +1462,7 @@ class VisitorTest extends ValidatorTestCase
['leave', 'Field', null, 'QueryRoot', 'Alien', null],
['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],
['leave', 'OperationDefinition', null, null, 'QueryRoot', null],
- ['leave', 'Document', null, null, null, null]
+ ['leave', 'Document', null, null, null, null],
], $visited);
}
}