Skip to content

Commit

Permalink
fix: handle variadic parameters declared in docblock
Browse files Browse the repository at this point in the history
Co-authored-by: Romain Canon <romain.hydrocanon@gmail.com>
  • Loading branch information
simPod and romm authored Sep 11, 2023
1 parent c231020 commit f4884cf
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 28 deletions.
22 changes: 16 additions & 6 deletions src/Definition/Repository/Reflection/ReflectionTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use CuyZ\Valinor\Type\Parser\Exception\InvalidType;
use CuyZ\Valinor\Type\Parser\TypeParser;
use CuyZ\Valinor\Type\Type;
use CuyZ\Valinor\Type\Types\ArrayKeyType;
use CuyZ\Valinor\Type\Types\ArrayType;
use CuyZ\Valinor\Type\Types\MixedType;
use CuyZ\Valinor\Type\Types\UnresolvableType;
use CuyZ\Valinor\Utility\Reflection\DocParser;
Expand Down Expand Up @@ -75,7 +77,9 @@ private function typeFromDocBlock(ReflectionProperty|ReflectionParameter|Reflect
return null;
}

return $this->parseType($type, $reflection, $this->advancedParser);
$type = $this->parseType($type, $reflection, $this->advancedParser);

return $this->handleVariadicType($reflection, $type);
}

private function nativeType(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection): ?Type
Expand All @@ -89,12 +93,9 @@ private function nativeType(ReflectionProperty|ReflectionParameter|ReflectionFun
}

$type = Reflection::flattenType($reflectionType);
$type = $this->parseType($type, $reflection, $this->nativeParser);

if ($reflection instanceof ReflectionParameter && $reflection->isVariadic()) {
$type .= '[]';
}

return $this->parseType($type, $reflection, $this->nativeParser);
return $this->handleVariadicType($reflection, $type);
}

private function parseType(string $raw, ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection, TypeParser $parser): Type
Expand All @@ -116,4 +117,13 @@ private function parseType(string $raw, ReflectionProperty|ReflectionParameter|R
return UnresolvableType::forMethodReturnType($raw, $signature, $exception);
}
}

private function handleVariadicType(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection, Type $type): Type
{
if (! $reflection instanceof ReflectionParameter || ! $reflection->isVariadic()) {
return $type;
}

return new ArrayType(ArrayKeyType::default(), $type);
}
}
1 change: 1 addition & 0 deletions src/Utility/Reflection/DocParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use function str_split;
use function strrpos;
use function substr;
use function trim;

/** @internal */
final class DocParser
Expand Down
42 changes: 20 additions & 22 deletions tests/Integration/Mapping/VariadicParameterMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,17 @@ public function test_variadic_parameters_are_mapped_properly_when_string_keys_ar
self::assertSame(['foo', 'bar', 'baz'], $object->values);
}

public function test_named_constructor_with_only_variadic_parameters_are_mapped_properly(): void
public function test_constructor_with_variadic_parameters_with_dots_in_dot_blocks_are_defined_properly(): void
{
try {
$object = (new MapperBuilder())
// PHP8.1 first-class callable syntax
->registerConstructor([SomeClassWithNamedConstructorWithOnlyVariadicParameters::class, 'new'])
(new MapperBuilder())
->mapper()
->map(SomeClassWithNamedConstructorWithOnlyVariadicParameters::class, ['foo', 'bar', 'baz']);
} catch (MappingError $error) {
$this->mappingFail($error);
}
->map(SomeClassWithVariadicParametersInDocBlock::class, ['']);
} catch (MappingError $exception) {
$error = $exception->node()->children()[0]->messages()[0];

self::assertSame(['foo', 'bar', 'baz'], $object->values);
self::assertSame("Value '' is not a valid non-empty string.", (string)$error);
}
}

public function test_non_variadic_and_variadic_parameters_are_mapped_properly(): void
Expand Down Expand Up @@ -113,19 +111,19 @@ public static function new(string ...$values): self
}
}

//final class SomeClassWithListVariadicParameters
//{
// /** @var list<string> */
// public array $values;
//
// /**
// * @param list<string> $values
// */
// public function __construct(string ...$values)
// {
// $this->values = $values;
// }
//}
final class SomeClassWithVariadicParametersInDocBlock
{
/** @var array<non-empty-string> */
public array $values;

/**
* @param non-empty-string ...$values
*/
public function __construct(string ...$values)
{
$this->values = $values;
}
}

final class SomeClassWithNonVariadicAndVariadicParameters
{
Expand Down

0 comments on commit f4884cf

Please sign in to comment.