-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathTypeResolver.php
83 lines (70 loc) · 2.49 KB
/
TypeResolver.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
<?php
declare(strict_types=1);
namespace TypeLang\Parser;
use TypeLang\Parser\Node\FullQualifiedName;
use TypeLang\Parser\Node\Name;
use TypeLang\Parser\Node\Stmt\TypeStatement;
use TypeLang\Parser\Traverser\TypeMapVisitor;
final class TypeResolver implements TypeResolverInterface
{
public function resolve(TypeStatement $type, callable $transform): TypeStatement
{
Traverser::through(
visitor: new TypeMapVisitor($transform(...)),
nodes: [$type],
);
return $type;
}
/**
* Use for example for code like this:
* ```php
* use TypeLang\Parser\Node;
* use TypeLang\Parser\Exception as Error;
*
* $parser = new TypeLang\Parser\Parser();
* $result = $parser->parse(<<<'PHP'
* array { Node, Error\SemanticException }
* PHP);
*
* $resolver = new \TypeLang\Parser\TypeResolver();
* $result = $resolver->resolveWith($expected, [
* 'TypeLang\Parser\Node', // use TypeLang\Parser\Node;
* 'Error' => 'TypeLang\Parser\Exception', // use TypeLang\Parser\Exception as Error;
* ]);
*
* // Expected Output:
* // > array{
* // > TypeLang\Parser\Node,
* // > TypeLang\Parser\Exception\SemanticException
* // > }
* ```
*
* @param array<non-empty-string|array-key, non-empty-string|Name> $replacements
*/
public function resolveWith(TypeStatement $type, array $replacements): TypeStatement
{
foreach ($replacements as $key => $replacement) {
// normalize value
if (\is_string($replacement)) {
$replacement = \str_starts_with($replacement, '\\')
? new FullQualifiedName($replacement)
: new Name($replacement);
}
// normalize key
if (\is_int($key)) {
unset($replacements[$key]);
$key = $replacement->getLastPartAsString();
}
$replacements[\strtolower($key)] = $replacement;
}
/** @var array<non-empty-lowercase-string, Name> $replacements */
return $this->resolve($type, static function (Name $name) use ($replacements) {
$first = \strtolower($name->getFirstPartAsString());
if (isset($replacements[$first])) {
$prefix = $replacements[$first];
return $prefix->mergeWith($name);
}
return null;
});
}
}