-
-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: improve union type narrowing during mapping
The algorithm used by the mapper to narrow a union type has been greatly improved, and should cover more edge-cases that would previously prevent the mapper from performing well. If an interface, a class or a shaped array is matched by the input, it will take precedence over arrays or scalars. ```php (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map( signature: 'array<int>|' . Color::class, source: [ 'red' => 255, 'green' => 128, 'blue' => 64, ], ); // Returns an instance of `Color` ``` When superfluous keys are allowed, if the input matches several interfaces, classes or shaped array, the one with the most children node will be prioritized, as it is considered the most specific type: ```php (new \CuyZ\Valinor\MapperBuilder()) ->allowSuperfluousKeys() ->mapper() ->map( // Even if the first shaped array matches the input, the second one is // used because it's more specific. signature: 'array{foo: int}|array{foo: int, bar: int}', source: [ 'foo' => 42, 'bar' => 1337, ], ); ``` If the input matches several types within the union, a collision will occur and cause the mapper to fail: ```php (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map( // Even if the first shaped array matches the input, the second one is // used because it's more specific. signature: 'array{red: int, green: int, blue: int}|' . Color::class, source: [ 'red' => 255, 'green' => 128, 'blue' => 64, ], ); //⚠️ Invalid value array{red: 255, green: 128, blue: 64}, it matches at // least two types from union. ```
- Loading branch information
Showing
15 changed files
with
581 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace CuyZ\Valinor\Mapper\Tree\Builder; | ||
|
||
use CuyZ\Valinor\Mapper\Tree\Exception\SourceIsNotNull; | ||
use CuyZ\Valinor\Mapper\Tree\Shell; | ||
use CuyZ\Valinor\Type\Types\NullType; | ||
|
||
use function assert; | ||
|
||
/** @internal */ | ||
final class NullNodeBuilder implements NodeBuilder | ||
{ | ||
public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode | ||
{ | ||
$type = $shell->type(); | ||
$value = $shell->value(); | ||
|
||
assert($type instanceof NullType); | ||
|
||
if ($value !== null) { | ||
throw new SourceIsNotNull(); | ||
} | ||
|
||
return TreeNode::leaf($shell, null); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace CuyZ\Valinor\Mapper\Tree\Exception; | ||
|
||
use CuyZ\Valinor\Mapper\Tree\Message\ErrorMessage; | ||
use RuntimeException; | ||
|
||
/** @internal */ | ||
final class SourceIsNotNull extends RuntimeException implements ErrorMessage | ||
{ | ||
private string $body; | ||
|
||
public function __construct() | ||
{ | ||
$this->body = 'Value {source_value} is not null.'; | ||
|
||
parent::__construct($this->body, 1710263908); | ||
} | ||
|
||
public function body(): string | ||
{ | ||
return $this->body; | ||
} | ||
} |
Oops, something went wrong.