Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Definition/ClassDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public function __construct(
public ObjectType $type,
public Attributes $attributes,
public Properties $properties,
public Properties $magicProperties,
public Methods $methods,
public bool $isFinal,
public bool $isAbstract,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ public function compile(ClassDefinition $value): string

$properties = implode(', ', $properties);

$magicProperties = array_map(
$this->propertyCompiler->compile(...),
iterator_to_array($value->magicProperties)
);

$magicProperties = implode(', ', $magicProperties);

$methods = array_map(
$this->methodCompiler->compile(...),
iterator_to_array($value->methods)
Expand All @@ -60,6 +67,7 @@ public function compile(ClassDefinition $value): string
$type,
$attributes,
new \CuyZ\Valinor\Definition\Properties($properties),
new \CuyZ\Valinor\Definition\Properties($magicProperties),
new \CuyZ\Valinor\Definition\Methods($methods),
$isFinal,
$isAbstract,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use CuyZ\Valinor\Type\Types\InterfaceType;
use CuyZ\Valinor\Type\Types\NativeClassType;
use CuyZ\Valinor\Type\Types\UnresolvableType;
use CuyZ\Valinor\Utility\Reflection\Annotations;
use CuyZ\Valinor\Utility\Reflection\Reflection;
use ReflectionMethod;
use ReflectionProperty;
Expand Down Expand Up @@ -89,7 +90,8 @@ public function for(ObjectType $type): ClassDefinition
$reflection->name,
$type,
new Attributes(...$this->attributesRepository->for($reflection)),
new Properties(...$this->properties($type, $typeResolver)),
new Properties(...$this->properties($type, $typeResolver, false)),
new Properties(...$this->properties($type, $typeResolver, true)),
new Methods(...$this->methods($type, $typeResolver)),
$reflection->isFinal(),
$reflection->isAbstract(),
Expand Down Expand Up @@ -131,10 +133,34 @@ private function vacantTypes(ObjectType $type): array
/**
* @return list<PropertyDefinition>
*/
private function properties(ObjectType $type, ReflectionTypeResolver $typeResolver): array
private function properties(ObjectType $type, ReflectionTypeResolver $typeResolver, bool $magic): array
{
$reflection = Reflection::class($type->className());

if ($magic) {
$result = [];
$className = $type->className();
foreach (Annotations::magicProperties($reflection) as $name => $propertyType) {
$signature = "$className::\$$name";
$type = $typeResolver->resolveType(null, $propertyType);
$hasDefaultValue = false;
$defaultValue = null;
$isPublic = true;
$attributes = new Attributes();

$result [] = new PropertyDefinition(
$name,
$signature,
$type,
$type,
$hasDefaultValue,
$defaultValue,
$isPublic,
$attributes
);
}
return $result;
}
$properties = [];

foreach ($reflection->getProperties() as $property) {
Expand Down
25 changes: 23 additions & 2 deletions src/Utility/Reflection/Annotations.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use function current;
use function end;
use function in_array;
use function preg_match_all;
use function preg_replace;
use function str_starts_with;
use function trim;
Expand All @@ -35,7 +36,7 @@ private function __construct(string|false $docBlock)
return;
}

$docBlock = $this->sanitizeDocComment($docBlock);
$docBlock = self::sanitizeDocComment($docBlock);

$tokens = (new TokensExtractor($docBlock))->all();

Expand Down Expand Up @@ -182,13 +183,33 @@ private function filteredByPriority(string ...$allowed): array
return $result;
}

private function sanitizeDocComment(string $value): string
private static function sanitizeDocComment(string $value): string
{
$value = preg_replace('#^\s*/\*\*([^/]+)\*/\s*$#', '$1', $value);

return preg_replace('/^\s*\*\s*(\S*)/mU', '$1', $value); // @phpstan-ignore-line / We know the regex is correct
}

/**
* @param ReflectionClass<covariant object> $reflection
* @return array<non-empty-string, string>
*/
public static function magicProperties(ReflectionClass $reflection): array
{
$types = [];
$docComment = self::sanitizeDocComment($reflection->__toString());

$expression = '/@property\s+(?<type>.+)\s+\$([a-zA-Z_0-9]+)/u';

preg_match_all($expression, $docComment, $matches);

foreach ($matches[2] as $key => $name) {
$types[$name] = $matches[1][$key];
}

return $types;
}

/**
* @param list<string> $array
* @return list<string>
Expand Down
2 changes: 2 additions & 0 deletions tests/Fake/Definition/FakeClassDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public static function new(string $name = stdClass::class): ClassDefinition
new NativeClassType($name),
new Attributes(),
new Properties(),
new Properties(),
new Methods(),
true,
false,
Expand All @@ -54,6 +55,7 @@ public static function fromReflection(ReflectionClass $reflection): ClassDefinit
new NativeClassType($reflection->name),
new Attributes(),
new Properties(...$properties),
new Properties(),
new Methods(...$methods),
$reflection->isFinal(),
$reflection->isAbstract(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public function __construct(array $transformers, CuyZ\Valinor\Normalizer\Transfo
public function transform(mixed $value): mixed
{
$references = new WeakMap();
return $this->transform_cuyz_valinor_tests_integration_normalizer_temporaryphp85_classwithtransformerwithcallable_0c11da6260a6db3553df282aa070e27a0303112f($value, $references);
return $this->transform_cuyz_valinor_tests_integration_normalizer_temporaryphp85_classwithtransformerwithcallable_4249691f5c85877eea732e0938d14fd26ec54786($value, $references);
}

private function transform_object_cuyz_valinor_tests_integration_normalizer_temporaryphp85_classwithtransformerwithcallable_ca2b7327(CuyZ\Valinor\Tests\Integration\Normalizer\TemporaryPHP85\ClassWithTransformerWithCallable $value, WeakMap $references): array
Expand All @@ -29,7 +29,7 @@ private function transform_object_cuyz_valinor_tests_integration_normalizer_temp
return $values;
}

private function transform_cuyz_valinor_tests_integration_normalizer_temporaryphp85_classwithtransformerwithcallable_0c11da6260a6db3553df282aa070e27a0303112f(mixed $value, WeakMap $references): mixed
private function transform_cuyz_valinor_tests_integration_normalizer_temporaryphp85_classwithtransformerwithcallable_4249691f5c85877eea732e0938d14fd26ec54786(mixed $value, WeakMap $references): mixed
{
$next = fn () => $this->transform_object_cuyz_valinor_tests_integration_normalizer_temporaryphp85_classwithtransformerwithcallable_ca2b7327($value, $references);
$next = fn () => ((new ReflectionClass(CuyZ\Valinor\Tests\Integration\Normalizer\TemporaryPHP85\ClassWithTransformerWithCallable::class))->getAttributes()[0]->newInstance())->normalize($value, $next);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ private function transform_object_cuyz_valinor_tests_integration_normalizer_temp
'value' => $value->value,
];
$transformed = [];
$transformed['value'] = $this->transform_string_ee734ad1df9498f24acd0cad1cd2fed3e95f69b3($values['value'], $references);
$transformed['value'] = $this->transform_string_996b61d05a213b4a77de5f27b57df2564765d558($values['value'], $references);
return $transformed;
}

private function transform_string_ee734ad1df9498f24acd0cad1cd2fed3e95f69b3(mixed $value, WeakMap $references): mixed
private function transform_string_996b61d05a213b4a77de5f27b57df2564765d558(mixed $value, WeakMap $references): mixed
{
$next = fn () => $value;
$next = fn () => ((new ReflectionProperty(CuyZ\Valinor\Tests\Integration\Normalizer\TemporaryPHP85\ClassWithPropertyTransformerWithCallable::class, 'value'))->getAttributes()[0]->newInstance())->normalize($value, $next);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private function transform_object_cuyz_valinor_tests_integration_normalizer_clas
'value' => $value->value,
];
$transformed = [];
$transformed['value'] = $this->transform_mixed_81119e8ac7b14bb88fa09fcfa886afe87aa69fa1($values['value'], $references);
$transformed['value'] = $this->transform_mixed_470fe1dfefcac95513283699f5d61a2abba0c1f8($values['value'], $references);
return $transformed;
}

Expand Down Expand Up @@ -75,7 +75,7 @@ private function transform_iterable_mixed_bf66259c(iterable $value, WeakMap $ref
})();
}

private function transform_mixed_81119e8ac7b14bb88fa09fcfa886afe87aa69fa1(mixed $value, WeakMap $references): mixed
private function transform_mixed_470fe1dfefcac95513283699f5d61a2abba0c1f8(mixed $value, WeakMap $references): mixed
{
$next = fn () => $this->transform_mixed($value, $references);
if (\is_string($value)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ private function transform_object_cuyz_valinor_tests_integration_normalizer_clas
'value' => $value->value,
];
$transformed = [];
$transformed['value'] = $this->transform_string_c80acf3f0352152a3298abfbddc6f6c62c5da4b6($values['value'], $references);
$transformed['value'] = $this->transform_string_570c90bf0c9037b1771b87d70b8c18cd95dd7982($values['value'], $references);
return $transformed;
}

private function transform_string_c80acf3f0352152a3298abfbddc6f6c62c5da4b6(mixed $value, WeakMap $references): mixed
private function transform_string_570c90bf0c9037b1771b87d70b8c18cd95dd7982(mixed $value, WeakMap $references): mixed
{
$next = fn () => $value;
$next = fn () => (new CuyZ\Valinor\Tests\Integration\Normalizer\PrependToStringAttribute())->normalize($value, $next);
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Definition/ClassDefinitionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function test_class_data_can_be_retrieved(): void
$properties = new Properties(FakePropertyDefinition::new());
$methods = new Methods(FakeMethodDefinition::new());

$class = new ClassDefinition(stdClass::class, $type, $attributes, $properties, $methods, true, false);
$class = new ClassDefinition(stdClass::class, $type, $attributes, $properties, new Properties(), $methods, true, false);

self::assertSame(stdClass::class, $class->name);
self::assertSame($type, $class->type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use CuyZ\Valinor\Tests\Fixture\Object\StringableObject;
use CuyZ\Valinor\Tests\Unit\UnitTestCase;
use CuyZ\Valinor\Type\Types\NativeClassType;
use CuyZ\Valinor\Type\Types\NativeIntegerType;
use CuyZ\Valinor\Type\Types\NativeStringType;
use Error;
use ReflectionClass;
Expand All @@ -23,21 +24,27 @@ final class ClassDefinitionCompilerTest extends UnitTestCase
public function test_class_definition_is_compiled_correctly(): void
{
$object =
new class () {
public string $property = 'Some property default value';

#[Constructor]
public static function method(string $parameter = 'Some parameter default value', string ...$variadic): string
{
return $parameter . implode(' / ', $variadic);
}

#[Constructor]
public static function methodWithDefaultObjectValue(StringableObject $object = new StringableObject('bar')): StringableObject
{
return $object;
new
/**
* @property string $v
* @property int $vInt
*/
class () {
public string $property = 'Some property default value';

#[Constructor]
public static function method(string $parameter = 'Some parameter default value', string ...$variadic): string
{
return $parameter . implode(' / ', $variadic);
}

#[Constructor]
public static function methodWithDefaultObjectValue(StringableObject $object = new StringableObject('bar')): StringableObject
{
return $object;
}
}
};
;

$className = $object::class;

Expand Down Expand Up @@ -66,6 +73,30 @@ public static function methodWithDefaultObjectValue(StringableObject $object = n
self::assertSame('Some property default value', $property->defaultValue);
self::assertTrue($property->isPublic);

$magicProperties = $class->magicProperties;

self::assertTrue($magicProperties->has('v'));

$mp = $magicProperties->get('v');

self::assertSame('v', $mp->name);
self::assertSame($className . '::$v', $mp->signature);
self::assertSame(NativeStringType::get(), $mp->type);
self::assertFalse($mp->hasDefaultValue);
self::assertSame(null, $mp->defaultValue);
self::assertTrue($mp->isPublic);

self::assertTrue($magicProperties->has('vInt'));

$mp = $magicProperties->get('vInt');

self::assertSame('vInt', $mp->name);
self::assertSame($className . '::$vInt', $mp->signature);
self::assertSame(NativeIntegerType::get(), $mp->type);
self::assertFalse($mp->hasDefaultValue);
self::assertSame(null, $mp->defaultValue);
self::assertTrue($mp->isPublic);

$method = $class->methods->get('method');

self::assertSame('method', $method->name);
Expand Down
Loading