From 55ebc56630fa852ae370319a3a6e85dd9fe3b4cb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Fri, 25 Aug 2023 12:35:34 +0200 Subject: [PATCH] Update composer dependencies --- .../files/lib/system/api/composer.json | 2 +- .../files/lib/system/api/composer.lock | 18 +- .../system/api/composer/autoload_classmap.php | 11 +- .../system/api/composer/autoload_static.php | 11 +- .../lib/system/api/composer/installed.json | 18 +- .../lib/system/api/composer/installed.php | 6 +- .../lib/system/api/cuyz/valinor/composer.json | 5 +- .../api/cuyz/valinor/src/Cache/ChainCache.php | 13 +- .../Cache/Compiled/CompiledPhpFileCache.php | 28 ++- .../valinor/src/Cache/FileSystemCache.php | 13 +- .../valinor/src/Cache/FileWatchingCache.php | 11 +- .../valinor/src/Cache/KeySanitizerCache.php | 11 +- .../Warmup/RecursiveCacheWarmupService.php | 16 +- .../cuyz/valinor/src/Cache/WarmupCache.php | 16 ++ .../src/Definition/AttributesContainer.php | 32 ++- .../src/Definition/NativeAttributes.php | 7 +- .../Cache/Compiler/AttributesCompiler.php | 38 ++- .../ReflectionClassDefinitionRepository.php | 23 +- .../Reflection/ReflectionTypeResolver.php | 28 ++- .../cuyz/valinor/src/Library/Container.php | 9 +- .../api/cuyz/valinor/src/Library/Settings.php | 6 +- .../Object/DateTimeFormatConstructor.php | 2 +- .../Mapper/Tree/Builder/ArrayNodeBuilder.php | 9 +- .../api/cuyz/valinor/src/MapperBuilder.php | 4 +- .../Constant/MissingClassConstantColon.php | 27 --- .../Exception/Enum/MissingEnumColon.php | 28 --- .../Exception/Iterable/InvalidArrayKey.php | 15 +- .../Template/DuplicatedTemplateName.php | 9 +- .../Template/InvalidClassTemplate.php | 7 +- .../Exception/Template/InvalidTemplate.php | 10 - .../Template/InvalidTemplateType.php | 21 -- .../Factory/LexingTypeParserFactory.php | 11 +- .../valinor/src/Type/Parser/LazyParser.php | 31 --- .../Type/Parser/Lexer/AdvancedClassLexer.php | 4 +- .../src/Type/Parser/Lexer/AliasLexer.php | 4 +- .../src/Type/Parser/Lexer/NativeLexer.php | 2 + .../Lexer/Token/AdvancedClassNameToken.php | 58 +++-- .../Type/Parser/Lexer/Token/ArrayToken.php | 20 +- .../Parser/Lexer/Token/ClassNameToken.php | 26 +-- .../Parser/Lexer/Token/DoubleColonToken.php | 18 ++ .../Type/Parser/Lexer/Token/EnumNameToken.php | 26 +-- .../valinor/src/Type/Parser/LexingParser.php | 48 +--- .../valinor/src/Type/Parser/ParserSymbols.php | 82 +++++++ .../Parser/Template/BasicTemplateParser.php | 53 ----- .../Type/Parser/Template/TemplateParser.php | 18 -- .../valinor/src/Type/Types/ArrayKeyType.php | 52 +++-- .../src/Utility/Reflection/DocParser.php | 217 ++++++++++++++++++ .../src/Utility/Reflection/Reflection.php | 148 ------------ .../src/Utility/String/StringFormatter.php | 14 +- .../Utility/String/StringFormatterError.php | 4 +- 50 files changed, 677 insertions(+), 613 deletions(-) create mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/WarmupCache.php delete mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingClassConstantColon.php delete mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Enum/MissingEnumColon.php delete mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplate.php delete mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplateType.php delete mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/LazyParser.php create mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/DoubleColonToken.php create mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/ParserSymbols.php delete mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Template/BasicTemplateParser.php delete mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Template/TemplateParser.php create mode 100644 wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/Reflection/DocParser.php diff --git a/wcfsetup/install/files/lib/system/api/composer.json b/wcfsetup/install/files/lib/system/api/composer.json index da9210b11e..8717ec93f3 100644 --- a/wcfsetup/install/files/lib/system/api/composer.json +++ b/wcfsetup/install/files/lib/system/api/composer.json @@ -10,7 +10,7 @@ } }, "require": { - "cuyz/valinor": "^1.5.0", + "cuyz/valinor": "^1.6.0", "dragonmantank/cron-expression": "^3.3.3", "erusev/parsedown": "^1.7.4", "ezyang/htmlpurifier": "^4.16", diff --git a/wcfsetup/install/files/lib/system/api/composer.lock b/wcfsetup/install/files/lib/system/api/composer.lock index f17665620c..007747f7d0 100644 --- a/wcfsetup/install/files/lib/system/api/composer.lock +++ b/wcfsetup/install/files/lib/system/api/composer.lock @@ -4,25 +4,25 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "01e02021c96e84abaabbe0d212001568", + "content-hash": "7044d6daf69850dcfd60f482ab45327c", "packages": [ { "name": "cuyz/valinor", - "version": "1.5.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/CuyZ/Valinor.git", - "reference": "668cd3f0f95c57d75981a31d63b5b1422606bc7e" + "reference": "f3f3429d90be77f59903923f9bb5ce93c484dfd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/668cd3f0f95c57d75981a31d63b5b1422606bc7e", - "reference": "668cd3f0f95c57d75981a31d63b5b1422606bc7e", + "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/f3f3429d90be77f59903923f9bb5ce93c484dfd7", + "reference": "f3f3429d90be77f59903923f9bb5ce93c484dfd7", "shasum": "" }, "require": { "composer-runtime-api": "^2.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { @@ -34,7 +34,7 @@ "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", - "rector/rector": "~0.15.0", + "rector/rector": "~0.17.0", "vimeo/psalm": "^5.0" }, "type": "library", @@ -69,7 +69,7 @@ ], "support": { "issues": "https://github.com/CuyZ/Valinor/issues", - "source": "https://github.com/CuyZ/Valinor/tree/1.5.0" + "source": "https://github.com/CuyZ/Valinor/tree/1.6.0" }, "funding": [ { @@ -77,7 +77,7 @@ "type": "github" } ], - "time": "2023-08-07T18:29:08+00:00" + "time": "2023-08-25T10:26:38+00:00" }, { "name": "dragonmantank/cron-expression", diff --git a/wcfsetup/install/files/lib/system/api/composer/autoload_classmap.php b/wcfsetup/install/files/lib/system/api/composer/autoload_classmap.php index 20085d82af..a7bfbf9a4d 100644 --- a/wcfsetup/install/files/lib/system/api/composer/autoload_classmap.php +++ b/wcfsetup/install/files/lib/system/api/composer/autoload_classmap.php @@ -32,6 +32,7 @@ return array( 'CuyZ\\Valinor\\Cache\\FileWatchingCache' => $vendorDir . '/cuyz/valinor/src/Cache/FileWatchingCache.php', 'CuyZ\\Valinor\\Cache\\KeySanitizerCache' => $vendorDir . '/cuyz/valinor/src/Cache/KeySanitizerCache.php', 'CuyZ\\Valinor\\Cache\\RuntimeCache' => $vendorDir . '/cuyz/valinor/src/Cache/RuntimeCache.php', + 'CuyZ\\Valinor\\Cache\\WarmupCache' => $vendorDir . '/cuyz/valinor/src/Cache/WarmupCache.php', 'CuyZ\\Valinor\\Cache\\Warmup\\RecursiveCacheWarmupService' => $vendorDir . '/cuyz/valinor/src/Cache/Warmup/RecursiveCacheWarmupService.php', 'CuyZ\\Valinor\\Definition\\Attributes' => $vendorDir . '/cuyz/valinor/src/Definition/Attributes.php', 'CuyZ\\Valinor\\Definition\\AttributesContainer' => $vendorDir . '/cuyz/valinor/src/Definition/AttributesContainer.php', @@ -196,11 +197,9 @@ return array( 'CuyZ\\Valinor\\Type\\Parser\\CachedParser' => $vendorDir . '/cuyz/valinor/src/Type/Parser/CachedParser.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Constant\\ClassConstantCaseNotFound' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Constant/ClassConstantCaseNotFound.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Constant\\MissingClassConstantCase' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingClassConstantCase.php', - 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Constant\\MissingClassConstantColon' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingClassConstantColon.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Constant\\MissingSpecificClassConstantCase' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingSpecificClassConstantCase.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Enum\\EnumCaseNotFound' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Enum/EnumCaseNotFound.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Enum\\MissingEnumCase' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Enum/MissingEnumCase.php', - 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Enum\\MissingEnumColon' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Enum/MissingEnumColon.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Enum\\MissingSpecificEnumCase' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Enum/MissingSpecificEnumCase.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Generic\\AssignedGenericNotFound' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Generic/AssignedGenericNotFound.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Generic\\CannotAssignGeneric' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Generic/CannotAssignGeneric.php', @@ -243,8 +242,6 @@ return array( 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Scalar\\SameValueForIntegerRange' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Scalar/SameValueForIntegerRange.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Template\\DuplicatedTemplateName' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Template/DuplicatedTemplateName.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Template\\InvalidClassTemplate' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidClassTemplate.php', - 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Template\\InvalidTemplate' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplate.php', - 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Template\\InvalidTemplateType' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplateType.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\UnknownSymbol' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Exception/UnknownSymbol.php', 'CuyZ\\Valinor\\Type\\Parser\\Factory\\LexingTypeParserFactory' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Factory/LexingTypeParserFactory.php', 'CuyZ\\Valinor\\Type\\Parser\\Factory\\Specifications\\AliasSpecification' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Factory/Specifications/AliasSpecification.php', @@ -252,7 +249,6 @@ return array( 'CuyZ\\Valinor\\Type\\Parser\\Factory\\Specifications\\TypeAliasAssignerSpecification' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Factory/Specifications/TypeAliasAssignerSpecification.php', 'CuyZ\\Valinor\\Type\\Parser\\Factory\\Specifications\\TypeParserSpecification' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Factory/Specifications/TypeParserSpecification.php', 'CuyZ\\Valinor\\Type\\Parser\\Factory\\TypeParserFactory' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Factory/TypeParserFactory.php', - 'CuyZ\\Valinor\\Type\\Parser\\LazyParser' => $vendorDir . '/cuyz/valinor/src/Type/Parser/LazyParser.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\AdvancedClassLexer' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/AdvancedClassLexer.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\AliasLexer' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\ClassContextLexer' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/ClassContextLexer.php', @@ -268,6 +264,7 @@ return array( 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\ClosingSquareBracketToken' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/Token/ClosingSquareBracketToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\ColonToken' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/Token/ColonToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\CommaToken' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/Token/CommaToken.php', + 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\DoubleColonToken' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/Token/DoubleColonToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\EnumNameToken' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/Token/EnumNameToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\FloatValueToken' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/Token/FloatValueToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\IntegerToken' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/Token/IntegerToken.php', @@ -290,8 +287,7 @@ return array( 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\TypeAliasLexer' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/TypeAliasLexer.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\TypeLexer' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Lexer/TypeLexer.php', 'CuyZ\\Valinor\\Type\\Parser\\LexingParser' => $vendorDir . '/cuyz/valinor/src/Type/Parser/LexingParser.php', - 'CuyZ\\Valinor\\Type\\Parser\\Template\\BasicTemplateParser' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Template/BasicTemplateParser.php', - 'CuyZ\\Valinor\\Type\\Parser\\Template\\TemplateParser' => $vendorDir . '/cuyz/valinor/src/Type/Parser/Template/TemplateParser.php', + 'CuyZ\\Valinor\\Type\\Parser\\ParserSymbols' => $vendorDir . '/cuyz/valinor/src/Type/Parser/ParserSymbols.php', 'CuyZ\\Valinor\\Type\\Parser\\TypeParser' => $vendorDir . '/cuyz/valinor/src/Type/Parser/TypeParser.php', 'CuyZ\\Valinor\\Type\\ScalarType' => $vendorDir . '/cuyz/valinor/src/Type/ScalarType.php', 'CuyZ\\Valinor\\Type\\StringType' => $vendorDir . '/cuyz/valinor/src/Type/StringType.php', @@ -336,6 +332,7 @@ return array( 'CuyZ\\Valinor\\Utility\\PermissiveTypeFound' => $vendorDir . '/cuyz/valinor/src/Utility/PermissiveTypeFound.php', 'CuyZ\\Valinor\\Utility\\Priority\\HasPriority' => $vendorDir . '/cuyz/valinor/src/Utility/Priority/HasPriority.php', 'CuyZ\\Valinor\\Utility\\Priority\\PrioritizedList' => $vendorDir . '/cuyz/valinor/src/Utility/Priority/PrioritizedList.php', + 'CuyZ\\Valinor\\Utility\\Reflection\\DocParser' => $vendorDir . '/cuyz/valinor/src/Utility/Reflection/DocParser.php', 'CuyZ\\Valinor\\Utility\\Reflection\\PhpParser' => $vendorDir . '/cuyz/valinor/src/Utility/Reflection/PhpParser.php', 'CuyZ\\Valinor\\Utility\\Reflection\\Reflection' => $vendorDir . '/cuyz/valinor/src/Utility/Reflection/Reflection.php', 'CuyZ\\Valinor\\Utility\\Reflection\\TokenParser' => $vendorDir . '/cuyz/valinor/src/Utility/Reflection/TokenParser.php', diff --git a/wcfsetup/install/files/lib/system/api/composer/autoload_static.php b/wcfsetup/install/files/lib/system/api/composer/autoload_static.php index 2dde04ac5a..c837b0ca6c 100644 --- a/wcfsetup/install/files/lib/system/api/composer/autoload_static.php +++ b/wcfsetup/install/files/lib/system/api/composer/autoload_static.php @@ -220,6 +220,7 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d 'CuyZ\\Valinor\\Cache\\FileWatchingCache' => __DIR__ . '/..' . '/cuyz/valinor/src/Cache/FileWatchingCache.php', 'CuyZ\\Valinor\\Cache\\KeySanitizerCache' => __DIR__ . '/..' . '/cuyz/valinor/src/Cache/KeySanitizerCache.php', 'CuyZ\\Valinor\\Cache\\RuntimeCache' => __DIR__ . '/..' . '/cuyz/valinor/src/Cache/RuntimeCache.php', + 'CuyZ\\Valinor\\Cache\\WarmupCache' => __DIR__ . '/..' . '/cuyz/valinor/src/Cache/WarmupCache.php', 'CuyZ\\Valinor\\Cache\\Warmup\\RecursiveCacheWarmupService' => __DIR__ . '/..' . '/cuyz/valinor/src/Cache/Warmup/RecursiveCacheWarmupService.php', 'CuyZ\\Valinor\\Definition\\Attributes' => __DIR__ . '/..' . '/cuyz/valinor/src/Definition/Attributes.php', 'CuyZ\\Valinor\\Definition\\AttributesContainer' => __DIR__ . '/..' . '/cuyz/valinor/src/Definition/AttributesContainer.php', @@ -384,11 +385,9 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d 'CuyZ\\Valinor\\Type\\Parser\\CachedParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/CachedParser.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Constant\\ClassConstantCaseNotFound' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Constant/ClassConstantCaseNotFound.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Constant\\MissingClassConstantCase' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingClassConstantCase.php', - 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Constant\\MissingClassConstantColon' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingClassConstantColon.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Constant\\MissingSpecificClassConstantCase' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingSpecificClassConstantCase.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Enum\\EnumCaseNotFound' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Enum/EnumCaseNotFound.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Enum\\MissingEnumCase' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Enum/MissingEnumCase.php', - 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Enum\\MissingEnumColon' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Enum/MissingEnumColon.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Enum\\MissingSpecificEnumCase' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Enum/MissingSpecificEnumCase.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Generic\\AssignedGenericNotFound' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Generic/AssignedGenericNotFound.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Generic\\CannotAssignGeneric' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Generic/CannotAssignGeneric.php', @@ -431,8 +430,6 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Scalar\\SameValueForIntegerRange' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Scalar/SameValueForIntegerRange.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Template\\DuplicatedTemplateName' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Template/DuplicatedTemplateName.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Template\\InvalidClassTemplate' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidClassTemplate.php', - 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Template\\InvalidTemplate' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplate.php', - 'CuyZ\\Valinor\\Type\\Parser\\Exception\\Template\\InvalidTemplateType' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplateType.php', 'CuyZ\\Valinor\\Type\\Parser\\Exception\\UnknownSymbol' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Exception/UnknownSymbol.php', 'CuyZ\\Valinor\\Type\\Parser\\Factory\\LexingTypeParserFactory' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Factory/LexingTypeParserFactory.php', 'CuyZ\\Valinor\\Type\\Parser\\Factory\\Specifications\\AliasSpecification' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Factory/Specifications/AliasSpecification.php', @@ -440,7 +437,6 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d 'CuyZ\\Valinor\\Type\\Parser\\Factory\\Specifications\\TypeAliasAssignerSpecification' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Factory/Specifications/TypeAliasAssignerSpecification.php', 'CuyZ\\Valinor\\Type\\Parser\\Factory\\Specifications\\TypeParserSpecification' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Factory/Specifications/TypeParserSpecification.php', 'CuyZ\\Valinor\\Type\\Parser\\Factory\\TypeParserFactory' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Factory/TypeParserFactory.php', - 'CuyZ\\Valinor\\Type\\Parser\\LazyParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/LazyParser.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\AdvancedClassLexer' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/AdvancedClassLexer.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\AliasLexer' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\ClassContextLexer' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/ClassContextLexer.php', @@ -456,6 +452,7 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\ClosingSquareBracketToken' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/Token/ClosingSquareBracketToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\ColonToken' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/Token/ColonToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\CommaToken' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/Token/CommaToken.php', + 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\DoubleColonToken' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/Token/DoubleColonToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\EnumNameToken' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/Token/EnumNameToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\FloatValueToken' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/Token/FloatValueToken.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\Token\\IntegerToken' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/Token/IntegerToken.php', @@ -478,8 +475,7 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\TypeAliasLexer' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/TypeAliasLexer.php', 'CuyZ\\Valinor\\Type\\Parser\\Lexer\\TypeLexer' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Lexer/TypeLexer.php', 'CuyZ\\Valinor\\Type\\Parser\\LexingParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/LexingParser.php', - 'CuyZ\\Valinor\\Type\\Parser\\Template\\BasicTemplateParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Template/BasicTemplateParser.php', - 'CuyZ\\Valinor\\Type\\Parser\\Template\\TemplateParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/Template/TemplateParser.php', + 'CuyZ\\Valinor\\Type\\Parser\\ParserSymbols' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/ParserSymbols.php', 'CuyZ\\Valinor\\Type\\Parser\\TypeParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/Parser/TypeParser.php', 'CuyZ\\Valinor\\Type\\ScalarType' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/ScalarType.php', 'CuyZ\\Valinor\\Type\\StringType' => __DIR__ . '/..' . '/cuyz/valinor/src/Type/StringType.php', @@ -524,6 +520,7 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d 'CuyZ\\Valinor\\Utility\\PermissiveTypeFound' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/PermissiveTypeFound.php', 'CuyZ\\Valinor\\Utility\\Priority\\HasPriority' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Priority/HasPriority.php', 'CuyZ\\Valinor\\Utility\\Priority\\PrioritizedList' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Priority/PrioritizedList.php', + 'CuyZ\\Valinor\\Utility\\Reflection\\DocParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Reflection/DocParser.php', 'CuyZ\\Valinor\\Utility\\Reflection\\PhpParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Reflection/PhpParser.php', 'CuyZ\\Valinor\\Utility\\Reflection\\Reflection' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Reflection/Reflection.php', 'CuyZ\\Valinor\\Utility\\Reflection\\TokenParser' => __DIR__ . '/..' . '/cuyz/valinor/src/Utility/Reflection/TokenParser.php', diff --git a/wcfsetup/install/files/lib/system/api/composer/installed.json b/wcfsetup/install/files/lib/system/api/composer/installed.json index 6089d8c0c6..0863aadc5e 100644 --- a/wcfsetup/install/files/lib/system/api/composer/installed.json +++ b/wcfsetup/install/files/lib/system/api/composer/installed.json @@ -2,22 +2,22 @@ "packages": [ { "name": "cuyz/valinor", - "version": "1.5.0", - "version_normalized": "1.5.0.0", + "version": "1.6.0", + "version_normalized": "1.6.0.0", "source": { "type": "git", "url": "https://github.com/CuyZ/Valinor.git", - "reference": "668cd3f0f95c57d75981a31d63b5b1422606bc7e" + "reference": "f3f3429d90be77f59903923f9bb5ce93c484dfd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/668cd3f0f95c57d75981a31d63b5b1422606bc7e", - "reference": "668cd3f0f95c57d75981a31d63b5b1422606bc7e", + "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/f3f3429d90be77f59903923f9bb5ce93c484dfd7", + "reference": "f3f3429d90be77f59903923f9bb5ce93c484dfd7", "shasum": "" }, "require": { "composer-runtime-api": "^2.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { @@ -29,10 +29,10 @@ "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", - "rector/rector": "~0.15.0", + "rector/rector": "~0.17.0", "vimeo/psalm": "^5.0" }, - "time": "2023-08-07T18:29:08+00:00", + "time": "2023-08-25T10:26:38+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -66,7 +66,7 @@ ], "support": { "issues": "https://github.com/CuyZ/Valinor/issues", - "source": "https://github.com/CuyZ/Valinor/tree/1.5.0" + "source": "https://github.com/CuyZ/Valinor/tree/1.6.0" }, "funding": [ { diff --git a/wcfsetup/install/files/lib/system/api/composer/installed.php b/wcfsetup/install/files/lib/system/api/composer/installed.php index 8ff9b620a7..7b29adc6b1 100644 --- a/wcfsetup/install/files/lib/system/api/composer/installed.php +++ b/wcfsetup/install/files/lib/system/api/composer/installed.php @@ -20,9 +20,9 @@ 'dev_requirement' => false, ), 'cuyz/valinor' => array( - 'pretty_version' => '1.5.0', - 'version' => '1.5.0.0', - 'reference' => '668cd3f0f95c57d75981a31d63b5b1422606bc7e', + 'pretty_version' => '1.6.0', + 'version' => '1.6.0.0', + 'reference' => 'f3f3429d90be77f59903923f9bb5ce93c484dfd7', 'type' => 'library', 'install_path' => __DIR__ . '/../cuyz/valinor', 'aliases' => array(), diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/composer.json b/wcfsetup/install/files/lib/system/api/cuyz/valinor/composer.json index 2e7a92015c..c699d56465 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/composer.json +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "composer-runtime-api": "^2.0", "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" }, @@ -29,7 +29,7 @@ "marcocesarato/php-conventional-changelog": "^1.12", "vimeo/psalm": "^5.0", "mikey179/vfsstream": "^1.6.10", - "rector/rector": "~0.15.0" + "rector/rector": "~0.17.0" }, "autoload": { "psr-4": { @@ -64,6 +64,7 @@ "rector" ], "mutation": [ + "@putenv XDEBUG_MODE=off", "infection --threads=max --git-diff-lines" ], "doc": [ diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/ChainCache.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/ChainCache.php index d97fdb4a36..57e609845d 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/ChainCache.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/ChainCache.php @@ -11,9 +11,9 @@ use Traversable; * @internal * * @template EntryType - * @implements CacheInterface + * @implements WarmupCache */ -final class ChainCache implements CacheInterface +final class ChainCache implements WarmupCache { /** @var array> */ private array $delegates; @@ -29,6 +29,15 @@ final class ChainCache implements CacheInterface $this->count = count($delegates); } + public function warmup(): void + { + foreach ($this->delegates as $delegate) { + if ($delegate instanceof WarmupCache) { + $delegate->warmup(); + } + } + } + public function get($key, $default = null): mixed { foreach ($this->delegates as $i => $delegate) { diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/Compiled/CompiledPhpFileCache.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/Compiled/CompiledPhpFileCache.php index 88cbe17963..39ce5d57c0 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/Compiled/CompiledPhpFileCache.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/Compiled/CompiledPhpFileCache.php @@ -7,11 +7,11 @@ namespace CuyZ\Valinor\Cache\Compiled; use CuyZ\Valinor\Cache\Exception\CacheDirectoryNotWritable; use CuyZ\Valinor\Cache\Exception\CompiledPhpCacheFileNotWritten; use CuyZ\Valinor\Cache\Exception\CorruptedCompiledPhpCacheFile; +use CuyZ\Valinor\Cache\WarmupCache; use DateInterval; use DateTime; use Error; use FilesystemIterator; -use Psr\SimpleCache\CacheInterface; use Traversable; use function bin2hex; @@ -30,9 +30,9 @@ use function unlink; * @internal * * @template EntryType - * @implements CacheInterface + * @implements WarmupCache */ -final class CompiledPhpFileCache implements CacheInterface +final class CompiledPhpFileCache implements WarmupCache { private const TEMPORARY_DIR_PERMISSION = 510; @@ -46,6 +46,11 @@ final class CompiledPhpFileCache implements CacheInterface private CacheCompiler $compiler ) {} + public function warmup(): void + { + $this->createTemporaryDir(); + } + public function has($key): bool { $filename = $this->path($key); @@ -74,11 +79,7 @@ final class CompiledPhpFileCache implements CacheInterface $code = $this->compile($value, $ttl); - $tmpDir = $this->cacheDir . DIRECTORY_SEPARATOR . '.valinor.tmp'; - - if (! is_dir($tmpDir) && ! @mkdir($tmpDir, self::TEMPORARY_DIR_PERMISSION, true)) { - throw new CacheDirectoryNotWritable($this->cacheDir); - } + $tmpDir = $this->createTemporaryDir(); /** @infection-ignore-all */ $tmpFilename = $tmpDir . DIRECTORY_SEPARATOR . bin2hex(random_bytes(16)); @@ -228,6 +229,17 @@ final class CompiledPhpFileCache implements CacheInterface return $this->files[$filename]; } + private function createTemporaryDir(): string + { + $tmpDir = $this->cacheDir . DIRECTORY_SEPARATOR . '.valinor.tmp'; + + if (! is_dir($tmpDir) && ! @mkdir($tmpDir, self::TEMPORARY_DIR_PERMISSION, true)) { + throw new CacheDirectoryNotWritable($this->cacheDir); + } + + return $tmpDir; + } + private function path(string $key): string { /** @infection-ignore-all */ diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/FileSystemCache.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/FileSystemCache.php index 0082308e36..ded11aa117 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/FileSystemCache.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/FileSystemCache.php @@ -20,9 +20,9 @@ use function sys_get_temp_dir; * @api * * @template EntryType - * @implements CacheInterface + * @implements WarmupCache */ -final class FileSystemCache implements CacheInterface +final class FileSystemCache implements WarmupCache { /** @var array> */ private array $delegates; @@ -39,6 +39,15 @@ final class FileSystemCache implements CacheInterface ]; } + public function warmup(): void + { + foreach ($this->delegates as $delegate) { + if ($delegate instanceof WarmupCache) { + $delegate->warmup(); + } + } + } + public function has($key): bool { foreach ($this->delegates as $delegate) { diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/FileWatchingCache.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/FileWatchingCache.php index 770d38c689..417762bb08 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/FileWatchingCache.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/FileWatchingCache.php @@ -29,9 +29,9 @@ use function is_string; * * @phpstan-type TimestampsArray = array * @template EntryType - * @implements CacheInterface + * @implements WarmupCache */ -final class FileWatchingCache implements CacheInterface +final class FileWatchingCache implements WarmupCache { /** @var array */ private array $timestamps = []; @@ -41,6 +41,13 @@ final class FileWatchingCache implements CacheInterface private CacheInterface $delegate ) {} + public function warmup(): void + { + if ($this->delegate instanceof WarmupCache) { + $this->delegate->warmup(); + } + } + public function has($key): bool { foreach ($this->timestamps($key) as $fileName => $timestamp) { diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/KeySanitizerCache.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/KeySanitizerCache.php index bd83af13a7..6950e44627 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/KeySanitizerCache.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/KeySanitizerCache.php @@ -15,9 +15,9 @@ use function sha1; * @internal * * @template EntryType - * @implements CacheInterface + * @implements WarmupCache */ -final class KeySanitizerCache implements CacheInterface +final class KeySanitizerCache implements WarmupCache { private static string $version; @@ -38,6 +38,13 @@ final class KeySanitizerCache implements CacheInterface $this->sanitize = static fn (string $key) => sha1("$key." . self::$version ??= PHP_VERSION . '/' . Package::version()); } + public function warmup(): void + { + if ($this->delegate instanceof WarmupCache) { + $this->delegate->warmup(); + } + } + public function get($key, $default = null): mixed { return $this->delegate->get(($this->sanitize)($key), $default); diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/Warmup/RecursiveCacheWarmupService.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/Warmup/RecursiveCacheWarmupService.php index f22beca305..4648fc681d 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/Warmup/RecursiveCacheWarmupService.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/Warmup/RecursiveCacheWarmupService.php @@ -5,15 +5,17 @@ declare(strict_types=1); namespace CuyZ\Valinor\Cache\Warmup; use CuyZ\Valinor\Cache\Exception\InvalidSignatureToWarmup; +use CuyZ\Valinor\Cache\WarmupCache; use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository; use CuyZ\Valinor\Mapper\Object\Factory\ObjectBuilderFactory; use CuyZ\Valinor\Mapper\Tree\Builder\ObjectImplementations; +use CuyZ\Valinor\Type\ClassType; use CuyZ\Valinor\Type\CompositeType; use CuyZ\Valinor\Type\Parser\Exception\InvalidType; use CuyZ\Valinor\Type\Parser\TypeParser; use CuyZ\Valinor\Type\Type; -use CuyZ\Valinor\Type\ClassType; use CuyZ\Valinor\Type\Types\InterfaceType; +use Psr\SimpleCache\CacheInterface; use function in_array; @@ -23,8 +25,12 @@ final class RecursiveCacheWarmupService /** @var list */ private array $classesWarmedUp = []; + private bool $warmupWasDone = false; + public function __construct( private TypeParser $parser, + /** @var CacheInterface */ + private CacheInterface $cache, private ObjectImplementations $implementations, private ClassDefinitionRepository $classDefinitionRepository, private ObjectBuilderFactory $objectBuilderFactory @@ -32,6 +38,14 @@ final class RecursiveCacheWarmupService public function warmup(string ...$signatures): void { + if (! $this->warmupWasDone) { + $this->warmupWasDone = true; + + if ($this->cache instanceof WarmupCache) { + $this->cache->warmup(); + } + } + foreach ($signatures as $signature) { try { $this->warmupType($this->parser->parse($signature)); diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/WarmupCache.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/WarmupCache.php new file mode 100644 index 0000000000..97a4684300 --- /dev/null +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Cache/WarmupCache.php @@ -0,0 +1,16 @@ + + */ +interface WarmupCache extends CacheInterface +{ + public function warmup(): void; +} diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/AttributesContainer.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/AttributesContainer.php index ba6ae279f2..f60353c854 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/AttributesContainer.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/AttributesContainer.php @@ -7,18 +7,28 @@ namespace CuyZ\Valinor\Definition; use Traversable; use function array_filter; +use function array_map; use function array_values; use function count; +use function is_a; -/** @internal */ +/** + * @phpstan-type AttributeParam = array{class: class-string, callback: callable(): object} + * + * @internal + */ final class AttributesContainer implements Attributes { private static self $empty; - /** @var array */ + /** @var list */ private array $attributes; - public function __construct(object ...$attributes) + /** + * @no-named-arguments + * @param AttributeParam ...$attributes + */ + public function __construct(array ...$attributes) { $this->attributes = $attributes; } @@ -31,7 +41,7 @@ final class AttributesContainer implements Attributes public function has(string $className): bool { foreach ($this->attributes as $attribute) { - if ($attribute instanceof $className) { + if (is_a($attribute['class'], $className, true)) { return true; } } @@ -41,9 +51,15 @@ final class AttributesContainer implements Attributes public function ofType(string $className): array { - return array_values(array_filter( + $attributes = array_filter( $this->attributes, - static fn (object $attribute): bool => $attribute instanceof $className + static fn (array $attribute): bool => is_a($attribute['class'], $className, true) + ); + + /** @phpstan-ignore-next-line */ + return array_values(array_map( + fn (array $attribute) => $attribute['callback'](), + $attributes )); } @@ -57,6 +73,8 @@ final class AttributesContainer implements Attributes */ public function getIterator(): Traversable { - return yield from $this->attributes; + foreach ($this->attributes as $attribute) { + yield $attribute['callback'](); + } } } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/NativeAttributes.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/NativeAttributes.php index f4a7b98022..064702aeb9 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/NativeAttributes.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/NativeAttributes.php @@ -32,7 +32,12 @@ final class NativeAttributes implements Attributes array_map( static function (ReflectionAttribute $attribute) { try { - return $attribute->newInstance(); + $instance = $attribute->newInstance(); + + return [ + 'class' => $attribute->getName(), + 'callback' => fn () => $instance + ]; } catch (Error) { // Race condition when the attribute is affected to a property/parameter // that was PROMOTED, in this case the attribute will be applied to both diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Cache/Compiler/AttributesCompiler.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Cache/Compiler/AttributesCompiler.php index a872f9dd4a..8870630787 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Cache/Compiler/AttributesCompiler.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Cache/Compiler/AttributesCompiler.php @@ -10,6 +10,8 @@ use CuyZ\Valinor\Definition\NativeAttributes; use function count; use function implode; +use function is_array; +use function is_object; use function var_export; /** @internal */ @@ -32,24 +34,38 @@ final class AttributesCompiler private function compileNativeAttributes(NativeAttributes $attributes): string { - $attributes = $attributes->definition(); + $attributesListCode = []; - if (count($attributes) === 0) { - return '[]'; + foreach ($attributes->definition() as $className => $arguments) { + $argumentsCode = $this->compileAttributeArguments($arguments); + + $attributesListCode[] = "['class' => '$className', 'callback' => fn () => new $className($argumentsCode)]"; } - $attributesListCode = []; + return implode(', ', $attributesListCode); + } - foreach ($attributes as $className => $arguments) { - if (count($arguments) === 0) { - $argumentsCode = ''; + /** + * @param array $arguments + */ + private function compileAttributeArguments(array $arguments): string + { + if (count($arguments) === 0) { + return ''; + } + + $argumentsCode = []; + + foreach ($arguments as $argument) { + if (is_object($argument)) { + $argumentsCode[] = 'unserialize(' . var_export(serialize($argument), true) . ')'; + } elseif (is_array($argument)) { + $argumentsCode[] = '[' . $this->compileAttributeArguments($argument) . ']'; } else { - $argumentsCode = '...unserialize(' . var_export(serialize($arguments), true) . ')'; + $argumentsCode[] = var_export($argument, true); } - - $attributesListCode[] = "new $className($argumentsCode)"; } - return '...[' . implode(",\n", $attributesListCode) . ']'; + return implode(', ', $argumentsCode); } } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionClassDefinitionRepository.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionClassDefinitionRepository.php index 5140d86552..7824749bd1 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionClassDefinitionRepository.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionClassDefinitionRepository.php @@ -15,6 +15,7 @@ use CuyZ\Valinor\Definition\Properties; use CuyZ\Valinor\Definition\PropertyDefinition; use CuyZ\Valinor\Definition\Repository\AttributesRepository; use CuyZ\Valinor\Definition\Repository\ClassDefinitionRepository; +use CuyZ\Valinor\Type\ClassType; use CuyZ\Valinor\Type\GenericType; use CuyZ\Valinor\Type\Parser\Exception\InvalidType; use CuyZ\Valinor\Type\Parser\Factory\Specifications\AliasSpecification; @@ -23,11 +24,12 @@ use CuyZ\Valinor\Type\Parser\Factory\Specifications\TypeAliasAssignerSpecificati use CuyZ\Valinor\Type\Parser\Factory\TypeParserFactory; use CuyZ\Valinor\Type\Parser\TypeParser; use CuyZ\Valinor\Type\Type; -use CuyZ\Valinor\Type\ClassType; use CuyZ\Valinor\Type\Types\UnresolvableType; use CuyZ\Valinor\Utility\Reflection\Reflection; +use ReflectionClass; use ReflectionMethod; use ReflectionProperty; +use CuyZ\Valinor\Utility\Reflection\DocParser; use function array_filter; use function array_keys; @@ -76,7 +78,7 @@ final class ReflectionClassDefinitionRepository implements ClassDefinitionReposi { return array_map( function (ReflectionProperty $property) use ($type) { - $typeResolver = $this->typeResolver($type, $property->class); + $typeResolver = $this->typeResolver($type, $property->getDeclaringClass()); return $this->propertyBuilder->for($property, $typeResolver); }, @@ -100,21 +102,26 @@ final class ReflectionClassDefinitionRepository implements ClassDefinitionReposi } return array_map(function (ReflectionMethod $method) use ($type) { - $typeResolver = $this->typeResolver($type, $method->class); + $typeResolver = $this->typeResolver($type, $method->getDeclaringClass()); return $this->methodBuilder->for($method, $typeResolver); }, $methods); } - private function typeResolver(ClassType $type, string $targetClass): ReflectionTypeResolver + /** + * @param ReflectionClass $target + */ + private function typeResolver(ClassType $type, ReflectionClass $target): ReflectionTypeResolver { - $typeKey = "{$type->toString()}/$targetClass"; + $typeKey = $target->isInterface() + ? "{$type->toString()}/{$type->className()}" + : "{$type->toString()}/$target->name"; if (isset($this->typeResolver[$typeKey])) { return $this->typeResolver[$typeKey]; } - while ($type->className() !== $targetClass) { + while ($type->className() !== $target->name) { $type = $type->parent(); } @@ -156,7 +163,7 @@ final class ReflectionClassDefinitionRepository implements ClassDefinitionReposi private function localTypeAliases(ClassType $type): array { $reflection = Reflection::class($type->className()); - $rawTypes = Reflection::localTypeAliases($reflection); + $rawTypes = DocParser::localTypeAliases($reflection); $typeParser = $this->typeParser($type); @@ -181,7 +188,7 @@ final class ReflectionClassDefinitionRepository implements ClassDefinitionReposi private function importedTypeAliases(ClassType $type): array { $reflection = Reflection::class($type->className()); - $importedTypesRaw = Reflection::importedTypeAliases($reflection); + $importedTypesRaw = DocParser::importedTypeAliases($reflection); $typeParser = $this->typeParser($type); diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionTypeResolver.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionTypeResolver.php index ca6a4e1d1e..b2e5391030 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionTypeResolver.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Definition/Repository/Reflection/ReflectionTypeResolver.php @@ -10,6 +10,7 @@ use CuyZ\Valinor\Type\Parser\TypeParser; use CuyZ\Valinor\Type\Type; use CuyZ\Valinor\Type\Types\MixedType; use CuyZ\Valinor\Type\Types\UnresolvableType; +use CuyZ\Valinor\Utility\Reflection\DocParser; use CuyZ\Valinor\Utility\Reflection\Reflection; use ReflectionFunctionAbstract; use ReflectionParameter; @@ -23,7 +24,7 @@ final class ReflectionTypeResolver private TypeParser $advancedParser ) {} - public function resolveType(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): Type + public function resolveType(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection): Type { $nativeType = $this->nativeType($reflection); $typeFromDocBlock = $this->typeFromDocBlock($reflection); @@ -51,11 +52,24 @@ final class ReflectionTypeResolver return $typeFromDocBlock; } - private function typeFromDocBlock(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): ?Type + private function typeFromDocBlock(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection): ?Type { - $type = $reflection instanceof ReflectionFunctionAbstract - ? Reflection::docBlockReturnType($reflection) - : Reflection::docBlockType($reflection); + if ($reflection instanceof ReflectionFunctionAbstract) { + $type = DocParser::functionReturnType($reflection); + } elseif ($reflection instanceof ReflectionProperty) { + $type = DocParser::propertyType($reflection); + } else { + $type = null; + + if ($reflection->isPromoted()) { + // @phpstan-ignore-next-line / parameter is promoted so class exists for sure + $type = DocParser::propertyType($reflection->getDeclaringClass()->getProperty($reflection->name)); + } + + if ($type === null) { + $type = DocParser::parameterType($reflection); + } + } if ($type === null) { return null; @@ -64,7 +78,7 @@ final class ReflectionTypeResolver return $this->parseType($type, $reflection, $this->advancedParser); } - private function nativeType(\ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection): ?Type + private function nativeType(ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection): ?Type { $reflectionType = $reflection instanceof ReflectionFunctionAbstract ? $reflection->getReturnType() @@ -83,7 +97,7 @@ final class ReflectionTypeResolver return $this->parseType($type, $reflection, $this->nativeParser); } - private function parseType(string $raw, \ReflectionProperty|\ReflectionParameter|\ReflectionFunctionAbstract $reflection, TypeParser $parser): Type + private function parseType(string $raw, ReflectionProperty|ReflectionParameter|ReflectionFunctionAbstract $reflection, TypeParser $parser): Type { try { return $parser->parse($raw); diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Library/Container.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Library/Container.php index 3fc9618f3c..eb19d8bbd2 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Library/Container.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Library/Container.php @@ -50,8 +50,6 @@ use CuyZ\Valinor\Mapper\TypeTreeMapper; use CuyZ\Valinor\Type\ClassType; use CuyZ\Valinor\Type\Parser\Factory\LexingTypeParserFactory; use CuyZ\Valinor\Type\Parser\Factory\TypeParserFactory; -use CuyZ\Valinor\Type\Parser\Template\BasicTemplateParser; -use CuyZ\Valinor\Type\Parser\Template\TemplateParser; use CuyZ\Valinor\Type\Parser\TypeParser; use CuyZ\Valinor\Type\ScalarType; use CuyZ\Valinor\Type\Types\ArrayType; @@ -196,16 +194,13 @@ final class Container AttributesRepository::class => fn () => new NativeAttributesRepository(), - TypeParserFactory::class => fn () => new LexingTypeParserFactory( - $this->get(TemplateParser::class) - ), + TypeParserFactory::class => fn () => new LexingTypeParserFactory(), TypeParser::class => fn () => $this->get(TypeParserFactory::class)->get(), - TemplateParser::class => fn () => new BasicTemplateParser(), - RecursiveCacheWarmupService::class => fn () => new RecursiveCacheWarmupService( $this->get(TypeParser::class), + $this->get(CacheInterface::class), $this->get(ObjectImplementations::class), $this->get(ClassDefinitionRepository::class), $this->get(ObjectBuilderFactory::class) diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Library/Settings.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Library/Settings.php index 143eac2f3f..54d2617d7d 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Library/Settings.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Library/Settings.php @@ -14,7 +14,11 @@ use Throwable; final class Settings { /** @var non-empty-array */ - public const DEFAULT_SUPPORTED_DATETIME_FORMATS = [DATE_ATOM, 'U']; + public const DEFAULT_SUPPORTED_DATETIME_FORMATS = [ + 'Y-m-d\\TH:i:sP', // RFC 3339 + 'Y-m-d\\TH:i:s.uP', // RFC 3339 with microseconds + 'U', // Unix Timestamp + ]; /** @var array */ public array $inferredMapping = []; diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Mapper/Object/DateTimeFormatConstructor.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Mapper/Object/DateTimeFormatConstructor.php index 2e2c53f82c..98298f22ad 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Mapper/Object/DateTimeFormatConstructor.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Mapper/Object/DateTimeFormatConstructor.php @@ -14,7 +14,7 @@ use DateTimeInterface; * date formats should be allowed during mapping. * * By default, if this constructor is never registered, the dates will accept - * any valid timestamp or ATOM-formatted value. + * any valid timestamp or RFC 3339-formatted value. * * Usage: * diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Mapper/Tree/Builder/ArrayNodeBuilder.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Mapper/Tree/Builder/ArrayNodeBuilder.php index bcacaca5a6..2ab1340aa7 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Mapper/Tree/Builder/ArrayNodeBuilder.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Mapper/Tree/Builder/ArrayNodeBuilder.php @@ -54,12 +54,13 @@ final class ArrayNodeBuilder implements NodeBuilder $children = []; foreach ($values as $key => $value) { + $child = $shell->child((string)$key, $subType); + if (! $keyType->accepts($key)) { - throw new InvalidTraversableKey($key, $keyType); + $children[$key] = TreeNode::error($child, new InvalidTraversableKey($key, $keyType)); + } else { + $children[$key] = $rootBuilder->build($child->withValue($value)); } - - $child = $shell->child((string)$key, $subType)->withValue($value); - $children[$key] = $rootBuilder->build($child); } return $children; diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/MapperBuilder.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/MapperBuilder.php index 30c191fac5..3cce949ef1 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/MapperBuilder.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/MapperBuilder.php @@ -219,7 +219,7 @@ final class MapperBuilder /** * Describes which date formats will be supported during mapping. * - * By default, the dates will accept any valid timestamp or ATOM-formatted + * By default, the dates will accept any valid timestamp or RFC 3339-formatted * value. * * ```php @@ -244,7 +244,7 @@ final class MapperBuilder /** * Returns the date formats supported during mapping. * - * By default, any valid timestamp or ATOM-formatted value are accepted. + * By default, any valid timestamp or RFC 3339-formatted value are accepted. * Custom formats can be set using method `supportDateFormats()`. * * @return non-empty-array diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingClassConstantColon.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingClassConstantColon.php deleted file mode 100644 index 6838823c0b..0000000000 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Constant/MissingClassConstantColon.php +++ /dev/null @@ -1,27 +0,0 @@ - $enumName - */ - public function __construct(string $enumName, string $case) - { - if ($case === ':') { - $case = '?'; - } - - parent::__construct( - "Missing second colon symbol for enum `$enumName::$case`.", - 1653468435 - ); - } -} diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Iterable/InvalidArrayKey.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Iterable/InvalidArrayKey.php index 243687c256..a94089aaec 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Iterable/InvalidArrayKey.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Iterable/InvalidArrayKey.php @@ -6,26 +6,15 @@ namespace CuyZ\Valinor\Type\Parser\Exception\Iterable; use CuyZ\Valinor\Type\Parser\Exception\InvalidType; use CuyZ\Valinor\Type\Type; -use CuyZ\Valinor\Type\Types\ArrayType; -use CuyZ\Valinor\Type\Types\NonEmptyArrayType; use RuntimeException; /** @internal */ final class InvalidArrayKey extends RuntimeException implements InvalidType { - /** - * @param class-string $arrayType - */ - public function __construct(string $arrayType, Type $keyType, Type $subType) + public function __construct(Type $keyType) { - $signature = "array<{$keyType->toString()}, {$subType->toString()}>"; - - if ($arrayType === NonEmptyArrayType::class) { - $signature = "non-empty-array<{$keyType->toString()}, {$subType->toString()}>"; - } - parent::__construct( - "Invalid key type `{$keyType->toString()}` for `$signature`. It must be one of `array-key`, `int` or `string`.", + "Invalid array key type `{$keyType->toString()}`, it must be a valid string or integer.", 1604335007 ); } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/DuplicatedTemplateName.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/DuplicatedTemplateName.php index 7f599ef787..c15e06f7ec 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/DuplicatedTemplateName.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/DuplicatedTemplateName.php @@ -7,12 +7,15 @@ namespace CuyZ\Valinor\Type\Parser\Exception\Template; use LogicException; /** @internal */ -final class DuplicatedTemplateName extends LogicException implements InvalidTemplate +final class DuplicatedTemplateName extends LogicException { - public function __construct(string $template) + /** + * @param class-string $className + */ + public function __construct(string $className, string $template) { parent::__construct( - "The template `$template` was defined at least twice.", + "The template `$template` in class `$className` was defined at least twice.", 1604612898 ); } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidClassTemplate.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidClassTemplate.php index b70e07ff20..c09077328d 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidClassTemplate.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidClassTemplate.php @@ -4,18 +4,19 @@ declare(strict_types=1); namespace CuyZ\Valinor\Type\Parser\Exception\Template; +use CuyZ\Valinor\Type\Parser\Exception\InvalidType; use LogicException; /** @internal */ -final class InvalidClassTemplate extends LogicException implements InvalidTemplate +final class InvalidClassTemplate extends LogicException { /** * @param class-string $className */ - public function __construct(string $className, InvalidTemplate $exception) + public function __construct(string $className, string $template, InvalidType $exception) { parent::__construct( - "Template error for class `$className`: {$exception->getMessage()}", + "Invalid template `$template` for class `$className`: {$exception->getMessage()}", 1630092678, $exception ); diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplate.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplate.php deleted file mode 100644 index 5e4594e466..0000000000 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Exception/Template/InvalidTemplate.php +++ /dev/null @@ -1,10 +0,0 @@ -getMessage()}", - 1607445951, - $exception - ); - } -} diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Factory/LexingTypeParserFactory.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Factory/LexingTypeParserFactory.php index 08d0eea3ae..facde9206e 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Factory/LexingTypeParserFactory.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Factory/LexingTypeParserFactory.php @@ -9,7 +9,6 @@ use CuyZ\Valinor\Type\Parser\Factory\Specifications\TypeParserSpecification; use CuyZ\Valinor\Type\Parser\Lexer\AdvancedClassLexer; use CuyZ\Valinor\Type\Parser\Lexer\NativeLexer; use CuyZ\Valinor\Type\Parser\LexingParser; -use CuyZ\Valinor\Type\Parser\Template\TemplateParser; use CuyZ\Valinor\Type\Parser\TypeParser; /** @internal */ @@ -17,8 +16,6 @@ final class LexingTypeParserFactory implements TypeParserFactory { private TypeParser $nativeParser; - public function __construct(private TemplateParser $templateParser) {} - public function get(TypeParserSpecification ...$specifications): TypeParser { if (empty($specifications)) { @@ -26,7 +23,7 @@ final class LexingTypeParserFactory implements TypeParserFactory } $lexer = new NativeLexer(); - $lexer = new AdvancedClassLexer($lexer, $this, $this->templateParser); + $lexer = new AdvancedClassLexer($lexer, $this); foreach ($specifications as $specification) { $lexer = $specification->transform($lexer); @@ -38,9 +35,9 @@ final class LexingTypeParserFactory implements TypeParserFactory private function nativeParser(): TypeParser { $lexer = new NativeLexer(); - $lexer = new AdvancedClassLexer($lexer, $this, $this->templateParser); - $lexer = new LexingParser($lexer); + $lexer = new AdvancedClassLexer($lexer, $this); + $parser = new LexingParser($lexer); - return new CachedParser($lexer); + return new CachedParser($parser); } } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/LazyParser.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/LazyParser.php deleted file mode 100644 index ade312624c..0000000000 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/LazyParser.php +++ /dev/null @@ -1,31 +0,0 @@ -callback = $callback; - } - - public function parse(string $raw): Type - { - $this->delegate ??= ($this->callback)(); - - return $this->delegate->parse($raw); - } -} diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/AdvancedClassLexer.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/AdvancedClassLexer.php index 0ac28d38eb..6601ef8962 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/AdvancedClassLexer.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/AdvancedClassLexer.php @@ -8,7 +8,6 @@ use CuyZ\Valinor\Type\Parser\Factory\TypeParserFactory; use CuyZ\Valinor\Type\Parser\Lexer\Token\ClassNameToken; use CuyZ\Valinor\Type\Parser\Lexer\Token\AdvancedClassNameToken; use CuyZ\Valinor\Type\Parser\Lexer\Token\Token; -use CuyZ\Valinor\Type\Parser\Template\TemplateParser; /** @internal */ final class AdvancedClassLexer implements TypeLexer @@ -16,7 +15,6 @@ final class AdvancedClassLexer implements TypeLexer public function __construct( private TypeLexer $delegate, private TypeParserFactory $typeParserFactory, - private TemplateParser $templateParser ) {} public function tokenize(string $symbol): Token @@ -24,7 +22,7 @@ final class AdvancedClassLexer implements TypeLexer $token = $this->delegate->tokenize($symbol); if ($token instanceof ClassNameToken) { - return new AdvancedClassNameToken($token, $this->typeParserFactory, $this->templateParser); + return new AdvancedClassNameToken($token, $this->typeParserFactory); } return $token; diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php index 96c2ac469d..d5320a30ed 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/AliasLexer.php @@ -31,7 +31,9 @@ final class AliasLexer implements TypeLexer private function resolve(string $symbol): string { - if (Reflection::classOrInterfaceExists($symbol)) { + // Matches the case where a class extends a class with the same name but + // in a different namespace. + if ($symbol === $this->reflection->getShortName() && Reflection::classOrInterfaceExists($symbol)) { return $symbol; } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/NativeLexer.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/NativeLexer.php index 9111ecda24..f319f35672 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/NativeLexer.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/NativeLexer.php @@ -12,6 +12,7 @@ use CuyZ\Valinor\Type\Parser\Lexer\Token\ClosingCurlyBracketToken; use CuyZ\Valinor\Type\Parser\Lexer\Token\ClosingSquareBracketToken; use CuyZ\Valinor\Type\Parser\Lexer\Token\ColonToken; use CuyZ\Valinor\Type\Parser\Lexer\Token\CommaToken; +use CuyZ\Valinor\Type\Parser\Lexer\Token\DoubleColonToken; use CuyZ\Valinor\Type\Parser\Lexer\Token\EnumNameToken; use CuyZ\Valinor\Type\Parser\Lexer\Token\FloatValueToken; use CuyZ\Valinor\Type\Parser\Lexer\Token\IntegerToken; @@ -53,6 +54,7 @@ final class NativeLexer implements TypeLexer ']' => ClosingSquareBracketToken::get(), '{' => OpeningCurlyBracketToken::get(), '}' => ClosingCurlyBracketToken::get(), + '::' => DoubleColonToken::get(), ':' => ColonToken::get(), '?' => NullableToken::get(), ',' => CommaToken::get(), diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/AdvancedClassNameToken.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/AdvancedClassNameToken.php index e5bafa96a6..adb3dc2e2c 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/AdvancedClassNameToken.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/AdvancedClassNameToken.php @@ -17,20 +17,20 @@ use CuyZ\Valinor\Type\Parser\Exception\Generic\ExtendTagTypeError; use CuyZ\Valinor\Type\Parser\Exception\Generic\SeveralExtendTagsFound; use CuyZ\Valinor\Type\Parser\Exception\InvalidType; use CuyZ\Valinor\Type\Parser\Exception\Template\InvalidClassTemplate; -use CuyZ\Valinor\Type\Parser\Exception\Template\InvalidTemplate; use CuyZ\Valinor\Type\Parser\Factory\Specifications\AliasSpecification; use CuyZ\Valinor\Type\Parser\Factory\Specifications\ClassContextSpecification; use CuyZ\Valinor\Type\Parser\Factory\Specifications\TypeAliasAssignerSpecification; +use CuyZ\Valinor\Type\Parser\Factory\Specifications\TypeParserSpecification; use CuyZ\Valinor\Type\Parser\Factory\TypeParserFactory; -use CuyZ\Valinor\Type\Parser\LazyParser; use CuyZ\Valinor\Type\Parser\Lexer\TokenStream; -use CuyZ\Valinor\Type\Parser\Template\TemplateParser; use CuyZ\Valinor\Type\Parser\TypeParser; use CuyZ\Valinor\Type\StringType; use CuyZ\Valinor\Type\Type; use CuyZ\Valinor\Type\Types\ArrayKeyType; use CuyZ\Valinor\Type\ClassType; +use CuyZ\Valinor\Type\Types\MixedType; use CuyZ\Valinor\Type\Types\NativeClassType; +use CuyZ\Valinor\Utility\Reflection\DocParser; use CuyZ\Valinor\Utility\Reflection\Reflection; use ReflectionClass; @@ -45,7 +45,6 @@ final class AdvancedClassNameToken implements TraversingToken public function __construct( private ClassNameToken $delegate, private TypeParserFactory $typeParserFactory, - private TemplateParser $templateParser ) {} public function traverse(TokenStream $stream): Type @@ -65,25 +64,14 @@ final class AdvancedClassNameToken implements TraversingToken new AliasSpecification($reflection), ]; - try { - $docComment = $reflection->getDocComment() ?: ''; - $parser = new LazyParser( - fn () => $this->typeParserFactory->get(...$specifications) - ); - - $templates = $this->templateParser->templates($docComment, $parser); - } catch (InvalidTemplate $exception) { - throw new InvalidClassTemplate($className, $exception); - } + $templates = $this->templatesTypes($reflection, ...$specifications); $generics = $this->generics($stream, $className, $templates); $generics = $this->assignGenerics($className, $templates, $generics); - $parserWithGenerics = new LazyParser( - fn () => $this->typeParserFactory->get(new TypeAliasAssignerSpecification($generics), ...$specifications) - ); - if ($parentReflection) { + $parserWithGenerics = $this->typeParserFactory->get(new TypeAliasAssignerSpecification($generics), ...$specifications); + $parentType = $this->parentType($reflection, $parentReflection, $parserWithGenerics); } @@ -95,6 +83,38 @@ final class AdvancedClassNameToken implements TraversingToken return $this->delegate->symbol(); } + /** + * @param ReflectionClass $reflection + * @return array + */ + private function templatesTypes(ReflectionClass $reflection, TypeParserSpecification ...$specifications): array + { + $templates = DocParser::classTemplates($reflection); + + if ($templates === []) { + return []; + } + + $types = []; + + foreach ($templates as $templateName => $type) { + try { + if ($type === '') { + $types[$templateName] = MixedType::get(); + } else { + /** @infection-ignore-all */ + $parser ??= $this->typeParserFactory->get(...$specifications); + + $types[$templateName] = $parser->parse($type); + } + } catch (InvalidType $invalidType) { + throw new InvalidClassTemplate($reflection->name, $templateName, $invalidType); + } + } + + return $types; + } + /** * @param array $templates * @param class-string $className @@ -182,7 +202,7 @@ final class AdvancedClassNameToken implements TraversingToken */ private function parentType(ReflectionClass $reflection, ReflectionClass $parentReflection, TypeParser $typeParser): NativeClassType { - $extendedClass = Reflection::extendedClassAnnotation($reflection); + $extendedClass = DocParser::classExtendsTypes($reflection); if (count($extendedClass) > 1) { throw new SeveralExtendTagsFound($reflection); diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/ArrayToken.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/ArrayToken.php index 6d37b433e3..8d1563f069 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/ArrayToken.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/ArrayToken.php @@ -5,17 +5,14 @@ declare(strict_types=1); namespace CuyZ\Valinor\Type\Parser\Lexer\Token; use CuyZ\Valinor\Type\CompositeTraversableType; -use CuyZ\Valinor\Type\IntegerType; use CuyZ\Valinor\Type\Parser\Exception\Iterable\ArrayClosingBracketMissing; use CuyZ\Valinor\Type\Parser\Exception\Iterable\ArrayCommaMissing; -use CuyZ\Valinor\Type\Parser\Exception\Iterable\InvalidArrayKey; use CuyZ\Valinor\Type\Parser\Exception\Iterable\ShapedArrayClosingBracketMissing; use CuyZ\Valinor\Type\Parser\Exception\Iterable\ShapedArrayColonTokenMissing; use CuyZ\Valinor\Type\Parser\Exception\Iterable\ShapedArrayCommaMissing; use CuyZ\Valinor\Type\Parser\Exception\Iterable\ShapedArrayElementTypeMissing; use CuyZ\Valinor\Type\Parser\Exception\Iterable\ShapedArrayEmptyElements; use CuyZ\Valinor\Type\Parser\Lexer\TokenStream; -use CuyZ\Valinor\Type\StringType; use CuyZ\Valinor\Type\Type; use CuyZ\Valinor\Type\Types\ArrayKeyType; use CuyZ\Valinor\Type\Types\ArrayType; @@ -84,17 +81,10 @@ final class ArrayToken implements TraversingToken throw new ArrayCommaMissing($this->arrayType, $type); } + $keyType = ArrayKeyType::from($type); $subType = $stream->read(); - if ($type instanceof ArrayKeyType) { - $arrayType = new ($this->arrayType)($type, $subType); - } elseif ($type instanceof IntegerType) { - $arrayType = new ($this->arrayType)(ArrayKeyType::integer(), $subType); - } elseif ($type instanceof StringType) { - $arrayType = new ($this->arrayType)(ArrayKeyType::string(), $subType); - } else { - throw new InvalidArrayKey($this->arrayType, $type, $subType); - } + $arrayType = new ($this->arrayType)($keyType, $subType); if ($stream->done() || ! $stream->forward() instanceof ClosingBracketToken) { throw new ArrayClosingBracketMissing($arrayType); @@ -120,6 +110,10 @@ final class ArrayToken implements TraversingToken throw new ShapedArrayCommaMissing($elements); } + if ($stream->done()) { + throw new ShapedArrayClosingBracketMissing($elements); + } + if ($stream->next() instanceof ClosingCurlyBracketToken) { $stream->forward(); break; @@ -134,7 +128,7 @@ final class ArrayToken implements TraversingToken } if ($stream->done()) { - $elements[] = new ShapedArrayElement(new StringValueType((string)$index), $type); + $elements[] = new ShapedArrayElement(new IntegerValueType($index), $type); throw new ShapedArrayClosingBracketMissing($elements); } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/ClassNameToken.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/ClassNameToken.php index d95a5be34f..f3be92690a 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/ClassNameToken.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/ClassNameToken.php @@ -6,7 +6,6 @@ namespace CuyZ\Valinor\Type\Parser\Lexer\Token; use CuyZ\Valinor\Type\Parser\Exception\Constant\ClassConstantCaseNotFound; use CuyZ\Valinor\Type\Parser\Exception\Constant\MissingClassConstantCase; -use CuyZ\Valinor\Type\Parser\Exception\Constant\MissingClassConstantColon; use CuyZ\Valinor\Type\Parser\Exception\Constant\MissingSpecificClassConstantCase; use CuyZ\Valinor\Type\Parser\Lexer\TokenStream; use CuyZ\Valinor\Type\Type; @@ -58,37 +57,22 @@ final class ClassNameToken implements TraversingToken private function classConstant(TokenStream $stream): ?Type { - if ($stream->done() || ! $stream->next() instanceof ColonToken) { + if ($stream->done() || ! $stream->next() instanceof DoubleColonToken) { return null; } - $case = $stream->forward(); - $missingColon = true; + $stream->forward(); - if (! $stream->done()) { - $case = $stream->forward(); - - $missingColon = ! $case instanceof ColonToken; - } - - if (! $missingColon) { - if ($stream->done()) { - throw new MissingClassConstantCase($this->reflection->name); - } - - $case = $stream->forward(); + if ($stream->done()) { + throw new MissingClassConstantCase($this->reflection->name); } - $symbol = $case->symbol(); + $symbol = $stream->forward()->symbol(); if ($symbol === '*') { throw new MissingSpecificClassConstantCase($this->reflection->name); } - if ($missingColon) { - throw new MissingClassConstantColon($this->reflection->name, $symbol); - } - $cases = []; if (! preg_match('/\*\s*\*/', $symbol)) { diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/DoubleColonToken.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/DoubleColonToken.php new file mode 100644 index 0000000000..a38a2eaa19 --- /dev/null +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Lexer/Token/DoubleColonToken.php @@ -0,0 +1,18 @@ +done() || ! $stream->next() instanceof ColonToken) { + if ($stream->done() || ! $stream->next() instanceof DoubleColonToken) { return null; } - $case = $stream->forward(); - $missingColon = true; + $stream->forward(); - if (! $stream->done()) { - $case = $stream->forward(); - - $missingColon = ! $case instanceof ColonToken; - } - - if (! $missingColon) { - if ($stream->done()) { - throw new MissingEnumCase($this->enumName); - } - - $case = $stream->forward(); + if ($stream->done()) { + throw new MissingEnumCase($this->enumName); } - $symbol = $case->symbol(); + $symbol = $stream->forward()->symbol(); if ($symbol === '*') { throw new MissingSpecificEnumCase($this->enumName); } - if ($missingColon) { - throw new MissingEnumColon($this->enumName, $symbol); - } - return EnumType::fromPattern($this->enumName, $symbol); } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/LexingParser.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/LexingParser.php index a1a8379c27..116de4ce0f 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/LexingParser.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/LexingParser.php @@ -1,67 +1,25 @@ splitTokens($raw); - $symbols = array_map('trim', $symbols); - $symbols = array_filter($symbols, static fn ($value) => $value !== ''); + $symbols = new ParserSymbols($raw); $tokens = array_map( fn (string $symbol) => $this->lexer->tokenize($symbol), - $symbols + $symbols->all() ); return (new TokenStream(...$tokens))->read(); } - - /** - * @return string[] - */ - private function splitTokens(string $raw): array - { - if (str_contains($raw, "@anonymous\0")) { - return $this->splitTokensContainingAnonymousClass($raw); - } - - /** @phpstan-ignore-next-line */ - return preg_split('/([\s?|&<>,\[\]{}:\'"])/', $raw, -1, PREG_SPLIT_DELIM_CAPTURE); - } - - /** - * @return string[] - */ - private function splitTokensContainingAnonymousClass(string $raw): array - { - /** @var string[] $splits */ - $splits = preg_split('/([a-zA-Z_\x7f-\xff][\\\\\w\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:\d++\$)[\da-fA-F]++)/', $raw, -1, PREG_SPLIT_DELIM_CAPTURE); - $symbols = []; - - foreach ($splits as $symbol) { - if (str_contains($symbol, "@anonymous\0")) { - $symbols[] = $symbol; - } else { - $symbols = [...$symbols, ...$this->splitTokens($symbol)]; - } - } - - return $symbols; - } } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/ParserSymbols.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/ParserSymbols.php new file mode 100644 index 0000000000..15053aec54 --- /dev/null +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/ParserSymbols.php @@ -0,0 +1,82 @@ +', '[', ']', '{', '}', ':', '?', ',', "'", '"']; + + /** @var list */ + private array $symbols = []; + + public function __construct(string $string) + { + $current = null; + $quote = null; + + foreach (str_split($string) as $char) { + if ($char === $quote) { + $quote = null; + } elseif ($char === '"' || $char === "'") { + $quote = $char; + } elseif ($quote !== null || ! in_array($char, self::OPERATORS, true)) { + $current .= $char; + continue; + } + + if ($current !== null) { + $this->symbols[] = $current; + $current = null; + } + + $this->symbols[] = $char; + } + + if ($current !== null) { + $this->symbols[] = $current; + } + + $this->symbols = array_map('trim', $this->symbols); + $this->symbols = array_filter($this->symbols, static fn ($value) => $value !== ''); + + $this->mergeDoubleColons(); + $this->detectAnonymousClass(); + } + + /** + * @return list + */ + public function all(): array + { + return $this->symbols; + } + + private function mergeDoubleColons(): void + { + foreach ($this->symbols as $key => $symbol) { + /** @infection-ignore-all should not happen so it is not tested */ + if ($key === 0) { + continue; + } + + if ($symbol === ':' && $this->symbols[$key - 1] === ':') { + $this->symbols[$key - 1] = '::'; + unset($this->symbols[$key]); + } + } + } + + private function detectAnonymousClass(): void + { + foreach ($this->symbols as $key => $symbol) { + if (! str_starts_with($symbol, "class@anonymous\0")) { + continue; + } + + $this->symbols[$key] = $symbol . $this->symbols[$key + 1] . $this->symbols[$key + 2]; + + array_splice($this->symbols, $key + 1, 2); + } + } +} diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Template/BasicTemplateParser.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Template/BasicTemplateParser.php deleted file mode 100644 index be9f40f30f..0000000000 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Template/BasicTemplateParser.php +++ /dev/null @@ -1,53 +0,0 @@ -'\",-:\\\\\[\]{}]+))?/", $source, $raw); - - /** @var string[] $list */ - $list = $raw[2]; - - if (empty($list)) { - return []; - } - - foreach ($list as $key => $name) { - if (isset($templates[$name])) { - throw new DuplicatedTemplateName($name); - } - - $boundTypeSymbol = trim($raw[4][$key]); - - if (empty($boundTypeSymbol)) { - $templates[$name] = MixedType::get(); - continue; - } - - try { - $templates[$name] = $typeParser->parse($boundTypeSymbol); - } catch (InvalidType $invalidType) { - throw new InvalidTemplateType($boundTypeSymbol, $name, $invalidType); - } - } - - return $templates; - } -} diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Template/TemplateParser.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Template/TemplateParser.php deleted file mode 100644 index 1155c909ce..0000000000 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Parser/Template/TemplateParser.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @throws InvalidTemplate - */ - public function templates(string $source, TypeParser $typeParser): array; -} diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Types/ArrayKeyType.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Types/ArrayKeyType.php index 2655d3b44d..dd0bd84777 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Types/ArrayKeyType.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Type/Types/ArrayKeyType.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace CuyZ\Valinor\Type\Types; +use CuyZ\Valinor\Type\CombiningType; use CuyZ\Valinor\Type\IntegerType; +use CuyZ\Valinor\Type\Parser\Exception\Iterable\InvalidArrayKey; use CuyZ\Valinor\Type\StringType; use CuyZ\Valinor\Type\Type; @@ -13,32 +15,34 @@ use function is_int; /** @internal */ final class ArrayKeyType implements Type { + private static self $default; + private static self $integer; private static self $string; - private static self $integerAndString; - - /** @var array */ + /** @var array */ private array $types; private string $signature; - /** - * @codeCoverageIgnore - * @infection-ignore-all - */ - private function __construct(IntegerType|StringType ...$types) + private function __construct(Type $type) { - $this->types = $types; - $this->signature = count($this->types) === 1 - ? $this->types[0]->toString() - : 'array-key'; + $this->signature = $type->toString(); + $this->types = $type instanceof CombiningType + ? [...$type->types()] + : [$type]; + + foreach ($this->types as $subType) { + if (! $subType instanceof IntegerType && ! $subType instanceof StringType) { + throw new InvalidArrayKey($subType); + } + } } public static function default(): self { - return self::$integerAndString ??= new self(NativeIntegerType::get(), NativeStringType::get()); + return self::$default ??= new self(new UnionType(NativeIntegerType::get(), NativeStringType::get())); } public static function integer(): self @@ -51,16 +55,24 @@ final class ArrayKeyType implements Type return self::$string ??= new self(NativeStringType::get()); } - public function accepts(mixed $value): bool + public static function from(Type $type): ?self { - // If an array key can be evaluated as an integer, it will always be - // cast to an integer, even if the actual key is a string. - if (is_int($value)) { - return true; - } + return match (true) { + $type instanceof self => $type, + $type instanceof NativeIntegerType => self::integer(), + $type instanceof NativeStringType => self::string(), + default => new self($type), + }; + } + public function accepts(mixed $value): bool + { foreach ($this->types as $type) { - if ($type->accepts($value)) { + // If an array key can be evaluated as an integer, it will always be + // cast to an integer, even if the actual key is a string. + if (is_int($value) && $type instanceof NativeStringType) { + return true; + } elseif ($type->accepts($value)) { return true; } } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/Reflection/DocParser.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/Reflection/DocParser.php new file mode 100644 index 0000000000..4acc47ddc7 --- /dev/null +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/Reflection/DocParser.php @@ -0,0 +1,217 @@ +getDocComment()); + + if ($doc === null) { + return null; + } + + return self::annotationType($doc, 'var'); + } + + public static function parameterType(ReflectionParameter $reflection): ?string + { + $doc = self::sanitizeDocComment($reflection->getDeclaringFunction()->getDocComment()); + + if ($doc === null) { + return null; + } + + if (! preg_match("/(?.*)\\$$reflection->name(\s|\z)/s", $doc, $matches)) { + return null; + } + + return self::annotationType($matches['type'], 'param'); + } + + public static function functionReturnType(ReflectionFunctionAbstract $reflection): ?string + { + $doc = self::sanitizeDocComment($reflection->getDocComment()); + + if ($doc === null) { + return null; + } + + return self::annotationType($doc, 'return'); + } + + /** + * @param ReflectionClass $reflection + * @return array + */ + public static function localTypeAliases(ReflectionClass $reflection): array + { + $doc = self::sanitizeDocComment($reflection->getDocComment()); + + if ($doc === null) { + return []; + } + + $types = []; + + preg_match_all('/@(phpstan|psalm)-type\s+(?[a-zA-Z]\w*)\s*=?\s*(?.*)/', $doc, $matches); + + foreach ($matches['name'] as $key => $name) { + /** @var string $name */ + $types[$name] = self::findType($matches['type'][$key]); + } + + return $types; + } + + /** + * @param ReflectionClass $reflection + * @return array + */ + public static function importedTypeAliases(ReflectionClass $reflection): array + { + $doc = self::sanitizeDocComment($reflection->getDocComment()); + + if ($doc === null) { + return []; + } + + $types = []; + + preg_match_all('/@(phpstan|psalm)-import-type\s+(?[a-zA-Z]\w*)\s*from\s*(?\w+)/', $doc, $matches); + + foreach ($matches['name'] as $key => $name) { + /** @var class-string $class */ + $class = $matches['class'][$key]; + + $types[$class][] = $name; + } + + return $types; + } + + /** + * @param ReflectionClass $reflection + * @return array + */ + public static function classExtendsTypes(ReflectionClass $reflection): array + { + $doc = self::sanitizeDocComment($reflection->getDocComment()); + + if ($doc === null) { + return []; + } + + preg_match_all('/@(phpstan-|psalm-)?extends\s+(?.+)/', $doc, $matches); + + return $matches['type']; + } + + /** + * @param ReflectionClass $reflection + * @return array + */ + public static function classTemplates(ReflectionClass $reflection): array + { + $doc = self::sanitizeDocComment($reflection->getDocComment()); + + if ($doc === null) { + return []; + } + + $templates = []; + + preg_match_all("/@(phpstan-|psalm-)?template\s+(?\w+)(\s+of\s+(?.+))?/", $doc, $matches); + + foreach ($matches['name'] as $key => $name) { + /** @var string $name */ + if (isset($templates[$name])) { + throw new DuplicatedTemplateName($reflection->name, $name); + } + + $templates[$name] = self::findType($matches['type'][$key]); + } + + return $templates; + } + + private static function annotationType(string $string, string $annotation): ?string + { + foreach (["@phpstan-$annotation", "@psalm-$annotation", "@$annotation"] as $case) { + $pos = strrpos($string, $case); + + if ($pos !== false) { + return self::findType(substr($string, $pos + strlen($case))); + } + } + + return null; + } + + private static function findType(string $string): string + { + $operatorsMatrix = [ + '{' => '}', + '<' => '>', + '"' => '"', + "'" => "'", + ]; + + $type = ''; + $operators = []; + $expectExpression = true; + + $string = str_replace("\n", ' ', $string); + $chars = str_split($string); + + foreach ($chars as $key => $char) { + if ($operators === []) { + if ($char === '|' || $char === '&') { + $expectExpression = true; + } elseif (! $expectExpression && $chars[$key - 1] === ' ') { + break; + } elseif ($char !== ' ') { + $expectExpression = false; + } + } + + if (isset($operatorsMatrix[$char])) { + $operators[] = $operatorsMatrix[$char]; + } elseif ($operators !== [] && $char === end($operators)) { + array_pop($operators); + } + + $type .= $char; + } + + return trim($type); + } + + private static function sanitizeDocComment(string|false $doc): ?string + { + /** @infection-ignore-all mutating `$doc` to `true` makes no sense */ + if ($doc === false) { + return null; + } + + $doc = preg_replace('#^\s*/\*\*([^/]+)\*/\s*$#', '$1', $doc); + + return preg_replace('/^\s*\*\s*(\S*)/m', '$1', $doc); // @phpstan-ignore-line + } +} diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/Reflection/Reflection.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/Reflection/Reflection.php index 4c1c82d4fc..307f7f51ed 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/Reflection/Reflection.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/Reflection/Reflection.php @@ -7,7 +7,6 @@ namespace CuyZ\Valinor\Utility\Reflection; use Closure; use ReflectionClass; use ReflectionFunction; -use ReflectionFunctionAbstract; use ReflectionIntersectionType; use ReflectionMethod; use ReflectionNamedType; @@ -18,25 +17,15 @@ use ReflectionUnionType; use Reflector; use RuntimeException; -use function assert; use function class_exists; -use function count; use function implode; use function interface_exists; -use function is_array; -use function preg_match_all; -use function preg_replace; use function spl_object_hash; use function str_contains; -use function trim; /** @internal */ final class Reflection { - private const TOOL_NONE = ''; - private const TOOL_EXPRESSION = '((?psalm|phpstan)-)'; - private const TYPE_EXPRESSION = '(?[\w\s?|&<>\'",-:\\\\\[\]{}*]+)'; - /** @var array> */ private static array $classReflection = []; @@ -133,141 +122,4 @@ final class Reflection return $name; } - - public static function docBlockType(\ReflectionProperty|\ReflectionParameter $reflection): ?string - { - if ($reflection instanceof ReflectionProperty) { - return self::parseDocBlock( - self::sanitizeDocComment($reflection), - sprintf('@%s?var\s+%s', self::TOOL_EXPRESSION, self::TYPE_EXPRESSION) - ); - } - - if ($reflection->isPromoted()) { - $type = self::parseDocBlock( - // @phpstan-ignore-next-line / parameter is promoted so class exists for sure - self::sanitizeDocComment($reflection->getDeclaringClass()->getProperty($reflection->name)), - sprintf('@%s?var\s+%s', self::TOOL_EXPRESSION, self::TYPE_EXPRESSION) - ); - - if ($type !== null) { - return $type; - } - } - - return self::parseDocBlock( - self::sanitizeDocComment($reflection->getDeclaringFunction()), - sprintf('@%s?param\s+%s\s+\$\b%s\b', self::TOOL_EXPRESSION, self::TYPE_EXPRESSION, $reflection->name) - ); - } - - private static function parseDocBlock(string $docComment, string $expression): ?string - { - if (! preg_match_all("/$expression/", $docComment, $matches)) { - return null; - } - - foreach ($matches['tool'] as $index => $tool) { - if ($tool === self::TOOL_NONE) { - continue; - } - - return trim($matches['type'][$index]); - } - - return trim($matches['type'][0]); - } - - public static function docBlockReturnType(ReflectionFunctionAbstract $reflection): ?string - { - $docComment = self::sanitizeDocComment($reflection); - - $expression = sprintf('/@%s?return\s+%s/', self::TOOL_EXPRESSION, self::TYPE_EXPRESSION); - - if (! preg_match_all($expression, $docComment, $matches)) { - return null; - } - - foreach ($matches['tool'] as $index => $tool) { - if ($tool === self::TOOL_NONE) { - continue; - } - - return trim($matches['type'][$index]); - } - - return trim($matches['type'][0]); - } - - /** - * @param ReflectionClass $reflection - * @return array - */ - public static function localTypeAliases(ReflectionClass $reflection): array - { - $types = []; - $docComment = self::sanitizeDocComment($reflection); - - $expression = sprintf('/@(phpstan|psalm)-type\s+([a-zA-Z]\w*)\s*=?\s*%s/', self::TYPE_EXPRESSION); - - preg_match_all($expression, $docComment, $matches); - - foreach ($matches[2] as $key => $name) { - $types[(string)$name] = $matches[3][$key]; - } - - return $types; - } - - /** - * @param ReflectionClass $reflection - * @return array - */ - public static function importedTypeAliases(ReflectionClass $reflection): array - { - $types = []; - $docComment = self::sanitizeDocComment($reflection); - - $expression = sprintf('/@(phpstan|psalm)-import-type\s+([a-zA-Z]\w*)\s*from\s*%s/', self::TYPE_EXPRESSION); - preg_match_all($expression, $docComment, $matches); - - foreach ($matches[2] as $key => $name) { - /** @var class-string $classString */ - $classString = $matches[3][$key]; - - $types[$classString][] = $name; - } - - return $types; - } - - /** - * @param ReflectionClass $reflection - * @return array - */ - public static function extendedClassAnnotation(ReflectionClass $reflection): array - { - $docComment = self::sanitizeDocComment($reflection); - - $expression = sprintf('/@%s?extends\s+%s/', self::TOOL_EXPRESSION, self::TYPE_EXPRESSION); - preg_match_all($expression, $docComment, $matches); - - assert(is_array($matches['type'])); - - if (count($matches['type']) === 0) { - return []; - } - - return $matches['type']; - } - - /** - * @param ReflectionClass|ReflectionProperty|ReflectionFunctionAbstract $reflection - */ - private static function sanitizeDocComment(\ReflectionClass|\ReflectionProperty|ReflectionFunctionAbstract $reflection): string - { - $docComment = preg_replace('#^\s*/\*\*([^/]+)\*/\s*$#', '$1', $reflection->getDocComment() ?: ''); - - return trim(preg_replace('/^\s*\*\s*(\S*)/m', '$1', $docComment)); // @phpstan-ignore-line - } } diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/String/StringFormatter.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/String/StringFormatter.php index 4fa5d286d0..7a70da5e07 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/String/StringFormatter.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/String/StringFormatter.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace CuyZ\Valinor\Utility\String; use CuyZ\Valinor\Mapper\Tree\Message\HasParameters; +use IntlException; use MessageFormatter; use function class_exists; @@ -37,8 +38,17 @@ final class StringFormatter */ private static function formatWithIntl(string $locale, string $body, array $parameters): string { - return MessageFormatter::formatMessage($locale, $body, $parameters) - ?: throw new StringFormatterError($body, intl_get_error_message()); + try { + $formatted = MessageFormatter::formatMessage($locale, $body, $parameters); + + if ($formatted === false) { + throw new StringFormatterError($body, intl_get_error_message()); + } + + return $formatted; + } catch (IntlException $e) { + throw new StringFormatterError($body, $e->getMessage(), $e); + } } /** diff --git a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/String/StringFormatterError.php b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/String/StringFormatterError.php index f99729377b..191fe8516d 100644 --- a/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/String/StringFormatterError.php +++ b/wcfsetup/install/files/lib/system/api/cuyz/valinor/src/Utility/String/StringFormatterError.php @@ -9,11 +9,11 @@ use RuntimeException; /** @internal */ final class StringFormatterError extends RuntimeException { - public function __construct(string $body, string $message = '') + public function __construct(string $body, string $message = '', ?\Throwable $previous = null) { if ($message !== '') { $message = ": $message"; } - parent::__construct("Message formatter error using `$body`$message.", 1652901203); + parent::__construct("Message formatter error using `$body`$message.", 1652901203, $previous); } } -- 2.20.1