Files
2025-12-19 16:05:19 -08:00

155 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
namespace GraphQL\Language\AST;
use ArrayAccess;
use Countable;
use GraphQL\Utils\AST;
use InvalidArgumentException;
use IteratorAggregate;
use ReturnTypeWillChange;
use Traversable;
use function array_merge;
use function array_splice;
use function count;
use function is_array;
/**
* @template T of Node
* @phpstan-implements ArrayAccess<int|string, T>
* @phpstan-implements IteratorAggregate<T>
*/
class NodeList implements ArrayAccess, IteratorAggregate, Countable
{
/**
* @var Node[]
* @phpstan-var array<T>
*/
private $nodes;
/**
* @param Node[] $nodes
*
* @phpstan-param array<T> $nodes
* @phpstan-return self<T>
*/
public static function create(array $nodes) : self
{
return new static($nodes);
}
/**
* @param Node[] $nodes
*
* @phpstan-param array<T> $nodes
*/
public function __construct(array $nodes)
{
$this->nodes = $nodes;
}
/**
* @param int|string $offset
*/
public function offsetExists($offset) : bool
{
return isset($this->nodes[$offset]);
}
/**
* TODO enable strict typing by changing how the Visitor deals with NodeList.
* Ideally, this function should always return a Node instance.
* However, the Visitor currently allows mutation of the NodeList
* and puts arbitrary values in the NodeList, such as strings.
* We will have to switch to using an array or a less strict
* type instead so we can enable strict typing in this class.
*
* @param int|string $offset
*
* @phpstan-return T
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)// : Node
{
$item = $this->nodes[$offset];
if (is_array($item) && isset($item['kind'])) {
/** @phpstan-var T $node */
$node = AST::fromArray($item);
$this->nodes[$offset] = $node;
}
return $this->nodes[$offset];
}
/**
* @param int|string|null $offset
* @param Node|mixed[] $value
*
* @phpstan-param T|mixed[] $value
*/
public function offsetSet($offset, $value) : void
{
if (is_array($value)) {
/** @phpstan-var T $value */
$value = AST::fromArray($value);
}
// Happens when a Node is pushed via []=
if ($offset === null) {
$this->nodes[] = $value;
return;
}
$this->nodes[$offset] = $value;
}
/**
* @param int|string $offset
*/
public function offsetUnset($offset) : void
{
unset($this->nodes[$offset]);
}
/**
* @param mixed $replacement
*
* @phpstan-return NodeList<T>
*/
public function splice(int $offset, int $length, $replacement = null) : NodeList
{
return new NodeList(array_splice($this->nodes, $offset, $length, $replacement));
}
/**
* @param NodeList|Node[] $list
*
* @phpstan-param NodeList<T>|array<T> $list
* @phpstan-return NodeList<T>
*/
public function merge($list) : NodeList
{
if ($list instanceof self) {
$list = $list->nodes;
}
return new NodeList(array_merge($this->nodes, $list));
}
public function getIterator() : Traversable
{
foreach ($this->nodes as $key => $_) {
yield $this->offsetGet($key);
}
}
public function count() : int
{
return count($this->nodes);
}
}