Skip to content

Commit 18ce038

Browse files
committed
Improve more types
1 parent cfee503 commit 18ce038

File tree

5 files changed

+85
-17
lines changed

5 files changed

+85
-17
lines changed

src/Platform/StandardPlatform.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function getTypes(): iterable
5555
\Generator::class,
5656
\Traversable::class,
5757
\IteratorAggregate::class,
58-
]);
58+
], 'array-key', 'mixed');
5959

6060
// Adds support for the "object" type
6161
yield new Builder\ObjectTypeBuilder([

src/Type/Builder/ArrayTypeBuilder.php

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,34 @@
2121
class ArrayTypeBuilder extends NamedTypeBuilder
2222
{
2323
/**
24+
* @var non-empty-lowercase-string
25+
*/
26+
public const DEFAULT_INNER_KEY_TYPE = 'array-key';
27+
28+
/**
29+
* @var non-empty-lowercase-string
30+
*/
31+
public const DEFAULT_INNER_VALUE_TYPE = 'mixed';
32+
33+
/**
34+
* @param non-empty-array<non-empty-string>|non-empty-string $names
35+
* @param non-empty-string $keyType
36+
* @param non-empty-string $valueType
37+
*/
38+
public function __construct(
39+
array|string $names,
40+
protected readonly string $keyType = self::DEFAULT_INNER_KEY_TYPE,
41+
protected readonly string $valueType = self::DEFAULT_INNER_VALUE_TYPE,
42+
) {
43+
parent::__construct($names);
44+
}
45+
46+
/**
47+
* @throws ShapeFieldsNotSupportedException
2448
* @throws TemplateArgumentHintsNotSupportedException
2549
* @throws TooManyTemplateArgumentsException
2650
* @throws TypeNotFoundException
27-
* @throws ShapeFieldsNotSupportedException
51+
* @throws \Throwable
2852
*/
2953
public function build(
3054
TypeStatement $statement,
@@ -36,9 +60,9 @@ public function build(
3660
$arguments = $statement->arguments->items ?? [];
3761

3862
return match (\count($arguments)) {
39-
0 => new ArrayType(),
40-
1 => $this->buildByValue($statement, $types),
41-
2 => $this->buildByKeyValue($statement, $types),
63+
0 => $this->buildWithNoKeyValue($types, $parser),
64+
1 => $this->buildWithValue($statement, $types, $parser),
65+
2 => $this->buildWithKeyValue($statement, $types),
4266
default => throw TooManyTemplateArgumentsException::becauseTemplateArgumentsRangeOverflows(
4367
passedArgumentsCount: \count($arguments),
4468
minSupportedArgumentsCount: 0,
@@ -48,12 +72,32 @@ public function build(
4872
};
4973
}
5074

75+
/**
76+
* @throws TypeNotFoundException
77+
* @throws \Throwable
78+
*/
79+
private function buildWithNoKeyValue(TypeRepositoryInterface $types, TypeParserInterface $parser): ArrayType
80+
{
81+
return new ArrayType(
82+
key: $types->getTypeByStatement(
83+
statement: $parser->getStatementByDefinition(
84+
definition: $this->keyType,
85+
),
86+
),
87+
value: $types->getTypeByStatement(
88+
statement: $parser->getStatementByDefinition(
89+
definition: $this->valueType,
90+
),
91+
),
92+
);
93+
}
94+
5195
/**
5296
* @throws TemplateArgumentHintsNotSupportedException
5397
* @throws TypeNotFoundException
5498
* @throws \Throwable
5599
*/
56-
private function buildByKeyValue(NamedTypeNode $statement, TypeRepositoryInterface $types): ArrayType
100+
private function buildWithKeyValue(NamedTypeNode $statement, TypeRepositoryInterface $types): ArrayType
57101
{
58102
$arguments = $statement->arguments->items ?? [];
59103

@@ -79,8 +123,11 @@ private function buildByKeyValue(NamedTypeNode $statement, TypeRepositoryInterfa
79123
* @throws TypeNotFoundException
80124
* @throws \Throwable
81125
*/
82-
private function buildByValue(NamedTypeNode $statement, TypeRepositoryInterface $types): ArrayType
83-
{
126+
private function buildWithValue(
127+
NamedTypeNode $statement,
128+
TypeRepositoryInterface $types,
129+
TypeParserInterface $parser,
130+
): ArrayType {
84131
$arguments = $statement->arguments->items ?? [];
85132

86133
assert(\array_key_exists(0, $arguments));
@@ -91,6 +138,11 @@ private function buildByValue(NamedTypeNode $statement, TypeRepositoryInterface
91138
$this->expectNoTemplateArgumentHint($statement, $value);
92139

93140
return new ArrayType(
141+
key: $types->getTypeByStatement(
142+
statement: $parser->getStatementByDefinition(
143+
definition: $this->keyType,
144+
),
145+
),
94146
value: $types->getTypeByStatement($value->value),
95147
);
96148
}

src/Type/Builder/UnitEnumTypeBuilder.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@
1616
*/
1717
class UnitEnumTypeBuilder extends Builder
1818
{
19+
/**
20+
* @var non-empty-lowercase-string
21+
*/
22+
public const DEFAULT_INNER_SCALAR_TYPE = 'string';
23+
24+
/**
25+
* @param non-empty-string $type
26+
*/
27+
public function __construct(
28+
protected readonly string $type = self::DEFAULT_INNER_SCALAR_TYPE,
29+
) {}
30+
1931
public function isSupported(TypeStatement $statement): bool
2032
{
2133
if (!$statement instanceof NamedTypeNode) {
@@ -50,6 +62,11 @@ public function build(
5062
// @phpstan-ignore-next-line
5163
class: $statement->name->toString(),
5264
cases: $names,
65+
type: $types->getTypeByStatement(
66+
statement: $parser->getStatementByDefinition(
67+
definition: $this->type,
68+
),
69+
),
5370
);
5471
}
5572

src/Type/UnitEnumType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ class UnitEnumType extends AsymmetricType
1616
* @param class-string<\UnitEnum> $class
1717
* @param non-empty-list<non-empty-string> $cases
1818
*/
19-
public function __construct(string $class, array $cases)
19+
public function __construct(string $class, array $cases, TypeInterface $type)
2020
{
2121
parent::__construct(
2222
normalizer: new UnitEnumTypeNormalizer($class),
23-
denormalizer: new UnitEnumTypeDenormalizer($class, $cases),
23+
denormalizer: new UnitEnumTypeDenormalizer($class, $cases, $type),
2424
);
2525
}
2626
}

src/Type/UnitEnumType/UnitEnumTypeDenormalizer.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,28 @@ class UnitEnumTypeDenormalizer implements TypeInterface
1717
public function __construct(
1818
protected readonly string $class,
1919
protected readonly array $cases,
20+
protected readonly TypeInterface $string,
2021
) {}
2122

2223
public function match(mixed $value, Context $context): bool
2324
{
24-
if (!\is_string($value) || $value === '') {
25-
return false;
26-
}
27-
2825
return \in_array($value, $this->cases, true);
2926
}
3027

3128
public function cast(mixed $value, Context $context): \UnitEnum
3229
{
33-
if (!$this->match($value, $context)) {
30+
$string = $this->string->cast($value, $context);
31+
32+
if (!$this->match($string, $context)) {
3433
throw InvalidValueException::createFromContext(
3534
value: $value,
3635
context: $context,
3736
);
3837
}
3938

4039
try {
41-
// @phpstan-ignore-next-line
42-
return \constant($this->class . '::' . $value);
40+
// @phpstan-ignore-next-line : Handle Error manually
41+
return \constant($this->class . '::' . $string);
4342
} catch (\Error $e) {
4443
throw InvalidValueException::createFromContext(
4544
value: $value,

0 commit comments

Comments
 (0)