allow vendord
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
This commit is contained in:
18
vendor/cuyz/valinor/LICENSE.md
vendored
Normal file
18
vendor/cuyz/valinor/LICENSE.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
Copyright (c) 2021 Romain Canon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
129
vendor/cuyz/valinor/README.md
vendored
Normal file
129
vendor/cuyz/valinor/README.md
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
<div>— From boring old arrays to shiny typed objects —</div>
|
||||
|
||||
<br>
|
||||
|
||||
[][link-packagist]
|
||||
[][link-packagist]
|
||||
[][link-packagist]
|
||||
[](https://dashboard.stryker-mutator.io/reports/github.com/CuyZ/Valinor/master)
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Valinor takes care of the construction and validation of raw inputs (JSON, plain
|
||||
arrays, etc.) into objects, ensuring a perfectly valid state. It allows the
|
||||
objects to be used without having to worry about their integrity during the
|
||||
whole application lifecycle.
|
||||
|
||||
The validation system will detect any incorrect value and help the developers by
|
||||
providing precise and human-readable error messages.
|
||||
|
||||
The mapper can handle native PHP types as well as other advanced types supported
|
||||
by [PHPStan] and [Psalm] like shaped arrays, generics, integer ranges and more.
|
||||
|
||||
The library also provides a normalization mechanism that can help transform any
|
||||
input into a data format (JSON, CSV, …), while preserving the original
|
||||
structure.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
composer require cuyz/valinor
|
||||
```
|
||||
|
||||
**📔 Read more on the [online documentation](https://valinor.cuyz.io)**
|
||||
|
||||
## Example
|
||||
|
||||
```php
|
||||
final class Country
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
public readonly string $name,
|
||||
|
||||
/** @var list<City> */
|
||||
public readonly array $cities,
|
||||
) {}
|
||||
}
|
||||
|
||||
final class City
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
public readonly string $name,
|
||||
|
||||
public readonly DateTimeZone $timeZone,
|
||||
) {}
|
||||
}
|
||||
|
||||
$json = <<<JSON
|
||||
{
|
||||
"name": "France",
|
||||
"cities": [
|
||||
{"name": "Paris", "timeZone": "Europe/Paris"},
|
||||
{"name": "Lyon", "timeZone": "Europe/Paris"}
|
||||
]
|
||||
}
|
||||
JSON;
|
||||
|
||||
try {
|
||||
$country = (new \CuyZ\Valinor\MapperBuilder())
|
||||
->mapper()
|
||||
->map(Country::class, \CuyZ\Valinor\Mapper\Source\Source::json($json));
|
||||
|
||||
echo $country->name; // France
|
||||
echo $country->cities[0]->name; // Paris
|
||||
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
|
||||
// Handle the error…
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The full documentation is available on [valinor.cuyz.io].
|
||||
|
||||
## Credits & thank you
|
||||
|
||||
The development of this library is mainly motivated by the kind words and the
|
||||
help of many people. I am grateful to everyone, especially to the contributors
|
||||
of this repository who directly help to push the project forward:
|
||||
|
||||
[](https://github.com/cuyz/valinor/graphs/contributors)
|
||||
|
||||
### Powered by
|
||||
|
||||
[](https://jb.gg/OpenSourceSupport)
|
||||
|
||||
I have to give [JetBrains] credits for providing [a free PhpStorm license] for
|
||||
the development of this open-source package.
|
||||
|
||||
### Special thanks
|
||||
|
||||
I also want to thank
|
||||
[![blackfire-logo] Blackfire](https://www.blackfire.io/?utm_source=valinor&utm_medium=readme&utm_campaign=free-open-source)
|
||||
for providing a license of their awesome tool, leading to notable performance
|
||||
gains when using this library.
|
||||
|
||||
[link-packagist]: https://packagist.org/packages/cuyz/valinor
|
||||
|
||||
[contributors]: https://github.com/CuyZ/Valinor/graphs/contributors
|
||||
|
||||
[PHPStan]: https://phpstan.org/
|
||||
|
||||
[Psalm]: https://psalm.dev/
|
||||
|
||||
[Jetbrains]: https://www.jetbrains.com/
|
||||
|
||||
[a free PhpStorm license]: https://jb.gg/OpenSourceSupport
|
||||
|
||||
[Blackfire]: https://www.blackfire.io/?utm_source=valinor&utm_medium=readme&utm_campaign=free-open-source
|
||||
|
||||
[blackfire-logo]: docs/pages/img/blackfire-logo.svg "Blackfire logo"
|
||||
|
||||
[valinor.cuyz.io]: https://valinor.cuyz.io
|
||||
97
vendor/cuyz/valinor/composer.json
vendored
Normal file
97
vendor/cuyz/valinor/composer.json
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"name": "cuyz/valinor",
|
||||
"type": "library",
|
||||
"description": "Library that helps to map any input into a strongly-typed value object structure.",
|
||||
"keywords": [
|
||||
"object", "tree", "mapper", "mapping", "hydrator", "array", "conversion", "json", "yaml"
|
||||
],
|
||||
"homepage": "https://github.com/CuyZ/Valinor",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Romain Canon",
|
||||
"email": "romain.hydrocanon@gmail.com",
|
||||
"homepage": "https://github.com/romm"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
|
||||
"composer-runtime-api": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"infection/infection": "^0.31",
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.4",
|
||||
"marcocesarato/php-conventional-changelog": "^1.12",
|
||||
"vimeo/psalm": "^6.0",
|
||||
"mikey179/vfsstream": "^1.6.10",
|
||||
"rector/rector": "^2.0",
|
||||
"phpbench/phpbench": "^1.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"CuyZ\\Valinor\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"CuyZ\\Valinor\\Tests\\": "tests",
|
||||
"CuyZ\\Valinor\\QA\\": "qa"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"check": [
|
||||
"@putenv XDEBUG_MODE=off",
|
||||
"phpunit",
|
||||
"phpstan",
|
||||
"psalm --config=tests/StaticAnalysis/psalm-without-plugin.xml",
|
||||
"psalm --config=tests/StaticAnalysis/psalm-with-plugin.xml",
|
||||
"phpstan --configuration=tests/StaticAnalysis/phpstan-without-extension.neon.dist",
|
||||
"phpstan --configuration=tests/StaticAnalysis/phpstan-with-extension.neon.dist",
|
||||
"php-cs-fixer fix --dry-run",
|
||||
"rector --dry-run",
|
||||
"@check-todo"
|
||||
],
|
||||
"check-todo": [
|
||||
"! git --no-pager grep --extended-regexp --ignore-case 'todo|fixme' -- ':!composer.json' ':!*/quality-assurance.yml'"
|
||||
],
|
||||
"fix": [
|
||||
"@putenv XDEBUG_MODE=off",
|
||||
"php-cs-fixer fix",
|
||||
"rector"
|
||||
],
|
||||
"test": [
|
||||
"@putenv XDEBUG_MODE=off",
|
||||
"phpunit"
|
||||
],
|
||||
"mutation": [
|
||||
"infection --threads=max --git-diff-lines --with-uncovered --min-msi=100"
|
||||
],
|
||||
"doc": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"docker build -t valinor-doc ./docs",
|
||||
"docker run --name valinor-doc --rm -it -p 8000:8000 -v ${PWD}/docs:/docs valinor-doc"
|
||||
],
|
||||
"benchmark-baseline": [
|
||||
"phpbench run --tag=original --retry-threshold=5 --iterations=10"
|
||||
],
|
||||
"benchmark-compare": [
|
||||
"phpbench run --report=aggregate --ref=original --retry-threshold=5 --iterations=10 --assert='mode(variant.time.avg) <= mode(baseline.time.avg) +/- 10%'"
|
||||
],
|
||||
"benchmark": [
|
||||
"phpbench run --report=aggregate --iterations=10"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"infection/extension-installer": false
|
||||
}
|
||||
},
|
||||
"conflict": {
|
||||
"vimeo/psalm": "<5.0 || >=7.0",
|
||||
"phpstan/phpstan": "<1.0 || >= 3.0"
|
||||
}
|
||||
}
|
||||
56
vendor/cuyz/valinor/qa/PHPStan/Extension/ApiAndInternalAnnotationCheck.php
vendored
Normal file
56
vendor/cuyz/valinor/qa/PHPStan/Extension/ApiAndInternalAnnotationCheck.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\QA\PHPStan\Extension;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Node\InClassNode;
|
||||
use PHPStan\Rules\Rule;
|
||||
use PHPStan\Rules\RuleErrorBuilder;
|
||||
|
||||
use function str_contains;
|
||||
use function str_starts_with;
|
||||
|
||||
/**
|
||||
* @implements Rule<InClassNode>
|
||||
*/
|
||||
final class ApiAndInternalAnnotationCheck implements Rule
|
||||
{
|
||||
public function getNodeType(): string
|
||||
{
|
||||
return InClassNode::class;
|
||||
}
|
||||
|
||||
public function processNode(Node $node, Scope $scope): array
|
||||
{
|
||||
$reflection = $scope->getClassReflection();
|
||||
|
||||
if (! $reflection) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($reflection->isAnonymous()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (str_contains($reflection->getFileName() ?? '', '/tests/')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (str_starts_with($reflection->getName(), 'CuyZ\Valinor\QA')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (! preg_match('/@(api|internal)\s+/', $reflection->getResolvedPhpDoc()?->getPhpDocString() ?? '')) {
|
||||
return [
|
||||
RuleErrorBuilder::message(
|
||||
'Missing annotation `@api` or `@internal`.'
|
||||
)->identifier('valinor.apiOrInternalAnnotation')->build(),
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
61
vendor/cuyz/valinor/qa/PHPStan/Extension/ArgumentsMapperPHPStanExtension.php
vendored
Normal file
61
vendor/cuyz/valinor/qa/PHPStan/Extension/ArgumentsMapperPHPStanExtension.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\QA\PHPStan\Extension;
|
||||
|
||||
use CuyZ\Valinor\Mapper\ArgumentsMapper;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
|
||||
use PHPStan\Type\Constant\ConstantStringType;
|
||||
use PHPStan\Type\DynamicMethodReturnTypeExtension;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
|
||||
use function count;
|
||||
|
||||
final class ArgumentsMapperPHPStanExtension implements DynamicMethodReturnTypeExtension
|
||||
{
|
||||
public function getClass(): string
|
||||
{
|
||||
return ArgumentsMapper::class;
|
||||
}
|
||||
|
||||
public function isMethodSupported(MethodReflection $methodReflection): bool
|
||||
{
|
||||
return $methodReflection->getName() === 'mapArguments';
|
||||
}
|
||||
|
||||
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
|
||||
{
|
||||
$arguments = $methodCall->getArgs();
|
||||
|
||||
if (count($arguments) === 0) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
$type = $scope->getType($arguments[0]->value);
|
||||
|
||||
if (! $type->isCallable()->yes()) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
$acceptors = $type->getCallableParametersAcceptors($scope);
|
||||
|
||||
if (count($acceptors) !== 1) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
$parameters = $acceptors[0]->getParameters();
|
||||
|
||||
$builder = ConstantArrayTypeBuilder::createEmpty();
|
||||
|
||||
foreach ($parameters as $parameter) {
|
||||
$builder->setOffsetValueType(new ConstantStringType($parameter->getName()), $parameter->getType(), $parameter->isOptional());
|
||||
}
|
||||
|
||||
return $builder->getArray();
|
||||
}
|
||||
}
|
||||
91
vendor/cuyz/valinor/qa/PHPStan/Extension/SuppressPureErrors.php
vendored
Normal file
91
vendor/cuyz/valinor/qa/PHPStan/Extension/SuppressPureErrors.php
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\QA\PHPStan\Extension;
|
||||
|
||||
use CuyZ\Valinor\MapperBuilder;
|
||||
use CuyZ\Valinor\NormalizerBuilder;
|
||||
use CuyZ\Valinor\Utility\Polyfill;
|
||||
use PhpParser\Node;
|
||||
use PHPStan\Analyser\Error;
|
||||
use PHPStan\Analyser\IgnoreErrorExtension;
|
||||
use PHPStan\Analyser\Scope;
|
||||
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* This extension should not be used by default, as it suppresses errors that
|
||||
* are typically indicative of purity issues in the codebase. It is advised to
|
||||
* first address the root causes of these errors before enabling this extension.
|
||||
*
|
||||
* When enabled, it will ignore all purity-related errors of method calls in the
|
||||
* context of `MapperBuilder` and `NormalizerBuilder`.
|
||||
*/
|
||||
final class SuppressPureErrors implements IgnoreErrorExtension
|
||||
{
|
||||
public function shouldIgnore(Error $error, Node $node, Scope $scope): bool
|
||||
{
|
||||
if ($error->getIdentifier() !== 'argument.type') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $node instanceof Node\Expr\MethodCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$type = $scope->getType($node->var);
|
||||
|
||||
if (! $type->isObject()->yes()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! Polyfill::array_find($type->getObjectClassNames(), fn (string $className) => $className === MapperBuilder::class || $className === NormalizerBuilder::class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $node->name instanceof Node\Identifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$methodName = $node->name->toString();
|
||||
|
||||
if (! in_array($methodName, [
|
||||
'infer',
|
||||
'registerConstructor',
|
||||
'registerConverter',
|
||||
'registerTransformer',
|
||||
], true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($node->args === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$callableArgumentIndex = [
|
||||
'infer' => 1,
|
||||
'registerConstructor' => 0,
|
||||
'registerConverter' => 0,
|
||||
'registerTransformer' => 0,
|
||||
][$methodName];
|
||||
|
||||
$argument = $node->args[$callableArgumentIndex];
|
||||
|
||||
if (! $argument instanceof Node\Arg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$argumentType = $scope->getType($argument->value);
|
||||
|
||||
if ($argumentType->isCallable()->yes()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($argumentType->isArray()->yes() && $argumentType->getIterableValueType()->isCallable()->yes()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
80
vendor/cuyz/valinor/qa/PHPStan/Extension/TreeMapperPHPStanExtension.php
vendored
Normal file
80
vendor/cuyz/valinor/qa/PHPStan/Extension/TreeMapperPHPStanExtension.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\QA\PHPStan\Extension;
|
||||
|
||||
use CuyZ\Valinor\Mapper\TreeMapper;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\PhpDoc\TypeStringResolver;
|
||||
use PHPStan\PhpDocParser\Parser\ParserException;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Type\DynamicMethodReturnTypeExtension;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
|
||||
use function implode;
|
||||
use function method_exists;
|
||||
|
||||
final class TreeMapperPHPStanExtension implements DynamicMethodReturnTypeExtension
|
||||
{
|
||||
public function __construct(private TypeStringResolver $resolver) {}
|
||||
|
||||
public function getClass(): string
|
||||
{
|
||||
return TreeMapper::class;
|
||||
}
|
||||
|
||||
public function isMethodSupported(MethodReflection $methodReflection): bool
|
||||
{
|
||||
return $methodReflection->getName() === 'map';
|
||||
}
|
||||
|
||||
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
|
||||
{
|
||||
$arguments = $methodCall->getArgs();
|
||||
|
||||
if (count($arguments) === 0) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
$type = $scope->getType($arguments[0]->value);
|
||||
|
||||
if ($type instanceof UnionType) {
|
||||
return $type->traverse(fn (Type $type) => $this->type($type));
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->type($type);
|
||||
} catch (ParserException) {
|
||||
// Fallback to `mixed` type if the type cannot be resolved. This can
|
||||
// occur with a type that is not understood/supported by PHPStan. If
|
||||
// that happens, returning a mixed type is the safest option, as it
|
||||
// will not make the analysis fail.
|
||||
return new MixedType();
|
||||
}
|
||||
}
|
||||
|
||||
private function type(Type $type): Type
|
||||
{
|
||||
if ($type->isConstantValue()->yes()) {
|
||||
$value = implode('', $type->getConstantScalarValues());
|
||||
|
||||
return $this->resolver->resolve($value);
|
||||
}
|
||||
|
||||
// @phpstan-ignore function.alreadyNarrowedType (support for PHPStan v1)
|
||||
if (method_exists($type, 'isClassString') && $type->isClassString()->yes()) {
|
||||
return $type->getClassStringObjectType();
|
||||
}
|
||||
|
||||
// @phpstan-ignore method.nonObject (support for PHPStan v1)
|
||||
if (method_exists($type, 'isClassStringType') && $type->isClassStringType()->yes()) {
|
||||
return $type->getClassStringObjectType();
|
||||
}
|
||||
|
||||
return new MixedType();
|
||||
}
|
||||
}
|
||||
19
vendor/cuyz/valinor/qa/PHPStan/valinor-phpstan-configuration.php
vendored
Normal file
19
vendor/cuyz/valinor/qa/PHPStan/valinor-phpstan-configuration.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
use CuyZ\Valinor\QA\PHPStan\Extension\ArgumentsMapperPHPStanExtension;
|
||||
use CuyZ\Valinor\QA\PHPStan\Extension\TreeMapperPHPStanExtension;
|
||||
|
||||
require_once 'Extension/ArgumentsMapperPHPStanExtension.php';
|
||||
require_once 'Extension/TreeMapperPHPStanExtension.php';
|
||||
|
||||
return [
|
||||
'services' => [
|
||||
[
|
||||
'class' => TreeMapperPHPStanExtension::class,
|
||||
'tags' => ['phpstan.broker.dynamicMethodReturnTypeExtension']
|
||||
], [
|
||||
'class' => ArgumentsMapperPHPStanExtension::class,
|
||||
'tags' => ['phpstan.broker.dynamicMethodReturnTypeExtension']
|
||||
],
|
||||
],
|
||||
];
|
||||
14
vendor/cuyz/valinor/qa/PHPStan/valinor-phpstan-suppress-pure-errors.php
vendored
Normal file
14
vendor/cuyz/valinor/qa/PHPStan/valinor-phpstan-suppress-pure-errors.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use CuyZ\Valinor\QA\PHPStan\Extension\SuppressPureErrors;
|
||||
|
||||
require_once 'Extension/SuppressPureErrors.php';
|
||||
|
||||
return [
|
||||
'services' => [
|
||||
[
|
||||
'class' => SuppressPureErrors::class,
|
||||
'tags' => ['phpstan.ignoreErrorExtension'],
|
||||
],
|
||||
],
|
||||
];
|
||||
75
vendor/cuyz/valinor/qa/Psalm/Plugin/ArgumentsMapperPsalmPlugin.php
vendored
Normal file
75
vendor/cuyz/valinor/qa/Psalm/Plugin/ArgumentsMapperPsalmPlugin.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\QA\Psalm\Plugin;
|
||||
|
||||
use CuyZ\Valinor\Mapper\ArgumentsMapper;
|
||||
use Psalm\Internal\Type\Comparator\CallableTypeComparator;
|
||||
use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent;
|
||||
use Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface;
|
||||
use Psalm\Type\Atomic\TClosure;
|
||||
use Psalm\Type\Atomic\TKeyedArray;
|
||||
use Psalm\Type\Atomic\TMixed;
|
||||
use Psalm\Type\Union;
|
||||
|
||||
use function count;
|
||||
use function reset;
|
||||
|
||||
final class ArgumentsMapperPsalmPlugin implements MethodReturnTypeProviderInterface
|
||||
{
|
||||
public static function getClassLikeNames(): array
|
||||
{
|
||||
return [ArgumentsMapper::class];
|
||||
}
|
||||
|
||||
public static function getMethodReturnType(MethodReturnTypeProviderEvent $event): ?Union
|
||||
{
|
||||
if ($event->getMethodNameLowercase() !== 'maparguments') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$arguments = $event->getCallArgs();
|
||||
|
||||
if (count($arguments) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$types = $event->getSource()->getNodeTypeProvider()->getType($arguments[0]->value);
|
||||
|
||||
if ($types === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$types = $types->getAtomicTypes();
|
||||
|
||||
if (count($types) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$type = reset($types);
|
||||
|
||||
if ($type instanceof TKeyedArray) {
|
||||
// Internal class usage, see https://github.com/vimeo/psalm/issues/8726
|
||||
$type = CallableTypeComparator::getCallableFromAtomic($event->getSource()->getCodebase(), $type);
|
||||
}
|
||||
|
||||
if (! $type instanceof TClosure) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$typeParams = $type->params ?? [];
|
||||
|
||||
if ($typeParams === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$params = [];
|
||||
|
||||
foreach ($typeParams as $param) {
|
||||
$params[$param->name] = $param->type ?? new Union([new TMixed()]);
|
||||
}
|
||||
|
||||
return new Union([new TKeyedArray($params)]);
|
||||
}
|
||||
}
|
||||
66
vendor/cuyz/valinor/qa/Psalm/Plugin/TreeMapperPsalmPlugin.php
vendored
Normal file
66
vendor/cuyz/valinor/qa/Psalm/Plugin/TreeMapperPsalmPlugin.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\QA\Psalm\Plugin;
|
||||
|
||||
use CuyZ\Valinor\Mapper\TreeMapper;
|
||||
use Psalm\Plugin\EventHandler\Event\MethodReturnTypeProviderEvent;
|
||||
use Psalm\Plugin\EventHandler\MethodReturnTypeProviderInterface;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic;
|
||||
use Psalm\Type\Atomic\TClassString;
|
||||
use Psalm\Type\Atomic\TDependentGetClass;
|
||||
use Psalm\Type\Atomic\TLiteralString;
|
||||
use Psalm\Type\Union;
|
||||
|
||||
final class TreeMapperPsalmPlugin implements MethodReturnTypeProviderInterface
|
||||
{
|
||||
public static function getClassLikeNames(): array
|
||||
{
|
||||
return [TreeMapper::class];
|
||||
}
|
||||
|
||||
public static function getMethodReturnType(MethodReturnTypeProviderEvent $event): ?Union
|
||||
{
|
||||
if ($event->getMethodNameLowercase() !== 'map') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$arguments = $event->getCallArgs();
|
||||
|
||||
if (count($arguments) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$type = $event->getSource()->getNodeTypeProvider()->getType($arguments[0]->value);
|
||||
|
||||
if (! $type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$types = [];
|
||||
|
||||
foreach ($type->getAtomicTypes() as $node) {
|
||||
$inferred = self::type($node);
|
||||
|
||||
if ($inferred === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$types[] = $inferred;
|
||||
}
|
||||
|
||||
return Type::combineUnionTypeArray($types, $event->getSource()->getCodebase());
|
||||
}
|
||||
|
||||
private static function type(Atomic $node): ?Union
|
||||
{
|
||||
return match (true) {
|
||||
$node instanceof TLiteralString => Type::parseString($node->value),
|
||||
$node instanceof TDependentGetClass => $node->as_type,
|
||||
$node instanceof TClassString && $node->as_type => new Union([$node->as_type]),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
21
vendor/cuyz/valinor/qa/Psalm/ValinorPsalmPlugin.php
vendored
Normal file
21
vendor/cuyz/valinor/qa/Psalm/ValinorPsalmPlugin.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace CuyZ\Valinor\QA\Psalm;
|
||||
|
||||
use CuyZ\Valinor\QA\Psalm\Plugin\ArgumentsMapperPsalmPlugin;
|
||||
use CuyZ\Valinor\QA\Psalm\Plugin\TreeMapperPsalmPlugin;
|
||||
use Psalm\Plugin\PluginEntryPointInterface;
|
||||
use Psalm\Plugin\RegistrationInterface;
|
||||
use SimpleXMLElement;
|
||||
|
||||
class ValinorPsalmPlugin implements PluginEntryPointInterface
|
||||
{
|
||||
public function __invoke(RegistrationInterface $api, ?SimpleXMLElement $config = null): void
|
||||
{
|
||||
require_once __DIR__ . '/Plugin/TreeMapperPsalmPlugin.php';
|
||||
require_once __DIR__ . '/Plugin/ArgumentsMapperPsalmPlugin.php';
|
||||
|
||||
$api->registerHooksFromClass(TreeMapperPsalmPlugin::class);
|
||||
$api->registerHooksFromClass(ArgumentsMapperPsalmPlugin::class);
|
||||
}
|
||||
}
|
||||
11
vendor/cuyz/valinor/qa/Psalm/valinor-psalm-suppress-pure-errors.xml
vendored
Normal file
11
vendor/cuyz/valinor/qa/Psalm/valinor-psalm-suppress-pure-errors.xml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issueHandlers xmlns="https://getpsalm.org/schema/config">
|
||||
<InvalidArgument>
|
||||
<errorLevel type="suppress">
|
||||
<referencedFunction name="CuyZ\Valinor\NormalizerBuilder::registerTransformer"/>
|
||||
<referencedFunction name="\CuyZ\Valinor\MapperBuilder::infer"/>
|
||||
<referencedFunction name="\CuyZ\Valinor\MapperBuilder::registerConstructor"/>
|
||||
<referencedFunction name="\CuyZ\Valinor\MapperBuilder::registerConverter"/>
|
||||
</errorLevel>
|
||||
</InvalidArgument>
|
||||
</issueHandlers>
|
||||
26
vendor/cuyz/valinor/src/Cache/Cache.php
vendored
Normal file
26
vendor/cuyz/valinor/src/Cache/Cache.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @template T = mixed
|
||||
*/
|
||||
interface Cache
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $key
|
||||
* @return null|T
|
||||
*/
|
||||
public function get(string $key, mixed ...$arguments): mixed;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $key
|
||||
*/
|
||||
public function set(string $key, CacheEntry $entry): void;
|
||||
|
||||
public function clear(): void;
|
||||
}
|
||||
15
vendor/cuyz/valinor/src/Cache/CacheEntry.php
vendored
Normal file
15
vendor/cuyz/valinor/src/Cache/CacheEntry.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache;
|
||||
|
||||
/** @internal */
|
||||
final class CacheEntry
|
||||
{
|
||||
public function __construct(
|
||||
public readonly string $code,
|
||||
/** @var list<non-empty-string> */
|
||||
public readonly array $filesToWatch = [],
|
||||
) {}
|
||||
}
|
||||
16
vendor/cuyz/valinor/src/Cache/Exception/CacheDirectoryNotWritable.php
vendored
Normal file
16
vendor/cuyz/valinor/src/Cache/Exception/CacheDirectoryNotWritable.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/** @internal */
|
||||
final class CacheDirectoryNotWritable extends RuntimeException
|
||||
{
|
||||
public function __construct(string $directory)
|
||||
{
|
||||
parent::__construct("Provided directory `$directory` is not writable.");
|
||||
}
|
||||
}
|
||||
16
vendor/cuyz/valinor/src/Cache/Exception/CompiledPhpCacheFileNotWritten.php
vendored
Normal file
16
vendor/cuyz/valinor/src/Cache/Exception/CompiledPhpCacheFileNotWritten.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/** @internal */
|
||||
final class CompiledPhpCacheFileNotWritten extends RuntimeException
|
||||
{
|
||||
public function __construct(string $file)
|
||||
{
|
||||
parent::__construct("File `$file` could not be written.");
|
||||
}
|
||||
}
|
||||
16
vendor/cuyz/valinor/src/Cache/Exception/CorruptedCompiledPhpCacheFile.php
vendored
Normal file
16
vendor/cuyz/valinor/src/Cache/Exception/CorruptedCompiledPhpCacheFile.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/** @internal */
|
||||
final class CorruptedCompiledPhpCacheFile extends RuntimeException
|
||||
{
|
||||
public function __construct(string $filename)
|
||||
{
|
||||
parent::__construct("Compiled php cache file `$filename` has corrupted value.");
|
||||
}
|
||||
}
|
||||
21
vendor/cuyz/valinor/src/Cache/Exception/InvalidSignatureToWarmup.php
vendored
Normal file
21
vendor/cuyz/valinor/src/Cache/Exception/InvalidSignatureToWarmup.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache\Exception;
|
||||
|
||||
use CuyZ\Valinor\Type\Types\UnresolvableType;
|
||||
use RuntimeException;
|
||||
|
||||
use function lcfirst;
|
||||
|
||||
/** @internal */
|
||||
final class InvalidSignatureToWarmup extends RuntimeException
|
||||
{
|
||||
public function __construct(UnresolvableType $unresolvableType)
|
||||
{
|
||||
parent::__construct(
|
||||
"Cannot warm up invalid signature `{$unresolvableType->toString()}`: " . lcfirst($unresolvableType->message()),
|
||||
);
|
||||
}
|
||||
}
|
||||
120
vendor/cuyz/valinor/src/Cache/FileSystemCache.php
vendored
Normal file
120
vendor/cuyz/valinor/src/Cache/FileSystemCache.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache;
|
||||
|
||||
use CuyZ\Valinor\Cache\Exception\CacheDirectoryNotWritable;
|
||||
use CuyZ\Valinor\Cache\Exception\CompiledPhpCacheFileNotWritten;
|
||||
use CuyZ\Valinor\Cache\Exception\CorruptedCompiledPhpCacheFile;
|
||||
use Error;
|
||||
|
||||
use FilesystemIterator;
|
||||
|
||||
use function bin2hex;
|
||||
use function file_exists;
|
||||
use function file_put_contents;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function random_bytes;
|
||||
use function rename;
|
||||
use function rmdir;
|
||||
use function str_contains;
|
||||
use function umask;
|
||||
use function unlink;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*
|
||||
* @template EntryType
|
||||
* @implements Cache<EntryType>
|
||||
*/
|
||||
final class FileSystemCache implements Cache
|
||||
{
|
||||
private const GENERATED_MESSAGE = 'Generated by ' . self::class;
|
||||
|
||||
public function __construct(
|
||||
private string $cacheDir,
|
||||
) {}
|
||||
|
||||
/** @internal */
|
||||
public function get(string $key, mixed ...$arguments): mixed
|
||||
{
|
||||
$filename = $this->cacheDir . DIRECTORY_SEPARATOR . $key . '.php';
|
||||
|
||||
if (! file_exists($filename)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (require $filename)(...$arguments); // @phpstan-ignore callable.nonCallable
|
||||
} catch (Error) {
|
||||
throw new CorruptedCompiledPhpCacheFile($filename);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function set(string $key, CacheEntry $entry): void
|
||||
{
|
||||
$tmpDir = $this->cacheDir . DIRECTORY_SEPARATOR . '.valinor.tmp';
|
||||
$filename = $this->cacheDir . DIRECTORY_SEPARATOR . $key . '.php';
|
||||
|
||||
if (! is_dir($tmpDir) && ! @mkdir($tmpDir, 0777, true)) {
|
||||
throw new CacheDirectoryNotWritable($this->cacheDir);
|
||||
}
|
||||
|
||||
/** @infection-ignore-all */
|
||||
$tmpFilename = $tmpDir . DIRECTORY_SEPARATOR . bin2hex(random_bytes(16));
|
||||
|
||||
try {
|
||||
$code = '<?php // ' . self::GENERATED_MESSAGE . PHP_EOL . "return $entry->code;" . PHP_EOL;
|
||||
|
||||
if (! @file_put_contents($tmpFilename, $code)) {
|
||||
throw new CompiledPhpCacheFileNotWritten($tmpFilename);
|
||||
}
|
||||
|
||||
if (! @rename($tmpFilename, $filename)) {
|
||||
throw new CompiledPhpCacheFileNotWritten($filename);
|
||||
}
|
||||
|
||||
@chmod($filename, 0666 & ~umask());
|
||||
} finally {
|
||||
@unlink($tmpFilename);
|
||||
}
|
||||
}
|
||||
|
||||
public function clear(): void
|
||||
{
|
||||
if (! is_dir($this->cacheDir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$shouldDeleteRootDir = true;
|
||||
|
||||
/** @var FilesystemIterator $file */
|
||||
foreach (new FilesystemIterator($this->cacheDir) as $file) {
|
||||
if ($file->getFilename() === '.valinor.tmp') {
|
||||
@rmdir($file->getPathname());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $file->isFile()) {
|
||||
$shouldDeleteRootDir = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
$line = $file->openFile()->getCurrentLine();
|
||||
|
||||
if (! $line || ! str_contains($line, self::GENERATED_MESSAGE)) {
|
||||
$shouldDeleteRootDir = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
@unlink($file->getPathname());
|
||||
}
|
||||
|
||||
if ($shouldDeleteRootDir) {
|
||||
@rmdir($this->cacheDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
90
vendor/cuyz/valinor/src/Cache/FileWatchingCache.php
vendored
Normal file
90
vendor/cuyz/valinor/src/Cache/FileWatchingCache.php
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache;
|
||||
|
||||
use function file_exists;
|
||||
use function filemtime;
|
||||
use function var_export;
|
||||
|
||||
/**
|
||||
* This cache implementation will watch the files of the application and
|
||||
* invalidate cache entries when a PHP file is modified — preventing the library
|
||||
* not behaving as expected when the signature of a property or a method
|
||||
* changes.
|
||||
*
|
||||
* This is especially useful when the application runs in a development
|
||||
* environment, where source files are often modified by developers.
|
||||
*
|
||||
* It should decorate the original cache implementation and should be given to
|
||||
* the mapper builder: @see \CuyZ\Valinor\MapperBuilder::withCache
|
||||
*
|
||||
* @api
|
||||
*
|
||||
* @template EntryType
|
||||
* @implements Cache<EntryType>
|
||||
*/
|
||||
final class FileWatchingCache implements Cache
|
||||
{
|
||||
/** @var array<string, array<string, int>> */
|
||||
private array $timestamps = [];
|
||||
|
||||
public function __construct(
|
||||
/** @var Cache<EntryType> */
|
||||
private Cache $delegate,
|
||||
) {}
|
||||
|
||||
/** @internal */
|
||||
public function get(string $key, mixed ...$arguments): mixed
|
||||
{
|
||||
$this->timestamps[$key] ??= $this->delegate->get("$key.timestamps"); // @phpstan-ignore assign.propertyType
|
||||
|
||||
if ($this->timestamps[$key] === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
assert(is_array($this->timestamps[$key]));
|
||||
|
||||
foreach ($this->timestamps[$key] as $fileName => $timestamp) {
|
||||
if (! file_exists($fileName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (filemtime($fileName) !== $timestamp) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->delegate->get($key, ...$arguments);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public function set(string $key, CacheEntry $entry): void
|
||||
{
|
||||
$this->delegate->set($key, $entry);
|
||||
|
||||
$this->timestamps[$key] = [];
|
||||
|
||||
foreach ($entry->filesToWatch as $fileName) {
|
||||
$time = @filemtime($fileName);
|
||||
|
||||
if (false === $time) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->timestamps[$key][$fileName] = $time;
|
||||
}
|
||||
|
||||
$code = 'fn () => ' . var_export($this->timestamps[$key], true);
|
||||
|
||||
$this->delegate->set("$key.timestamps", new CacheEntry($code));
|
||||
}
|
||||
|
||||
public function clear(): void
|
||||
{
|
||||
$this->timestamps = [];
|
||||
|
||||
$this->delegate->clear();
|
||||
}
|
||||
}
|
||||
57
vendor/cuyz/valinor/src/Cache/KeySanitizerCache.php
vendored
Normal file
57
vendor/cuyz/valinor/src/Cache/KeySanitizerCache.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache;
|
||||
|
||||
use CuyZ\Valinor\Library\Settings;
|
||||
use CuyZ\Valinor\Utility\Package;
|
||||
|
||||
use function hash;
|
||||
use function strstr;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @template EntryType
|
||||
* @implements Cache<EntryType>
|
||||
*/
|
||||
final class KeySanitizerCache implements Cache
|
||||
{
|
||||
private static string $version;
|
||||
|
||||
public function __construct(
|
||||
/** @var Cache<EntryType> */
|
||||
private Cache $delegate,
|
||||
private Settings $settings,
|
||||
) {}
|
||||
|
||||
public function get(string $key, mixed ...$arguments): mixed
|
||||
{
|
||||
return $this->delegate->get($this->sanitize($key), ...$arguments);
|
||||
}
|
||||
|
||||
public function set(string $key, CacheEntry $entry): void
|
||||
{
|
||||
$this->delegate->set($this->sanitize($key), $entry);
|
||||
}
|
||||
|
||||
public function clear(): void
|
||||
{
|
||||
$this->delegate->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
private function sanitize(string $key): string
|
||||
{
|
||||
// @infection-ignore-all
|
||||
self::$version ??= PHP_VERSION . '/' . Package::version();
|
||||
|
||||
$firstPart = strstr($key, "\0", before_needle: true);
|
||||
|
||||
// @infection-ignore-all
|
||||
return $firstPart . hash('xxh128', $key . $this->settings->hash() . self::$version);
|
||||
}
|
||||
}
|
||||
39
vendor/cuyz/valinor/src/Cache/RuntimeCache.php
vendored
Normal file
39
vendor/cuyz/valinor/src/Cache/RuntimeCache.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @template EntryType
|
||||
* @implements Cache<EntryType>
|
||||
*/
|
||||
final class RuntimeCache implements Cache
|
||||
{
|
||||
/** @var array<string, EntryType|null> */
|
||||
private array $entries = [];
|
||||
|
||||
public function __construct(
|
||||
/** @var Cache<EntryType> */
|
||||
private Cache $delegate,
|
||||
) {}
|
||||
|
||||
public function get(string $key, mixed ...$arguments): mixed
|
||||
{
|
||||
return $this->entries[$key] ??= $this->delegate->get($key, ...$arguments);
|
||||
}
|
||||
|
||||
public function set(string $key, CacheEntry $entry): void
|
||||
{
|
||||
$this->delegate->set($key, $entry);
|
||||
}
|
||||
|
||||
public function clear(): void
|
||||
{
|
||||
$this->entries = [];
|
||||
|
||||
$this->delegate->clear();
|
||||
}
|
||||
}
|
||||
118
vendor/cuyz/valinor/src/Cache/TypeFilesWatcher.php
vendored
Normal file
118
vendor/cuyz/valinor/src/Cache/TypeFilesWatcher.php
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache;
|
||||
|
||||
use Closure;
|
||||
use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository;
|
||||
use CuyZ\Valinor\Library\Settings;
|
||||
use CuyZ\Valinor\Type\ObjectType;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Utility\Reflection\Reflection;
|
||||
use CuyZ\Valinor\Utility\TypeHelper;
|
||||
use ReflectionFunction;
|
||||
|
||||
use function array_filter;
|
||||
use function array_unique;
|
||||
use function array_values;
|
||||
|
||||
/** @internal */
|
||||
final class TypeFilesWatcher
|
||||
{
|
||||
public function __construct(
|
||||
private Settings $settings,
|
||||
private ClassDefinitionRepository $classDefinitionRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* This method returns a list of files in which are declared all types that
|
||||
* compose the given type. If the given type is composed of other types,
|
||||
* they are recursively resolved as well. If the type is a class, all
|
||||
* properties are also resolved.
|
||||
*
|
||||
* In addition, all callable that were given to the global settings are
|
||||
* checked, and their file names are added to the list.
|
||||
*
|
||||
* This file list can then be used by the `FileWatchingCache` to detect
|
||||
* changes to these files and invalidate the cache entries if needed.
|
||||
*
|
||||
* Example of returned value:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* // An entity representing a user
|
||||
* '/root/path/src/Domain/User/User.php',
|
||||
*
|
||||
* // The user has an `$email` property and a `$phoneNumber` property
|
||||
* '/root/path/src/Domain/Shared/Email.php',
|
||||
* '/root/path/src/Domain/Shared/PhoneNumber.php',
|
||||
*
|
||||
* // The settings contain a custom constructor defined in a file
|
||||
* '/root/path/src/Infrastructure/Mapper/CustomConstructor.php',
|
||||
*
|
||||
* // The settings contain a custom exception filter
|
||||
* '/root/path/src/Infrastructure/Mapper/CustomExceptionFilter.php',
|
||||
*
|
||||
* // And maybe more…
|
||||
* ];
|
||||
* ```
|
||||
*
|
||||
* @return list<non-empty-string>
|
||||
*/
|
||||
public function for(Type $type): array
|
||||
{
|
||||
// Merging the files bound to settings and the files bound to the type
|
||||
$files = [
|
||||
...array_map(
|
||||
fn (callable $callable) => (new ReflectionFunction(Closure::fromCallable($callable)))->getFileName(),
|
||||
$this->settings->callables(),
|
||||
),
|
||||
...$this->filesToWatch($type),
|
||||
];
|
||||
|
||||
// Removing the duplicates
|
||||
$files = array_unique($files);
|
||||
|
||||
// Filtering the empty/invalid file names
|
||||
$files = array_filter($files, fn ($value) => is_string($value));
|
||||
|
||||
/** @var list<non-empty-string> */
|
||||
return array_values($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<non-empty-string> $files
|
||||
* @return array<non-empty-string>
|
||||
*/
|
||||
private function filesToWatch(Type $type, array $files = []): array
|
||||
{
|
||||
if (isset($files[$type->toString()])) {
|
||||
// Prevents infinite loop in case of circular references
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach (TypeHelper::traverseRecursively($type) as $subType) {
|
||||
$files = [...$files, ...$this->filesToWatch($subType, $files)];
|
||||
}
|
||||
|
||||
if ($type instanceof ObjectType) {
|
||||
$fileName = Reflection::class($type->className())->getFileName();
|
||||
|
||||
if (! $fileName) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$files[$type->toString()] = $fileName;
|
||||
|
||||
$class = $this->classDefinitionRepository->for($type);
|
||||
|
||||
foreach ($class->properties as $property) {
|
||||
$files = [...$files, ...$this->filesToWatch($property->type, $files)];
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
}
|
||||
95
vendor/cuyz/valinor/src/Cache/Warmup/RecursiveCacheWarmupService.php
vendored
Normal file
95
vendor/cuyz/valinor/src/Cache/Warmup/RecursiveCacheWarmupService.php
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Cache\Warmup;
|
||||
|
||||
use CuyZ\Valinor\Cache\Exception\InvalidSignatureToWarmup;
|
||||
use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository;
|
||||
use CuyZ\Valinor\Mapper\Object\Factory\ObjectBuilderFactory;
|
||||
use CuyZ\Valinor\Mapper\Tree\Builder\InterfaceInferringContainer;
|
||||
use CuyZ\Valinor\Type\ClassType;
|
||||
use CuyZ\Valinor\Type\Parser\TypeParser;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\InterfaceType;
|
||||
use CuyZ\Valinor\Type\Types\UnresolvableType;
|
||||
use CuyZ\Valinor\Utility\TypeHelper;
|
||||
|
||||
use function in_array;
|
||||
|
||||
/** @internal */
|
||||
final class RecursiveCacheWarmupService
|
||||
{
|
||||
/** @var list<class-string> */
|
||||
private array $classesWarmedUp = [];
|
||||
|
||||
public function __construct(
|
||||
private TypeParser $parser,
|
||||
private InterfaceInferringContainer $interfaceInferringContainer,
|
||||
private ClassDefinitionRepository $classDefinitionRepository,
|
||||
private ObjectBuilderFactory $objectBuilderFactory
|
||||
) {}
|
||||
|
||||
public function warmup(string ...$signatures): void
|
||||
{
|
||||
foreach ($signatures as $signature) {
|
||||
$type = $this->parser->parse($signature);
|
||||
|
||||
if ($type instanceof UnresolvableType) {
|
||||
throw new InvalidSignatureToWarmup($type);
|
||||
}
|
||||
|
||||
$this->warmupType($type);
|
||||
}
|
||||
}
|
||||
|
||||
private function warmupType(Type $type): void
|
||||
{
|
||||
if ($type instanceof InterfaceType) {
|
||||
$this->warmupInterfaceType($type);
|
||||
}
|
||||
|
||||
if ($type instanceof ClassType) {
|
||||
$this->warmupClassType($type);
|
||||
}
|
||||
|
||||
foreach (TypeHelper::traverseRecursively($type) as $subType) {
|
||||
$this->warmupType($subType);
|
||||
}
|
||||
}
|
||||
|
||||
private function warmupInterfaceType(InterfaceType $type): void
|
||||
{
|
||||
$interfaceName = $type->className();
|
||||
|
||||
if (! $this->interfaceInferringContainer->has($interfaceName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$function = $this->interfaceInferringContainer->inferFunctionFor($interfaceName);
|
||||
|
||||
$this->warmupType($function->returnType);
|
||||
|
||||
foreach ($function->parameters as $parameter) {
|
||||
$this->warmupType($parameter->type);
|
||||
}
|
||||
}
|
||||
|
||||
private function warmupClassType(ClassType $type): void
|
||||
{
|
||||
if (in_array($type->className(), $this->classesWarmedUp, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->classesWarmedUp[] = $type->className();
|
||||
|
||||
$classDefinition = $this->classDefinitionRepository->for($type);
|
||||
$objectBuilders = $this->objectBuilderFactory->for($classDefinition);
|
||||
|
||||
foreach ($objectBuilders as $builder) {
|
||||
foreach ($builder->describeArguments() as $argument) {
|
||||
$this->warmupType($argument->type());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
vendor/cuyz/valinor/src/Compiler/Compiler.php
vendored
Normal file
60
vendor/cuyz/valinor/src/Compiler/Compiler.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler;
|
||||
|
||||
use function str_repeat;
|
||||
use function str_replace;
|
||||
|
||||
/** @internal */
|
||||
final class Compiler
|
||||
{
|
||||
private string $code = '';
|
||||
|
||||
/** @var non-negative-int */
|
||||
private int $indentation = 0;
|
||||
|
||||
public function compile(Node ...$nodes): self
|
||||
{
|
||||
$compiler = $this;
|
||||
|
||||
while ($current = array_shift($nodes)) {
|
||||
$compiler = $current->compile($compiler);
|
||||
|
||||
if ($nodes !== []) {
|
||||
$compiler = $compiler->write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return $compiler;
|
||||
}
|
||||
|
||||
public function sub(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function write(string $code): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->code .= $code;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function indent(): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->indentation++;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function code(): string
|
||||
{
|
||||
$indent = str_repeat(' ', $this->indentation);
|
||||
|
||||
return $indent . str_replace("\n", "\n" . $indent, $this->code);
|
||||
}
|
||||
}
|
||||
44
vendor/cuyz/valinor/src/Compiler/Library/NewAttributeNode.php
vendored
Normal file
44
vendor/cuyz/valinor/src/Compiler/Library/NewAttributeNode.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Library;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
use CuyZ\Valinor\Definition\AttributeDefinition;
|
||||
use ReflectionClass;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function array_map;
|
||||
|
||||
/** @internal */
|
||||
final class NewAttributeNode extends Node
|
||||
{
|
||||
public function __construct(private AttributeDefinition $attribute) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
if ($this->attribute->arguments !== null) {
|
||||
return $compiler->compile(
|
||||
Node::newClass(
|
||||
$this->attribute->class->name,
|
||||
...array_map(Node::value(...), $this->attribute->arguments),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// @phpstan-ignore match.unhandled (for now only those two cases can be handled here anyway)
|
||||
$node = match ($this->attribute->reflectionParts[0]) {
|
||||
'class' => Node::newClass(ReflectionClass::class, Node::className($this->attribute->reflectionParts[1])),
|
||||
'property' => Node::newClass(ReflectionProperty::class, Node::className($this->attribute->reflectionParts[1]), Node::value($this->attribute->reflectionParts[2])),
|
||||
};
|
||||
|
||||
return $compiler->compile(
|
||||
$node->wrap()
|
||||
->callMethod('getAttributes')
|
||||
->key(Node::value($this->attribute->attributeIndex))
|
||||
->callMethod('newInstance'),
|
||||
);
|
||||
}
|
||||
}
|
||||
24
vendor/cuyz/valinor/src/Compiler/Library/TypeAcceptNode.php
vendored
Normal file
24
vendor/cuyz/valinor/src/Compiler/Library/TypeAcceptNode.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Library;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Native\ComplianceNode;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
|
||||
/** @internal */
|
||||
final class TypeAcceptNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private ComplianceNode $node,
|
||||
private Type $type,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->compile($this->type->compiledAccept($this->node));
|
||||
}
|
||||
}
|
||||
105
vendor/cuyz/valinor/src/Compiler/Native/AnonymousClassNode.php
vendored
Normal file
105
vendor/cuyz/valinor/src/Compiler/Native/AnonymousClassNode.php
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
use function array_map;
|
||||
use function implode;
|
||||
|
||||
/** @internal */
|
||||
final class AnonymousClassNode extends Node
|
||||
{
|
||||
/** @var array<Node> */
|
||||
private array $arguments = [];
|
||||
|
||||
/** @var array<interface-string> */
|
||||
private array $interfaces = [];
|
||||
|
||||
/** @var array<PropertyDeclarationNode> */
|
||||
private array $properties = [];
|
||||
|
||||
/** @var array<non-empty-string, MethodNode> */
|
||||
private array $methods = [];
|
||||
|
||||
public function withArguments(Node ...$arguments): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->arguments = $arguments;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param interface-string ...$interfaces
|
||||
*/
|
||||
public function implements(string ...$interfaces): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->interfaces = $interfaces;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function withProperties(PropertyDeclarationNode ...$properties): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->properties = $properties;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function withMethods(MethodNode ...$methods): self
|
||||
{
|
||||
$self = clone $this;
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$self->methods[$method->name()] = $method;
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function hasMethod(string $name): bool
|
||||
{
|
||||
return isset($this->methods[$name]);
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$arguments = implode(', ', array_map(
|
||||
fn (Node $argument) => $compiler->sub()->compile($argument)->code(),
|
||||
$this->arguments,
|
||||
));
|
||||
|
||||
$compiler = $compiler->write("new class ($arguments)");
|
||||
|
||||
if ($this->interfaces !== []) {
|
||||
$compiler = $compiler->write(
|
||||
' implements ' . implode(', ', $this->interfaces),
|
||||
);
|
||||
}
|
||||
|
||||
$body = [
|
||||
...array_map(
|
||||
fn (PropertyDeclarationNode $property) => $compiler->sub()->indent()->compile($property)->code(),
|
||||
$this->properties,
|
||||
),
|
||||
...array_map(
|
||||
fn (MethodNode $method) => $compiler->sub()->indent()->compile($method)->code(),
|
||||
$this->methods,
|
||||
),
|
||||
];
|
||||
|
||||
$compiler = $compiler->write(' {');
|
||||
|
||||
if ($body !== []) {
|
||||
$compiler = $compiler->write(PHP_EOL . implode(PHP_EOL . PHP_EOL, $body) . PHP_EOL);
|
||||
}
|
||||
|
||||
return $compiler->write('}');
|
||||
}
|
||||
}
|
||||
26
vendor/cuyz/valinor/src/Compiler/Native/ArrayKeyAccessNode.php
vendored
Normal file
26
vendor/cuyz/valinor/src/Compiler/Native/ArrayKeyAccessNode.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ArrayKeyAccessNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
private Node $key,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$key = $compiler->sub()->compile($this->key)->code();
|
||||
|
||||
return $compiler
|
||||
->compile($this->node)
|
||||
->write('[' . $key . ']');
|
||||
}
|
||||
}
|
||||
36
vendor/cuyz/valinor/src/Compiler/Native/ArrayNode.php
vendored
Normal file
36
vendor/cuyz/valinor/src/Compiler/Native/ArrayNode.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
use function var_export;
|
||||
|
||||
/** @internal */
|
||||
final class ArrayNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
/** @var array<Node> */
|
||||
private array $assignments
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
if ($this->assignments === []) {
|
||||
return $compiler->write('[]');
|
||||
}
|
||||
|
||||
$sub = [];
|
||||
|
||||
foreach ($this->assignments as $key => $assignment) {
|
||||
$sub[] = ' ' . var_export($key, true) . ' => ' . $compiler->sub()->compile($assignment)->code() . ",";
|
||||
}
|
||||
|
||||
$sub = implode("\n", $sub);
|
||||
|
||||
return $compiler->write("[\n$sub\n]");
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/AssignNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/AssignNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class AssignNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
private Node $value,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->node)
|
||||
->write(' = ')
|
||||
->compile($this->value);
|
||||
}
|
||||
}
|
||||
39
vendor/cuyz/valinor/src/Compiler/Native/CallNode.php
vendored
Normal file
39
vendor/cuyz/valinor/src/Compiler/Native/CallNode.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
use function array_map;
|
||||
use function implode;
|
||||
|
||||
/** @internal */
|
||||
final class CallNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
/** @var array<Node> */
|
||||
private array $arguments = [],
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$compiler = $compiler
|
||||
->compile($this->node)
|
||||
->write('(');
|
||||
|
||||
if ($this->arguments !== []) {
|
||||
$arguments = array_map(
|
||||
fn (Node $argument) => $compiler->sub()->compile($argument)->code(),
|
||||
$this->arguments,
|
||||
);
|
||||
|
||||
$compiler = $compiler->write(implode(', ', $arguments));
|
||||
}
|
||||
|
||||
return $compiler->write(')');
|
||||
}
|
||||
}
|
||||
29
vendor/cuyz/valinor/src/Compiler/Native/CastNode.php
vendored
Normal file
29
vendor/cuyz/valinor/src/Compiler/Native/CastNode.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class CastNode extends Node
|
||||
{
|
||||
private function __construct(
|
||||
private string $type,
|
||||
private Node $node,
|
||||
) {}
|
||||
|
||||
public static function toArray(Node $node): self
|
||||
{
|
||||
return new self('array', $node);
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->write('(' . $this->type . ')')
|
||||
->compile($this->node);
|
||||
}
|
||||
}
|
||||
22
vendor/cuyz/valinor/src/Compiler/Native/ClassNameNode.php
vendored
Normal file
22
vendor/cuyz/valinor/src/Compiler/Native/ClassNameNode.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ClassNameNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
/** @var class-string */
|
||||
private string $className,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->write($this->className . '::class');
|
||||
}
|
||||
}
|
||||
33
vendor/cuyz/valinor/src/Compiler/Native/ClassNode.php
vendored
Normal file
33
vendor/cuyz/valinor/src/Compiler/Native/ClassNode.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ClassNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
/** @var class-string */
|
||||
private string $name,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $method
|
||||
* @param array<Node> $arguments
|
||||
*/
|
||||
public function callStaticMethod(
|
||||
string $method,
|
||||
array $arguments = [],
|
||||
): Node {
|
||||
return new StaticMethodCallNode($this, $method, $arguments);
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->write($this->name);
|
||||
}
|
||||
}
|
||||
23
vendor/cuyz/valinor/src/Compiler/Native/CloneNode.php
vendored
Normal file
23
vendor/cuyz/valinor/src/Compiler/Native/CloneNode.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class CloneNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->write('clone ')
|
||||
->compile($this->node);
|
||||
}
|
||||
}
|
||||
53
vendor/cuyz/valinor/src/Compiler/Native/ClosureNode.php
vendored
Normal file
53
vendor/cuyz/valinor/src/Compiler/Native/ClosureNode.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
use function array_map;
|
||||
use function implode;
|
||||
|
||||
/** @internal */
|
||||
final class ClosureNode extends Node
|
||||
{
|
||||
/** @var list<string> */
|
||||
private array $use = [];
|
||||
|
||||
/** @var array<Node> */
|
||||
private array $nodes;
|
||||
|
||||
public function __construct(Node ...$nodes)
|
||||
{
|
||||
$this->nodes = $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @no-named-arguments
|
||||
* @param non-empty-string ...$names
|
||||
*/
|
||||
public function uses(string ...$names): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->use = array_map(fn (string $name) => '$' . $name, $names);
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$use = $this->use !== [] ? ' use (' . implode(', ', $this->use) . ')' : '';
|
||||
|
||||
$body = $compiler->sub()->indent()->compile(...$this->nodes)->code();
|
||||
|
||||
$code = <<<PHP
|
||||
function ()$use {
|
||||
$body
|
||||
}
|
||||
PHP;
|
||||
|
||||
return $compiler->write($code);
|
||||
}
|
||||
}
|
||||
118
vendor/cuyz/valinor/src/Compiler/Native/ComplianceNode.php
vendored
Normal file
118
vendor/cuyz/valinor/src/Compiler/Native/ComplianceNode.php
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ComplianceNode extends Node
|
||||
{
|
||||
public function __construct(private Node $node) {}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $value
|
||||
*/
|
||||
public function access(string $value): self
|
||||
{
|
||||
return new self(new VariableAccessNode($this, $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @no-named-arguments
|
||||
*/
|
||||
public function and(Node ...$nodes): self
|
||||
{
|
||||
return new self(new LogicalAndNode($this, ...$nodes));
|
||||
}
|
||||
|
||||
public function castToArray(): self
|
||||
{
|
||||
return new self(CastNode::toArray($this));
|
||||
}
|
||||
|
||||
public function clone(): self
|
||||
{
|
||||
return new self(new CloneNode($this));
|
||||
}
|
||||
|
||||
public function key(Node $key): self
|
||||
{
|
||||
return new self(new ArrayKeyAccessNode($this, $key));
|
||||
}
|
||||
|
||||
public function assign(Node $value): self
|
||||
{
|
||||
return new self(new AssignNode($this, $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Node> $arguments
|
||||
*/
|
||||
public function call(array $arguments = []): self
|
||||
{
|
||||
return new self(new CallNode($this, $arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $method
|
||||
* @param array<Node> $arguments
|
||||
*/
|
||||
public function callMethod(string $method, array $arguments = []): self
|
||||
{
|
||||
return new self(new MethodCallNode($this, $method, $arguments));
|
||||
}
|
||||
|
||||
public function different(Node $right): self
|
||||
{
|
||||
return new self(new DifferentNode($this, $right));
|
||||
}
|
||||
|
||||
public function equals(Node $right): self
|
||||
{
|
||||
return new self(new EqualsNode($this, $right));
|
||||
}
|
||||
|
||||
/**
|
||||
* @no-named-arguments
|
||||
*/
|
||||
public function or(Node ...$nodes): self
|
||||
{
|
||||
return new self(new LogicalOrNode($this, ...$nodes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*/
|
||||
public function instanceOf(string $className): self
|
||||
{
|
||||
return new self(new InstanceOfNode($this, $className));
|
||||
}
|
||||
|
||||
public function isLessThan(Node $right): self
|
||||
{
|
||||
return new self(new LessThanNode($this, $right));
|
||||
}
|
||||
|
||||
public function isLessOrEqualsTo(Node $right): self
|
||||
{
|
||||
return new self(new LessOrEqualsToNode($this, $right));
|
||||
}
|
||||
|
||||
public function isGreaterThan(Node $right): self
|
||||
{
|
||||
return new self(new GreaterThanNode($this, $right));
|
||||
}
|
||||
|
||||
public function isGreaterOrEqualsTo(Node $right): self
|
||||
{
|
||||
return new self(new GreaterOrEqualsToNode($this, $right));
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->compile($this->node);
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/DifferentNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/DifferentNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class DifferentNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $left,
|
||||
private Node $right,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->left)
|
||||
->write(' !== ')
|
||||
->compile($this->right);
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/EqualsNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/EqualsNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class EqualsNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $left,
|
||||
private Node $right,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->left)
|
||||
->write(' === ')
|
||||
->compile($this->right);
|
||||
}
|
||||
}
|
||||
19
vendor/cuyz/valinor/src/Compiler/Native/ExpressionNode.php
vendored
Normal file
19
vendor/cuyz/valinor/src/Compiler/Native/ExpressionNode.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ExpressionNode extends Node
|
||||
{
|
||||
public function __construct(private Node $node) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->write($compiler->sub()->compile($this->node)->code() . ';');
|
||||
}
|
||||
}
|
||||
35
vendor/cuyz/valinor/src/Compiler/Native/ForEachNode.php
vendored
Normal file
35
vendor/cuyz/valinor/src/Compiler/Native/ForEachNode.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ForEachNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $value,
|
||||
/** @var non-empty-string */
|
||||
private string $key,
|
||||
/** @var non-empty-string */
|
||||
private string $item,
|
||||
private Node $body,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$value = $compiler->sub()->compile($this->value)->code();
|
||||
$body = $compiler->sub()->indent()->compile($this->body)->code();
|
||||
|
||||
return $compiler->write(
|
||||
<<<PHP
|
||||
foreach ($value as $$this->key => $$this->item) {
|
||||
$body
|
||||
}
|
||||
PHP
|
||||
);
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/FunctionCallNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/FunctionCallNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class FunctionCallNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
private string $name,
|
||||
/** @var array<Node> */
|
||||
private array $arguments = [],
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile(new CallNode(new FunctionNameNode($this->name), $this->arguments));
|
||||
}
|
||||
}
|
||||
32
vendor/cuyz/valinor/src/Compiler/Native/FunctionNameNode.php
vendored
Normal file
32
vendor/cuyz/valinor/src/Compiler/Native/FunctionNameNode.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
use function in_array;
|
||||
|
||||
/** @internal */
|
||||
final class FunctionNameNode extends Node
|
||||
{
|
||||
private const RESERVED_FUNCTIONS = [
|
||||
'isset',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
private string $name
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$function = in_array($this->name, self::RESERVED_FUNCTIONS, true)
|
||||
? $this->name
|
||||
: '\\' . $this->name;
|
||||
|
||||
return $compiler->write($function);
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/GreaterOrEqualsToNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/GreaterOrEqualsToNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class GreaterOrEqualsToNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $left,
|
||||
private Node $right,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->left)
|
||||
->write(' >= ')
|
||||
->compile($this->right);
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/GreaterThanNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/GreaterThanNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class GreaterThanNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $left,
|
||||
private Node $right,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->left)
|
||||
->write(' > ')
|
||||
->compile($this->right);
|
||||
}
|
||||
}
|
||||
31
vendor/cuyz/valinor/src/Compiler/Native/IfNode.php
vendored
Normal file
31
vendor/cuyz/valinor/src/Compiler/Native/IfNode.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class IfNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $condition,
|
||||
private Node $body,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$condition = $compiler->sub()->compile($this->condition)->code();
|
||||
$body = $compiler->sub()->indent()->compile($this->body)->code();
|
||||
|
||||
return $compiler->write(
|
||||
<<<PHP
|
||||
if ($condition) {
|
||||
$body
|
||||
}
|
||||
PHP,
|
||||
);
|
||||
}
|
||||
}
|
||||
28
vendor/cuyz/valinor/src/Compiler/Native/InstanceOfNode.php
vendored
Normal file
28
vendor/cuyz/valinor/src/Compiler/Native/InstanceOfNode.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class InstanceOfNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
/** @var class-string */
|
||||
private string $className,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$className = $this->className;
|
||||
|
||||
return $compiler
|
||||
->compile($this->node)
|
||||
->write(' instanceof ')
|
||||
->write($className);
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/LessOrEqualsToNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/LessOrEqualsToNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class LessOrEqualsToNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $left,
|
||||
private Node $right,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->left)
|
||||
->write(' <= ')
|
||||
->compile($this->right);
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/LessThanNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/LessThanNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class LessThanNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $left,
|
||||
private Node $right,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->left)
|
||||
->write(' < ')
|
||||
->compile($this->right);
|
||||
}
|
||||
}
|
||||
38
vendor/cuyz/valinor/src/Compiler/Native/LogicalAndNode.php
vendored
Normal file
38
vendor/cuyz/valinor/src/Compiler/Native/LogicalAndNode.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class LogicalAndNode extends Node
|
||||
{
|
||||
/** @var list<Node> */
|
||||
private array $nodes;
|
||||
|
||||
/**
|
||||
* @no-named-arguments
|
||||
*/
|
||||
public function __construct(Node ...$nodes)
|
||||
{
|
||||
$this->nodes = $nodes;
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$nodes = $this->nodes;
|
||||
|
||||
while ($node = array_shift($nodes)) {
|
||||
$compiler = $compiler->compile($node);
|
||||
|
||||
if ($nodes !== []) {
|
||||
$compiler = $compiler->write(' && ');
|
||||
}
|
||||
}
|
||||
|
||||
return $compiler;
|
||||
}
|
||||
}
|
||||
38
vendor/cuyz/valinor/src/Compiler/Native/LogicalOrNode.php
vendored
Normal file
38
vendor/cuyz/valinor/src/Compiler/Native/LogicalOrNode.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class LogicalOrNode extends Node
|
||||
{
|
||||
/** @var list<Node> */
|
||||
private array $nodes;
|
||||
|
||||
/**
|
||||
* @no-named-arguments
|
||||
*/
|
||||
public function __construct(Node ...$nodes)
|
||||
{
|
||||
$this->nodes = $nodes;
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$nodes = $this->nodes;
|
||||
|
||||
while ($node = array_shift($nodes)) {
|
||||
$compiler = $compiler->compile($node);
|
||||
|
||||
if ($nodes !== []) {
|
||||
$compiler = $compiler->write(' || ');
|
||||
}
|
||||
}
|
||||
|
||||
return $compiler;
|
||||
}
|
||||
}
|
||||
65
vendor/cuyz/valinor/src/Compiler/Native/MatchNode.php
vendored
Normal file
65
vendor/cuyz/valinor/src/Compiler/Native/MatchNode.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class MatchNode extends Node
|
||||
{
|
||||
/** @var list<array{condition: Node, body: Node}> */
|
||||
private array $cases = [];
|
||||
|
||||
private Node $defaultCase;
|
||||
|
||||
public function __construct(private Node $value) {}
|
||||
|
||||
public function withCase(Node $condition, Node $body): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->cases[] = ['condition' => $condition, 'body' => $body];
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function withDefaultCase(Node $defaultCase): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->defaultCase = $defaultCase;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$value = $compiler->sub()->compile($this->value)->code();
|
||||
$body = [];
|
||||
|
||||
foreach ($this->cases as $case) {
|
||||
$body[] = $compiler->sub()->indent()->compile($case['condition'])->code() .
|
||||
' => ' .
|
||||
$compiler->sub()->compile($case['body'])->code() .
|
||||
',';
|
||||
}
|
||||
|
||||
if (isset($this->defaultCase)) {
|
||||
$body[] = $compiler->sub()->indent()->write('default')->code() .
|
||||
' => ' .
|
||||
$compiler->sub()->compile($this->defaultCase)->code() .
|
||||
',';
|
||||
}
|
||||
|
||||
$body = implode("\n", $body);
|
||||
|
||||
return $compiler->write(
|
||||
<<<PHP
|
||||
match ($value) {
|
||||
$body
|
||||
}
|
||||
PHP,
|
||||
);
|
||||
}
|
||||
}
|
||||
27
vendor/cuyz/valinor/src/Compiler/Native/MethodCallNode.php
vendored
Normal file
27
vendor/cuyz/valinor/src/Compiler/Native/MethodCallNode.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class MethodCallNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
/** @var non-empty-string */
|
||||
private string $method,
|
||||
/** @var array<Node> */
|
||||
private array $arguments = [],
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->compile(
|
||||
new CallNode(new VariableAccessNode($this->node, $this->method), $this->arguments)
|
||||
);
|
||||
}
|
||||
}
|
||||
109
vendor/cuyz/valinor/src/Compiler/Native/MethodNode.php
vendored
Normal file
109
vendor/cuyz/valinor/src/Compiler/Native/MethodNode.php
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
use function array_map;
|
||||
|
||||
/** @internal */
|
||||
final class MethodNode extends Node
|
||||
{
|
||||
/** @var 'public'|'private' */
|
||||
private string $visibility = 'private';
|
||||
|
||||
/** @var non-empty-string */
|
||||
private string $name;
|
||||
|
||||
private string $returnType;
|
||||
|
||||
/** @var array<ParameterDeclarationNode> */
|
||||
private array $parameters = [];
|
||||
|
||||
/** @var array<Node> */
|
||||
private array $nodes = [];
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
*/
|
||||
public function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public static function constructor(): self
|
||||
{
|
||||
return new self('__construct');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function witParameters(ParameterDeclarationNode ...$parameters): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->parameters = $parameters;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param 'public'|'private' $visibility
|
||||
*/
|
||||
public function withVisibility(string $visibility): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->visibility = $visibility;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $type
|
||||
*/
|
||||
public function withReturnType(string $type): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->returnType = $type;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function withBody(Node ...$nodes): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->nodes = $nodes;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$parameters = implode(', ', array_map(
|
||||
fn (ParameterDeclarationNode $parameter) => $compiler->sub()->compile($parameter)->code(),
|
||||
$this->parameters,
|
||||
));
|
||||
|
||||
$compiler = $compiler->write("$this->visibility function $this->name($parameters)");
|
||||
|
||||
if ($this->name !== '__construct') {
|
||||
$compiler = $compiler->write(': ' . ($this->returnType ?? 'void'));
|
||||
}
|
||||
|
||||
if ($this->nodes === []) {
|
||||
return $compiler->write(' {}');
|
||||
}
|
||||
|
||||
$body = $compiler->sub()->indent()->compile(...$this->nodes)->code();
|
||||
|
||||
return $compiler->write(PHP_EOL . '{' . PHP_EOL . $body . PHP_EOL . '}');
|
||||
}
|
||||
}
|
||||
19
vendor/cuyz/valinor/src/Compiler/Native/NegateNode.php
vendored
Normal file
19
vendor/cuyz/valinor/src/Compiler/Native/NegateNode.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class NegateNode extends Node
|
||||
{
|
||||
public function __construct(private Node $node) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->write('! ')->compile($this->node);
|
||||
}
|
||||
}
|
||||
40
vendor/cuyz/valinor/src/Compiler/Native/NewClassNode.php
vendored
Normal file
40
vendor/cuyz/valinor/src/Compiler/Native/NewClassNode.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
use function array_map;
|
||||
|
||||
/** @internal */
|
||||
final class NewClassNode extends Node
|
||||
{
|
||||
/** @var class-string */
|
||||
private string $className;
|
||||
|
||||
/** @var array<Node> */
|
||||
private array $arguments;
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*/
|
||||
public function __construct(string $className, Node ...$arguments)
|
||||
{
|
||||
$this->className = $className;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$arguments = array_map(
|
||||
fn (Node $argument) => $compiler->sub()->compile($argument)->code(),
|
||||
$this->arguments,
|
||||
);
|
||||
$arguments = implode(', ', $arguments);
|
||||
|
||||
return $compiler->write("new {$this->className}($arguments)");
|
||||
}
|
||||
}
|
||||
23
vendor/cuyz/valinor/src/Compiler/Native/ParameterDeclarationNode.php
vendored
Normal file
23
vendor/cuyz/valinor/src/Compiler/Native/ParameterDeclarationNode.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ParameterDeclarationNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
private string $name,
|
||||
private string $type,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->write($this->type . ' $' . $this->name);
|
||||
}
|
||||
}
|
||||
27
vendor/cuyz/valinor/src/Compiler/Native/PhpFileNode.php
vendored
Normal file
27
vendor/cuyz/valinor/src/Compiler/Native/PhpFileNode.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class PhpFileNode extends Node
|
||||
{
|
||||
/** @var array<Node> */
|
||||
private array $nodes;
|
||||
|
||||
public function __construct(Node ...$nodes)
|
||||
{
|
||||
$this->nodes = $nodes;
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->write("<?php\n\ndeclare(strict_types=1);\n\n")
|
||||
->compile(...$this->nodes);
|
||||
}
|
||||
}
|
||||
23
vendor/cuyz/valinor/src/Compiler/Native/PropertyDeclarationNode.php
vendored
Normal file
23
vendor/cuyz/valinor/src/Compiler/Native/PropertyDeclarationNode.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class PropertyDeclarationNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
private string $name,
|
||||
private string $type,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->write('private ' . $this->type . ' $' . $this->name . ';');
|
||||
}
|
||||
}
|
||||
19
vendor/cuyz/valinor/src/Compiler/Native/PropertyNode.php
vendored
Normal file
19
vendor/cuyz/valinor/src/Compiler/Native/PropertyNode.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class PropertyNode extends Node
|
||||
{
|
||||
public function __construct(private string $name) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->write('$this->' . $this->name);
|
||||
}
|
||||
}
|
||||
22
vendor/cuyz/valinor/src/Compiler/Native/ReturnNode.php
vendored
Normal file
22
vendor/cuyz/valinor/src/Compiler/Native/ReturnNode.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ReturnNode extends Node
|
||||
{
|
||||
public function __construct(private ?Node $node = null) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$code = $this->node ? ' ' . $compiler->sub()->compile($this->node)->code() : '';
|
||||
|
||||
return $compiler->write("return$code;");
|
||||
}
|
||||
|
||||
}
|
||||
46
vendor/cuyz/valinor/src/Compiler/Native/ShortClosureNode.php
vendored
Normal file
46
vendor/cuyz/valinor/src/Compiler/Native/ShortClosureNode.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ShortClosureNode extends Node
|
||||
{
|
||||
private Node $returnNode;
|
||||
|
||||
/** @var array<ParameterDeclarationNode> */
|
||||
private array $parameters = [];
|
||||
|
||||
public function __construct(Node $returnNode)
|
||||
{
|
||||
$this->returnNode = $returnNode;
|
||||
}
|
||||
|
||||
public function witParameters(ParameterDeclarationNode ...$parameters): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->parameters = $parameters;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
$parameters = implode(', ', array_map(
|
||||
fn (ParameterDeclarationNode $parameter) => $compiler->sub()->compile($parameter)->code(),
|
||||
$this->parameters,
|
||||
));
|
||||
|
||||
$return = $compiler->sub()->compile($this->returnNode)->code();
|
||||
|
||||
return $compiler->write(
|
||||
<<<PHP
|
||||
fn ($parameters) => $return
|
||||
PHP,
|
||||
);
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/StaticAccessNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/StaticAccessNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class StaticAccessNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $left,
|
||||
/** @var non-empty-string */
|
||||
private string $name,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->left)
|
||||
->write("::$this->name");
|
||||
}
|
||||
}
|
||||
27
vendor/cuyz/valinor/src/Compiler/Native/StaticMethodCallNode.php
vendored
Normal file
27
vendor/cuyz/valinor/src/Compiler/Native/StaticMethodCallNode.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class StaticMethodCallNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
/** @var non-empty-string */
|
||||
private string $method,
|
||||
/** @var array<Node> */
|
||||
private array $arguments = [],
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->compile(
|
||||
new CallNode(new StaticAccessNode($this->node, $this->method), $this->arguments)
|
||||
);
|
||||
}
|
||||
}
|
||||
28
vendor/cuyz/valinor/src/Compiler/Native/TernaryNode.php
vendored
Normal file
28
vendor/cuyz/valinor/src/Compiler/Native/TernaryNode.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class TernaryNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $condition,
|
||||
private Node $ifTrue,
|
||||
private Node $ifFalse,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->condition)
|
||||
->write(' ? ')
|
||||
->compile($this->ifTrue)
|
||||
->write(' : ')
|
||||
->compile($this->ifFalse);
|
||||
}
|
||||
}
|
||||
23
vendor/cuyz/valinor/src/Compiler/Native/ThrowNode.php
vendored
Normal file
23
vendor/cuyz/valinor/src/Compiler/Native/ThrowNode.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class ThrowNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->write('throw ')
|
||||
->compile($this->node);
|
||||
}
|
||||
}
|
||||
49
vendor/cuyz/valinor/src/Compiler/Native/ValueNode.php
vendored
Normal file
49
vendor/cuyz/valinor/src/Compiler/Native/ValueNode.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
use function is_array;
|
||||
use function var_export;
|
||||
|
||||
/** @internal */
|
||||
final class ValueNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
/** @var array<mixed>|bool|float|int|string|null */
|
||||
private array|bool|float|int|string|null $value,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $this->compileValue($this->value, $compiler);
|
||||
}
|
||||
|
||||
private function compileValue(mixed $value, Compiler $compiler): Compiler
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$compiler = $compiler->write('[');
|
||||
|
||||
$i = 0;
|
||||
$numItems = count($value);
|
||||
foreach ($value as $key => $item) {
|
||||
$compiler = $compiler->write(var_export($key, true) . ' => ');
|
||||
$compiler = $this->compileValue($item, $compiler);
|
||||
|
||||
if (++$i !== $numItems) {
|
||||
$compiler = $compiler->write(', ');
|
||||
}
|
||||
}
|
||||
|
||||
$compiler = $compiler->write(']');
|
||||
} else {
|
||||
$compiler = $compiler->write(var_export($value, true));
|
||||
}
|
||||
|
||||
return $compiler;
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Compiler/Native/VariableAccessNode.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Compiler/Native/VariableAccessNode.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class VariableAccessNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $node,
|
||||
/** @var non-empty-string */
|
||||
private string $value
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->compile($this->node)
|
||||
->write('->' . $this->value);
|
||||
}
|
||||
}
|
||||
19
vendor/cuyz/valinor/src/Compiler/Native/VariableNode.php
vendored
Normal file
19
vendor/cuyz/valinor/src/Compiler/Native/VariableNode.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class VariableNode extends Node
|
||||
{
|
||||
public function __construct(private string $name) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler->write('$' . $this->name);
|
||||
}
|
||||
}
|
||||
22
vendor/cuyz/valinor/src/Compiler/Native/WrapNode.php
vendored
Normal file
22
vendor/cuyz/valinor/src/Compiler/Native/WrapNode.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class WrapNode extends Node
|
||||
{
|
||||
public function __construct(private Node $node) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->write('(')
|
||||
->compile($this->node)
|
||||
->write(')');
|
||||
}
|
||||
}
|
||||
26
vendor/cuyz/valinor/src/Compiler/Native/YieldNode.php
vendored
Normal file
26
vendor/cuyz/valinor/src/Compiler/Native/YieldNode.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler\Native;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Compiler;
|
||||
use CuyZ\Valinor\Compiler\Node;
|
||||
|
||||
/** @internal */
|
||||
final class YieldNode extends Node
|
||||
{
|
||||
public function __construct(
|
||||
private Node $key,
|
||||
private Node $value,
|
||||
) {}
|
||||
|
||||
public function compile(Compiler $compiler): Compiler
|
||||
{
|
||||
return $compiler
|
||||
->write('yield ')
|
||||
->compile($this->key)
|
||||
->write(' => ')
|
||||
->compile($this->value);
|
||||
}
|
||||
}
|
||||
212
vendor/cuyz/valinor/src/Compiler/Node.php
vendored
Normal file
212
vendor/cuyz/valinor/src/Compiler/Node.php
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Compiler;
|
||||
|
||||
use CuyZ\Valinor\Compiler\Native\AnonymousClassNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ArrayNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ClassNameNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ClassNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ClosureNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ComplianceNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ExpressionNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ForEachNode;
|
||||
use CuyZ\Valinor\Compiler\Native\FunctionCallNode;
|
||||
use CuyZ\Valinor\Compiler\Native\IfNode;
|
||||
use CuyZ\Valinor\Compiler\Native\LogicalAndNode;
|
||||
use CuyZ\Valinor\Compiler\Native\LogicalOrNode;
|
||||
use CuyZ\Valinor\Compiler\Native\MatchNode;
|
||||
use CuyZ\Valinor\Compiler\Native\MethodNode;
|
||||
use CuyZ\Valinor\Compiler\Native\NegateNode;
|
||||
use CuyZ\Valinor\Compiler\Native\NewClassNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ParameterDeclarationNode;
|
||||
use CuyZ\Valinor\Compiler\Native\PropertyDeclarationNode;
|
||||
use CuyZ\Valinor\Compiler\Native\PropertyNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ReturnNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ShortClosureNode;
|
||||
use CuyZ\Valinor\Compiler\Native\TernaryNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ThrowNode;
|
||||
use CuyZ\Valinor\Compiler\Native\ValueNode;
|
||||
use CuyZ\Valinor\Compiler\Native\VariableNode;
|
||||
use CuyZ\Valinor\Compiler\Native\WrapNode;
|
||||
use CuyZ\Valinor\Compiler\Native\YieldNode;
|
||||
|
||||
/** @internal */
|
||||
abstract class Node
|
||||
{
|
||||
abstract public function compile(Compiler $compiler): Compiler;
|
||||
|
||||
public function asExpression(): ExpressionNode
|
||||
{
|
||||
return new ExpressionNode($this);
|
||||
}
|
||||
|
||||
public function wrap(): ComplianceNode
|
||||
{
|
||||
return new ComplianceNode(new WrapNode($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Node> $assignments
|
||||
*/
|
||||
public static function array(array $assignments = []): ArrayNode
|
||||
{
|
||||
return new ArrayNode($assignments);
|
||||
}
|
||||
|
||||
public static function anonymousClass(): AnonymousClassNode
|
||||
{
|
||||
return new AnonymousClassNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $name
|
||||
*/
|
||||
public static function class(string $name): ClassNode
|
||||
{
|
||||
return new ClassNode($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*/
|
||||
public static function className(string $className): ClassNameNode
|
||||
{
|
||||
return new ClassNameNode($className);
|
||||
}
|
||||
|
||||
public static function closure(Node ...$nodes): ClosureNode
|
||||
{
|
||||
return new ClosureNode(...$nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $key
|
||||
* @param non-empty-string $item
|
||||
*/
|
||||
public static function forEach(Node $value, string $key, string $item, Node $body): ForEachNode
|
||||
{
|
||||
return new ForEachNode($value, $key, $item, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
* @param array<Node> $arguments
|
||||
*/
|
||||
public static function functionCall(string $name, array $arguments = []): ComplianceNode
|
||||
{
|
||||
return new ComplianceNode(new FunctionCallNode($name, $arguments));
|
||||
}
|
||||
|
||||
public static function if(Node $condition, Node $body): IfNode
|
||||
{
|
||||
return new IfNode($condition, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @no-named-arguments
|
||||
*/
|
||||
public static function logicalAnd(Node ...$nodes): ComplianceNode
|
||||
{
|
||||
return new ComplianceNode(new LogicalAndNode(...$nodes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @no-named-arguments
|
||||
*/
|
||||
public static function logicalOr(Node ...$nodes): ComplianceNode
|
||||
{
|
||||
return new ComplianceNode(new LogicalOrNode(...$nodes));
|
||||
}
|
||||
|
||||
public static function match(Node $value): MatchNode
|
||||
{
|
||||
return new MatchNode($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
*/
|
||||
public static function method(string $name): MethodNode
|
||||
{
|
||||
return new MethodNode($name);
|
||||
}
|
||||
|
||||
public static function negate(Node $node): NegateNode
|
||||
{
|
||||
return new NegateNode($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*/
|
||||
public static function newClass(string $className, Node ...$arguments): NewClassNode
|
||||
{
|
||||
return new NewClassNode($className, ...$arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
*/
|
||||
public static function parameterDeclaration(string $name, string $type): ParameterDeclarationNode
|
||||
{
|
||||
return new ParameterDeclarationNode($name, $type);
|
||||
}
|
||||
|
||||
public static function property(string $name): ComplianceNode
|
||||
{
|
||||
return new ComplianceNode(new PropertyNode($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $name
|
||||
*/
|
||||
public static function propertyDeclaration(string $name, string $type): PropertyDeclarationNode
|
||||
{
|
||||
return new PropertyDeclarationNode($name, $type);
|
||||
}
|
||||
|
||||
public static function return(Node $node): ReturnNode
|
||||
{
|
||||
return new ReturnNode($node);
|
||||
}
|
||||
|
||||
public static function shortClosure(Node $return): ShortClosureNode
|
||||
{
|
||||
return new ShortClosureNode($return);
|
||||
}
|
||||
|
||||
public static function ternary(Node $condition, Node $ifTrue, Node $ifFalse): TernaryNode
|
||||
{
|
||||
return new TernaryNode($condition, $ifTrue, $ifFalse);
|
||||
}
|
||||
|
||||
public static function this(): ComplianceNode
|
||||
{
|
||||
return self::variable('this');
|
||||
}
|
||||
|
||||
public static function throw(Node $node): ThrowNode
|
||||
{
|
||||
return new ThrowNode($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed>|bool|float|int|string|null $value
|
||||
*/
|
||||
public static function value(array|bool|float|int|string|null $value): ComplianceNode
|
||||
{
|
||||
return new ComplianceNode(new ValueNode($value));
|
||||
}
|
||||
|
||||
public static function variable(string $name): ComplianceNode
|
||||
{
|
||||
return new ComplianceNode(new VariableNode($name));
|
||||
}
|
||||
|
||||
public static function yield(Node $key, Node $value): YieldNode
|
||||
{
|
||||
return new YieldNode($key, $value);
|
||||
}
|
||||
}
|
||||
74
vendor/cuyz/valinor/src/Definition/AttributeDefinition.php
vendored
Normal file
74
vendor/cuyz/valinor/src/Definition/AttributeDefinition.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use Closure;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
|
||||
/** @internal */
|
||||
final class AttributeDefinition
|
||||
{
|
||||
/** @var callable */
|
||||
private mixed $callable;
|
||||
|
||||
public function __construct(
|
||||
public readonly ClassDefinition $class,
|
||||
|
||||
/** @var null|list<array<scalar>|scalar> */
|
||||
public readonly ?array $arguments,
|
||||
|
||||
/** @var array{'closure'}
|
||||
* | array{'class', class-string}
|
||||
* | array{'property', class-string, string}
|
||||
* | array{'method', class-string, string}
|
||||
* | array{'methodParameter', class-string, string, int}
|
||||
* | array{'closureParameter', int}
|
||||
*/
|
||||
public readonly array $reflectionParts,
|
||||
public readonly int $attributeIndex,
|
||||
) {}
|
||||
|
||||
public function forCallable(callable $callable): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->callable = $callable;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
/**
|
||||
* There are two ways of instantiating an attribute:
|
||||
*
|
||||
* 1. If the attribute's arguments contain only scalar, we can directly
|
||||
* instantiate the attribute using its class and arguments.
|
||||
* 2. If the attribute arguments contain any object or callable, we are
|
||||
* forced to use reflection to instantiate it, as it is not possible to
|
||||
* properly compile it.
|
||||
*
|
||||
* The first solution is by far more performant, so we prefer using it when
|
||||
* possible.
|
||||
*/
|
||||
public function instantiate(): object
|
||||
{
|
||||
if ($this->arguments !== null) {
|
||||
return new ($this->class->type->className())(...$this->arguments);
|
||||
}
|
||||
|
||||
$reflection = match ($this->reflectionParts[0]) {
|
||||
'class' => new ReflectionClass($this->reflectionParts[1]),
|
||||
'property' => new ReflectionProperty($this->reflectionParts[1], $this->reflectionParts[2]),
|
||||
'method' => new ReflectionMethod($this->reflectionParts[1], $this->reflectionParts[2]),
|
||||
'methodParameter' => (new ReflectionMethod($this->reflectionParts[1], $this->reflectionParts[2]))->getParameters()[$this->reflectionParts[3]],
|
||||
'closure' => new ReflectionFunction(Closure::fromCallable($this->callable)),
|
||||
'closureParameter' => new ReflectionParameter(Closure::fromCallable($this->callable), $this->reflectionParts[1]),
|
||||
};
|
||||
|
||||
return $reflection->getAttributes()[$this->attributeIndex]->newInstance();
|
||||
}
|
||||
}
|
||||
98
vendor/cuyz/valinor/src/Definition/Attributes.php
vendored
Normal file
98
vendor/cuyz/valinor/src/Definition/Attributes.php
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function is_a;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @implements IteratorAggregate<AttributeDefinition>
|
||||
*/
|
||||
final class Attributes implements IteratorAggregate, Countable
|
||||
{
|
||||
private static self $empty;
|
||||
|
||||
/** @var list<AttributeDefinition> */
|
||||
private array $attributes;
|
||||
|
||||
/**
|
||||
* @no-named-arguments
|
||||
*/
|
||||
public function __construct(AttributeDefinition ...$attributes)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
public static function empty(): self
|
||||
{
|
||||
return self::$empty ??= new self();
|
||||
}
|
||||
|
||||
public function forCallable(callable $callable): self
|
||||
{
|
||||
return new self(...array_map(
|
||||
fn (AttributeDefinition $attribute) => $attribute->forCallable($callable),
|
||||
$this->attributes,
|
||||
));
|
||||
}
|
||||
|
||||
public function has(string $className): bool
|
||||
{
|
||||
foreach ($this->attributes as $attribute) {
|
||||
if (is_a($attribute->class->type->className(), $className, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable(AttributeDefinition): bool $callback
|
||||
*/
|
||||
public function filter(callable $callback): self
|
||||
{
|
||||
return new self(
|
||||
...array_filter($this->attributes, $callback)
|
||||
);
|
||||
}
|
||||
|
||||
public function merge(self $other): self
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->attributes = [...$this->attributes, ...$other->attributes];
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<AttributeDefinition>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Traversable<AttributeDefinition>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
yield from $this->attributes;
|
||||
}
|
||||
}
|
||||
22
vendor/cuyz/valinor/src/Definition/ClassDefinition.php
vendored
Normal file
22
vendor/cuyz/valinor/src/Definition/ClassDefinition.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use CuyZ\Valinor\Type\ObjectType;
|
||||
|
||||
/** @internal */
|
||||
final class ClassDefinition
|
||||
{
|
||||
public function __construct(
|
||||
/** @var class-string */
|
||||
public readonly string $name,
|
||||
public readonly ObjectType $type,
|
||||
public readonly Attributes $attributes,
|
||||
public readonly Properties $properties,
|
||||
public readonly Methods $methods,
|
||||
public readonly bool $isFinal,
|
||||
public readonly bool $isAbstract,
|
||||
) {}
|
||||
}
|
||||
63
vendor/cuyz/valinor/src/Definition/FunctionDefinition.php
vendored
Normal file
63
vendor/cuyz/valinor/src/Definition/FunctionDefinition.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\Generics;
|
||||
use CuyZ\Valinor\Utility\TypeHelper;
|
||||
|
||||
/** @internal */
|
||||
final class FunctionDefinition
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
public readonly string $name,
|
||||
/** @var non-empty-string */
|
||||
public readonly string $signature,
|
||||
public readonly Attributes $attributes,
|
||||
/** @var non-empty-string|null */
|
||||
public readonly ?string $fileName,
|
||||
/** @var class-string|null */
|
||||
public readonly ?string $class,
|
||||
public readonly bool $isStatic,
|
||||
public readonly bool $isClosure,
|
||||
public readonly Parameters $parameters,
|
||||
public readonly Type $returnType,
|
||||
) {}
|
||||
|
||||
public function forCallable(callable $callable): self
|
||||
{
|
||||
return new self(
|
||||
$this->name,
|
||||
$this->signature,
|
||||
$this->attributes->forCallable($callable),
|
||||
$this->fileName,
|
||||
$this->class,
|
||||
$this->isStatic,
|
||||
$this->isClosure,
|
||||
$this->parameters->forCallable($callable),
|
||||
$this->returnType
|
||||
);
|
||||
}
|
||||
|
||||
public function assignGenerics(Generics $generics): self
|
||||
{
|
||||
if ($generics->items === []) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return new self(
|
||||
$this->name,
|
||||
$this->signature,
|
||||
$this->attributes,
|
||||
$this->fileName,
|
||||
$this->class,
|
||||
$this->isStatic,
|
||||
$this->isClosure,
|
||||
$this->parameters->assignGenerics($generics),
|
||||
TypeHelper::assignVacantTypes($this->returnType, $generics->items),
|
||||
);
|
||||
}
|
||||
}
|
||||
20
vendor/cuyz/valinor/src/Definition/FunctionObject.php
vendored
Normal file
20
vendor/cuyz/valinor/src/Definition/FunctionObject.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
/** @internal */
|
||||
final class FunctionObject
|
||||
{
|
||||
public readonly FunctionDefinition $definition;
|
||||
|
||||
/** @var callable */
|
||||
public readonly mixed $callback;
|
||||
|
||||
public function __construct(FunctionDefinition $definition, callable $callback)
|
||||
{
|
||||
$this->definition = $definition;
|
||||
$this->callback = $callback;
|
||||
}
|
||||
}
|
||||
69
vendor/cuyz/valinor/src/Definition/FunctionsContainer.php
vendored
Normal file
69
vendor/cuyz/valinor/src/Definition/FunctionsContainer.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use Countable;
|
||||
use CuyZ\Valinor\Definition\Repository\FunctionDefinitionRepository;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
use function array_keys;
|
||||
use function count;
|
||||
use function iterator_to_array;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @implements IteratorAggregate<string|int, FunctionObject>
|
||||
*/
|
||||
final class FunctionsContainer implements IteratorAggregate, Countable
|
||||
{
|
||||
/** @var array<FunctionObject> */
|
||||
private array $functions = [];
|
||||
|
||||
public function __construct(
|
||||
private FunctionDefinitionRepository $functionDefinitionRepository,
|
||||
/** @var array<callable> */
|
||||
private array $callables
|
||||
) {}
|
||||
|
||||
public function has(string|int $key): bool
|
||||
{
|
||||
return isset($this->callables[$key]);
|
||||
}
|
||||
|
||||
public function get(string|int $key): FunctionObject
|
||||
{
|
||||
return $this->function($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<FunctionObject>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return iterator_to_array($this);
|
||||
}
|
||||
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
foreach (array_keys($this->callables) as $key) {
|
||||
yield $key => $this->function($key);
|
||||
}
|
||||
}
|
||||
|
||||
private function function(string|int $key): FunctionObject
|
||||
{
|
||||
return $this->functions[$key] ??= new FunctionObject(
|
||||
$this->functionDefinitionRepository->for($this->callables[$key]),
|
||||
$this->callables[$key]
|
||||
);
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->callables);
|
||||
}
|
||||
}
|
||||
23
vendor/cuyz/valinor/src/Definition/MethodDefinition.php
vendored
Normal file
23
vendor/cuyz/valinor/src/Definition/MethodDefinition.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
|
||||
/** @internal */
|
||||
final class MethodDefinition
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
public readonly string $name,
|
||||
/** @var non-empty-string */
|
||||
public readonly string $signature,
|
||||
public readonly Attributes $attributes,
|
||||
public readonly Parameters $parameters,
|
||||
public readonly bool $isStatic,
|
||||
public readonly bool $isPublic,
|
||||
public readonly Type $returnType
|
||||
) {}
|
||||
}
|
||||
60
vendor/cuyz/valinor/src/Definition/Methods.php
vendored
Normal file
60
vendor/cuyz/valinor/src/Definition/Methods.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @implements IteratorAggregate<string, MethodDefinition>
|
||||
*/
|
||||
final class Methods implements IteratorAggregate, Countable
|
||||
{
|
||||
/** @var MethodDefinition[] */
|
||||
private array $methods = [];
|
||||
|
||||
public function __construct(MethodDefinition ...$methods)
|
||||
{
|
||||
foreach ($methods as $method) {
|
||||
$this->methods[$method->name] = $method;
|
||||
}
|
||||
}
|
||||
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return isset($this->methods[$name]);
|
||||
}
|
||||
|
||||
public function get(string $name): MethodDefinition
|
||||
{
|
||||
return $this->methods[$name];
|
||||
}
|
||||
|
||||
public function hasConstructor(): bool
|
||||
{
|
||||
return $this->has('__construct');
|
||||
}
|
||||
|
||||
public function constructor(): MethodDefinition
|
||||
{
|
||||
return $this->get('__construct');
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Traversable<string, MethodDefinition>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
yield from $this->methods;
|
||||
}
|
||||
}
|
||||
56
vendor/cuyz/valinor/src/Definition/ParameterDefinition.php
vendored
Normal file
56
vendor/cuyz/valinor/src/Definition/ParameterDefinition.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\Generics;
|
||||
use CuyZ\Valinor\Utility\TypeHelper;
|
||||
|
||||
/** @internal */
|
||||
final class ParameterDefinition
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
public readonly string $name,
|
||||
/** @var non-empty-string */
|
||||
public readonly string $signature,
|
||||
public readonly Type $type,
|
||||
public readonly Type $nativeType,
|
||||
public readonly bool $isOptional,
|
||||
public readonly bool $isVariadic,
|
||||
public readonly mixed $defaultValue,
|
||||
public readonly Attributes $attributes
|
||||
) {}
|
||||
|
||||
public function forCallable(callable $callable): self
|
||||
{
|
||||
return new self(
|
||||
$this->name,
|
||||
$this->signature,
|
||||
$this->type,
|
||||
$this->nativeType,
|
||||
$this->isOptional,
|
||||
$this->isVariadic,
|
||||
$this->defaultValue,
|
||||
$this->attributes->forCallable($callable)
|
||||
);
|
||||
}
|
||||
|
||||
public function assignGenerics(Generics $generics): self
|
||||
{
|
||||
assert($generics->items !== []);
|
||||
|
||||
return new self(
|
||||
$this->name,
|
||||
$this->signature,
|
||||
TypeHelper::assignVacantTypes($this->type, $generics->items),
|
||||
$this->nativeType,
|
||||
$this->isOptional,
|
||||
$this->isVariadic,
|
||||
$this->defaultValue,
|
||||
$this->attributes
|
||||
);
|
||||
}
|
||||
}
|
||||
88
vendor/cuyz/valinor/src/Definition/Parameters.php
vendored
Normal file
88
vendor/cuyz/valinor/src/Definition/Parameters.php
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use Countable;
|
||||
use CuyZ\Valinor\Type\Types\Generics;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
use function array_map;
|
||||
use function array_values;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @implements IteratorAggregate<string, ParameterDefinition>
|
||||
*/
|
||||
final class Parameters implements IteratorAggregate, Countable
|
||||
{
|
||||
/** @var array<non-empty-string, ParameterDefinition> */
|
||||
private array $parameters = [];
|
||||
|
||||
public function __construct(ParameterDefinition ...$parameters)
|
||||
{
|
||||
foreach ($parameters as $parameter) {
|
||||
$this->parameters[$parameter->name] = $parameter;
|
||||
}
|
||||
}
|
||||
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return isset($this->parameters[$name]);
|
||||
}
|
||||
|
||||
public function get(string $name): ParameterDefinition
|
||||
{
|
||||
return $this->parameters[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int<0, max> $index
|
||||
*/
|
||||
public function at(int $index): ParameterDefinition
|
||||
{
|
||||
return array_values($this->parameters)[$index];
|
||||
}
|
||||
|
||||
public function assignGenerics(Generics $generics): self
|
||||
{
|
||||
return new self(
|
||||
...array_map(
|
||||
static fn (ParameterDefinition $parameter) => $parameter->assignGenerics($generics),
|
||||
$this->parameters,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, ParameterDefinition>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->parameters);
|
||||
}
|
||||
|
||||
public function forCallable(callable $callable): self
|
||||
{
|
||||
return new self(...array_map(
|
||||
fn (ParameterDefinition $parameter) => $parameter->forCallable($callable),
|
||||
$this->parameters
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Traversable<string, ParameterDefinition>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
yield from $this->parameters;
|
||||
}
|
||||
}
|
||||
50
vendor/cuyz/valinor/src/Definition/Properties.php
vendored
Normal file
50
vendor/cuyz/valinor/src/Definition/Properties.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @implements IteratorAggregate<string, PropertyDefinition>
|
||||
*/
|
||||
final class Properties implements IteratorAggregate, Countable
|
||||
{
|
||||
/** @var PropertyDefinition[] */
|
||||
private array $properties = [];
|
||||
|
||||
public function __construct(PropertyDefinition ...$properties)
|
||||
{
|
||||
foreach ($properties as $property) {
|
||||
$this->properties[$property->name] = $property;
|
||||
}
|
||||
}
|
||||
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return isset($this->properties[$name]);
|
||||
}
|
||||
|
||||
public function get(string $name): PropertyDefinition
|
||||
{
|
||||
return $this->properties[$name];
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Traversable<string, PropertyDefinition>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
yield from $this->properties;
|
||||
}
|
||||
}
|
||||
24
vendor/cuyz/valinor/src/Definition/PropertyDefinition.php
vendored
Normal file
24
vendor/cuyz/valinor/src/Definition/PropertyDefinition.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition;
|
||||
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
|
||||
/** @internal */
|
||||
final class PropertyDefinition
|
||||
{
|
||||
public function __construct(
|
||||
/** @var non-empty-string */
|
||||
public readonly string $name,
|
||||
/** @var non-empty-string */
|
||||
public readonly string $signature,
|
||||
public readonly Type $type,
|
||||
public readonly Type $nativeType,
|
||||
public readonly bool $hasDefaultValue,
|
||||
public readonly mixed $defaultValue,
|
||||
public readonly bool $isPublic,
|
||||
public readonly Attributes $attributes
|
||||
) {}
|
||||
}
|
||||
23
vendor/cuyz/valinor/src/Definition/Repository/AttributesRepository.php
vendored
Normal file
23
vendor/cuyz/valinor/src/Definition/Repository/AttributesRepository.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository;
|
||||
|
||||
use CuyZ\Valinor\Definition\AttributeDefinition;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use Reflector;
|
||||
|
||||
/** @internal */
|
||||
interface AttributesRepository
|
||||
{
|
||||
/**
|
||||
* @param ReflectionClass<covariant object>|ReflectionProperty|ReflectionMethod|ReflectionFunction|ReflectionParameter $reflection
|
||||
* @return list<AttributeDefinition>
|
||||
*/
|
||||
public function for(Reflector $reflection): array;
|
||||
}
|
||||
68
vendor/cuyz/valinor/src/Definition/Repository/Cache/CompiledClassDefinitionRepository.php
vendored
Normal file
68
vendor/cuyz/valinor/src/Definition/Repository/Cache/CompiledClassDefinitionRepository.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache;
|
||||
|
||||
use CuyZ\Valinor\Cache\Cache;
|
||||
use CuyZ\Valinor\Cache\CacheEntry;
|
||||
use CuyZ\Valinor\Definition\ClassDefinition;
|
||||
use CuyZ\Valinor\Definition\Repository\Cache\Compiler\ClassDefinitionCompiler;
|
||||
use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository;
|
||||
use CuyZ\Valinor\Type\ObjectType;
|
||||
use CuyZ\Valinor\Utility\Reflection\Reflection;
|
||||
|
||||
use function is_string;
|
||||
|
||||
/** @internal */
|
||||
final class CompiledClassDefinitionRepository implements ClassDefinitionRepository
|
||||
{
|
||||
public function __construct(
|
||||
private ClassDefinitionRepository $delegate,
|
||||
/** @var Cache<ClassDefinition> */
|
||||
private Cache $cache,
|
||||
private ClassDefinitionCompiler $compiler,
|
||||
) {}
|
||||
|
||||
public function for(ObjectType $type): ClassDefinition
|
||||
{
|
||||
// @infection-ignore-all
|
||||
$key = "class-definition-\0" . $type->toString();
|
||||
|
||||
$entry = $this->cache->get($key);
|
||||
|
||||
if ($entry) {
|
||||
return $entry;
|
||||
}
|
||||
|
||||
$class = $this->delegate->for($type);
|
||||
|
||||
$code = 'fn () => ' . $this->compiler->compile($class);
|
||||
$filesToWatch = $this->filesToWatch($type);
|
||||
|
||||
$this->cache->set($key, new CacheEntry($code, $filesToWatch));
|
||||
|
||||
/** @var ClassDefinition */
|
||||
return $this->cache->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<non-empty-string>
|
||||
*/
|
||||
private function filesToWatch(ObjectType $type): array
|
||||
{
|
||||
$reflection = Reflection::class($type->className());
|
||||
|
||||
$fileNames = [];
|
||||
|
||||
do {
|
||||
$fileName = $reflection->getFileName();
|
||||
|
||||
if (is_string($fileName)) {
|
||||
$fileNames[] = $fileName;
|
||||
}
|
||||
} while ($reflection = $reflection->getParentClass());
|
||||
|
||||
return $fileNames;
|
||||
}
|
||||
}
|
||||
47
vendor/cuyz/valinor/src/Definition/Repository/Cache/CompiledFunctionDefinitionRepository.php
vendored
Normal file
47
vendor/cuyz/valinor/src/Definition/Repository/Cache/CompiledFunctionDefinitionRepository.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache;
|
||||
|
||||
use CuyZ\Valinor\Cache\Cache;
|
||||
use CuyZ\Valinor\Cache\CacheEntry;
|
||||
use CuyZ\Valinor\Definition\FunctionDefinition;
|
||||
use CuyZ\Valinor\Definition\Repository\Cache\Compiler\FunctionDefinitionCompiler;
|
||||
use CuyZ\Valinor\Definition\Repository\FunctionDefinitionRepository;
|
||||
use CuyZ\Valinor\Utility\Reflection\Reflection;
|
||||
|
||||
/** @internal */
|
||||
final class CompiledFunctionDefinitionRepository implements FunctionDefinitionRepository
|
||||
{
|
||||
public function __construct(
|
||||
private FunctionDefinitionRepository $delegate,
|
||||
/** @var Cache<FunctionDefinition> */
|
||||
private Cache $cache,
|
||||
private FunctionDefinitionCompiler $compiler,
|
||||
) {}
|
||||
|
||||
public function for(callable $function): FunctionDefinition
|
||||
{
|
||||
$reflection = Reflection::function($function);
|
||||
|
||||
// @infection-ignore-all
|
||||
$key = "function-definition-\0" . $reflection->getFileName() . ':' . $reflection->getStartLine() . '-' . $reflection->getEndLine();
|
||||
|
||||
$entry = $this->cache->get($key);
|
||||
|
||||
if ($entry) {
|
||||
return $entry->forCallable($function);
|
||||
}
|
||||
|
||||
$definition = $this->delegate->for($function);
|
||||
|
||||
$code = 'fn () => ' . $this->compiler->compile($definition);
|
||||
$filesToWatch = $definition->fileName ? [$definition->fileName] : [];
|
||||
|
||||
$this->cache->set($key, new CacheEntry($code, $filesToWatch));
|
||||
|
||||
/** @var FunctionDefinition */
|
||||
return $this->cache->get($key)?->forCallable($function);
|
||||
}
|
||||
}
|
||||
68
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/AttributesCompiler.php
vendored
Normal file
68
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/AttributesCompiler.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler;
|
||||
|
||||
use CuyZ\Valinor\Definition\Attributes;
|
||||
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function var_export;
|
||||
|
||||
/** @internal */
|
||||
final class AttributesCompiler
|
||||
{
|
||||
public function __construct(private ClassDefinitionCompiler $classDefinitionCompiler) {}
|
||||
|
||||
public function compile(Attributes $attributes): string
|
||||
{
|
||||
if (count($attributes) === 0) {
|
||||
return Attributes::class . '::empty()';
|
||||
}
|
||||
|
||||
$attributesListCode = $this->compileAttributes($attributes);
|
||||
|
||||
return <<<PHP
|
||||
new \CuyZ\Valinor\Definition\Attributes($attributesListCode)
|
||||
PHP;
|
||||
}
|
||||
|
||||
private function compileAttributes(Attributes $attributes): string
|
||||
{
|
||||
$attributesListCode = [];
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
$class = $this->classDefinitionCompiler->compile($attribute->class);
|
||||
$argumentsCode = $this->compileAttributeArguments($attribute->arguments);
|
||||
$reflectionParts = var_export($attribute->reflectionParts, true);
|
||||
$attributeIndex = var_export($attribute->attributeIndex, true);
|
||||
|
||||
$attributesListCode[] = <<<PHP
|
||||
new \CuyZ\Valinor\Definition\AttributeDefinition(
|
||||
$class,
|
||||
$argumentsCode,
|
||||
$reflectionParts,
|
||||
$attributeIndex,
|
||||
)
|
||||
PHP;
|
||||
}
|
||||
|
||||
return implode(', ', $attributesListCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|list<array<scalar>|scalar> $arguments
|
||||
*/
|
||||
private function compileAttributeArguments(?array $arguments): string
|
||||
{
|
||||
if ($arguments === null) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
$code = array_map(static fn ($value) => var_export($value, true), $arguments);
|
||||
|
||||
return '[' . implode(', ', $code) . ']';
|
||||
}
|
||||
}
|
||||
71
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/ClassDefinitionCompiler.php
vendored
Normal file
71
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/ClassDefinitionCompiler.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler;
|
||||
|
||||
use CuyZ\Valinor\Definition\ClassDefinition;
|
||||
use CuyZ\Valinor\Definition\MethodDefinition;
|
||||
use CuyZ\Valinor\Definition\PropertyDefinition;
|
||||
|
||||
use function array_map;
|
||||
use function implode;
|
||||
use function iterator_to_array;
|
||||
use function var_export;
|
||||
|
||||
/** @internal */
|
||||
final class ClassDefinitionCompiler
|
||||
{
|
||||
private TypeCompiler $typeCompiler;
|
||||
|
||||
private AttributesCompiler $attributesCompiler;
|
||||
|
||||
private MethodDefinitionCompiler $methodCompiler;
|
||||
|
||||
private PropertyDefinitionCompiler $propertyCompiler;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->attributesCompiler = new AttributesCompiler($this);
|
||||
$this->typeCompiler = new TypeCompiler($this->attributesCompiler);
|
||||
|
||||
$this->methodCompiler = new MethodDefinitionCompiler($this->typeCompiler, $this->attributesCompiler);
|
||||
$this->propertyCompiler = new PropertyDefinitionCompiler($this->typeCompiler, $this->attributesCompiler);
|
||||
}
|
||||
|
||||
public function compile(ClassDefinition $value): string
|
||||
{
|
||||
$name = var_export($value->name, true);
|
||||
$type = $this->typeCompiler->compile($value->type);
|
||||
|
||||
$properties = array_map(
|
||||
fn (PropertyDefinition $property) => $this->propertyCompiler->compile($property),
|
||||
iterator_to_array($value->properties)
|
||||
);
|
||||
|
||||
$properties = implode(', ', $properties);
|
||||
|
||||
$methods = array_map(
|
||||
fn (MethodDefinition $method) => $this->methodCompiler->compile($method),
|
||||
iterator_to_array($value->methods)
|
||||
);
|
||||
|
||||
$methods = implode(', ', $methods);
|
||||
$attributes = $this->attributesCompiler->compile($value->attributes);
|
||||
|
||||
$isFinal = var_export($value->isFinal, true);
|
||||
$isAbstract = var_export($value->isAbstract, true);
|
||||
|
||||
return <<<PHP
|
||||
new \CuyZ\Valinor\Definition\ClassDefinition(
|
||||
$name,
|
||||
$type,
|
||||
$attributes,
|
||||
new \CuyZ\Valinor\Definition\Properties($properties),
|
||||
new \CuyZ\Valinor\Definition\Methods($methods),
|
||||
$isFinal,
|
||||
$isAbstract,
|
||||
)
|
||||
PHP;
|
||||
}
|
||||
}
|
||||
19
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/Exception/TypeCannotBeCompiled.php
vendored
Normal file
19
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/Exception/TypeCannotBeCompiled.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler\Exception;
|
||||
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use LogicException;
|
||||
|
||||
/** @internal */
|
||||
final class TypeCannotBeCompiled extends LogicException
|
||||
{
|
||||
public function __construct(Type $type)
|
||||
{
|
||||
$class = $type::class;
|
||||
|
||||
parent::__construct("The type `$class` cannot be compiled.");
|
||||
}
|
||||
}
|
||||
58
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/FunctionDefinitionCompiler.php
vendored
Normal file
58
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/FunctionDefinitionCompiler.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler;
|
||||
|
||||
use CuyZ\Valinor\Definition\FunctionDefinition;
|
||||
use CuyZ\Valinor\Definition\ParameterDefinition;
|
||||
|
||||
use function var_export;
|
||||
|
||||
/** @internal */
|
||||
final class FunctionDefinitionCompiler
|
||||
{
|
||||
private TypeCompiler $typeCompiler;
|
||||
|
||||
private AttributesCompiler $attributesCompiler;
|
||||
|
||||
private ParameterDefinitionCompiler $parameterCompiler;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->attributesCompiler = new AttributesCompiler(new ClassDefinitionCompiler());
|
||||
$this->typeCompiler = new TypeCompiler($this->attributesCompiler);
|
||||
|
||||
$this->parameterCompiler = new ParameterDefinitionCompiler($this->typeCompiler, $this->attributesCompiler);
|
||||
}
|
||||
|
||||
public function compile(FunctionDefinition $value): string
|
||||
{
|
||||
$parameters = array_map(
|
||||
fn (ParameterDefinition $parameter) => $this->parameterCompiler->compile($parameter),
|
||||
iterator_to_array($value->parameters)
|
||||
);
|
||||
|
||||
$attributes = $this->attributesCompiler->compile($value->attributes);
|
||||
$fileName = var_export($value->fileName, true);
|
||||
$class = var_export($value->class, true);
|
||||
$isStatic = var_export($value->isStatic, true);
|
||||
$isClosure = var_export($value->isClosure, true);
|
||||
$parameters = implode(', ', $parameters);
|
||||
$returnType = $this->typeCompiler->compile($value->returnType);
|
||||
|
||||
return <<<PHP
|
||||
new \CuyZ\Valinor\Definition\FunctionDefinition(
|
||||
'{$value->name}',
|
||||
'{$value->signature}',
|
||||
$attributes,
|
||||
$fileName,
|
||||
$class,
|
||||
$isStatic,
|
||||
$isClosure,
|
||||
new \CuyZ\Valinor\Definition\Parameters($parameters),
|
||||
$returnType
|
||||
)
|
||||
PHP;
|
||||
}
|
||||
}
|
||||
54
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/MethodDefinitionCompiler.php
vendored
Normal file
54
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/MethodDefinitionCompiler.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler;
|
||||
|
||||
use CuyZ\Valinor\Definition\MethodDefinition;
|
||||
use CuyZ\Valinor\Definition\ParameterDefinition;
|
||||
|
||||
use function var_export;
|
||||
|
||||
/** @internal */
|
||||
final class MethodDefinitionCompiler
|
||||
{
|
||||
private TypeCompiler $typeCompiler;
|
||||
|
||||
private AttributesCompiler $attributesCompiler;
|
||||
|
||||
private ParameterDefinitionCompiler $parameterCompiler;
|
||||
|
||||
public function __construct(TypeCompiler $typeCompiler, AttributesCompiler $attributesCompiler)
|
||||
{
|
||||
$this->typeCompiler = $typeCompiler;
|
||||
$this->attributesCompiler = $attributesCompiler;
|
||||
$this->parameterCompiler = new ParameterDefinitionCompiler($typeCompiler, $attributesCompiler);
|
||||
}
|
||||
|
||||
public function compile(MethodDefinition $method): string
|
||||
{
|
||||
$attributes = $this->attributesCompiler->compile($method->attributes);
|
||||
|
||||
$parameters = array_map(
|
||||
fn (ParameterDefinition $parameter) => $this->parameterCompiler->compile($parameter),
|
||||
iterator_to_array($method->parameters)
|
||||
);
|
||||
|
||||
$parameters = implode(', ', $parameters);
|
||||
$isStatic = var_export($method->isStatic, true);
|
||||
$isPublic = var_export($method->isPublic, true);
|
||||
$returnType = $this->typeCompiler->compile($method->returnType);
|
||||
|
||||
return <<<PHP
|
||||
new \CuyZ\Valinor\Definition\MethodDefinition(
|
||||
'{$method->name}',
|
||||
'{$method->signature}',
|
||||
$attributes,
|
||||
new \CuyZ\Valinor\Definition\Parameters($parameters),
|
||||
$isStatic,
|
||||
$isPublic,
|
||||
$returnType
|
||||
)
|
||||
PHP;
|
||||
}
|
||||
}
|
||||
48
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/ParameterDefinitionCompiler.php
vendored
Normal file
48
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/ParameterDefinitionCompiler.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler;
|
||||
|
||||
use CuyZ\Valinor\Definition\ParameterDefinition;
|
||||
|
||||
/** @internal */
|
||||
final class ParameterDefinitionCompiler
|
||||
{
|
||||
public function __construct(
|
||||
private TypeCompiler $typeCompiler,
|
||||
private AttributesCompiler $attributesCompiler
|
||||
) {}
|
||||
|
||||
public function compile(ParameterDefinition $parameter): string
|
||||
{
|
||||
$isOptional = var_export($parameter->isOptional, true);
|
||||
$isVariadic = var_export($parameter->isVariadic, true);
|
||||
$defaultValue = $this->defaultValue($parameter);
|
||||
$type = $this->typeCompiler->compile($parameter->type);
|
||||
$nativeType = $this->typeCompiler->compile($parameter->nativeType);
|
||||
$attributes = $this->attributesCompiler->compile($parameter->attributes);
|
||||
|
||||
return <<<PHP
|
||||
new \CuyZ\Valinor\Definition\ParameterDefinition(
|
||||
'{$parameter->name}',
|
||||
'{$parameter->signature}',
|
||||
$type,
|
||||
$nativeType,
|
||||
$isOptional,
|
||||
$isVariadic,
|
||||
$defaultValue,
|
||||
$attributes
|
||||
)
|
||||
PHP;
|
||||
}
|
||||
|
||||
private function defaultValue(ParameterDefinition $parameter): string
|
||||
{
|
||||
$defaultValue = $parameter->defaultValue;
|
||||
|
||||
return is_object($defaultValue)
|
||||
? 'unserialize(' . var_export(serialize($defaultValue), true) . ')'
|
||||
: var_export($defaultValue, true);
|
||||
}
|
||||
}
|
||||
39
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/PropertyDefinitionCompiler.php
vendored
Normal file
39
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/PropertyDefinitionCompiler.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler;
|
||||
|
||||
use CuyZ\Valinor\Definition\PropertyDefinition;
|
||||
|
||||
/** @internal */
|
||||
final class PropertyDefinitionCompiler
|
||||
{
|
||||
public function __construct(
|
||||
private TypeCompiler $typeCompiler,
|
||||
private AttributesCompiler $attributesCompiler
|
||||
) {}
|
||||
|
||||
public function compile(PropertyDefinition $property): string
|
||||
{
|
||||
$type = $this->typeCompiler->compile($property->type);
|
||||
$nativeType = $this->typeCompiler->compile($property->nativeType);
|
||||
$hasDefaultValue = var_export($property->hasDefaultValue, true);
|
||||
$defaultValue = var_export($property->defaultValue, true);
|
||||
$isPublic = var_export($property->isPublic, true);
|
||||
$attributes = $this->attributesCompiler->compile($property->attributes);
|
||||
|
||||
return <<<PHP
|
||||
new \CuyZ\Valinor\Definition\PropertyDefinition(
|
||||
'{$property->name}',
|
||||
'{$property->signature}',
|
||||
$type,
|
||||
$nativeType,
|
||||
$hasDefaultValue,
|
||||
$defaultValue,
|
||||
$isPublic,
|
||||
$attributes
|
||||
)
|
||||
PHP;
|
||||
}
|
||||
}
|
||||
214
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/TypeCompiler.php
vendored
Normal file
214
vendor/cuyz/valinor/src/Definition/Repository/Cache/Compiler/TypeCompiler.php
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache\Compiler;
|
||||
|
||||
use CuyZ\Valinor\Definition\Repository\Cache\Compiler\Exception\TypeCannotBeCompiled;
|
||||
use CuyZ\Valinor\Type\Type;
|
||||
use CuyZ\Valinor\Type\Types\ArrayKeyType;
|
||||
use CuyZ\Valinor\Type\Types\ArrayType;
|
||||
use CuyZ\Valinor\Type\Types\BooleanValueType;
|
||||
use CuyZ\Valinor\Type\Types\CallableType;
|
||||
use CuyZ\Valinor\Type\Types\ClassStringType;
|
||||
use CuyZ\Valinor\Type\Types\EnumType;
|
||||
use CuyZ\Valinor\Type\Types\FloatValueType;
|
||||
use CuyZ\Valinor\Type\Types\GenericType;
|
||||
use CuyZ\Valinor\Type\Types\IntegerRangeType;
|
||||
use CuyZ\Valinor\Type\Types\IntegerValueType;
|
||||
use CuyZ\Valinor\Type\Types\InterfaceType;
|
||||
use CuyZ\Valinor\Type\Types\IntersectionType;
|
||||
use CuyZ\Valinor\Type\Types\IterableType;
|
||||
use CuyZ\Valinor\Type\Types\ListType;
|
||||
use CuyZ\Valinor\Type\Types\MixedType;
|
||||
use CuyZ\Valinor\Type\Types\NativeBooleanType;
|
||||
use CuyZ\Valinor\Type\Types\NativeClassType;
|
||||
use CuyZ\Valinor\Type\Types\NativeFloatType;
|
||||
use CuyZ\Valinor\Type\Types\NativeIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\NativeStringType;
|
||||
use CuyZ\Valinor\Type\Types\NegativeIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\NonEmptyArrayType;
|
||||
use CuyZ\Valinor\Type\Types\NonEmptyListType;
|
||||
use CuyZ\Valinor\Type\Types\NonEmptyStringType;
|
||||
use CuyZ\Valinor\Type\Types\NonNegativeIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\NonPositiveIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\NullType;
|
||||
use CuyZ\Valinor\Type\Types\NumericStringType;
|
||||
use CuyZ\Valinor\Type\Types\PositiveIntegerType;
|
||||
use CuyZ\Valinor\Type\Types\ScalarConcreteType;
|
||||
use CuyZ\Valinor\Type\Types\ShapedArrayElement;
|
||||
use CuyZ\Valinor\Type\Types\ShapedArrayType;
|
||||
use CuyZ\Valinor\Type\Types\StringValueType;
|
||||
use CuyZ\Valinor\Type\Types\UndefinedObjectType;
|
||||
use CuyZ\Valinor\Type\Types\UnionType;
|
||||
use CuyZ\Valinor\Type\Types\UnresolvableType;
|
||||
use UnitEnum;
|
||||
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function implode;
|
||||
use function var_export;
|
||||
|
||||
/** @internal */
|
||||
final class TypeCompiler
|
||||
{
|
||||
public function __construct(
|
||||
private AttributesCompiler $attributesCompiler,
|
||||
) {}
|
||||
|
||||
public function compile(Type $type): string
|
||||
{
|
||||
$class = $type::class;
|
||||
|
||||
switch (true) {
|
||||
case $type instanceof NullType:
|
||||
case $type instanceof NativeBooleanType:
|
||||
case $type instanceof NativeFloatType:
|
||||
case $type instanceof NativeIntegerType:
|
||||
case $type instanceof PositiveIntegerType:
|
||||
case $type instanceof NegativeIntegerType:
|
||||
case $type instanceof NonPositiveIntegerType:
|
||||
case $type instanceof NonNegativeIntegerType:
|
||||
case $type instanceof NativeStringType:
|
||||
case $type instanceof NonEmptyStringType:
|
||||
case $type instanceof NumericStringType:
|
||||
case $type instanceof UndefinedObjectType:
|
||||
case $type instanceof MixedType:
|
||||
case $type instanceof ScalarConcreteType:
|
||||
return "$class::get()";
|
||||
case $type instanceof BooleanValueType:
|
||||
return $type->value() === true
|
||||
? "$class::true()"
|
||||
: "$class::false()";
|
||||
case $type instanceof IntegerRangeType:
|
||||
return "new $class({$type->min()}, {$type->max()})";
|
||||
case $type instanceof StringValueType:
|
||||
$value = var_export($type->toString(), true);
|
||||
|
||||
return "$class::from($value)";
|
||||
case $type instanceof IntegerValueType:
|
||||
case $type instanceof FloatValueType:
|
||||
$value = var_export($type->value(), true);
|
||||
|
||||
return "new $class($value)";
|
||||
case $type instanceof IntersectionType:
|
||||
case $type instanceof UnionType:
|
||||
$subTypes = array_map(
|
||||
fn (Type $subType) => $this->compile($subType),
|
||||
$type->types()
|
||||
);
|
||||
|
||||
return "new $class(" . implode(', ', $subTypes) . ')';
|
||||
case $type instanceof ArrayKeyType:
|
||||
return match ($type->toString()) {
|
||||
'array-key' => "$class::default()",
|
||||
'string' => "$class::string()",
|
||||
'int' => "$class::integer()",
|
||||
default => (function () use ($type, $class) {
|
||||
$types = array_map(
|
||||
fn (Type $subType) => $this->compile($subType),
|
||||
$type->types,
|
||||
);
|
||||
|
||||
return "new $class([" . implode(', ', $types) . '])';
|
||||
})(),
|
||||
};
|
||||
case $type instanceof ShapedArrayType:
|
||||
$elements = [];
|
||||
|
||||
foreach ($type->elements as $key => $element) {
|
||||
$subkey = $this->compile($element->key());
|
||||
$subtype = $this->compile($element->type());
|
||||
$optional = var_export($element->isOptional(), true);
|
||||
$attributes = $this->attributesCompiler->compile($element->attributes());
|
||||
|
||||
$elements[] = var_export($key, true) . ' => new ' . ShapedArrayElement::class . "($subkey, $subtype, $optional, $attributes)";
|
||||
}
|
||||
|
||||
$elements = implode(', ', $elements);
|
||||
$isUnsealed = var_export($type->isUnsealed, true);
|
||||
$unsealedType = $type->hasUnsealedType() ? $this->compile($type->unsealedType()) : 'null';
|
||||
|
||||
return "new $class([$elements], $isUnsealed, $unsealedType)";
|
||||
case $type instanceof ArrayType:
|
||||
case $type instanceof NonEmptyArrayType:
|
||||
if ($type->toString() === 'array' || $type->toString() === 'non-empty-array') {
|
||||
return "$class::native()";
|
||||
}
|
||||
|
||||
$subType = $this->compile($type->subType());
|
||||
|
||||
if (str_ends_with($type->toString(), '[]')) {
|
||||
return "$class::simple($subType)";
|
||||
}
|
||||
|
||||
$keyType = $this->compile($type->keyType());
|
||||
|
||||
return "new $class($keyType, $subType)";
|
||||
case $type instanceof ListType:
|
||||
case $type instanceof NonEmptyListType:
|
||||
if ($type->toString() === 'list' || $type->toString() === 'non-empty-list') {
|
||||
return "$class::native()";
|
||||
}
|
||||
|
||||
$subType = $this->compile($type->subType());
|
||||
|
||||
return "new $class($subType)";
|
||||
case $type instanceof IterableType:
|
||||
$keyType = $this->compile($type->keyType());
|
||||
$subType = $this->compile($type->subType());
|
||||
|
||||
return "new $class($keyType, $subType)";
|
||||
case $type instanceof NativeClassType:
|
||||
case $type instanceof InterfaceType:
|
||||
$generics = [];
|
||||
|
||||
foreach ($type->generics() as $key => $generic) {
|
||||
$generics[] = var_export($key, true) . ' => ' . $this->compile($generic);
|
||||
}
|
||||
|
||||
$generics = implode(', ', $generics);
|
||||
|
||||
return "new $class('{$type->className()}', [$generics])";
|
||||
case $type instanceof ClassStringType:
|
||||
$subTypes = implode(', ', array_map(
|
||||
fn (Type $subType) => $this->compile($subType),
|
||||
$type->subTypes(),
|
||||
));
|
||||
|
||||
return "new $class([$subTypes])";
|
||||
case $type instanceof EnumType:
|
||||
$enumName = var_export($type->className(), true);
|
||||
$pattern = var_export($type->pattern(), true);
|
||||
|
||||
$cases = array_map(
|
||||
fn (string|int $key, UnitEnum $case) => var_export($key, true) . ' => ' . var_export($case, true),
|
||||
array_keys($type->cases()),
|
||||
$type->cases()
|
||||
);
|
||||
$cases = implode(', ', $cases);
|
||||
|
||||
return "new $class($enumName, $pattern, [$cases])";
|
||||
case $type instanceof CallableType:
|
||||
$returnType = $this->compile($type->returnType);
|
||||
$parameters = implode(', ', array_map(
|
||||
fn (Type $subType) => $this->compile($subType),
|
||||
$type->parameters,
|
||||
));
|
||||
|
||||
return "new $class([$parameters], $returnType)";
|
||||
case $type instanceof GenericType:
|
||||
$symbol = var_export($type->symbol, true);
|
||||
$innerType = $this->compile($type->innerType);
|
||||
|
||||
return "new $class($symbol, $innerType)";
|
||||
case $type instanceof UnresolvableType:
|
||||
$raw = var_export($type->toString(), true);
|
||||
$message = var_export($type->message(), true);
|
||||
|
||||
return "new $class($raw, $message)";
|
||||
default:
|
||||
throw new TypeCannotBeCompiled($type);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
vendor/cuyz/valinor/src/Definition/Repository/Cache/InMemoryClassDefinitionRepository.php
vendored
Normal file
25
vendor/cuyz/valinor/src/Definition/Repository/Cache/InMemoryClassDefinitionRepository.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache;
|
||||
|
||||
use CuyZ\Valinor\Definition\ClassDefinition;
|
||||
use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository;
|
||||
use CuyZ\Valinor\Type\ObjectType;
|
||||
|
||||
/** @internal */
|
||||
final class InMemoryClassDefinitionRepository implements ClassDefinitionRepository
|
||||
{
|
||||
/** @var array<string, ClassDefinition> */
|
||||
private array $classDefinitions = [];
|
||||
|
||||
public function __construct(
|
||||
private ClassDefinitionRepository $delegate,
|
||||
) {}
|
||||
|
||||
public function for(ObjectType $type): ClassDefinition
|
||||
{
|
||||
return $this->classDefinitions[$type->toString()] ??= $this->delegate->for($type);
|
||||
}
|
||||
}
|
||||
30
vendor/cuyz/valinor/src/Definition/Repository/Cache/InMemoryFunctionDefinitionRepository.php
vendored
Normal file
30
vendor/cuyz/valinor/src/Definition/Repository/Cache/InMemoryFunctionDefinitionRepository.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository\Cache;
|
||||
|
||||
use CuyZ\Valinor\Definition\FunctionDefinition;
|
||||
use CuyZ\Valinor\Definition\Repository\FunctionDefinitionRepository;
|
||||
use CuyZ\Valinor\Utility\Reflection\Reflection;
|
||||
|
||||
/** @internal */
|
||||
final class InMemoryFunctionDefinitionRepository implements FunctionDefinitionRepository
|
||||
{
|
||||
/** @var array<string, FunctionDefinition> */
|
||||
private array $functionDefinitions = [];
|
||||
|
||||
public function __construct(
|
||||
private FunctionDefinitionRepository $delegate,
|
||||
) {}
|
||||
|
||||
public function for(callable $function): FunctionDefinition
|
||||
{
|
||||
$reflection = Reflection::function($function);
|
||||
|
||||
// @infection-ignore-all
|
||||
$key = $reflection->getFileName() . ':' . $reflection->getStartLine() . '-' . $reflection->getEndLine();
|
||||
|
||||
return ($this->functionDefinitions[$key] ??= $this->delegate->for($function))->forCallable($function);
|
||||
}
|
||||
}
|
||||
14
vendor/cuyz/valinor/src/Definition/Repository/ClassDefinitionRepository.php
vendored
Normal file
14
vendor/cuyz/valinor/src/Definition/Repository/ClassDefinitionRepository.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CuyZ\Valinor\Definition\Repository;
|
||||
|
||||
use CuyZ\Valinor\Definition\ClassDefinition;
|
||||
use CuyZ\Valinor\Type\ObjectType;
|
||||
|
||||
/** @internal */
|
||||
interface ClassDefinitionRepository
|
||||
{
|
||||
public function for(ObjectType $type): ClassDefinition;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user