Skip to content

Commit 5df8b0c

Browse files
committed
Add support for more types
1 parent 25d065e commit 5df8b0c

File tree

2 files changed

+48
-36
lines changed

2 files changed

+48
-36
lines changed

src/Internal/ContextualTypeParser.php

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
2121
use Typhoon\PHPStanTypeParser\CustomTypeParser;
2222
use Typhoon\PHPStanTypeParser\TypeContext;
23+
use Typhoon\Type\ArrayDefaultT;
2324
use Typhoon\Type\ArrayT;
24-
use Typhoon\Type\ObjectT;
2525
use Typhoon\Type\Type;
2626
use function Typhoon\Type\andT;
2727
use function Typhoon\Type\floatRangeT;
@@ -37,6 +37,7 @@
3737
use const Typhoon\Type\falseT;
3838
use const Typhoon\Type\floatT;
3939
use const Typhoon\Type\intT;
40+
use const Typhoon\Type\literalStringT;
4041
use const Typhoon\Type\lowercaseStringT;
4142
use const Typhoon\Type\mixedT;
4243
use const Typhoon\Type\negativeIntT;
@@ -48,11 +49,13 @@
4849
use const Typhoon\Type\nullT;
4950
use const Typhoon\Type\numericStringT;
5051
use const Typhoon\Type\numericT;
52+
use const Typhoon\Type\objectT;
5153
use const Typhoon\Type\positiveIntT;
5254
use const Typhoon\Type\resourceT;
5355
use const Typhoon\Type\scalarT;
5456
use const Typhoon\Type\stringT;
5557
use const Typhoon\Type\trueT;
58+
use const Typhoon\Type\truthyStringT;
5659
use const Typhoon\Type\voidT;
5760

5861
/**
@@ -119,12 +122,14 @@ private function parseIdentifier(string $name, array $genericNodes = []): Type
119122
'non-empty-string' => nonEmptyStringT,
120123
'lowercase-string' => lowercaseStringT,
121124
'numeric-string' => numericStringT,
125+
'literal-string' => literalStringT,
122126
'string' => stringT,
127+
'truthy-string', 'non-falsy-string' => truthyStringT,
123128
'resource' => resourceT,
124129
'array-key' => arrayKeyT,
125130
'numeric' => numericT,
126131
'scalar' => scalarT,
127-
'object' => new ObjectT([]),
132+
'object' => objectT,
128133
'mixed' => mixedT,
129134
default => null,
130135
};
@@ -147,22 +152,8 @@ private function parseIdentifier(string $name, array $genericNodes = []): Type
147152

148153
$templateArguments = array_map($this->parseTypeNode(...), $genericNodes);
149154

150-
if ($name === 'array') {
151-
return match ($number = \count($templateArguments)) {
152-
0 => arrayT,
153-
1 => new ArrayT(valueType: $templateArguments[0]),
154-
2 => new ArrayT($templateArguments[0], $templateArguments[1]),
155-
default => throw new \LogicException(\sprintf('array type should have at most 2 type arguments, got %d', $number)),
156-
};
157-
}
158-
159-
if ($name === 'non-empty-array') {
160-
return match ($number = \count($templateArguments)) {
161-
0 => new ArrayT(isNonEmpty: true),
162-
1 => new ArrayT(valueType: $templateArguments[0], isNonEmpty: true),
163-
2 => new ArrayT($templateArguments[0], $templateArguments[1], isNonEmpty: true),
164-
default => throw new \LogicException(\sprintf('non-empty-array type should have at most 2 type arguments, got %d', $number)),
165-
};
155+
if ($name === 'array' || $name === 'non-empty-array') {
156+
return $this->parseArray($templateArguments, isNonEmpty: $name === 'non-empty-array');
166157
}
167158

168159
return $this->customTypeParser->parseCustomType($name, $templateArguments, $this->context)
@@ -187,24 +178,6 @@ private function parseInt(array $genericNodes): Type
187178
};
188179
}
189180

190-
/**
191-
* @param list<TypeNode> $genericNodes
192-
*/
193-
private function parseFloat(array $genericNodes): Type
194-
{
195-
return match (\count($genericNodes)) {
196-
0 => floatT,
197-
2 => floatRangeT(
198-
min: self::parseFloatRangeLimit($genericNodes[0], 'min'),
199-
max: self::parseFloatRangeLimit($genericNodes[1], 'max'),
200-
),
201-
default => throw new \LogicException(\sprintf(
202-
'Float range type should have 2 type arguments, got %d',
203-
\count($genericNodes),
204-
))
205-
};
206-
}
207-
208181
/**
209182
* @param 'min'|'max' $name
210183
*/
@@ -231,6 +204,24 @@ private function parseIntRangeLimit(TypeNode $type, string $name): ?int
231204
throw new \LogicException();
232205
}
233206

