Skip to content

Commit

Permalink
Update ClosureExporter.php
Browse files Browse the repository at this point in the history
  • Loading branch information
Shelamkoff authored Jan 11, 2023
1 parent 5d5f340 commit f8cde5f
Showing 1 changed file with 67 additions and 47 deletions.
114 changes: 67 additions & 47 deletions src/ClosureExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,18 @@

class ClosureExporter implements ClosureExporterInterface
{
protected static NodeFinder|null $nodeFinder = null;
public function exportClosure(\Closure $closure): string
{
$reflector = $this->getReflector($closure);
$parser = $this->createParser();

$code = $this->readFile($reflector->getFileName());
$ast = $parser->parse($code);

$nodeFinder = new NodeFinder;
$node = $nodeFinder->findFirst($ast, $this->createFindCallback($reflector));

if ($reflector->getReturnType()) {
if ($node->returnType instanceof Name) {
$node->returnType->parts = explode('\\', $reflector->getReturnType()->getName());
} elseif ($node->returnType instanceof Node\IntersectionType
|| $node->returnType instanceof Node\UnionType) {
$filtered = array_filter($node->returnType->types, static fn($v) => $v instanceof Name);
foreach ($reflector->getReturnType()->getTypes() as $type) {
if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
$parts = explode('\\', $type->getName());
foreach ($filtered as $item) {
if (end($item->parts) == end($parts)) {
$item->parts = $parts;
}
}
}
}
}
}
$code = $this->readFile(($reflector = new \ReflectionFunction($closure))
->getFileName());
$ast = $this->createParser()->parse($code);

if ($reflector->getParameters() != []) {
foreach ($reflector->getParameters() as $pos => $parameter) {
if ($parameter->getType() instanceof \ReflectionNamedType && !$parameter->getType()->isBuiltin()) {
$node->params[$pos]->type->parts = explode('\\', $parameter->getType()->getName());
} elseif ($parameter->getType() instanceof \ReflectionUnionType
|| $parameter->getType() instanceof \ReflectionIntersectionType) {
$filtered = array_filter($node->params[$pos]->type->types, static fn($v) => $v instanceof Name);
foreach ($parameter->getType()->getTypes() as $type) {
if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
$parts = explode('\\', $type->getName());
foreach ($filtered as $item) {
if (end($item->parts) == end($parts)) {
$item->parts = $parts;
}
}
}
}
}
}
}
$node = static::getFinder()->findFirst($ast, $this->createFindCallback($reflector));

$traverser = new NodeTraverser;
$traverser->addVisitor($this->getVisitor($this->getNamespace($ast), $this->getUseNodes($ast)));
$traverser->traverse([$node]);

return $this->getPrinter()->prettyPrintExpr($node);
}
Expand Down Expand Up @@ -104,4 +66,62 @@ protected function createFindCallback(\ReflectionFunction $reflector): callable
&& $node->getStartLine() == $reflector->getStartLine();
};
}

protected static function getFinder(): NodeFinder
{
return static::$nodeFinder ?? static::$nodeFinder = new NodeFinder;
}

protected function getNamespace(array $ast):? Node\Stmt\Namespace_
{
return static::getFinder()->findFirstInstanceOf($ast, Node\Stmt\Namespace_::class);
}

protected function getUseNodes(array $ast):? array
{
$ast = static::getFinder()->find($ast, static fn($node) => $node instanceof Node\Stmt\Use_
|| $node instanceof Node\Stmt\GroupUse
);

return $ast == [] ? null : $ast;
}

protected function getVisitor(?Node\Stmt\Namespace_ $namespace, ?array $uses)
{
return new class($namespace, $uses) extends NodeVisitorAbstract
{
public function __construct(
private ?Node\Stmt\Namespace_ $namespace,
private ?array $uses) {
}

public function enterNode(Node $node)
{
if ($node instanceof Name && !$node instanceof Name\FullyQualified) {
foreach ($this->uses as $use) {
$parts = [];
if ($use instanceof Node\Stmt\GroupUse) {
$parts = $use->prefix->parts;
}

foreach ($use->uses as $useUse) {
if (end($useUse->name->parts) == end($node->parts)) {
$parts = array_merge($parts, $useUse->name->parts);
return new Name\FullyQualified($parts, $node->getAttributes());
}
}
}
if ($this->namespace) {
return new Name\FullyQualified(
[...$this->namespace->name->parts, ...$node->parts],
$node->getAttributes()
);
}
}

return $node;
}

};
}
}

0 comments on commit f8cde5f

Please sign in to comment.