Skip to content

Commit 537254f

Browse files
authored
Added literal type (#1731)
1 parent 4dfa14d commit 537254f

5 files changed

Lines changed: 468 additions & 1 deletion

File tree

src/lib/types/src/Flow/Types/DSL/functions.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
InstanceOfType,
1313
JsonType,
1414
ListType,
15+
LiteralType,
1516
MapType,
1617
NonEmptyStringType,
1718
NumericStringType,
@@ -338,6 +339,19 @@ function type_enum(string $class) : EnumType
338339
return new EnumType($class);
339340
}
340341

342+
/**
343+
* @template T of bool|float|int|string
344+
*
345+
* @param T $value
346+
*
347+
* @return LiteralType<T>
348+
*/
349+
#[DocumentationDSL(module: Module::TYPES, type: DSLType::TYPE)]
350+
function type_literal(bool|float|int|string $value) : LiteralType
351+
{
352+
return new LiteralType($value);
353+
}
354+
341355
/**
342356
* @template T
343357
*
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Flow\Types\Type\Logical;
6+
7+
use Flow\Types\Exception\{CastingException, InvalidTypeException};
8+
use Flow\Types\Type;
9+
10+
/**
11+
* @template T of bool|float|int|string
12+
*
13+
* @implements Type<T>
14+
*/
15+
final readonly class LiteralType implements Type
16+
{
17+
/**
18+
* @param T $value
19+
*/
20+
public function __construct(
21+
private bool|float|int|string $value,
22+
) {
23+
}
24+
25+
public function assert(mixed $value) : bool|float|int|string
26+
{
27+
if ($this->isValid($value)) {
28+
return $value;
29+
}
30+
31+
throw InvalidTypeException::value($value, $this);
32+
}
33+
34+
public function cast(mixed $value) : bool|float|int|string
35+
{
36+
if ($this->isValid($value)) {
37+
return $value;
38+
}
39+
40+
throw new CastingException($value, $this);
41+
}
42+
43+
public function isValid(mixed $value) : bool
44+
{
45+
return $value === $this->value;
46+
}
47+
48+
public function normalize() : array
49+
{
50+
return [
51+
'type' => 'literal',
52+
'value' => (string) $this->value,
53+
];
54+
}
55+
56+
public function toString() : string
57+
{
58+
if (\is_string($this->value)) {
59+
return "'{$this->value}'";
60+
}
61+
62+
if (\is_bool($this->value)) {
63+
return $this->value ? 'true' : 'false';
64+
}
65+
66+
return (string) $this->value;
67+
}
68+
}

src/lib/types/src/Flow/Types/Type/TypeFactory.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
type_float,
1313
type_integer,
1414
type_json,
15+
type_literal,
1516
type_mixed,
1617
type_non_empty_string,
1718
type_null,
@@ -64,6 +65,7 @@ public static function fromArray(array $data) : Type
6465
'datetime' => type_datetime(),
6566
'json' => type_json(),
6667
'uuid' => type_uuid(),
68+
'literal' => self::createLiteralFromString($data['value']),
6769
/** @phpstan-ignore argument.type */
6870
'list' => ListType::fromArray($data),
6971
/** @phpstan-ignore argument.type */
@@ -100,4 +102,28 @@ public static function fromString(string $name) : Type
100102
default => self::fromArray(['type' => $name]),
101103
};
102104
}
105+
106+
/**
107+
* @return Type<mixed>
108+
*/
109+
private static function createLiteralFromString(string $value) : Type
110+
{
111+
if ($value === 'true') {
112+
return type_literal(true);
113+
}
114+
115+
if ($value === 'false') {
116+
return type_literal(false);
117+
}
118+
119+
if (\is_numeric($value)) {
120+
if (\str_contains($value, '.')) {
121+
return type_literal((float) $value);
122+
}
123+
124+
return type_literal((int) $value);
125+
}
126+
127+
return type_literal($value);
128+
}
103129
}

0 commit comments

Comments
 (0)