207+
/**
208+
* @param list<TypeNode> $genericNodes
209+
*/
210+
private function parseFloat(array $genericNodes): Type
211+
{
212+
return match (\count($genericNodes)) {
213+
0 => floatT,
214+
2 => floatRangeT(
215+
min: self::parseFloatRangeLimit($genericNodes[0], 'min'),
216+
max: self::parseFloatRangeLimit($genericNodes[1], 'max'),
217+
),
218+
default => throw new \LogicException(\sprintf(
219+
'Float range type should have 2 type arguments, got %d',
220+
\count($genericNodes),
221+
))
222+
};
223+
}
224+
234225
/**
235226
* @param 'min'|'max' $name
236227
* @return ?numeric-string
@@ -257,4 +248,17 @@ private function parseFloatRangeLimit(TypeNode $type, string $name): ?string
257248

258249
throw new \LogicException();
259250
}
251+
252+
/**
253+
* @param list<Type> $templateArguments
254+
*/
255+
private function parseArray(array $templateArguments, bool $isNonEmpty = false): ArrayDefaultT|ArrayT
256+
{
257+
return match ($number = \count($templateArguments)) {
258+
0 => $isNonEmpty ? new ArrayT(isNonEmpty: true) : arrayT,
259+
1 => new ArrayT(valueType: $templateArguments[0], isNonEmpty: $isNonEmpty),
260+
2 => new ArrayT(keyType: $templateArguments[0], valueType: $templateArguments[1], isNonEmpty: $isNonEmpty),
261+
default => throw new \LogicException(\sprintf('array type should have at most 2 type arguments, got %d', $number)),
262+
};
263+
}
260264
}

tests/PHPStanTypeParserTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,26 @@
2626
use const Typhoon\Type\falseT;
2727
use const Typhoon\Type\floatT;
2828
use const Typhoon\Type\intT;
29+
use const Typhoon\Type\literalStringT;
2930
use const Typhoon\Type\lowercaseStringT;
3031
use const Typhoon\Type\mixedT;
3132
use const Typhoon\Type\negativeIntT;
3233
use const Typhoon\Type\neverT;
3334
use const Typhoon\Type\nonEmptyStringT;
35+
use const Typhoon\Type\nonFalsyStringT;
3436
use const Typhoon\Type\nonNegativeIntT;
3537
use const Typhoon\Type\nonPositiveIntT;
3638
use const Typhoon\Type\nonZeroIntT;
3739
use const Typhoon\Type\nullT;
3840
use const Typhoon\Type\numericStringT;
3941
use const Typhoon\Type\numericT;
42+
use const Typhoon\Type\objectT;
4043
use const Typhoon\Type\positiveIntT;
4144
use const Typhoon\Type\resourceT;
4245
use const Typhoon\Type\scalarT;
4346
use const Typhoon\Type\stringT;
4447
use const Typhoon\Type\trueT;
48+
use const Typhoon\Type\truthyStringT;
4549
use const Typhoon\Type\voidT;
4650

4751
#[CoversClass(PHPStanTypeParser::class)]
@@ -90,6 +94,9 @@ private static function cases(): \Generator
9094
yield 'non-empty-string' => nonEmptyStringT;
9195
yield 'numeric-string' => numericStringT;
9296
yield 'lowercase-string' => lowercaseStringT;
97+
yield 'literal-string' => literalStringT;
98+
yield 'truthy-string' => truthyStringT;
99+
yield 'non-falsy-string' => nonFalsyStringT;
93100
yield 'string' => stringT;
94101
yield 'resource' => resourceT;
95102
yield 'array-key' => arrayKeyT;
@@ -105,6 +112,7 @@ private static function cases(): \Generator
105112
yield 'non-empty-array' => nonEmptyArrayT();
106113
yield 'non-empty-array<string>' => nonEmptyArrayT(value: stringT);
107114
yield 'non-empty-array<int, string>' => nonEmptyArrayT(intT, stringT);
115+
yield 'object' => objectT;
108116
yield 'mixed' => mixedT;
109117
yield \stdClass::class => namedObjectT(\stdClass::class);
110118
yield \Stringable::class => namedObjectT(\Stringable::class);

0 commit comments

Comments
 (0)