Skip to content

Instantly share code, notes, and snippets.

@chx
Created July 14, 2025 16:21
Show Gist options
  • Select an option

  • Save chx/f8e8728f901f66fa8b01db00db904be5 to your computer and use it in GitHub Desktop.

Select an option

Save chx/f8e8728f901f66fa8b01db00db904be5 to your computer and use it in GitHub Desktop.
<?php
namespace Drupal\api\DocParser;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
use PHPStan\PhpDocParser\Ast\Type\ObjectShapeItemNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
class TypeNodeTraverser {
/**
* @param \Drupal\api\DocParser\TypeNodeVisitorInterface[] $visitors
*/
public function __construct(protected array $visitors) {
}
/**
* Starts traversing.
*
* @param \PHPStan\PhpDocParser\Ast\Type\TypeNode $node
* The type.
*
* @return \PHPStan\PhpDocParser\Ast\Type\TypeNode
* The possibly changed type.
*/
public function traverse(TypeNode $node): TypeNode {
foreach ($this->visitors as $visitor) {
$node = $this->traverseTypeNode($node, $visitor);
}
return $node;
}
/**
* Actually traverse a type node.
*
* @param \PHPStan\PhpDocParser\Ast\Type\TypeNode $typeNode
* The node to traverse.
* @param \Drupal\api\DocParser\TypeNodeVisitorInterface $visitor
* The visitor doing the traversal.
*
* @return \PHPStan\PhpDocParser\Ast\Type\TypeNode
* The potentially changed type node.
*/
protected function traverseTypeNode(TypeNode $typeNode, TypeNodeVisitorInterface $visitor): TypeNode {
if ($newTypeNode = $visitor->enterNode($typeNode)) {
$typeNode = $newTypeNode;
}
foreach (get_object_vars($typeNode) as $key => $value) {
if ($value instanceof TypeNode) {
$typeNode->$key = $this->traverseTypeNode($value, $visitor);
}
elseif (is_array($value)) {
$first = reset($value);
// If one element is a type then every element is.
if ($first instanceof TypeNode) {
$typeNode->$key = array_map(fn (TypeNode $type) => $this->traverseTypeNode($type, $visitor), $value);
}
// Same for shape items.
elseif ($first instanceof ArrayShapeItemNode || $first instanceof ObjectShapeItemNode) {
foreach ($value as $item) {
$item->valueType = $this->traverseTypeNode($item->valueType, $visitor);
}
}
}
}
return $typeNode;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment