-
Notifications
You must be signed in to change notification settings - Fork 1
/
utils.php
94 lines (78 loc) · 2.14 KB
/
utils.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
declare(strict_types=1);
namespace Klimick\Decode\Utils;
use Fp\Functional\Option\Option;
use Klimick\Decode\Decoder\DecoderInterface;
use function Fp\Collection\every;
use function Fp\Collection\keys;
use function Fp\Collection\map;
use function Fp\Collection\tail;
/**
* @param list<string> $path
* @return Option<mixed>
* @psalm-pure
*/
function getByPath(array $path, array $shape): Option
{
if (empty($path)) {
return Option::none();
}
$key = $path[0];
$rest = tail($path);
if (array_key_exists($key, $shape)) {
if (empty($rest)) {
return Option::some($shape[$key]);
}
if (is_array($shape[$key])) {
return getByPath($rest, $shape[$key]);
}
}
return Option::none();
}
/**
* @return non-empty-string
* @psalm-pure
*/
function getTypename(mixed $value): string
{
/** @var non-empty-string */
return match (get_debug_type($value)) {
'null' => 'null',
'bool' => $value ? 'true' : 'false',
'int', 'float' => (string) $value,
'string' => "'{$value}'",
'array' => getArrayTypeName($value),
default => is_object($value) ? get_class($value) : 'unknown',
};
}
/**
* @return non-empty-string
* @psalm-pure
*/
function getArrayTypeName(array $arr): string
{
$isList = every(keys($arr), fn($k) => is_int($k));
$types = $isList
? map($arr, fn(mixed $v) => getTypename($v))
: map($arr, fn(mixed $v, string|int $k) => $k . ': ' . getTypename($v));
return 'array{' . implode(', ', $types) . '}';
}
/**
* string() -> 'string'
* string()->from('$.key1', '$.key2') -> 'array{key1: string} | array{key2: string}'
*
* @return non-empty-string
* @psalm-pure
*/
function getAliasedTypename(DecoderInterface $decoder): string
{
$aliases = $decoder->getAliases();
$typename = $decoder->name();
if (empty($aliases)) {
return $typename;
}
$withoutPrefix = fn(string $alias): string => str_replace('$.', '', $alias);
return implode(' | ', map($aliases, fn($alias) => $alias === '$'
? $typename
: "array{{$withoutPrefix($alias)}: {$typename}}"));
}