}
},
"require": {
- "cuyz/valinor": "^1.6.0",
+ "cuyz/valinor": "^1.6.1",
"dragonmantank/cron-expression": "^3.3.3",
"erusev/parsedown": "^1.7.4",
"ezyang/htmlpurifier": "^4.16",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "d1b286c6264e2d8bf1223ce6243ae1a9",
+ "content-hash": "3bcdf9c6922a05444493ea682a6bce01",
"packages": [
{
"name": "cuyz/valinor",
- "version": "1.6.0",
+ "version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/CuyZ/Valinor.git",
- "reference": "f3f3429d90be77f59903923f9bb5ce93c484dfd7"
+ "reference": "88c6b0f9299088de632d17610efffb54d55adba6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/f3f3429d90be77f59903923f9bb5ce93c484dfd7",
- "reference": "f3f3429d90be77f59903923f9bb5ce93c484dfd7",
+ "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/88c6b0f9299088de632d17610efffb54d55adba6",
+ "reference": "88c6b0f9299088de632d17610efffb54d55adba6",
"shasum": ""
},
"require": {
],
"support": {
"issues": "https://github.com/CuyZ/Valinor/issues",
- "source": "https://github.com/CuyZ/Valinor/tree/1.6.0"
+ "source": "https://github.com/CuyZ/Valinor/tree/1.6.1"
},
"funding": [
{
"type": "github"
}
],
- "time": "2023-08-25T10:26:38+00:00"
+ "time": "2023-10-11T08:40:51+00:00"
},
{
"name": "dragonmantank/cron-expression",
"packages": [
{
"name": "cuyz/valinor",
- "version": "1.6.0",
- "version_normalized": "1.6.0.0",
+ "version": "1.6.1",
+ "version_normalized": "1.6.1.0",
"source": {
"type": "git",
"url": "https://github.com/CuyZ/Valinor.git",
- "reference": "f3f3429d90be77f59903923f9bb5ce93c484dfd7"
+ "reference": "88c6b0f9299088de632d17610efffb54d55adba6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/f3f3429d90be77f59903923f9bb5ce93c484dfd7",
- "reference": "f3f3429d90be77f59903923f9bb5ce93c484dfd7",
+ "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/88c6b0f9299088de632d17610efffb54d55adba6",
+ "reference": "88c6b0f9299088de632d17610efffb54d55adba6",
"shasum": ""
},
"require": {
"rector/rector": "~0.17.0",
"vimeo/psalm": "^5.0"
},
- "time": "2023-08-25T10:26:38+00:00",
+ "time": "2023-10-11T08:40:51+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
],
"support": {
"issues": "https://github.com/CuyZ/Valinor/issues",
- "source": "https://github.com/CuyZ/Valinor/tree/1.6.0"
+ "source": "https://github.com/CuyZ/Valinor/tree/1.6.1"
},
"funding": [
{
<?php return array(
'root' => array(
'name' => '__root__',
- 'pretty_version' => '1.0.0+no-version-set',
- 'version' => '1.0.0.0',
- 'reference' => NULL,
+ 'pretty_version' => '6.0.x-dev',
+ 'version' => '6.0.9999999.9999999-dev',
+ 'reference' => 'ac5b81de7a0ce3346688fb80f203204aee5390e6',
'type' => 'project',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
),
'versions' => array(
'__root__' => array(
- 'pretty_version' => '1.0.0+no-version-set',
- 'version' => '1.0.0.0',
- 'reference' => NULL,
+ 'pretty_version' => '6.0.x-dev',
+ 'version' => '6.0.9999999.9999999-dev',
+ 'reference' => 'ac5b81de7a0ce3346688fb80f203204aee5390e6',
'type' => 'project',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
'dev_requirement' => false,
),
'cuyz/valinor' => array(
- 'pretty_version' => '1.6.0',
- 'version' => '1.6.0.0',
- 'reference' => 'f3f3429d90be77f59903923f9bb5ce93c484dfd7',
+ 'pretty_version' => '1.6.1',
+ 'version' => '1.6.1.0',
+ 'reference' => '88c6b0f9299088de632d17610efffb54d55adba6',
'type' => 'library',
'install_path' => __DIR__ . '/../cuyz/valinor',
'aliases' => array(),
],
"doc": [
"Composer\\Config::disableProcessTimeout",
- "pip install -r docs/requirements.txt",
- "mkdocs serve --config-file docs/mkdocs.yml"
+ "docker build -t valinor-doc ./docs",
+ "docker run --name valinor-doc --rm -it -p 8000:8000 -v ${PWD}/docs:/docs valinor-doc"
]
},
"config": {
/** @internal */
final class InvalidTypeAliasImportClass extends LogicException
{
- /**
- * @param class-string $className
- */
public function __construct(ClassType $type, string $className)
{
parent::__construct(
use CuyZ\Valinor\Type\Parser\Exception\InvalidType;
use CuyZ\Valinor\Type\Parser\TypeParser;
use CuyZ\Valinor\Type\Type;
+use CuyZ\Valinor\Type\Types\ArrayKeyType;
+use CuyZ\Valinor\Type\Types\ArrayType;
use CuyZ\Valinor\Type\Types\MixedType;
use CuyZ\Valinor\Type\Types\UnresolvableType;
use CuyZ\Valinor\Utility\Reflection\DocParser;
return null;
}
- return $this->parseType($type, $reflection, $this->advancedParser);
+ $type = $this->parseType($type, $reflection, $this->advancedParser);
+
+ return $this->handleVariadicType($reflection, $type);
}
private function nativeType(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection): ?Type
}
$type = Reflection::flattenType($reflectionType);
+ $type = $this->parseType($type, $reflection, $this->nativeParser);
- if ($reflection instanceof ReflectionParameter && $reflection->isVariadic()) {
- $type .= '[]';
- }
-
- return $this->parseType($type, $reflection, $this->nativeParser);
+ return $this->handleVariadicType($reflection, $type);
}
private function parseType(string $raw, ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection, TypeParser $parser): Type
return UnresolvableType::forMethodReturnType($raw, $signature, $exception);
}
}
+
+ private function handleVariadicType(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection, Type $type): Type
+ {
+ if (! $reflection instanceof ReflectionParameter || ! $reflection->isVariadic()) {
+ return $type;
+ }
+
+ return new ArrayType(ArrayKeyType::default(), $type);
+ }
}
{
$from = $this->keys[$atDepth] ?? null;
- return $from === $key || $from === '*';
+ return $from === (string)$key || $from === '*';
}
public function findMappedKey(int|string $key, int $atDepth): ?string
/**
* @param iterable<mixed> $source
- * @param array<string, string> $map
+ * @param array<string> $map
*/
public function __construct(iterable $source, array $map)
{
}
/**
- * @param array<string, string> $map
+ * @param array<string> $map
* @return array<Mapping>
*/
private function prepareMappings(array $map): array
$mappings = [];
foreach ($map as $from => $to) {
- $mappings[] = new Mapping(explode('.', $from), $to);
+ $mappings[] = new Mapping(explode('.', (string)$from), $to);
}
return $mappings;
}
/**
- * @param array<string, string> $map
+ * @param array<string> $map
*/
public function map(array $map): Source
{
use ReflectionParameter;
use ReflectionProperty;
+use function array_merge;
use function end;
+use function explode;
use function preg_match;
use function preg_match_all;
use function str_replace;
use function str_split;
use function strrpos;
use function substr;
+use function trim;
/** @internal */
final class DocParser
return [];
}
+ $cases = self::splitStringBy($doc, '@phpstan-type', '@psalm-type');
+
$types = [];
- preg_match_all('/@(phpstan|psalm)-type\s+(?<name>[a-zA-Z]\w*)\s*=?\s*(?<type>.*)/', $doc, $matches);
+ foreach ($cases as $case) {
+ if (! preg_match('/\s*(?<name>[a-zA-Z]\w*)\s*=?\s*(?<type>.*)/s', $case, $matches)) {
+ continue;
+ }
- foreach ($matches['name'] as $key => $name) {
- /** @var string $name */
- $types[$name] = self::findType($matches['type'][$key]);
+ $types[$matches['name']] = self::findType($matches['type']);
}
return $types;
/**
* @param ReflectionClass<object> $reflection
- * @return array<class-string, string[]>
+ * @return array<string, string[]>
*/
public static function importedTypeAliases(ReflectionClass $reflection): array
{
return [];
}
- $types = [];
+ $cases = self::splitStringBy($doc, '@phpstan-import-type', '@psalm-import-type');
- preg_match_all('/@(phpstan|psalm)-import-type\s+(?<name>[a-zA-Z]\w*)\s*from\s*(?<class>\w+)/', $doc, $matches);
+ $types = [];
- foreach ($matches['name'] as $key => $name) {
- /** @var class-string $class */
- $class = $matches['class'][$key];
+ foreach ($cases as $case) {
+ if (! preg_match('/\s*(?<name>[a-zA-Z]\w*)\s*from\s*(?<class>\w+)/', $case, $matches)) {
+ continue;
+ }
- $types[$class][] = $name;
+ $types[$matches['class']][] = $matches['name'];
}
return $types;
return preg_replace('/^\s*\*\s*(\S*)/m', '$1', $doc); // @phpstan-ignore-line
}
+
+ /**
+ * @param non-empty-string ...$cases
+ * @return list<string>
+ */
+ private static function splitStringBy(string $string, string ...$cases): array
+ {
+ $result = [$string];
+
+ foreach ($cases as $case) {
+ foreach ($result as $value) {
+ $result = array_merge($result, explode($case, $value));
+ }
+ }
+
+ return $result;
+ }
}