From 7799c7e2bf830646ebd0a3edfdfcff4a6062060a Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 12:23:59 +0800 Subject: [PATCH 01/31] Started Reorganizing folders --- src/Internal/{ => Ast}/ContractVisitor.php | 6 +----- src/Internal/{Visitor => Ast}/FunctionContractInjector.php | 2 +- src/Internal/{Visitor => Ast}/NodeBuilder.php | 2 +- src/Internal/{Visitor => Ast}/PropertyHookInjector.php | 2 +- src/Internal/{ => Ast}/ScopeCleaner.php | 2 +- src/Internal/{Visitor => Ast}/ScopeManager.php | 2 +- src/Internal/RuntimeTypeChecker.php | 1 + src/Internal/StreamWrapper.php | 1 + tests/Visitor/FunctionContractInjectorTest.php | 2 +- tests/Visitor/NodeBuilderTest.php | 2 +- tests/Visitor/PropertyHookInjectorTest.php | 2 +- tests/Visitor/ScopeManagerTest.php | 2 +- 12 files changed, 12 insertions(+), 14 deletions(-) rename src/Internal/{ => Ast}/ContractVisitor.php (97%) rename src/Internal/{Visitor => Ast}/FunctionContractInjector.php (99%) rename src/Internal/{Visitor => Ast}/NodeBuilder.php (98%) rename src/Internal/{Visitor => Ast}/PropertyHookInjector.php (99%) rename src/Internal/{ => Ast}/ScopeCleaner.php (91%) rename src/Internal/{Visitor => Ast}/ScopeManager.php (98%) diff --git a/src/Internal/ContractVisitor.php b/src/Internal/Ast/ContractVisitor.php similarity index 97% rename from src/Internal/ContractVisitor.php rename to src/Internal/Ast/ContractVisitor.php index fc03ad47..3aaa59f6 100644 --- a/src/Internal/ContractVisitor.php +++ b/src/Internal/Ast/ContractVisitor.php @@ -2,15 +2,11 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Ast; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; use TypePHP\Contract\DocblockExtractor; -use TypePHP\Internal\Visitor\FunctionContractInjector; -use TypePHP\Internal\Visitor\NodeBuilder; -use TypePHP\Internal\Visitor\PropertyHookInjector; -use TypePHP\Internal\Visitor\ScopeManager; /** * @internal AST Node Visitor that injects contract checks, scope tracking, property hook validation, and parameter/return wrappers into functions and methods. diff --git a/src/Internal/Visitor/FunctionContractInjector.php b/src/Internal/Ast/FunctionContractInjector.php similarity index 99% rename from src/Internal/Visitor/FunctionContractInjector.php rename to src/Internal/Ast/FunctionContractInjector.php index c7326214..bebbf5d0 100644 --- a/src/Internal/Visitor/FunctionContractInjector.php +++ b/src/Internal/Ast/FunctionContractInjector.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal\Visitor; +namespace TypePHP\Internal\Ast; use PhpParser\Node; use PhpParser\NodeTraverser; diff --git a/src/Internal/Visitor/NodeBuilder.php b/src/Internal/Ast/NodeBuilder.php similarity index 98% rename from src/Internal/Visitor/NodeBuilder.php rename to src/Internal/Ast/NodeBuilder.php index cdd4a98d..0f752bd6 100644 --- a/src/Internal/Visitor/NodeBuilder.php +++ b/src/Internal/Ast/NodeBuilder.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal\Visitor; +namespace TypePHP\Internal\Ast; use PhpParser\Node; diff --git a/src/Internal/Visitor/PropertyHookInjector.php b/src/Internal/Ast/PropertyHookInjector.php similarity index 99% rename from src/Internal/Visitor/PropertyHookInjector.php rename to src/Internal/Ast/PropertyHookInjector.php index 15cb9401..f3b677e1 100644 --- a/src/Internal/Visitor/PropertyHookInjector.php +++ b/src/Internal/Ast/PropertyHookInjector.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal\Visitor; +namespace TypePHP\Internal\Ast; use PhpParser\Node; use PhpParser\NodeTraverser; diff --git a/src/Internal/ScopeCleaner.php b/src/Internal/Ast/ScopeCleaner.php similarity index 91% rename from src/Internal/ScopeCleaner.php rename to src/Internal/Ast/ScopeCleaner.php index 18a22ba9..fc48f51c 100644 --- a/src/Internal/ScopeCleaner.php +++ b/src/Internal/Ast/ScopeCleaner.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Ast; use TypePHP\Resolver\TemplateManager; diff --git a/src/Internal/Visitor/ScopeManager.php b/src/Internal/Ast/ScopeManager.php similarity index 98% rename from src/Internal/Visitor/ScopeManager.php rename to src/Internal/Ast/ScopeManager.php index d6b31871..797c6707 100644 --- a/src/Internal/Visitor/ScopeManager.php +++ b/src/Internal/Ast/ScopeManager.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal\Visitor; +namespace TypePHP\Internal\Ast; use PhpParser\Node; use PHPStan\PhpDocParser\Parser\TokenIterator; diff --git a/src/Internal/RuntimeTypeChecker.php b/src/Internal/RuntimeTypeChecker.php index bcf3c779..d1a30c33 100644 --- a/src/Internal/RuntimeTypeChecker.php +++ b/src/Internal/RuntimeTypeChecker.php @@ -7,6 +7,7 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Ast\ScopeCleaner; use TypePHP\Internal\Checker\GeneratorChecker; use TypePHP\Internal\Checker\InlineChecker; use TypePHP\Internal\Checker\ParamChecker; diff --git a/src/Internal/StreamWrapper.php b/src/Internal/StreamWrapper.php index d9945748..2ec64668 100644 --- a/src/Internal/StreamWrapper.php +++ b/src/Internal/StreamWrapper.php @@ -9,6 +9,7 @@ use PhpParser\NodeTraverser; use PhpParser\NodeVisitor\CloningVisitor; use PhpParser\ParserFactory; +use TypePHP\Internal\Ast\ContractVisitor; use TypePHP\Resolver\SpecialTypeResolver; /** diff --git a/tests/Visitor/FunctionContractInjectorTest.php b/tests/Visitor/FunctionContractInjectorTest.php index 5ccc2b9e..f5b72175 100644 --- a/tests/Visitor/FunctionContractInjectorTest.php +++ b/tests/Visitor/FunctionContractInjectorTest.php @@ -5,7 +5,7 @@ use PhpParser\Comment\Doc; use PhpParser\Node; use TypePHP\Internal\Config; -use TypePHP\Internal\Visitor\FunctionContractInjector; +use TypePHP\Internal\Ast\FunctionContractInjector; describe('FunctionContractInjector Unit Tests', function () { beforeEach(function () { diff --git a/tests/Visitor/NodeBuilderTest.php b/tests/Visitor/NodeBuilderTest.php index fbbda9d2..8192220c 100644 --- a/tests/Visitor/NodeBuilderTest.php +++ b/tests/Visitor/NodeBuilderTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use PhpParser\Node; -use TypePHP\Internal\Visitor\NodeBuilder; +use TypePHP\Internal\Ast\NodeBuilder; describe('NodeBuilder Unit Tests', function () { test('createPropertyCheckCall creates FuncCall node for RuntimeTypeChecker::checkProperty', function () { diff --git a/tests/Visitor/PropertyHookInjectorTest.php b/tests/Visitor/PropertyHookInjectorTest.php index 71aaccc2..c678975b 100644 --- a/tests/Visitor/PropertyHookInjectorTest.php +++ b/tests/Visitor/PropertyHookInjectorTest.php @@ -9,7 +9,7 @@ use PhpParser\Comment\Doc; use PhpParser\Node; use TypePHP\Internal\Config; -use TypePHP\Internal\Visitor\PropertyHookInjector; +use TypePHP\Internal\Ast\PropertyHookInjector; describe('PropertyHookInjector Unit Tests', function () { beforeEach(function () { diff --git a/tests/Visitor/ScopeManagerTest.php b/tests/Visitor/ScopeManagerTest.php index 005a8a4c..43ca448a 100644 --- a/tests/Visitor/ScopeManagerTest.php +++ b/tests/Visitor/ScopeManagerTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use PhpParser\Node; -use TypePHP\Internal\Visitor\ScopeManager; +use TypePHP\Internal\Ast\ScopeManager; describe('ScopeManager Unit Tests', function () { test('manages scoped variable stack frames', function () { From 87f77ba3c34b05c29fda41b102d8d49f2ed83f7d Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 14:47:23 +0800 Subject: [PATCH 02/31] Progress on Reorganizing files and folders --- bin/typephp | 2 +- src/Internal/Ast/ContractVisitor.php | 2 +- src/Internal/Ast/FunctionContractInjector.php | 18 +++++++++--------- src/Internal/Ast/NodeBuilder.php | 4 ++-- src/Internal/Ast/PropertyHookInjector.php | 4 ++-- src/Internal/Ast/ScopeCleaner.php | 2 +- src/Internal/Ast/ScopeManager.php | 4 ++-- src/Internal/Checker/GeneratorChecker.php | 6 +++--- src/Internal/Checker/InlineChecker.php | 8 ++++---- src/Internal/Checker/ParamChecker.php | 12 ++++++------ src/Internal/Checker/ReturnChecker.php | 6 +++--- .../Cli}/CacheClearCommand.php | 2 +- .../Cli}/CacheRebuildCommand.php | 2 +- .../Cli}/CacheWarmCommand.php | 2 +- src/{Command => Internal/Cli}/CliFormatter.php | 2 +- .../Cli}/CommandInterface.php | 2 +- .../Cli}/CommandRunner.php | 2 +- .../Cli}/ConfigInitCommand.php | 2 +- src/{Command => Internal/Cli}/HelpCommand.php | 2 +- src/{Command => Internal/Cli}/RunCommand.php | 2 +- src/Internal/Config.php | 4 ++-- src/Internal/{ => Diagnostic}/ErrorFactory.php | 4 ++-- src/Internal/{ => Diagnostic}/ErrorMessage.php | 2 +- .../{ => Diagnostic}/TypeFormatter.php | 2 +- .../Docblock}/ContractParser.php | 2 +- .../Docblock}/DocblockExtractor.php | 3 +-- .../{ => Docblock}/DocblockNormalizer.php | 2 +- .../Generics}/TemplateManager.php | 10 +++++----- .../Generics}/TemplateSubstitutor.php | 2 +- src/Internal/RuntimeTypeChecker.php | 4 ++-- src/Resolver/SpecialTypeResolver.php | 6 +++--- src/TypePHP.php | 2 +- src/Validator/ArrayShapeValidator.php | 6 +++--- src/Validator/ArrayValidator.php | 6 +++--- src/Validator/ConstValidator.php | 6 +++--- src/Validator/GenericValidator.php | 6 +++--- src/Validator/IdentifierValidator.php | 6 +++--- src/Validator/IntersectionValidator.php | 2 +- src/Validator/NullableValidator.php | 2 +- src/Validator/ObjectShapeValidator.php | 6 +++--- src/Validator/TypeValidatorInterface.php | 2 +- src/Validator/TypeValidatorRegistry.php | 2 +- src/Validator/UnionValidator.php | 6 +++--- src/Wrapper/CallableWrapper.php | 10 +++++----- src/Wrapper/IterableWrapper.php | 8 ++++---- tests/Command/CommandRunnerTest.php | 2 +- tests/Contract/DocblockExtractorTest.php | 2 +- tests/Internal/ContractParserTest.php | 2 +- tests/Internal/DocblockNormalizerTest.php | 2 +- tests/Internal/ErrorFactoryTest.php | 4 ++-- tests/Internal/RuntimeTypeCheckerTest.php | 2 +- tests/Internal/TypeFormatterTest.php | 2 +- tests/Resolver/SpecialTypeResolverTest.php | 2 +- tests/Resolver/TemplateManagerTest.php | 4 ++-- tests/Resolver/TemplateSubstitutorTest.php | 2 +- tests/RuntimeChecker/GeneratorCheckerTest.php | 2 +- tests/RuntimeChecker/InlineCheckerTest.php | 4 ++-- tests/RuntimeChecker/ParamCheckerTest.php | 2 +- tests/RuntimeChecker/ReturnCheckerTest.php | 2 +- .../Boundaries/ParamContractsTest.php | 2 +- .../GenericTraitsUseAnnotationTest.php | 2 +- .../UnspecializedArrayKeyGenericTest.php | 2 +- .../UnspecializedGenericDefaultTest.php | 2 +- .../ConstructorPropertyTypeMismatchTest.php | 2 +- tests/Unit/ValidatorsTest.php | 2 +- 65 files changed, 121 insertions(+), 122 deletions(-) rename src/{Command => Internal/Cli}/CacheClearCommand.php (95%) rename src/{Command => Internal/Cli}/CacheRebuildCommand.php (93%) rename src/{Command => Internal/Cli}/CacheWarmCommand.php (97%) rename src/{Command => Internal/Cli}/CliFormatter.php (98%) rename src/{Command => Internal/Cli}/CommandInterface.php (93%) rename src/{Command => Internal/Cli}/CommandRunner.php (98%) rename src/{Command => Internal/Cli}/ConfigInitCommand.php (99%) rename src/{Command => Internal/Cli}/HelpCommand.php (97%) rename src/{Command => Internal/Cli}/RunCommand.php (98%) rename src/Internal/{ => Diagnostic}/ErrorFactory.php (98%) rename src/Internal/{ => Diagnostic}/ErrorMessage.php (89%) rename src/Internal/{ => Diagnostic}/TypeFormatter.php (98%) rename src/{Contract => Internal/Docblock}/ContractParser.php (99%) rename src/{Contract => Internal/Docblock}/DocblockExtractor.php (99%) rename src/Internal/{ => Docblock}/DocblockNormalizer.php (98%) rename src/{Resolver => Internal/Generics}/TemplateManager.php (99%) rename src/{Resolver => Internal/Generics}/TemplateSubstitutor.php (99%) diff --git a/bin/typephp b/bin/typephp index 33b63c8f..4f8f0448 100644 --- a/bin/typephp +++ b/bin/typephp @@ -15,7 +15,7 @@ foreach ($autoloadFiles as $file) { } } -use TypePHP\Command\CommandRunner; +use TypePHP\Internal\Cli\CommandRunner; $exitCode = CommandRunner::run(array_slice($argv, 1)); exit($exitCode); \ No newline at end of file diff --git a/src/Internal/Ast/ContractVisitor.php b/src/Internal/Ast/ContractVisitor.php index 3aaa59f6..6850a476 100644 --- a/src/Internal/Ast/ContractVisitor.php +++ b/src/Internal/Ast/ContractVisitor.php @@ -6,7 +6,7 @@ use PhpParser\Node; use PhpParser\NodeVisitorAbstract; -use TypePHP\Contract\DocblockExtractor; +use TypePHP\Internal\Docblock\DocblockExtractor; /** * @internal AST Node Visitor that injects contract checks, scope tracking, property hook validation, and parameter/return wrappers into functions and methods. diff --git a/src/Internal/Ast/FunctionContractInjector.php b/src/Internal/Ast/FunctionContractInjector.php index bebbf5d0..ed3d7674 100644 --- a/src/Internal/Ast/FunctionContractInjector.php +++ b/src/Internal/Ast/FunctionContractInjector.php @@ -217,7 +217,7 @@ private static function buildSetupScopeStmt(array $params, Node\Expr $thisArg): $ifStmt = new Node\Stmt\If_( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpErr'), $checkCall), - new Node\Name('\TypePHP\Internal\ErrorMessage') + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') ), ['stmts' => [$throwStmt]] ); @@ -373,7 +373,7 @@ public static function buildTypeErrorThrowStmt(Node\Expr $errorVar): Node\Stmt\E return new Node\Stmt\Expression( new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\ErrorFactory'), + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( @@ -417,7 +417,7 @@ public static function buildVoidReturnGuard(Node\Expr\FuncCall $checkCall): arra $ifStmt = new Node\Stmt\If_( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpRet'), $checkCall), - new Node\Name('\TypePHP\Internal\ErrorMessage') + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') ), ['stmts' => [self::buildTypeErrorThrowStmt(new Node\Expr\Variable('__typephpRet'))]] ); @@ -434,11 +434,11 @@ public static function buildTernaryReturnExpr(Node\Expr\FuncCall $checkCall): No return new Node\Expr\Ternary( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpRet'), $checkCall), - new Node\Name('\TypePHP\Internal\ErrorMessage') + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\ErrorFactory'), + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( @@ -473,11 +473,11 @@ public static function buildWrappedYieldNode(Node\Expr\Yield_ $n, Node\Expr $thi $n->value = new Node\Expr\Ternary( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpYld'), $checkYieldCall), - new Node\Name('\TypePHP\Internal\ErrorMessage') + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\ErrorFactory'), + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( @@ -509,11 +509,11 @@ public static function buildWrappedYieldNode(Node\Expr\Yield_ $n, Node\Expr $thi return new Node\Expr\Ternary( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpSnd'), $checkSendCall), - new Node\Name('\TypePHP\Internal\ErrorMessage') + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\ErrorFactory'), + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( diff --git a/src/Internal/Ast/NodeBuilder.php b/src/Internal/Ast/NodeBuilder.php index 0f752bd6..b754903c 100644 --- a/src/Internal/Ast/NodeBuilder.php +++ b/src/Internal/Ast/NodeBuilder.php @@ -65,11 +65,11 @@ public static function createTernaryThrowExpr(Node\Expr\FuncCall $checkCall, int new Node\Expr\Variable('__typephpVal'), $checkCall ), - new Node\Name('\TypePHP\Internal\ErrorMessage') + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\ErrorFactory'), + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', $args ) diff --git a/src/Internal/Ast/PropertyHookInjector.php b/src/Internal/Ast/PropertyHookInjector.php index f3b677e1..88e9d8b6 100644 --- a/src/Internal/Ast/PropertyHookInjector.php +++ b/src/Internal/Ast/PropertyHookInjector.php @@ -90,11 +90,11 @@ private static function buildExpressionSetHookTernary(Node\Expr\FuncCall $checkC return new Node\Expr\Ternary( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpVal'), $checkCall), - new Node\Name('\TypePHP\Internal\ErrorMessage') + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\ErrorFactory'), + new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( diff --git a/src/Internal/Ast/ScopeCleaner.php b/src/Internal/Ast/ScopeCleaner.php index fc48f51c..a85e4426 100644 --- a/src/Internal/Ast/ScopeCleaner.php +++ b/src/Internal/Ast/ScopeCleaner.php @@ -4,7 +4,7 @@ namespace TypePHP\Internal\Ast; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Generics\TemplateManager; /** * @internal ensures proper scope cleanup for variable tracking. diff --git a/src/Internal/Ast/ScopeManager.php b/src/Internal/Ast/ScopeManager.php index 797c6707..96127410 100644 --- a/src/Internal/Ast/ScopeManager.php +++ b/src/Internal/Ast/ScopeManager.php @@ -6,8 +6,8 @@ use PhpParser\Node; use PHPStan\PhpDocParser\Parser\TokenIterator; -use TypePHP\Contract\DocblockExtractor; -use TypePHP\Internal\DocblockNormalizer; +use TypePHP\Internal\Docblock\DocblockExtractor; +use TypePHP\Internal\Dockblock\DocblockNormalizer; /** * @internal Manages lexical scope stack frames and extracts local @var variable annotations. diff --git a/src/Internal/Checker/GeneratorChecker.php b/src/Internal/Checker/GeneratorChecker.php index 75163772..9c0f02ad 100644 --- a/src/Internal/Checker/GeneratorChecker.php +++ b/src/Internal/Checker/GeneratorChecker.php @@ -8,10 +8,10 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Resolver\SpecialTypeResolver; -use TypePHP\Resolver\TemplateManager; -use TypePHP\Resolver\TemplateSubstitutor; +use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; /** diff --git a/src/Internal/Checker/InlineChecker.php b/src/Internal/Checker/InlineChecker.php index d8361aef..2900bb1e 100644 --- a/src/Internal/Checker/InlineChecker.php +++ b/src/Internal/Checker/InlineChecker.php @@ -24,12 +24,12 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Config; -use TypePHP\Internal\DocblockNormalizer; +use TypePHP\Internal\Dockblock\DocblockNormalizer; use TypePHP\Resolver\SpecialTypeResolver; -use TypePHP\Resolver\TemplateManager; -use TypePHP\Resolver\TemplateSubstitutor; +use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; use TypePHP\Wrapper\CallableWrapper; diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index 7f30db1f..78243944 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -13,16 +13,16 @@ use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Contract\HierarchyResolver; use TypePHP\Internal\ClassNameValidator; use TypePHP\Internal\Config; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Diagnostic\TypeFormatter; use TypePHP\Resolver\SpecialTypeResolver; -use TypePHP\Resolver\TemplateManager; -use TypePHP\Resolver\TemplateSubstitutor; +use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; /** diff --git a/src/Internal/Checker/ReturnChecker.php b/src/Internal/Checker/ReturnChecker.php index cd96abf4..7d07b01b 100644 --- a/src/Internal/Checker/ReturnChecker.php +++ b/src/Internal/Checker/ReturnChecker.php @@ -13,13 +13,13 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use ReflectionClass; use Traversable; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Contract\HierarchyResolver; use TypePHP\Internal\ClassNameValidator; use TypePHP\Internal\Config; use TypePHP\Resolver\SpecialTypeResolver; -use TypePHP\Resolver\TemplateManager; -use TypePHP\Resolver\TemplateSubstitutor; +use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; use TypePHP\Wrapper\CallableWrapper; diff --git a/src/Command/CacheClearCommand.php b/src/Internal/Cli/CacheClearCommand.php similarity index 95% rename from src/Command/CacheClearCommand.php rename to src/Internal/Cli/CacheClearCommand.php index a92671a4..8ca7d1f7 100644 --- a/src/Command/CacheClearCommand.php +++ b/src/Internal/Cli/CacheClearCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; use TypePHP\Internal\CacheManager; diff --git a/src/Command/CacheRebuildCommand.php b/src/Internal/Cli/CacheRebuildCommand.php similarity index 93% rename from src/Command/CacheRebuildCommand.php rename to src/Internal/Cli/CacheRebuildCommand.php index 3441fcfc..3a6373bb 100644 --- a/src/Command/CacheRebuildCommand.php +++ b/src/Internal/Cli/CacheRebuildCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; /** * @internal Rebuilds the TypePHP cache. diff --git a/src/Command/CacheWarmCommand.php b/src/Internal/Cli/CacheWarmCommand.php similarity index 97% rename from src/Command/CacheWarmCommand.php rename to src/Internal/Cli/CacheWarmCommand.php index 5f924efd..a4dbc036 100644 --- a/src/Command/CacheWarmCommand.php +++ b/src/Internal/Cli/CacheWarmCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; use TypePHP\Internal\CacheManager; diff --git a/src/Command/CliFormatter.php b/src/Internal/Cli/CliFormatter.php similarity index 98% rename from src/Command/CliFormatter.php rename to src/Internal/Cli/CliFormatter.php index df4449d4..6aeb3615 100644 --- a/src/Command/CliFormatter.php +++ b/src/Internal/Cli/CliFormatter.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; /** * @internal Helper class for ANSI color formatting and terminal STDOUT/STDERR output styling. diff --git a/src/Command/CommandInterface.php b/src/Internal/Cli/CommandInterface.php similarity index 93% rename from src/Command/CommandInterface.php rename to src/Internal/Cli/CommandInterface.php index f904e32e..efc19d58 100644 --- a/src/Command/CommandInterface.php +++ b/src/Internal/Cli/CommandInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; /** * @internal Contract defining a CLI command action. diff --git a/src/Command/CommandRunner.php b/src/Internal/Cli/CommandRunner.php similarity index 98% rename from src/Command/CommandRunner.php rename to src/Internal/Cli/CommandRunner.php index 0d17e83a..939d6602 100644 --- a/src/Command/CommandRunner.php +++ b/src/Internal/Cli/CommandRunner.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; final class CommandRunner { diff --git a/src/Command/ConfigInitCommand.php b/src/Internal/Cli/ConfigInitCommand.php similarity index 99% rename from src/Command/ConfigInitCommand.php rename to src/Internal/Cli/ConfigInitCommand.php index 2a7d5d34..af9fdd06 100644 --- a/src/Command/ConfigInitCommand.php +++ b/src/Internal/Cli/ConfigInitCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; final class ConfigInitCommand implements CommandInterface { diff --git a/src/Command/HelpCommand.php b/src/Internal/Cli/HelpCommand.php similarity index 97% rename from src/Command/HelpCommand.php rename to src/Internal/Cli/HelpCommand.php index 56d466e1..a82d39ba 100644 --- a/src/Command/HelpCommand.php +++ b/src/Internal/Cli/HelpCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; final class HelpCommand implements CommandInterface { diff --git a/src/Command/RunCommand.php b/src/Internal/Cli/RunCommand.php similarity index 98% rename from src/Command/RunCommand.php rename to src/Internal/Cli/RunCommand.php index ffb3b559..a6050e11 100644 --- a/src/Command/RunCommand.php +++ b/src/Internal/Cli/RunCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Command; +namespace TypePHP\Internal\Cli; use TypePHP\TypePHP; diff --git a/src/Internal/Config.php b/src/Internal/Config.php index 9d5bb162..3f818f81 100644 --- a/src/Internal/Config.php +++ b/src/Internal/Config.php @@ -4,7 +4,7 @@ namespace TypePHP\Internal; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Contract\FileFilter; use TypePHP\Contract\HierarchyResolver; use TypePHP\Extension\ExtensionInterface; @@ -12,7 +12,7 @@ use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Checker\ReturnChecker; use TypePHP\Resolver\SpecialTypeResolver; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Generics\TemplateManager; /** * Global configuration manager for loading and dynamically overriding settings. diff --git a/src/Internal/ErrorFactory.php b/src/Internal/Diagnostic/ErrorFactory.php similarity index 98% rename from src/Internal/ErrorFactory.php rename to src/Internal/Diagnostic/ErrorFactory.php index 3ba4eb3f..bac3bd49 100644 --- a/src/Internal/ErrorFactory.php +++ b/src/Internal/Diagnostic/ErrorFactory.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Diagnostic; use ReflectionClass; use Throwable; @@ -157,7 +157,7 @@ private static function sanitizeMessage(string $message, ?string $targetFile, ?i $message = $cleaned; } - return str_replace('TypePHP\Command\RunCommand::', '', $message); + return str_replace('TypePHP\Internal\Cli\RunCommand::', '', $message); } /** diff --git a/src/Internal/ErrorMessage.php b/src/Internal/Diagnostic/ErrorMessage.php similarity index 89% rename from src/Internal/ErrorMessage.php rename to src/Internal/Diagnostic/ErrorMessage.php index 26ffd83c..f24f0222 100644 --- a/src/Internal/ErrorMessage.php +++ b/src/Internal/Diagnostic/ErrorMessage.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Diagnostic; /** * @internal Value object holding validation error messages prior to call-site exception throwing. diff --git a/src/Internal/TypeFormatter.php b/src/Internal/Diagnostic/TypeFormatter.php similarity index 98% rename from src/Internal/TypeFormatter.php rename to src/Internal/Diagnostic/TypeFormatter.php index 4a2b22a5..c536ffa1 100644 --- a/src/Internal/TypeFormatter.php +++ b/src/Internal/Diagnostic/TypeFormatter.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Diagnostic; /** * @internal diff --git a/src/Contract/ContractParser.php b/src/Internal/Docblock/ContractParser.php similarity index 99% rename from src/Contract/ContractParser.php rename to src/Internal/Docblock/ContractParser.php index 7aeb20d8..28bdf470 100644 --- a/src/Contract/ContractParser.php +++ b/src/Internal/Docblock/ContractParser.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Contract; +namespace TypePHP\Internal\Docblock; use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode; diff --git a/src/Contract/DocblockExtractor.php b/src/Internal/Docblock/DocblockExtractor.php similarity index 99% rename from src/Contract/DocblockExtractor.php rename to src/Internal/Docblock/DocblockExtractor.php index 5517ba70..b460502e 100644 --- a/src/Contract/DocblockExtractor.php +++ b/src/Internal/Docblock/DocblockExtractor.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Contract; +namespace TypePHP\Internal\Docblock; use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode; @@ -18,7 +18,6 @@ use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; use TypePHP\Internal\ClassNameValidator; -use TypePHP\Internal\DocblockNormalizer; use TypePHP\Internal\StubManager; use TypePHP\Resolver\SpecialTypeResolver; diff --git a/src/Internal/DocblockNormalizer.php b/src/Internal/Docblock/DocblockNormalizer.php similarity index 98% rename from src/Internal/DocblockNormalizer.php rename to src/Internal/Docblock/DocblockNormalizer.php index e293ea1e..d59247fc 100644 --- a/src/Internal/DocblockNormalizer.php +++ b/src/Internal/Docblock/DocblockNormalizer.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Docblock; /** * Normalizes PHPDoc comment strings before AST parsing. diff --git a/src/Resolver/TemplateManager.php b/src/Internal/Generics/TemplateManager.php similarity index 99% rename from src/Resolver/TemplateManager.php rename to src/Internal/Generics/TemplateManager.php index c9254c06..ae74b3b2 100644 --- a/src/Resolver/TemplateManager.php +++ b/src/Internal/Generics/TemplateManager.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Resolver; +namespace TypePHP\Internal\Generics; use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode; use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; @@ -18,13 +18,13 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; -use TypePHP\Contract\ContractParser; -use TypePHP\Contract\DocblockExtractor; +use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockExtractor; use TypePHP\Contract\FileFilter; use TypePHP\Contract\HierarchyResolver; use TypePHP\Internal\ClassNameValidator; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\StubManager; use WeakMap; diff --git a/src/Resolver/TemplateSubstitutor.php b/src/Internal/Generics/TemplateSubstitutor.php similarity index 99% rename from src/Resolver/TemplateSubstitutor.php rename to src/Internal/Generics/TemplateSubstitutor.php index b8860ed5..ef7654a1 100644 --- a/src/Resolver/TemplateSubstitutor.php +++ b/src/Internal/Generics/TemplateSubstitutor.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Resolver; +namespace TypePHP\Internal\Generics; use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode; use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode; diff --git a/src/Internal/RuntimeTypeChecker.php b/src/Internal/RuntimeTypeChecker.php index d1a30c33..69719b9c 100644 --- a/src/Internal/RuntimeTypeChecker.php +++ b/src/Internal/RuntimeTypeChecker.php @@ -6,13 +6,13 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Ast\ScopeCleaner; use TypePHP\Internal\Checker\GeneratorChecker; use TypePHP\Internal\Checker\InlineChecker; use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Checker\ReturnChecker; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Validator\TypeValidatorRegistry; use TypePHP\Wrapper\CallableWrapper; use TypePHP\Wrapper\IterableWrapper; diff --git a/src/Resolver/SpecialTypeResolver.php b/src/Resolver/SpecialTypeResolver.php index 1026bb2b..2dbab0d5 100644 --- a/src/Resolver/SpecialTypeResolver.php +++ b/src/Resolver/SpecialTypeResolver.php @@ -27,9 +27,9 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use TypePHP\Internal\ClassNameValidator; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Diagnostic\TypeFormatter; /** * Resolves special type identifiers (self, static, parent, FQCNs) against Reflection or file contexts. diff --git a/src/TypePHP.php b/src/TypePHP.php index 813038c0..44ec3018 100644 --- a/src/TypePHP.php +++ b/src/TypePHP.php @@ -6,7 +6,7 @@ use TypePHP\Internal\Config; use TypePHP\Internal\StreamWrapper; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Generics\TemplateManager; final class TypePHP { diff --git a/src/Validator/ArrayShapeValidator.php b/src/Validator/ArrayShapeValidator.php index b8db7906..a360ae82 100644 --- a/src/Validator/ArrayShapeValidator.php +++ b/src/Validator/ArrayShapeValidator.php @@ -9,9 +9,9 @@ use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Diagnostic\TypeFormatter; /** * @internal Class for validating array shapes and tuple shapes like array{0: string, 1: int} or array{string, int}. diff --git a/src/Validator/ArrayValidator.php b/src/Validator/ArrayValidator.php index 19f98d46..2f0a9651 100644 --- a/src/Validator/ArrayValidator.php +++ b/src/Validator/ArrayValidator.php @@ -9,9 +9,9 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use Traversable; use TypePHP\Internal\Config; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Diagnostic\TypeFormatter; /** * Validates array and Traversable collection instances against ArrayTypeNode ASTs (Type[]). diff --git a/src/Validator/ConstValidator.php b/src/Validator/ConstValidator.php index 0d17231e..909487e6 100644 --- a/src/Validator/ConstValidator.php +++ b/src/Validator/ConstValidator.php @@ -13,9 +13,9 @@ use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode; use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Diagnostic\TypeFormatter; /** * @internal Validates literal values, class constants, and wildcard constant patterns (Class::PREFIX_*) against ConstTypeNode ASTs. diff --git a/src/Validator/GenericValidator.php b/src/Validator/GenericValidator.php index 1a123d85..b1b8e4a0 100644 --- a/src/Validator/GenericValidator.php +++ b/src/Validator/GenericValidator.php @@ -16,10 +16,10 @@ use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use TypePHP\Internal\ClassNameValidator; use TypePHP\Internal\Config; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\RuntimeTypeChecker; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\TypeFormatter; /** * @internal Validates values against generic AST structures (int ranges, class-string, list, array, object generics, key-of, value-of, int-mask, int-mask-of). diff --git a/src/Validator/IdentifierValidator.php b/src/Validator/IdentifierValidator.php index 4a288771..358f9e01 100644 --- a/src/Validator/IdentifierValidator.php +++ b/src/Validator/IdentifierValidator.php @@ -7,9 +7,9 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use TypePHP\Internal\ClassNameValidator; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Diagnostic\TypeFormatter; use TypePHP\Wrapper\CallableWrapper; /** diff --git a/src/Validator/IntersectionValidator.php b/src/Validator/IntersectionValidator.php index e2133237..05963a5c 100644 --- a/src/Validator/IntersectionValidator.php +++ b/src/Validator/IntersectionValidator.php @@ -6,7 +6,7 @@ use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; /** * @internal Class for validating intersection types like int & string. diff --git a/src/Validator/NullableValidator.php b/src/Validator/NullableValidator.php index 81dec988..e9968bfc 100644 --- a/src/Validator/NullableValidator.php +++ b/src/Validator/NullableValidator.php @@ -6,7 +6,7 @@ use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; /** * @internal Class for validating nullable types like ?int. diff --git a/src/Validator/ObjectShapeValidator.php b/src/Validator/ObjectShapeValidator.php index 68b65ec5..355853da 100644 --- a/src/Validator/ObjectShapeValidator.php +++ b/src/Validator/ObjectShapeValidator.php @@ -6,9 +6,9 @@ use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Diagnostic\TypeFormatter; /** * @internal Validates stdClass dynamic properties and custom class instances against PHPDoc object shape structures. diff --git a/src/Validator/TypeValidatorInterface.php b/src/Validator/TypeValidatorInterface.php index 08ad6ba8..a85a76a2 100644 --- a/src/Validator/TypeValidatorInterface.php +++ b/src/Validator/TypeValidatorInterface.php @@ -5,7 +5,7 @@ namespace TypePHP\Validator; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; /** * Strategy interface for validating values against specific PHPDoc AST TypeNodes. diff --git a/src/Validator/TypeValidatorRegistry.php b/src/Validator/TypeValidatorRegistry.php index cdf2d3ac..d3223d37 100644 --- a/src/Validator/TypeValidatorRegistry.php +++ b/src/Validator/TypeValidatorRegistry.php @@ -14,7 +14,7 @@ use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; /** * Registry mapping AST TypeNodes to their corresponding validator strategy implementations. diff --git a/src/Validator/UnionValidator.php b/src/Validator/UnionValidator.php index 3c766d94..bb55e969 100644 --- a/src/Validator/UnionValidator.php +++ b/src/Validator/UnionValidator.php @@ -6,9 +6,9 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Diagnostic\TypeFormatter; /** * @internal Class for validating union types like int | string. diff --git a/src/Wrapper/CallableWrapper.php b/src/Wrapper/CallableWrapper.php index 0a6f40d8..20c78cc0 100644 --- a/src/Wrapper/CallableWrapper.php +++ b/src/Wrapper/CallableWrapper.php @@ -12,13 +12,13 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use ReflectionFunction; use TypeError; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Exception\TypeError as TypePHPTypeError; -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\TypeFormatter; use TypePHP\Resolver\SpecialTypeResolver; -use TypePHP\Resolver\TemplateManager; -use TypePHP\Resolver\TemplateSubstitutor; +use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; /** diff --git a/src/Wrapper/IterableWrapper.php b/src/Wrapper/IterableWrapper.php index 2943ba78..64507773 100644 --- a/src/Wrapper/IterableWrapper.php +++ b/src/Wrapper/IterableWrapper.php @@ -9,12 +9,12 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Exception\TypeError as TypePHPTypeError; -use TypePHP\Internal\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Resolver\SpecialTypeResolver; -use TypePHP\Resolver\TemplateManager; -use TypePHP\Resolver\TemplateSubstitutor; +use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; /** diff --git a/tests/Command/CommandRunnerTest.php b/tests/Command/CommandRunnerTest.php index 30ee72f5..8e85ee0e 100644 --- a/tests/Command/CommandRunnerTest.php +++ b/tests/Command/CommandRunnerTest.php @@ -4,7 +4,7 @@ namespace TypePHP\Tests\Command; -use TypePHP\Command\CommandRunner; +use TypePHP\Internal\Cli\CommandRunner; describe('CommandRunner Unit Tests', function () { test('routes help command successfully', function () { diff --git a/tests/Contract/DocblockExtractorTest.php b/tests/Contract/DocblockExtractorTest.php index 56df5b77..b8d452d0 100644 --- a/tests/Contract/DocblockExtractorTest.php +++ b/tests/Contract/DocblockExtractorTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode; -use TypePHP\Contract\DocblockExtractor; +use TypePHP\Internal\Docblock\DocblockExtractor; use TypePHP\Tests\Fixtures\Services\HelperService; use TypePHP\Tests\Fixtures\Services\UserService; use TypePHP\Tests\Fixtures\Shopware\Metric\Type as MetricTypeEnum; diff --git a/tests/Internal/ContractParserTest.php b/tests/Internal/ContractParserTest.php index 90144709..97d8a0f2 100644 --- a/tests/Internal/ContractParserTest.php +++ b/tests/Internal/ContractParserTest.php @@ -17,7 +17,7 @@ use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode; use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Config; use TypePHP\Tests\Fixtures\IgnoreTags\IgnoredMethod; use TypePHP\Tests\Fixtures\Services\ChildMagicMethodService; diff --git a/tests/Internal/DocblockNormalizerTest.php b/tests/Internal/DocblockNormalizerTest.php index 9005cd7a..4585a27a 100644 --- a/tests/Internal/DocblockNormalizerTest.php +++ b/tests/Internal/DocblockNormalizerTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\DocblockNormalizer; +use TypePHP\Internal\Dockblock\DocblockNormalizer; describe('DocblockNormalizer', function () { test('returns docblock string unchanged when no special keywords or curly braces are present', function () { diff --git a/tests/Internal/ErrorFactoryTest.php b/tests/Internal/ErrorFactoryTest.php index 265015c0..bfe9b361 100644 --- a/tests/Internal/ErrorFactoryTest.php +++ b/tests/Internal/ErrorFactoryTest.php @@ -2,8 +2,8 @@ declare(strict_types=1); -use TypePHP\Internal\ErrorFactory; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; test('error factory creates an ErrorMessage value object', function () { $err = ErrorFactory::createError('Test argument error message'); diff --git a/tests/Internal/RuntimeTypeCheckerTest.php b/tests/Internal/RuntimeTypeCheckerTest.php index 289395f3..daaa9e8a 100644 --- a/tests/Internal/RuntimeTypeCheckerTest.php +++ b/tests/Internal/RuntimeTypeCheckerTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Internal\Config; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\RuntimeTypeChecker; use TypePHP\Tests\Fixtures\Types\ConfiguredProperty; diff --git a/tests/Internal/TypeFormatterTest.php b/tests/Internal/TypeFormatterTest.php index 0a46c821..de582f55 100644 --- a/tests/Internal/TypeFormatterTest.php +++ b/tests/Internal/TypeFormatterTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\TypeFormatter; +use TypePHP\Internal\Diagnostic\TypeFormatter; test('formats negative integer correctly', function () { expect(TypeFormatter::formatGivenValue(-10))->toBe('negative int (-10)'); diff --git a/tests/Resolver/SpecialTypeResolverTest.php b/tests/Resolver/SpecialTypeResolverTest.php index 3026af0b..d3d79554 100644 --- a/tests/Resolver/SpecialTypeResolverTest.php +++ b/tests/Resolver/SpecialTypeResolverTest.php @@ -20,7 +20,7 @@ use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode; use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Resolver\SpecialTypeResolver; use TypePHP\Tests\Fixtures\Generics\InlineTraitUseService; use TypePHP\Tests\Fixtures\Services\BaseService; diff --git a/tests/Resolver/TemplateManagerTest.php b/tests/Resolver/TemplateManagerTest.php index 3f876c16..b4febba1 100644 --- a/tests/Resolver/TemplateManagerTest.php +++ b/tests/Resolver/TemplateManagerTest.php @@ -6,8 +6,8 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Tests\Fixtures\Domain\Animal; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Cat; diff --git a/tests/Resolver/TemplateSubstitutorTest.php b/tests/Resolver/TemplateSubstitutorTest.php index 021b28ef..39002dfe 100644 --- a/tests/Resolver/TemplateSubstitutorTest.php +++ b/tests/Resolver/TemplateSubstitutorTest.php @@ -19,7 +19,7 @@ use PHPStan\PhpDocParser\Ast\Type\ObjectShapeItemNode; use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Resolver\TemplateSubstitutor; +use TypePHP\Internal\Generics\TemplateSubstitutor; describe('TemplateSubstitutor Unit Tests', function () { test('substitutes simple identifier template placeholders', function () { diff --git a/tests/RuntimeChecker/GeneratorCheckerTest.php b/tests/RuntimeChecker/GeneratorCheckerTest.php index 520ba676..0d0c7b04 100644 --- a/tests/RuntimeChecker/GeneratorCheckerTest.php +++ b/tests/RuntimeChecker/GeneratorCheckerTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Internal\Checker\GeneratorChecker; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Validator\TypeValidatorRegistry; /** diff --git a/tests/RuntimeChecker/InlineCheckerTest.php b/tests/RuntimeChecker/InlineCheckerTest.php index 76f7d8e9..bfaa1aa5 100644 --- a/tests/RuntimeChecker/InlineCheckerTest.php +++ b/tests/RuntimeChecker/InlineCheckerTest.php @@ -4,8 +4,8 @@ use TypePHP\Internal\Checker\InlineChecker; use TypePHP\Internal\Config; -use TypePHP\Internal\ErrorMessage; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Generics\GenericCollection; diff --git a/tests/RuntimeChecker/ParamCheckerTest.php b/tests/RuntimeChecker/ParamCheckerTest.php index c5a8c340..c632dc37 100644 --- a/tests/RuntimeChecker/ParamCheckerTest.php +++ b/tests/RuntimeChecker/ParamCheckerTest.php @@ -4,7 +4,7 @@ use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Config; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Tests\Fixtures\Callables\GenericCallableService; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Services\ShiftedParamService; diff --git a/tests/RuntimeChecker/ReturnCheckerTest.php b/tests/RuntimeChecker/ReturnCheckerTest.php index 541ec7dd..01a22778 100644 --- a/tests/RuntimeChecker/ReturnCheckerTest.php +++ b/tests/RuntimeChecker/ReturnCheckerTest.php @@ -4,7 +4,7 @@ use TypePHP\Internal\Checker\ReturnChecker; use TypePHP\Internal\Config; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Tests\Fixtures\Collections\ConcreteFileCollection; use TypePHP\Tests\Fixtures\Collections\PluginConfiguration; use TypePHP\Tests\Fixtures\Conditionals\ConditionalReturnService; diff --git a/tests/TypeChecking/Boundaries/ParamContractsTest.php b/tests/TypeChecking/Boundaries/ParamContractsTest.php index d7b428cb..34d2f03f 100644 --- a/tests/TypeChecking/Boundaries/ParamContractsTest.php +++ b/tests/TypeChecking/Boundaries/ParamContractsTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Contract\ContractParser; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Services\VariadicPropertyService; diff --git a/tests/TypeChecking/Generics/GenericTraitsUseAnnotationTest.php b/tests/TypeChecking/Generics/GenericTraitsUseAnnotationTest.php index 52dd0f35..4ca556f0 100644 --- a/tests/TypeChecking/Generics/GenericTraitsUseAnnotationTest.php +++ b/tests/TypeChecking/Generics/GenericTraitsUseAnnotationTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Exception\TypeError; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Generics\ClassLevelTraitService; diff --git a/tests/TypeChecking/Generics/UnspecializedArrayKeyGenericTest.php b/tests/TypeChecking/Generics/UnspecializedArrayKeyGenericTest.php index de00a902..9baf7039 100644 --- a/tests/TypeChecking/Generics/UnspecializedArrayKeyGenericTest.php +++ b/tests/TypeChecking/Generics/UnspecializedArrayKeyGenericTest.php @@ -5,7 +5,7 @@ namespace TypePHP\Tests\TypeChecking\Generics; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Generics\TemplateManager; use TypePHP\TypePHP; /** diff --git a/tests/TypeChecking/Generics/UnspecializedGenericDefaultTest.php b/tests/TypeChecking/Generics/UnspecializedGenericDefaultTest.php index e1927244..bd24233c 100644 --- a/tests/TypeChecking/Generics/UnspecializedGenericDefaultTest.php +++ b/tests/TypeChecking/Generics/UnspecializedGenericDefaultTest.php @@ -4,7 +4,7 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use TypePHP\Exception\TypeError; -use TypePHP\Resolver\TemplateManager; +use TypePHP\Internal\Generics\TemplateManager; use TypePHP\TypePHP; interface SpecificAppMiddleware diff --git a/tests/TypeChecking/InheritanceAndAttributes/ConstructorPropertyTypeMismatchTest.php b/tests/TypeChecking/InheritanceAndAttributes/ConstructorPropertyTypeMismatchTest.php index a0a6d9f3..2c975b16 100644 --- a/tests/TypeChecking/InheritanceAndAttributes/ConstructorPropertyTypeMismatchTest.php +++ b/tests/TypeChecking/InheritanceAndAttributes/ConstructorPropertyTypeMismatchTest.php @@ -37,7 +37,7 @@ public function __construct(int $userId) }); test('ContractParser::parse resolves property aliases for constructor parameters', function () { - $contract = TypePHP\Contract\ContractParser::parse(ConstructorPromotionWithAlias::class . '::__construct'); + $contract = TypePHP\Internal\Docblock\ContractParser::parse(ConstructorPromotionWithAlias::class . '::__construct'); expect((string) $contract['types']['userId'])->toBe('positive-int'); }); diff --git a/tests/Unit/ValidatorsTest.php b/tests/Unit/ValidatorsTest.php index a94c61bf..2bba867e 100644 --- a/tests/Unit/ValidatorsTest.php +++ b/tests/Unit/ValidatorsTest.php @@ -8,7 +8,7 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; -use TypePHP\Internal\ErrorMessage; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Cat; use TypePHP\Tests\Fixtures\Domain\Dog; From 1b9e6144483a1a21aa5e5ae132dcbf0046dcff65 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 15:34:59 +0800 Subject: [PATCH 03/31] Organizing folders --- src/Internal/Ast/PropertyHookInjector.php | 2 +- src/Internal/{ => Ast}/TypePHPPrinter.php | 2 +- src/Internal/Checker/GeneratorChecker.php | 2 +- src/Internal/Checker/InlineChecker.php | 4 ++-- src/Internal/Checker/ParamChecker.php | 8 ++++---- src/Internal/Checker/ReturnChecker.php | 8 ++++---- src/Internal/Cli/CacheClearCommand.php | 2 +- src/Internal/Cli/CacheWarmCommand.php | 2 +- src/Internal/Docblock/ContractParser.php | 6 +++--- src/Internal/Docblock/DocblockExtractor.php | 6 +++--- src/Internal/Generics/TemplateManager.php | 6 +++--- src/Internal/{ => Io}/CacheManager.php | 3 ++- src/Internal/{ => Io}/StreamWrapper.php | 6 ++++-- src/Internal/{ => Io}/StreamWrapperInterface.php | 2 +- .../Resolver}/HierarchyResolver.php | 2 +- src/{ => Internal}/Resolver/SpecialTypeResolver.php | 4 ++-- src/Internal/{ => Util}/ClassNameValidator.php | 0 src/Internal/{ => Util}/Config.php | 11 ++++++----- src/{Extension => Internal/Util}/ExtensionManager.php | 4 +++- src/{Contract => Internal/Util}/FileFilter.php | 5 +---- src/Internal/{ => Util}/PathMatcher.php | 4 +++- src/Internal/{ => Util}/StubManager.php | 2 +- src/TypePHP.php | 4 ++-- src/Validator/ArrayValidator.php | 2 +- src/Validator/GenericValidator.php | 4 ++-- src/Validator/IdentifierValidator.php | 2 +- src/Wrapper/CallableWrapper.php | 2 +- src/Wrapper/IterableWrapper.php | 2 +- tests/Contract/DocblockExtractorTest.php | 4 ++-- tests/Contract/FileFilterTest.php | 2 +- tests/Contract/HierarchyResolverTest.php | 2 +- tests/Contract/PackagePathInclusionTest.php | 4 ++-- tests/Contract/VendorIsolationPathTest.php | 4 ++-- tests/Extension/ExtensionManagerTest.php | 4 ++-- tests/Internal/CacheManagerTest.php | 2 +- tests/Internal/ClassNameValidatorTest.php | 2 +- tests/Internal/ConfigTest.php | 2 +- tests/Internal/ContractParserTest.php | 2 +- tests/Internal/PathMatcherTest.php | 6 +++--- tests/Internal/RuntimeTypeCheckerTest.php | 2 +- tests/Internal/StreamWrapperTest.php | 4 ++-- tests/Internal/StubManagerTest.php | 4 ++-- tests/Resolver/SpecialTypeResolverTest.php | 2 +- tests/RuntimeChecker/InlineCheckerTest.php | 2 +- tests/RuntimeChecker/ParamCheckerTest.php | 2 +- tests/RuntimeChecker/ReturnCheckerTest.php | 2 +- .../ArraysAndShapes/AdvancedTypesAndEnumsTest.php | 2 +- .../ArraysAndShapes/ArrayComplexSubtypesTest.php | 2 +- tests/TypeChecking/Boundaries/CrlfLineDriftTest.php | 2 +- .../Boundaries/InlineReturnValidationTest.php | 2 +- .../Boundaries/InlineVariableValidationTest.php | 2 +- tests/TypeChecking/Boundaries/MagicMethodsTest.php | 2 +- tests/TypeChecking/Boundaries/MagicPropertiesTest.php | 2 +- tests/TypeChecking/Boundaries/PipeOperatorTest.php | 2 +- tests/TypeChecking/Boundaries/PropertyHooksTest.php | 2 +- .../Boundaries/PropertyValidationTest.php | 2 +- .../TypeChecking/Boundaries/ShopwareSyntaxBugTest.php | 2 +- .../TypeChecking/Configuration/BoundaryConfigTest.php | 2 +- .../Configuration/RespectIgnoreTagsConfigTest.php | 2 +- .../RespectNativeNullabilityTemplateTest.php | 2 +- .../RespectNativeReturnNullabilityTest.php | 2 +- .../Generics/ClassTemplateInlineVarTest.php | 2 +- .../LiskovAndVendorIsolationTest.php | 2 +- .../ParameterShiftInheritanceTest.php | 2 +- .../SameNamespaceGlobalCollisionTest.php | 2 +- .../SubNamespaceResolutionTest.php | 2 +- tests/TypeChecking/Stubs/StubSystemTest.php | 2 +- tests/Unit/LineNumberPreservationTest.php | 2 +- tests/Visitor/FunctionContractInjectorTest.php | 4 ++-- tests/Visitor/PropertyHookInjectorTest.php | 2 +- 70 files changed, 107 insertions(+), 102 deletions(-) rename src/Internal/{ => Ast}/TypePHPPrinter.php (97%) rename src/Internal/{ => Io}/CacheManager.php (99%) rename src/Internal/{ => Io}/StreamWrapper.php (99%) rename src/Internal/{ => Io}/StreamWrapperInterface.php (98%) rename src/{Contract => Internal/Resolver}/HierarchyResolver.php (99%) rename src/{ => Internal}/Resolver/SpecialTypeResolver.php (99%) rename src/Internal/{ => Util}/ClassNameValidator.php (100%) rename src/Internal/{ => Util}/Config.php (98%) rename src/{Extension => Internal/Util}/ExtensionManager.php (97%) rename src/{Contract => Internal/Util}/FileFilter.php (95%) rename src/Internal/{ => Util}/PathMatcher.php (99%) rename src/Internal/{ => Util}/StubManager.php (99%) diff --git a/src/Internal/Ast/PropertyHookInjector.php b/src/Internal/Ast/PropertyHookInjector.php index 88e9d8b6..01d15632 100644 --- a/src/Internal/Ast/PropertyHookInjector.php +++ b/src/Internal/Ast/PropertyHookInjector.php @@ -7,7 +7,7 @@ use PhpParser\Node; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; /** * @internal Injects property contract checks into PHP 8.4 get and set property hooks. diff --git a/src/Internal/TypePHPPrinter.php b/src/Internal/Ast/TypePHPPrinter.php similarity index 97% rename from src/Internal/TypePHPPrinter.php rename to src/Internal/Ast/TypePHPPrinter.php index e2b9341a..aefdd5bb 100644 --- a/src/Internal/TypePHPPrinter.php +++ b/src/Internal/Ast/TypePHPPrinter.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Ast; use PhpParser\Node; use PhpParser\PrettyPrinter\Standard; diff --git a/src/Internal/Checker/GeneratorChecker.php b/src/Internal/Checker/GeneratorChecker.php index 9c0f02ad..cfd4bbeb 100644 --- a/src/Internal/Checker/GeneratorChecker.php +++ b/src/Internal/Checker/GeneratorChecker.php @@ -9,7 +9,7 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; diff --git a/src/Internal/Checker/InlineChecker.php b/src/Internal/Checker/InlineChecker.php index 2900bb1e..dbdef58e 100644 --- a/src/Internal/Checker/InlineChecker.php +++ b/src/Internal/Checker/InlineChecker.php @@ -25,9 +25,9 @@ use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Dockblock\DocblockNormalizer; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index 78243944..364e9479 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -14,13 +14,13 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Contract\HierarchyResolver; -use TypePHP\Internal\ClassNameValidator; -use TypePHP\Internal\Config; +use TypePHP\Internal\Resolver\HierarchyResolver; +use TypePHP\Internal\Util\ClassNameValidator; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; diff --git a/src/Internal/Checker/ReturnChecker.php b/src/Internal/Checker/ReturnChecker.php index 7d07b01b..d8a7ac17 100644 --- a/src/Internal/Checker/ReturnChecker.php +++ b/src/Internal/Checker/ReturnChecker.php @@ -14,10 +14,10 @@ use ReflectionClass; use Traversable; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Contract\HierarchyResolver; -use TypePHP\Internal\ClassNameValidator; -use TypePHP\Internal\Config; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\HierarchyResolver; +use TypePHP\Internal\Util\ClassNameValidator; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; diff --git a/src/Internal/Cli/CacheClearCommand.php b/src/Internal/Cli/CacheClearCommand.php index 8ca7d1f7..556dd83a 100644 --- a/src/Internal/Cli/CacheClearCommand.php +++ b/src/Internal/Cli/CacheClearCommand.php @@ -4,7 +4,7 @@ namespace TypePHP\Internal\Cli; -use TypePHP\Internal\CacheManager; +use TypePHP\Internal\Io\CacheManager; /** * @Command Clears the TypePHP cache. diff --git a/src/Internal/Cli/CacheWarmCommand.php b/src/Internal/Cli/CacheWarmCommand.php index a4dbc036..d73a6984 100644 --- a/src/Internal/Cli/CacheWarmCommand.php +++ b/src/Internal/Cli/CacheWarmCommand.php @@ -4,7 +4,7 @@ namespace TypePHP\Internal\Cli; -use TypePHP\Internal\CacheManager; +use TypePHP\Internal\Io\CacheManager; /** * @internal Warms up the TypePHP cache. diff --git a/src/Internal/Docblock/ContractParser.php b/src/Internal/Docblock/ContractParser.php index 28bdf470..889b0b5a 100644 --- a/src/Internal/Docblock/ContractParser.php +++ b/src/Internal/Docblock/ContractParser.php @@ -22,9 +22,9 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use TypePHP\Internal\Checker\InlineChecker; -use TypePHP\Internal\Config; -use TypePHP\Internal\StubManager; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\StubManager; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Validator\TypeValidatorRegistry; /** diff --git a/src/Internal/Docblock/DocblockExtractor.php b/src/Internal/Docblock/DocblockExtractor.php index b460502e..177d6b52 100644 --- a/src/Internal/Docblock/DocblockExtractor.php +++ b/src/Internal/Docblock/DocblockExtractor.php @@ -17,9 +17,9 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; -use TypePHP\Internal\ClassNameValidator; -use TypePHP\Internal\StubManager; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Util\ClassNameValidator; +use TypePHP\Internal\Util\StubManager; +use TypePHP\Internal\Resolver\SpecialTypeResolver; /** * @internal Encapsulates PHPDoc AST parsing, tokenizing, and tag extractions. diff --git a/src/Internal/Generics/TemplateManager.php b/src/Internal/Generics/TemplateManager.php index ae74b3b2..5abd5b57 100644 --- a/src/Internal/Generics/TemplateManager.php +++ b/src/Internal/Generics/TemplateManager.php @@ -21,11 +21,11 @@ use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Docblock\DocblockExtractor; use TypePHP\Contract\FileFilter; -use TypePHP\Contract\HierarchyResolver; -use TypePHP\Internal\ClassNameValidator; +use TypePHP\Internal\Resolver\HierarchyResolver; +use TypePHP\Internal\Util\ClassNameValidator; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; -use TypePHP\Internal\StubManager; +use TypePHP\Internal\Util\StubManager; use WeakMap; /** diff --git a/src/Internal/CacheManager.php b/src/Internal/Io/CacheManager.php similarity index 99% rename from src/Internal/CacheManager.php rename to src/Internal/Io/CacheManager.php index 8846b8f8..e580dca2 100644 --- a/src/Internal/CacheManager.php +++ b/src/Internal/Io/CacheManager.php @@ -2,9 +2,10 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Io; use TypePHP\Contract\FileFilter; +use TypePHP\Internal\Util\Config; /** * @internal diff --git a/src/Internal/StreamWrapper.php b/src/Internal/Io/StreamWrapper.php similarity index 99% rename from src/Internal/StreamWrapper.php rename to src/Internal/Io/StreamWrapper.php index 2ec64668..cc38be9d 100644 --- a/src/Internal/StreamWrapper.php +++ b/src/Internal/Io/StreamWrapper.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Io; require_once __DIR__ . '/PathMatcher.php'; @@ -10,7 +10,9 @@ use PhpParser\NodeVisitor\CloningVisitor; use PhpParser\ParserFactory; use TypePHP\Internal\Ast\ContractVisitor; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Ast\TypePHPPrinter; +use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Util\Config; /** * Intercepts PHP 'file://' protocol operations to perform on-the-fly AST transformations diff --git a/src/Internal/StreamWrapperInterface.php b/src/Internal/Io/StreamWrapperInterface.php similarity index 98% rename from src/Internal/StreamWrapperInterface.php rename to src/Internal/Io/StreamWrapperInterface.php index 4eeb3cc4..a1f97ef6 100644 --- a/src/Internal/StreamWrapperInterface.php +++ b/src/Internal/Io/StreamWrapperInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Io; /** * @internal Contract defining PHP's native stream wrapper protocol methods. diff --git a/src/Contract/HierarchyResolver.php b/src/Internal/Resolver/HierarchyResolver.php similarity index 99% rename from src/Contract/HierarchyResolver.php rename to src/Internal/Resolver/HierarchyResolver.php index e14b714c..89dcd211 100644 --- a/src/Contract/HierarchyResolver.php +++ b/src/Internal/Resolver/HierarchyResolver.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Contract; +namespace TypePHP\Internal\Resolver; use ReflectionClass; use ReflectionMethod; diff --git a/src/Resolver/SpecialTypeResolver.php b/src/Internal/Resolver/SpecialTypeResolver.php similarity index 99% rename from src/Resolver/SpecialTypeResolver.php rename to src/Internal/Resolver/SpecialTypeResolver.php index 2dbab0d5..374fe297 100644 --- a/src/Resolver/SpecialTypeResolver.php +++ b/src/Internal/Resolver/SpecialTypeResolver.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Resolver; +namespace TypePHP\Internal\Resolver; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; @@ -26,7 +26,7 @@ use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\ClassNameValidator; +use TypePHP\Internal\Util\ClassNameValidator; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; diff --git a/src/Internal/ClassNameValidator.php b/src/Internal/Util/ClassNameValidator.php similarity index 100% rename from src/Internal/ClassNameValidator.php rename to src/Internal/Util/ClassNameValidator.php diff --git a/src/Internal/Config.php b/src/Internal/Util/Config.php similarity index 98% rename from src/Internal/Config.php rename to src/Internal/Util/Config.php index 3f818f81..d3c015c7 100644 --- a/src/Internal/Config.php +++ b/src/Internal/Util/Config.php @@ -2,17 +2,18 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Util; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Contract\FileFilter; -use TypePHP\Contract\HierarchyResolver; +use TypePHP\Internal\Resolver\HierarchyResolver; use TypePHP\Extension\ExtensionInterface; -use TypePHP\Extension\ExtensionManager; +use TypePHP\Internal\Util\ExtensionManager; use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Checker\ReturnChecker; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Io\CacheManager; +use TypePHP\Internal\Io\StreamWrapper; /** * Global configuration manager for loading and dynamically overriding settings. diff --git a/src/Extension/ExtensionManager.php b/src/Internal/Util/ExtensionManager.php similarity index 97% rename from src/Extension/ExtensionManager.php rename to src/Internal/Util/ExtensionManager.php index 41aaa679..38b33c89 100644 --- a/src/Extension/ExtensionManager.php +++ b/src/Internal/Util/ExtensionManager.php @@ -2,7 +2,9 @@ declare(strict_types=1); -namespace TypePHP\Extension; +namespace TypePHP\Internal\Util; + +use TypePHP\Extension\ExtensionInterface; /** * Loads explicitly registered TypePHP extensions from user configuration. diff --git a/src/Contract/FileFilter.php b/src/Internal/Util/FileFilter.php similarity index 95% rename from src/Contract/FileFilter.php rename to src/Internal/Util/FileFilter.php index c6d1189f..d097eeb0 100644 --- a/src/Contract/FileFilter.php +++ b/src/Internal/Util/FileFilter.php @@ -2,10 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Contract; - -use TypePHP\Internal\Config; -use TypePHP\Internal\PathMatcher; +namespace TypePHP\Internal\Util; /** * @internal Checks file paths against vendor directories, file extensions, and user-configured include/exclude globs. diff --git a/src/Internal/PathMatcher.php b/src/Internal/Util/PathMatcher.php similarity index 99% rename from src/Internal/PathMatcher.php rename to src/Internal/Util/PathMatcher.php index 98958dba..084f1836 100644 --- a/src/Internal/PathMatcher.php +++ b/src/Internal/Util/PathMatcher.php @@ -2,7 +2,9 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Util; + +use TypePHP\Internal\Io\CacheManager; require_once __DIR__ . '/CacheManager.php'; diff --git a/src/Internal/StubManager.php b/src/Internal/Util/StubManager.php similarity index 99% rename from src/Internal/StubManager.php rename to src/Internal/Util/StubManager.php index 507bb07a..db28ad94 100644 --- a/src/Internal/StubManager.php +++ b/src/Internal/Util/StubManager.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Util; use FilesystemIterator; use PhpParser\Node; diff --git a/src/TypePHP.php b/src/TypePHP.php index 44ec3018..b4d9af6b 100644 --- a/src/TypePHP.php +++ b/src/TypePHP.php @@ -4,8 +4,8 @@ namespace TypePHP; -use TypePHP\Internal\Config; -use TypePHP\Internal\StreamWrapper; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Io\StreamWrapper; use TypePHP\Internal\Generics\TemplateManager; final class TypePHP diff --git a/src/Validator/ArrayValidator.php b/src/Validator/ArrayValidator.php index 2f0a9651..ccd71866 100644 --- a/src/Validator/ArrayValidator.php +++ b/src/Validator/ArrayValidator.php @@ -8,7 +8,7 @@ use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use Traversable; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; diff --git a/src/Validator/GenericValidator.php b/src/Validator/GenericValidator.php index b1b8e4a0..a57a4816 100644 --- a/src/Validator/GenericValidator.php +++ b/src/Validator/GenericValidator.php @@ -14,8 +14,8 @@ use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\ClassNameValidator; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\ClassNameValidator; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\RuntimeTypeChecker; diff --git a/src/Validator/IdentifierValidator.php b/src/Validator/IdentifierValidator.php index 358f9e01..a33b19f1 100644 --- a/src/Validator/IdentifierValidator.php +++ b/src/Validator/IdentifierValidator.php @@ -6,7 +6,7 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\ClassNameValidator; +use TypePHP\Internal\Util\ClassNameValidator; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; diff --git a/src/Wrapper/CallableWrapper.php b/src/Wrapper/CallableWrapper.php index 20c78cc0..2ff2dd0d 100644 --- a/src/Wrapper/CallableWrapper.php +++ b/src/Wrapper/CallableWrapper.php @@ -16,7 +16,7 @@ use TypePHP\Exception\TypeError as TypePHPTypeError; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\TypeFormatter; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; diff --git a/src/Wrapper/IterableWrapper.php b/src/Wrapper/IterableWrapper.php index 64507773..f967fd23 100644 --- a/src/Wrapper/IterableWrapper.php +++ b/src/Wrapper/IterableWrapper.php @@ -12,7 +12,7 @@ use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Exception\TypeError as TypePHPTypeError; use TypePHP\Internal\Diagnostic\ErrorFactory; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Validator\TypeValidatorRegistry; diff --git a/tests/Contract/DocblockExtractorTest.php b/tests/Contract/DocblockExtractorTest.php index b8d452d0..3d41fbf4 100644 --- a/tests/Contract/DocblockExtractorTest.php +++ b/tests/Contract/DocblockExtractorTest.php @@ -274,7 +274,7 @@ class HelperService file_put_contents($stubPath, $stubContent); try { - TypePHP\Internal\Config::set([ + TypePHP\Internal\Util\Config::set([ 'stubs' => [ str_replace('\\', '/', $tempDir) . '/**', ], @@ -293,7 +293,7 @@ class HelperService if (is_dir($tempDir)) { @rmdir($tempDir); } - TypePHP\Internal\Config::reset(); + TypePHP\Internal\Util\Config::reset(); } }); diff --git a/tests/Contract/FileFilterTest.php b/tests/Contract/FileFilterTest.php index 15c178da..4db5422f 100644 --- a/tests/Contract/FileFilterTest.php +++ b/tests/Contract/FileFilterTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Contract\FileFilter; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; describe('FileFilter Unit Tests', function () { test('returns false for null, empty, or false file paths', function () { diff --git a/tests/Contract/HierarchyResolverTest.php b/tests/Contract/HierarchyResolverTest.php index 78b42c08..4a3414de 100644 --- a/tests/Contract/HierarchyResolverTest.php +++ b/tests/Contract/HierarchyResolverTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Contract\HierarchyResolver; +use TypePHP\Internal\Resolver\HierarchyResolver; use TypePHP\Tests\Fixtures\Services\BaseService; use TypePHP\Tests\Fixtures\Services\UserService; use TypePHP\Tests\Fixtures\Types\CountableArrayAccess; diff --git a/tests/Contract/PackagePathInclusionTest.php b/tests/Contract/PackagePathInclusionTest.php index efd94fc3..5da00b97 100644 --- a/tests/Contract/PackagePathInclusionTest.php +++ b/tests/Contract/PackagePathInclusionTest.php @@ -5,8 +5,8 @@ namespace TypePHP\Tests\Contract; use TypePHP\Contract\FileFilter; -use TypePHP\Internal\Config; -use TypePHP\Internal\PathMatcher; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\PathMatcher; describe('Packages and Monorepo Path Inclusion (packages/**/src/**)', function () { beforeEach(function () { diff --git a/tests/Contract/VendorIsolationPathTest.php b/tests/Contract/VendorIsolationPathTest.php index 1e5b5f26..150d3ec3 100644 --- a/tests/Contract/VendorIsolationPathTest.php +++ b/tests/Contract/VendorIsolationPathTest.php @@ -3,8 +3,8 @@ declare(strict_types=1); use TypePHP\Contract\FileFilter; -use TypePHP\Internal\Config; -use TypePHP\Internal\StreamWrapper; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Io\StreamWrapper; describe('Vendor Path Isolation & Whitelisting (Shopware Doctrine DBAL Reproduction)', function () { beforeEach(function () { diff --git a/tests/Extension/ExtensionManagerTest.php b/tests/Extension/ExtensionManagerTest.php index e1827083..58af018f 100644 --- a/tests/Extension/ExtensionManagerTest.php +++ b/tests/Extension/ExtensionManagerTest.php @@ -5,8 +5,8 @@ namespace TypePHP\Tests\Extension; use TypePHP\Contract\FileFilter; -use TypePHP\Extension\ExtensionManager; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\ExtensionManager; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Extensions\SampleRegisteredExtension; describe('ExtensionManager Unit Tests', function () { diff --git a/tests/Internal/CacheManagerTest.php b/tests/Internal/CacheManagerTest.php index b216c6d6..5ce01a64 100644 --- a/tests/Internal/CacheManagerTest.php +++ b/tests/Internal/CacheManagerTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\CacheManager; +use TypePHP\Internal\Io\CacheManager; describe('CacheManager Unit Tests', function () { test('returns valid cache directory path', function () { diff --git a/tests/Internal/ClassNameValidatorTest.php b/tests/Internal/ClassNameValidatorTest.php index f71070a2..b79e6cf8 100644 --- a/tests/Internal/ClassNameValidatorTest.php +++ b/tests/Internal/ClassNameValidatorTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\ClassNameValidator; +use TypePHP\Internal\Util\ClassNameValidator; describe('ClassNameValidator', function () { test('accepts valid simple and namespaced PHP class names', function () { diff --git a/tests/Internal/ConfigTest.php b/tests/Internal/ConfigTest.php index 1c0439c4..f2308dd8 100644 --- a/tests/Internal/ConfigTest.php +++ b/tests/Internal/ConfigTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; describe('Config Unit Tests', function () { afterEach(function () { diff --git a/tests/Internal/ContractParserTest.php b/tests/Internal/ContractParserTest.php index 97d8a0f2..25c706f4 100644 --- a/tests/Internal/ContractParserTest.php +++ b/tests/Internal/ContractParserTest.php @@ -18,7 +18,7 @@ use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\IgnoreTags\IgnoredMethod; use TypePHP\Tests\Fixtures\Services\ChildMagicMethodService; use TypePHP\Tests\Fixtures\Services\UserService; diff --git a/tests/Internal/PathMatcherTest.php b/tests/Internal/PathMatcherTest.php index cfd4e820..245a54e2 100644 --- a/tests/Internal/PathMatcherTest.php +++ b/tests/Internal/PathMatcherTest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -use TypePHP\Internal\CacheManager; -use TypePHP\Internal\Config; -use TypePHP\Internal\PathMatcher; +use TypePHP\Internal\Io\CacheManager; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\PathMatcher; describe('PathMatcher Unit Tests', function () { beforeEach(function () { diff --git a/tests/Internal/RuntimeTypeCheckerTest.php b/tests/Internal/RuntimeTypeCheckerTest.php index daaa9e8a..e92a8e3f 100644 --- a/tests/Internal/RuntimeTypeCheckerTest.php +++ b/tests/Internal/RuntimeTypeCheckerTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\RuntimeTypeChecker; use TypePHP\Tests\Fixtures\Types\ConfiguredProperty; diff --git a/tests/Internal/StreamWrapperTest.php b/tests/Internal/StreamWrapperTest.php index 664d80d9..921af438 100644 --- a/tests/Internal/StreamWrapperTest.php +++ b/tests/Internal/StreamWrapperTest.php @@ -3,8 +3,8 @@ declare(strict_types=1); use TypePHP\Contract\FileFilter; -use TypePHP\Internal\Config; -use TypePHP\Internal\StreamWrapper; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Io\StreamWrapper; describe('StreamWrapper Unit Tests', function () { beforeEach(function () { diff --git a/tests/Internal/StubManagerTest.php b/tests/Internal/StubManagerTest.php index af66c022..c4d82d59 100644 --- a/tests/Internal/StubManagerTest.php +++ b/tests/Internal/StubManagerTest.php @@ -2,8 +2,8 @@ declare(strict_types=1); -use TypePHP\Internal\Config; -use TypePHP\Internal\StubManager; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\StubManager; describe('StubManager Unit Tests', function () { beforeEach(function () { diff --git a/tests/Resolver/SpecialTypeResolverTest.php b/tests/Resolver/SpecialTypeResolverTest.php index d3d79554..3da440b4 100644 --- a/tests/Resolver/SpecialTypeResolverTest.php +++ b/tests/Resolver/SpecialTypeResolverTest.php @@ -21,7 +21,7 @@ use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use TypePHP\Internal\Diagnostic\ErrorMessage; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Tests\Fixtures\Generics\InlineTraitUseService; use TypePHP\Tests\Fixtures\Services\BaseService; use TypePHP\Tests\Fixtures\Services\UserService; diff --git a/tests/RuntimeChecker/InlineCheckerTest.php b/tests/RuntimeChecker/InlineCheckerTest.php index bfaa1aa5..60f5f580 100644 --- a/tests/RuntimeChecker/InlineCheckerTest.php +++ b/tests/RuntimeChecker/InlineCheckerTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Internal\Checker\InlineChecker; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Tests\Fixtures\Domain\Car; diff --git a/tests/RuntimeChecker/ParamCheckerTest.php b/tests/RuntimeChecker/ParamCheckerTest.php index c632dc37..e605f3b3 100644 --- a/tests/RuntimeChecker/ParamCheckerTest.php +++ b/tests/RuntimeChecker/ParamCheckerTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Internal\Checker\ParamChecker; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Tests\Fixtures\Callables\GenericCallableService; use TypePHP\Tests\Fixtures\Domain\Dog; diff --git a/tests/RuntimeChecker/ReturnCheckerTest.php b/tests/RuntimeChecker/ReturnCheckerTest.php index 01a22778..a7a5cd38 100644 --- a/tests/RuntimeChecker/ReturnCheckerTest.php +++ b/tests/RuntimeChecker/ReturnCheckerTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Internal\Checker\ReturnChecker; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Tests\Fixtures\Collections\ConcreteFileCollection; use TypePHP\Tests\Fixtures\Collections\PluginConfiguration; diff --git a/tests/TypeChecking/ArraysAndShapes/AdvancedTypesAndEnumsTest.php b/tests/TypeChecking/ArraysAndShapes/AdvancedTypesAndEnumsTest.php index 5c4beabb..15fd4d38 100644 --- a/tests/TypeChecking/ArraysAndShapes/AdvancedTypesAndEnumsTest.php +++ b/tests/TypeChecking/ArraysAndShapes/AdvancedTypesAndEnumsTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Types\ConfigApp; use TypePHP\Tests\Fixtures\Types\StatusEnum; use TypePHP\Tests\Fixtures\Types\UserObjectShape; diff --git a/tests/TypeChecking/ArraysAndShapes/ArrayComplexSubtypesTest.php b/tests/TypeChecking/ArraysAndShapes/ArrayComplexSubtypesTest.php index 2e1a2110..53a1bd63 100644 --- a/tests/TypeChecking/ArraysAndShapes/ArrayComplexSubtypesTest.php +++ b/tests/TypeChecking/ArraysAndShapes/ArrayComplexSubtypesTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Exception\TypeError; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Domain\Animal; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Cat; diff --git a/tests/TypeChecking/Boundaries/CrlfLineDriftTest.php b/tests/TypeChecking/Boundaries/CrlfLineDriftTest.php index 541ceb21..ee667fc2 100644 --- a/tests/TypeChecking/Boundaries/CrlfLineDriftTest.php +++ b/tests/TypeChecking/Boundaries/CrlfLineDriftTest.php @@ -6,7 +6,7 @@ return; } -use TypePHP\Internal\StreamWrapper; +use TypePHP\Internal\Io\StreamWrapper; describe('CRLF (\r\n) Windows Line-Drift Stress Test', function () { test('transforms CRLF (\r\n) functions with zero line-drift', function () { diff --git a/tests/TypeChecking/Boundaries/InlineReturnValidationTest.php b/tests/TypeChecking/Boundaries/InlineReturnValidationTest.php index cfad65e0..cd4e83ee 100644 --- a/tests/TypeChecking/Boundaries/InlineReturnValidationTest.php +++ b/tests/TypeChecking/Boundaries/InlineReturnValidationTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\StreamWrapper; +use TypePHP\Internal\Io\StreamWrapper; /** * Function with broad return type, but specific inline @var on return statement diff --git a/tests/TypeChecking/Boundaries/InlineVariableValidationTest.php b/tests/TypeChecking/Boundaries/InlineVariableValidationTest.php index 40bcaf3d..35d1f24f 100644 --- a/tests/TypeChecking/Boundaries/InlineVariableValidationTest.php +++ b/tests/TypeChecking/Boundaries/InlineVariableValidationTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Cat; use TypePHP\Tests\Fixtures\Domain\Dog; diff --git a/tests/TypeChecking/Boundaries/MagicMethodsTest.php b/tests/TypeChecking/Boundaries/MagicMethodsTest.php index 88338303..ea573a3a 100644 --- a/tests/TypeChecking/Boundaries/MagicMethodsTest.php +++ b/tests/TypeChecking/Boundaries/MagicMethodsTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Generics\Producer; diff --git a/tests/TypeChecking/Boundaries/MagicPropertiesTest.php b/tests/TypeChecking/Boundaries/MagicPropertiesTest.php index ed15793e..534a62b5 100644 --- a/tests/TypeChecking/Boundaries/MagicPropertiesTest.php +++ b/tests/TypeChecking/Boundaries/MagicPropertiesTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Generics\Producer; diff --git a/tests/TypeChecking/Boundaries/PipeOperatorTest.php b/tests/TypeChecking/Boundaries/PipeOperatorTest.php index 0db7638c..5a55db33 100644 --- a/tests/TypeChecking/Boundaries/PipeOperatorTest.php +++ b/tests/TypeChecking/Boundaries/PipeOperatorTest.php @@ -6,7 +6,7 @@ return; } -use TypePHP\Internal\StreamWrapper; +use TypePHP\Internal\Io\StreamWrapper; use TypePHP\Tests\Fixtures\Pipes\NativePipeRunner; use TypePHP\Tests\Fixtures\Pipes\PipePipelineService; diff --git a/tests/TypeChecking/Boundaries/PropertyHooksTest.php b/tests/TypeChecking/Boundaries/PropertyHooksTest.php index 064379a9..35d35bcb 100644 --- a/tests/TypeChecking/Boundaries/PropertyHooksTest.php +++ b/tests/TypeChecking/Boundaries/PropertyHooksTest.php @@ -6,7 +6,7 @@ return; } -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Types\HookedInterfaceImplementation; use TypePHP\Tests\Fixtures\Types\HookedUser; use TypePHP\Tests\Fixtures\Types\PropertyHooks; diff --git a/tests/TypeChecking/Boundaries/PropertyValidationTest.php b/tests/TypeChecking/Boundaries/PropertyValidationTest.php index caa42fb7..487c7fd2 100644 --- a/tests/TypeChecking/Boundaries/PropertyValidationTest.php +++ b/tests/TypeChecking/Boundaries/PropertyValidationTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Generics\Producer; diff --git a/tests/TypeChecking/Boundaries/ShopwareSyntaxBugTest.php b/tests/TypeChecking/Boundaries/ShopwareSyntaxBugTest.php index bfc52c7c..e7f90324 100644 --- a/tests/TypeChecking/Boundaries/ShopwareSyntaxBugTest.php +++ b/tests/TypeChecking/Boundaries/ShopwareSyntaxBugTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Shopware\Config\MetricConfigProvider; beforeEach(function () { diff --git a/tests/TypeChecking/Configuration/BoundaryConfigTest.php b/tests/TypeChecking/Configuration/BoundaryConfigTest.php index 1ba4a748..cafa98da 100644 --- a/tests/TypeChecking/Configuration/BoundaryConfigTest.php +++ b/tests/TypeChecking/Configuration/BoundaryConfigTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Exception\TypeError; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Generics\GenericCollection; diff --git a/tests/TypeChecking/Configuration/RespectIgnoreTagsConfigTest.php b/tests/TypeChecking/Configuration/RespectIgnoreTagsConfigTest.php index 9cbcad78..0b8bbfc1 100644 --- a/tests/TypeChecking/Configuration/RespectIgnoreTagsConfigTest.php +++ b/tests/TypeChecking/Configuration/RespectIgnoreTagsConfigTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\IgnoreTags\ForceCheckedMethod; describe('Respect Ignore Tags Configuration (respect_ignore_tags)', function () { diff --git a/tests/TypeChecking/Configuration/RespectNativeNullabilityTemplateTest.php b/tests/TypeChecking/Configuration/RespectNativeNullabilityTemplateTest.php index 4d51612a..99d72d64 100644 --- a/tests/TypeChecking/Configuration/RespectNativeNullabilityTemplateTest.php +++ b/tests/TypeChecking/Configuration/RespectNativeNullabilityTemplateTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Domain\Animal; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; diff --git a/tests/TypeChecking/Configuration/RespectNativeReturnNullabilityTest.php b/tests/TypeChecking/Configuration/RespectNativeReturnNullabilityTest.php index 4e4470c2..48cf228d 100644 --- a/tests/TypeChecking/Configuration/RespectNativeReturnNullabilityTest.php +++ b/tests/TypeChecking/Configuration/RespectNativeReturnNullabilityTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Exception\TypeError; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; /** * Function with native : ?array return, but non-nullable DocBlock diff --git a/tests/TypeChecking/Generics/ClassTemplateInlineVarTest.php b/tests/TypeChecking/Generics/ClassTemplateInlineVarTest.php index 04a8744a..627fbb05 100644 --- a/tests/TypeChecking/Generics/ClassTemplateInlineVarTest.php +++ b/tests/TypeChecking/Generics/ClassTemplateInlineVarTest.php @@ -3,7 +3,7 @@ declare(strict_types=1); use TypePHP\Exception\TypeError; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Collections\ShopwareCollection; use TypePHP\Tests\Fixtures\Collections\ShopwareEntityCollection; use TypePHP\Tests\Fixtures\Collections\ShopwareEntitySearchResult; diff --git a/tests/TypeChecking/InheritanceAndAttributes/LiskovAndVendorIsolationTest.php b/tests/TypeChecking/InheritanceAndAttributes/LiskovAndVendorIsolationTest.php index 3d8b8ec7..735a1ca8 100644 --- a/tests/TypeChecking/InheritanceAndAttributes/LiskovAndVendorIsolationTest.php +++ b/tests/TypeChecking/InheritanceAndAttributes/LiskovAndVendorIsolationTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Liskov\AppChildService; use TypePHP\Tests\Fixtures\Liskov\ChildLiskovService; use TypePHP\Tests\Fixtures\Liskov\RenamedParamImplementation; diff --git a/tests/TypeChecking/InheritanceAndAttributes/ParameterShiftInheritanceTest.php b/tests/TypeChecking/InheritanceAndAttributes/ParameterShiftInheritanceTest.php index 6c45504d..6e3b1296 100644 --- a/tests/TypeChecking/InheritanceAndAttributes/ParameterShiftInheritanceTest.php +++ b/tests/TypeChecking/InheritanceAndAttributes/ParameterShiftInheritanceTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Services\ChildShiftedMethodService; use TypePHP\Tests\Fixtures\Services\ChildShiftedOopService; use TypePHP\Tests\Fixtures\Services\ChildShiftedParamService; diff --git a/tests/TypeChecking/InheritanceAndAttributes/SameNamespaceGlobalCollisionTest.php b/tests/TypeChecking/InheritanceAndAttributes/SameNamespaceGlobalCollisionTest.php index 79bd7d42..e8c008bc 100644 --- a/tests/TypeChecking/InheritanceAndAttributes/SameNamespaceGlobalCollisionTest.php +++ b/tests/TypeChecking/InheritanceAndAttributes/SameNamespaceGlobalCollisionTest.php @@ -5,7 +5,7 @@ namespace TypePHP\Tests\TypeChecking\InheritanceAndAttributes; use ReflectionMethod; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Tests\Fixtures\Shopware\Error\Error; use TypePHP\Tests\Fixtures\Shopware\Error\ErrorCollection; use TypePHP\Tests\Fixtures\Shopware\Error\TestError; diff --git a/tests/TypeChecking/InheritanceAndAttributes/SubNamespaceResolutionTest.php b/tests/TypeChecking/InheritanceAndAttributes/SubNamespaceResolutionTest.php index 4dba052c..e566a839 100644 --- a/tests/TypeChecking/InheritanceAndAttributes/SubNamespaceResolutionTest.php +++ b/tests/TypeChecking/InheritanceAndAttributes/SubNamespaceResolutionTest.php @@ -8,7 +8,7 @@ use ReflectionFunction; use TypePHP\Exception\TypeError; -use TypePHP\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Tests\Fixtures\Domain; /** diff --git a/tests/TypeChecking/Stubs/StubSystemTest.php b/tests/TypeChecking/Stubs/StubSystemTest.php index 753ee939..1b504156 100644 --- a/tests/TypeChecking/Stubs/StubSystemTest.php +++ b/tests/TypeChecking/Stubs/StubSystemTest.php @@ -4,7 +4,7 @@ use TypePHP\Exception\TypeError; use TypePHP\Extension\ExtensionInterface; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Liskov\AppChildService; use TypePHP\Tests\Fixtures\Liskov\SimulatedVendorParent; use TypePHP\Tests\Fixtures\Services\ChildMagicMethodService; diff --git a/tests/Unit/LineNumberPreservationTest.php b/tests/Unit/LineNumberPreservationTest.php index 428360d1..e5cdd2f6 100644 --- a/tests/Unit/LineNumberPreservationTest.php +++ b/tests/Unit/LineNumberPreservationTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\StreamWrapper; +use TypePHP\Internal\Io\StreamWrapper; describe('Line Number Preservation', function () { test('transforms code without shifting original line numbers for parameter checks', function () { diff --git a/tests/Visitor/FunctionContractInjectorTest.php b/tests/Visitor/FunctionContractInjectorTest.php index f5b72175..407aa11d 100644 --- a/tests/Visitor/FunctionContractInjectorTest.php +++ b/tests/Visitor/FunctionContractInjectorTest.php @@ -4,7 +4,7 @@ use PhpParser\Comment\Doc; use PhpParser\Node; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Ast\FunctionContractInjector; describe('FunctionContractInjector Unit Tests', function () { @@ -60,7 +60,7 @@ public function dd(): never } PHP; - $transformed = TypePHP\Internal\StreamWrapper::transformSource($source, 'test_never_method.php'); + $transformed = TypePHP\Internal\Io\StreamWrapper::transformSource($source, 'test_never_method.php'); expect($transformed)->toContain('RuntimeTypeChecker::setupScope') ->and($transformed)->not()->toContain('return ($__typephpRet') diff --git a/tests/Visitor/PropertyHookInjectorTest.php b/tests/Visitor/PropertyHookInjectorTest.php index c678975b..8528a085 100644 --- a/tests/Visitor/PropertyHookInjectorTest.php +++ b/tests/Visitor/PropertyHookInjectorTest.php @@ -8,7 +8,7 @@ use PhpParser\Comment\Doc; use PhpParser\Node; -use TypePHP\Internal\Config; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Ast\PropertyHookInjector; describe('PropertyHookInjector Unit Tests', function () { From 13fadce40bc0df8ac45468bed5bb8c4cf944deb4 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 15:47:50 +0800 Subject: [PATCH 04/31] Organizing folders --- src/Internal/Checker/GeneratorChecker.php | 2 +- src/Internal/Checker/InlineChecker.php | 4 ++-- src/Internal/Checker/ParamChecker.php | 2 +- src/Internal/Checker/ReturnChecker.php | 4 ++-- src/Internal/Docblock/ContractParser.php | 2 +- src/Internal/Generics/TemplateManager.php | 3 ++- src/Internal/RuntimeTypeChecker.php | 8 +++++--- src/Internal/Util/ClassNameValidator.php | 2 +- src/{ => Internal}/Validator/ArrayShapeValidator.php | 2 +- src/{ => Internal}/Validator/ArrayValidator.php | 2 +- src/{ => Internal}/Validator/ConstValidator.php | 2 +- src/{ => Internal}/Validator/GenericValidator.php | 2 +- src/{ => Internal}/Validator/IdentifierValidator.php | 4 ++-- src/{ => Internal}/Validator/IntersectionValidator.php | 2 +- src/{ => Internal}/Validator/NullableValidator.php | 2 +- src/{ => Internal}/Validator/ObjectShapeValidator.php | 2 +- src/{ => Internal}/Validator/TypeValidatorInterface.php | 2 +- src/{ => Internal}/Validator/TypeValidatorRegistry.php | 2 +- src/{ => Internal}/Validator/UnionValidator.php | 2 +- src/{ => Internal}/Wrapper/CallableWrapper.php | 4 ++-- src/{ => Internal}/Wrapper/IterableWrapper.php | 4 ++-- src/{ => Internal}/Wrapper/IteratorProxy.php | 2 +- tests/RuntimeChecker/GeneratorCheckerTest.php | 2 +- tests/RuntimeChecker/InlineCheckerTest.php | 2 +- tests/RuntimeChecker/ParamCheckerTest.php | 2 +- tests/RuntimeChecker/ReturnCheckerTest.php | 2 +- tests/Unit/ValidatorsTest.php | 2 +- tests/Wrapper/CallableWrapperTest.php | 4 ++-- tests/Wrapper/IteratorProxyTest.php | 2 +- 29 files changed, 40 insertions(+), 37 deletions(-) rename src/{ => Internal}/Validator/ArrayShapeValidator.php (98%) rename src/{ => Internal}/Validator/ArrayValidator.php (99%) rename src/{ => Internal}/Validator/ConstValidator.php (99%) rename src/{ => Internal}/Validator/GenericValidator.php (99%) rename src/{ => Internal}/Validator/IdentifierValidator.php (98%) rename src/{ => Internal}/Validator/IntersectionValidator.php (95%) rename src/{ => Internal}/Validator/NullableValidator.php (94%) rename src/{ => Internal}/Validator/ObjectShapeValidator.php (98%) rename src/{ => Internal}/Validator/TypeValidatorInterface.php (92%) rename src/{ => Internal}/Validator/TypeValidatorRegistry.php (98%) rename src/{ => Internal}/Validator/UnionValidator.php (97%) rename src/{ => Internal}/Wrapper/CallableWrapper.php (98%) rename src/{ => Internal}/Wrapper/IterableWrapper.php (98%) rename src/{ => Internal}/Wrapper/IteratorProxy.php (98%) diff --git a/src/Internal/Checker/GeneratorChecker.php b/src/Internal/Checker/GeneratorChecker.php index cfd4bbeb..2962b283 100644 --- a/src/Internal/Checker/GeneratorChecker.php +++ b/src/Internal/Checker/GeneratorChecker.php @@ -12,7 +12,7 @@ use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; /** * @internal Evaluates generator yield and send (TSend) type validations. diff --git a/src/Internal/Checker/InlineChecker.php b/src/Internal/Checker/InlineChecker.php index dbdef58e..bc899c0b 100644 --- a/src/Internal/Checker/InlineChecker.php +++ b/src/Internal/Checker/InlineChecker.php @@ -30,8 +30,8 @@ use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; -use TypePHP\Validator\TypeValidatorRegistry; -use TypePHP\Wrapper\CallableWrapper; +use TypePHP\Internal\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Wrapper\CallableWrapper; /** * Evaluates inline variable (@var) and class property validation rules. diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index 364e9479..66d35581 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -23,7 +23,7 @@ use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; /** * @internal Evaluates function and method parameter contract validations (including dynamic @method calls via __call / __callStatic). diff --git a/src/Internal/Checker/ReturnChecker.php b/src/Internal/Checker/ReturnChecker.php index d8a7ac17..19c2eb05 100644 --- a/src/Internal/Checker/ReturnChecker.php +++ b/src/Internal/Checker/ReturnChecker.php @@ -20,8 +20,8 @@ use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; -use TypePHP\Validator\TypeValidatorRegistry; -use TypePHP\Wrapper\CallableWrapper; +use TypePHP\Internal\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Wrapper\CallableWrapper; /** * @internal Evaluates function and method return contract validations (including dynamic @method calls via __call / __callStatic). diff --git a/src/Internal/Docblock/ContractParser.php b/src/Internal/Docblock/ContractParser.php index 889b0b5a..8cbcb2d9 100644 --- a/src/Internal/Docblock/ContractParser.php +++ b/src/Internal/Docblock/ContractParser.php @@ -25,7 +25,7 @@ use TypePHP\Internal\Util\Config; use TypePHP\Internal\Util\StubManager; use TypePHP\Internal\Resolver\SpecialTypeResolver; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; /** * @internal Main orchestrator parsing and caching PHPDoc contracts (@param, @return, @template, @phpstan-type, @var, stubs). diff --git a/src/Internal/Generics/TemplateManager.php b/src/Internal/Generics/TemplateManager.php index 5abd5b57..24e0afd3 100644 --- a/src/Internal/Generics/TemplateManager.php +++ b/src/Internal/Generics/TemplateManager.php @@ -20,8 +20,9 @@ use PHPStan\PhpDocParser\ParserConfig; use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Docblock\DocblockExtractor; -use TypePHP\Contract\FileFilter; +use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Resolver\HierarchyResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Util\ClassNameValidator; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; diff --git a/src/Internal/RuntimeTypeChecker.php b/src/Internal/RuntimeTypeChecker.php index 69719b9c..da17e39d 100644 --- a/src/Internal/RuntimeTypeChecker.php +++ b/src/Internal/RuntimeTypeChecker.php @@ -6,6 +6,7 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Ast\ScopeCleaner; use TypePHP\Internal\Checker\GeneratorChecker; @@ -13,9 +14,10 @@ use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Checker\ReturnChecker; use TypePHP\Internal\Generics\TemplateManager; -use TypePHP\Validator\TypeValidatorRegistry; -use TypePHP\Wrapper\CallableWrapper; -use TypePHP\Wrapper\IterableWrapper; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Wrapper\CallableWrapper; +use TypePHP\Internal\Wrapper\IterableWrapper; /** * Core runtime type checking engine facade for parameter validation, return type enforcement, and variable tracking. diff --git a/src/Internal/Util/ClassNameValidator.php b/src/Internal/Util/ClassNameValidator.php index f2df59aa..b0717e48 100644 --- a/src/Internal/Util/ClassNameValidator.php +++ b/src/Internal/Util/ClassNameValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Internal; +namespace TypePHP\Internal\Util; /** * @internal diff --git a/src/Validator/ArrayShapeValidator.php b/src/Internal/Validator/ArrayShapeValidator.php similarity index 98% rename from src/Validator/ArrayShapeValidator.php rename to src/Internal/Validator/ArrayShapeValidator.php index a360ae82..df334cd7 100644 --- a/src/Validator/ArrayShapeValidator.php +++ b/src/Internal/Validator/ArrayShapeValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; diff --git a/src/Validator/ArrayValidator.php b/src/Internal/Validator/ArrayValidator.php similarity index 99% rename from src/Validator/ArrayValidator.php rename to src/Internal/Validator/ArrayValidator.php index ccd71866..d7447cc2 100644 --- a/src/Validator/ArrayValidator.php +++ b/src/Internal/Validator/ArrayValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use Generator; use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; diff --git a/src/Validator/ConstValidator.php b/src/Internal/Validator/ConstValidator.php similarity index 99% rename from src/Validator/ConstValidator.php rename to src/Internal/Validator/ConstValidator.php index 909487e6..df989bd1 100644 --- a/src/Validator/ConstValidator.php +++ b/src/Internal/Validator/ConstValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFalseNode; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFloatNode; diff --git a/src/Validator/GenericValidator.php b/src/Internal/Validator/GenericValidator.php similarity index 99% rename from src/Validator/GenericValidator.php rename to src/Internal/Validator/GenericValidator.php index a57a4816..743565f7 100644 --- a/src/Validator/GenericValidator.php +++ b/src/Internal/Validator/GenericValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; diff --git a/src/Validator/IdentifierValidator.php b/src/Internal/Validator/IdentifierValidator.php similarity index 98% rename from src/Validator/IdentifierValidator.php rename to src/Internal/Validator/IdentifierValidator.php index a33b19f1..add622bc 100644 --- a/src/Validator/IdentifierValidator.php +++ b/src/Internal/Validator/IdentifierValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; @@ -10,7 +10,7 @@ use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; -use TypePHP\Wrapper\CallableWrapper; +use TypePHP\Internal\Wrapper\CallableWrapper; /** * @internal Class for validating basic scalar identifier types like int, string, bool, array, list, object, callable, resource, null, true, false, mixed, scalar, void. diff --git a/src/Validator/IntersectionValidator.php b/src/Internal/Validator/IntersectionValidator.php similarity index 95% rename from src/Validator/IntersectionValidator.php rename to src/Internal/Validator/IntersectionValidator.php index 05963a5c..f3f78a90 100644 --- a/src/Validator/IntersectionValidator.php +++ b/src/Internal/Validator/IntersectionValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; diff --git a/src/Validator/NullableValidator.php b/src/Internal/Validator/NullableValidator.php similarity index 94% rename from src/Validator/NullableValidator.php rename to src/Internal/Validator/NullableValidator.php index e9968bfc..941058e8 100644 --- a/src/Validator/NullableValidator.php +++ b/src/Internal/Validator/NullableValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; diff --git a/src/Validator/ObjectShapeValidator.php b/src/Internal/Validator/ObjectShapeValidator.php similarity index 98% rename from src/Validator/ObjectShapeValidator.php rename to src/Internal/Validator/ObjectShapeValidator.php index 355853da..a4863aa6 100644 --- a/src/Validator/ObjectShapeValidator.php +++ b/src/Internal/Validator/ObjectShapeValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; diff --git a/src/Validator/TypeValidatorInterface.php b/src/Internal/Validator/TypeValidatorInterface.php similarity index 92% rename from src/Validator/TypeValidatorInterface.php rename to src/Internal/Validator/TypeValidatorInterface.php index a85a76a2..74d282d1 100644 --- a/src/Validator/TypeValidatorInterface.php +++ b/src/Internal/Validator/TypeValidatorInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use TypePHP\Internal\Diagnostic\ErrorMessage; diff --git a/src/Validator/TypeValidatorRegistry.php b/src/Internal/Validator/TypeValidatorRegistry.php similarity index 98% rename from src/Validator/TypeValidatorRegistry.php rename to src/Internal/Validator/TypeValidatorRegistry.php index d3223d37..c99f9875 100644 --- a/src/Validator/TypeValidatorRegistry.php +++ b/src/Internal/Validator/TypeValidatorRegistry.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; diff --git a/src/Validator/UnionValidator.php b/src/Internal/Validator/UnionValidator.php similarity index 97% rename from src/Validator/UnionValidator.php rename to src/Internal/Validator/UnionValidator.php index bb55e969..0bef7d5c 100644 --- a/src/Validator/UnionValidator.php +++ b/src/Internal/Validator/UnionValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Validator; +namespace TypePHP\Internal\Validator; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; diff --git a/src/Wrapper/CallableWrapper.php b/src/Internal/Wrapper/CallableWrapper.php similarity index 98% rename from src/Wrapper/CallableWrapper.php rename to src/Internal/Wrapper/CallableWrapper.php index 2ff2dd0d..63d9aa91 100644 --- a/src/Wrapper/CallableWrapper.php +++ b/src/Internal/Wrapper/CallableWrapper.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Wrapper; +namespace TypePHP\Internal\Wrapper; use Closure; use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; @@ -19,7 +19,7 @@ use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; /** * Wraps callables to enforce argument and return type contracts dynamically at runtime. diff --git a/src/Wrapper/IterableWrapper.php b/src/Internal/Wrapper/IterableWrapper.php similarity index 98% rename from src/Wrapper/IterableWrapper.php rename to src/Internal/Wrapper/IterableWrapper.php index f967fd23..ba5a8fb9 100644 --- a/src/Wrapper/IterableWrapper.php +++ b/src/Internal/Wrapper/IterableWrapper.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Wrapper; +namespace TypePHP\Internal\Wrapper; use Generator; use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; @@ -15,7 +15,7 @@ use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; /** * Wraps Traversable objects and Generators to evaluate key and value type constraints lazily during iteration. diff --git a/src/Wrapper/IteratorProxy.php b/src/Internal/Wrapper/IteratorProxy.php similarity index 98% rename from src/Wrapper/IteratorProxy.php rename to src/Internal/Wrapper/IteratorProxy.php index 7ddd8313..381193dd 100644 --- a/src/Wrapper/IteratorProxy.php +++ b/src/Internal/Wrapper/IteratorProxy.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace TypePHP\Wrapper; +namespace TypePHP\Internal\Wrapper; use Countable; use Iterator; diff --git a/tests/RuntimeChecker/GeneratorCheckerTest.php b/tests/RuntimeChecker/GeneratorCheckerTest.php index 0d0c7b04..e0850c4f 100644 --- a/tests/RuntimeChecker/GeneratorCheckerTest.php +++ b/tests/RuntimeChecker/GeneratorCheckerTest.php @@ -4,7 +4,7 @@ use TypePHP\Internal\Checker\GeneratorChecker; use TypePHP\Internal\Diagnostic\ErrorMessage; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; /** * @return Generator diff --git a/tests/RuntimeChecker/InlineCheckerTest.php b/tests/RuntimeChecker/InlineCheckerTest.php index 60f5f580..48f0ec37 100644 --- a/tests/RuntimeChecker/InlineCheckerTest.php +++ b/tests/RuntimeChecker/InlineCheckerTest.php @@ -12,7 +12,7 @@ use TypePHP\Tests\Fixtures\Generics\HookedCollection; use TypePHP\Tests\Fixtures\Types\ConfiguredProperty; use TypePHP\TypePHP; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; describe('InlineChecker Unit Tests', function () { beforeEach(function () { diff --git a/tests/RuntimeChecker/ParamCheckerTest.php b/tests/RuntimeChecker/ParamCheckerTest.php index e605f3b3..a52f998a 100644 --- a/tests/RuntimeChecker/ParamCheckerTest.php +++ b/tests/RuntimeChecker/ParamCheckerTest.php @@ -11,7 +11,7 @@ use TypePHP\Tests\Fixtures\Services\UserService; use TypePHP\Tests\Fixtures\Types\ClassStringFactoryContainer; use TypePHP\Tests\Fixtures\Types\MagicMethodFixture; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; describe('ParamChecker Unit Tests', function () { beforeEach(function () { diff --git a/tests/RuntimeChecker/ReturnCheckerTest.php b/tests/RuntimeChecker/ReturnCheckerTest.php index a7a5cd38..270f6f04 100644 --- a/tests/RuntimeChecker/ReturnCheckerTest.php +++ b/tests/RuntimeChecker/ReturnCheckerTest.php @@ -14,7 +14,7 @@ use TypePHP\Tests\Fixtures\Services\UserEntityFactory; use TypePHP\Tests\Fixtures\Services\UserService; use TypePHP\Tests\Fixtures\Types\MagicMethodFixture; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; describe('ReturnChecker Unit Tests', function () { beforeEach(function () { diff --git a/tests/Unit/ValidatorsTest.php b/tests/Unit/ValidatorsTest.php index 2bba867e..168c022c 100644 --- a/tests/Unit/ValidatorsTest.php +++ b/tests/Unit/ValidatorsTest.php @@ -24,7 +24,7 @@ use TypePHP\Tests\Fixtures\Types\StatusEnum; use TypePHP\Tests\Fixtures\Types\UserObjectShape; use TypePHP\Tests\Fixtures\Types\WildcardConstantFixture; -use TypePHP\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Validator\TypeValidatorRegistry; beforeEach(function () { $this->registry = new TypeValidatorRegistry(); diff --git a/tests/Wrapper/CallableWrapperTest.php b/tests/Wrapper/CallableWrapperTest.php index 8cdbe61c..2f3d58e7 100644 --- a/tests/Wrapper/CallableWrapperTest.php +++ b/tests/Wrapper/CallableWrapperTest.php @@ -6,8 +6,8 @@ use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use TypePHP\Exception\TypeError; -use TypePHP\Validator\TypeValidatorRegistry; -use TypePHP\Wrapper\CallableWrapper; +use TypePHP\Internal\Validator\TypeValidatorRegistry; +use TypePHP\Internal\Wrapper\CallableWrapper; describe('CallableWrapper Unit Tests', function () { test('returns raw value if callable is not valid or node is not CallableTypeNode', function () { diff --git a/tests/Wrapper/IteratorProxyTest.php b/tests/Wrapper/IteratorProxyTest.php index 397964f3..bd003118 100644 --- a/tests/Wrapper/IteratorProxyTest.php +++ b/tests/Wrapper/IteratorProxyTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Wrapper\IteratorProxy; +use TypePHP\Internal\Wrapper\IteratorProxy; describe('IteratorProxy Unit Tests', function () { test('iterates inner traversable cleanly while executing type check callback', function () { From cce4a213f16ef4b66a38f892902deb9db12df80d Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 15:58:30 +0800 Subject: [PATCH 05/31] fix code styling --- src/Internal/Ast/FunctionContractInjector.php | 2 +- src/Internal/Checker/GeneratorChecker.php | 2 +- src/Internal/Checker/InlineChecker.php | 6 +- src/Internal/Checker/ParamChecker.php | 10 +- src/Internal/Checker/ReturnChecker.php | 7 +- src/Internal/Docblock/ContractParser.php | 4 +- src/Internal/Docblock/DocblockExtractor.php | 2 +- src/Internal/Generics/TemplateManager.php | 12 +- src/Internal/Io/StreamWrapper.php | 3 +- src/Internal/Resolver/SpecialTypeResolver.php | 2 +- src/Internal/RuntimeTypeChecker.php | 4 +- src/Internal/Util/Config.php | 7 +- src/Internal/Util/PathMatcher.php | 2 +- src/Internal/Validator/ArrayValidator.php | 2 +- src/Internal/Validator/GenericValidator.php | 6 +- .../Validator/IdentifierValidator.php | 2 +- src/Internal/Wrapper/CallableWrapper.php | 4 +- src/Internal/Wrapper/IterableWrapper.php | 4 +- src/TypePHP.php | 4 +- tests/Contract/VendorIsolationPathTest.php | 2 +- tests/Extension/ExtensionManagerTest.php | 2 +- tests/Internal/RuntimeTypeCheckerTest.php | 2 +- tests/Internal/StreamWrapperTest.php | 2 +- tests/RuntimeChecker/InlineCheckerTest.php | 4 +- tests/RuntimeChecker/ParamCheckerTest.php | 4 +- tests/RuntimeChecker/ReturnCheckerTest.php | 4 +- .../ArrayComplexSubtypesTest.php | 119 ++++++++--- ...NormalUnionAndIntersectionSubtypesTest.php | 189 ++++++++++++++---- .../ListSubtypeOfArrayConditionalTest.php | 2 +- .../MutatedParamConditionalReturnTest.php | 2 +- .../NullableTemplateConditionalReturnTest.php | 2 +- ...omplexUnionAndIntersectionSubtypesTest.php | 104 ++++++++-- .../GenericUnionSubsetVarianceTest.php | 24 ++- tests/Unit/ValidatorsTest.php | 2 +- .../Visitor/FunctionContractInjectorTest.php | 2 +- tests/Visitor/PropertyHookInjectorTest.php | 2 +- 36 files changed, 407 insertions(+), 146 deletions(-) diff --git a/src/Internal/Ast/FunctionContractInjector.php b/src/Internal/Ast/FunctionContractInjector.php index ed3d7674..ccbb506a 100644 --- a/src/Internal/Ast/FunctionContractInjector.php +++ b/src/Internal/Ast/FunctionContractInjector.php @@ -649,4 +649,4 @@ public function enterNode(Node $n): int|array|null return $newStmts; } -} \ No newline at end of file +} diff --git a/src/Internal/Checker/GeneratorChecker.php b/src/Internal/Checker/GeneratorChecker.php index 2962b283..631873c3 100644 --- a/src/Internal/Checker/GeneratorChecker.php +++ b/src/Internal/Checker/GeneratorChecker.php @@ -9,9 +9,9 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Validator\TypeValidatorRegistry; /** diff --git a/src/Internal/Checker/InlineChecker.php b/src/Internal/Checker/InlineChecker.php index bc899c0b..d8c86305 100644 --- a/src/Internal/Checker/InlineChecker.php +++ b/src/Internal/Checker/InlineChecker.php @@ -25,11 +25,11 @@ use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Internal\Util\Config; -use TypePHP\Internal\Dockblock\DocblockNormalizer; -use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Docblock\DocblockNormalizer; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; +use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Validator\TypeValidatorRegistry; use TypePHP\Internal\Wrapper\CallableWrapper; diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index 66d35581..91b5a891 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -13,16 +13,16 @@ use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Internal\Resolver\HierarchyResolver; -use TypePHP\Internal\Util\ClassNameValidator; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; -use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; +use TypePHP\Internal\Resolver\HierarchyResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Util\ClassNameValidator; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Validator\TypeValidatorRegistry; /** diff --git a/src/Internal/Checker/ReturnChecker.php b/src/Internal/Checker/ReturnChecker.php index 19c2eb05..f31dda8c 100644 --- a/src/Internal/Checker/ReturnChecker.php +++ b/src/Internal/Checker/ReturnChecker.php @@ -14,12 +14,11 @@ use ReflectionClass; use Traversable; use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Internal\Resolver\HierarchyResolver; -use TypePHP\Internal\Util\ClassNameValidator; -use TypePHP\Internal\Util\Config; -use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; +use TypePHP\Internal\Resolver\HierarchyResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Util\Config; use TypePHP\Internal\Validator\TypeValidatorRegistry; use TypePHP\Internal\Wrapper\CallableWrapper; diff --git a/src/Internal/Docblock/ContractParser.php b/src/Internal/Docblock/ContractParser.php index 8cbcb2d9..f3ebced7 100644 --- a/src/Internal/Docblock/ContractParser.php +++ b/src/Internal/Docblock/ContractParser.php @@ -22,9 +22,11 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use TypePHP\Internal\Checker\InlineChecker; +use TypePHP\Internal\Resolver\HierarchyResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Util\StubManager; -use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Validator\TypeValidatorRegistry; /** diff --git a/src/Internal/Docblock/DocblockExtractor.php b/src/Internal/Docblock/DocblockExtractor.php index 177d6b52..ccdf4cc4 100644 --- a/src/Internal/Docblock/DocblockExtractor.php +++ b/src/Internal/Docblock/DocblockExtractor.php @@ -17,9 +17,9 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Util\ClassNameValidator; use TypePHP\Internal\Util\StubManager; -use TypePHP\Internal\Resolver\SpecialTypeResolver; /** * @internal Encapsulates PHPDoc AST parsing, tokenizing, and tag extractions. diff --git a/src/Internal/Generics/TemplateManager.php b/src/Internal/Generics/TemplateManager.php index 24e0afd3..a44b94e6 100644 --- a/src/Internal/Generics/TemplateManager.php +++ b/src/Internal/Generics/TemplateManager.php @@ -18,14 +18,14 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; +use TypePHP\Internal\Diagnostic\ErrorFactory; +use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Docblock\DocblockExtractor; -use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Resolver\HierarchyResolver; use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Util\ClassNameValidator; -use TypePHP\Internal\Diagnostic\ErrorFactory; -use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Util\StubManager; use WeakMap; @@ -1224,7 +1224,7 @@ private static function resolveTypeNodeAst(TypeNode $n, \ReflectionClass $ref): } if ($n instanceof GenericTypeNode) { $base = new IdentifierTypeNode(SpecialTypeResolver::resolveFqcn($n->type->name, $ref)); - $generics = array_map(fn($t) => self::resolveTypeNodeAst($t, $ref), $n->genericTypes); + $generics = array_map(fn ($t) => self::resolveTypeNodeAst($t, $ref), $n->genericTypes); return new GenericTypeNode($base, $generics, $n->variances); } @@ -1235,10 +1235,10 @@ private static function resolveTypeNodeAst(TypeNode $n, \ReflectionClass $ref): return new NullableTypeNode(self::resolveTypeNodeAst($n->type, $ref)); } if ($n instanceof UnionTypeNode) { - return new UnionTypeNode(array_map(fn($t) => self::resolveTypeNodeAst($t, $ref), $n->types)); + return new UnionTypeNode(array_map(fn ($t) => self::resolveTypeNodeAst($t, $ref), $n->types)); } if ($n instanceof IntersectionTypeNode) { - return new IntersectionTypeNode(array_map(fn($t) => self::resolveTypeNodeAst($t, $ref), $n->types)); + return new IntersectionTypeNode(array_map(fn ($t) => self::resolveTypeNodeAst($t, $ref), $n->types)); } return $n; diff --git a/src/Internal/Io/StreamWrapper.php b/src/Internal/Io/StreamWrapper.php index cc38be9d..02b06dbb 100644 --- a/src/Internal/Io/StreamWrapper.php +++ b/src/Internal/Io/StreamWrapper.php @@ -4,7 +4,7 @@ namespace TypePHP\Internal\Io; -require_once __DIR__ . '/PathMatcher.php'; +require_once __DIR__ . '/../Util/PathMatcher.php'; use PhpParser\NodeTraverser; use PhpParser\NodeVisitor\CloningVisitor; @@ -13,6 +13,7 @@ use TypePHP\Internal\Ast\TypePHPPrinter; use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\PathMatcher; /** * Intercepts PHP 'file://' protocol operations to perform on-the-fly AST transformations diff --git a/src/Internal/Resolver/SpecialTypeResolver.php b/src/Internal/Resolver/SpecialTypeResolver.php index 374fe297..c6d525e8 100644 --- a/src/Internal/Resolver/SpecialTypeResolver.php +++ b/src/Internal/Resolver/SpecialTypeResolver.php @@ -26,10 +26,10 @@ use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\Util\ClassNameValidator; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; +use TypePHP\Internal\Util\ClassNameValidator; /** * Resolves special type identifiers (self, static, parent, FQCNs) against Reflection or file contexts. diff --git a/src/Internal/RuntimeTypeChecker.php b/src/Internal/RuntimeTypeChecker.php index da17e39d..bd60f2f3 100644 --- a/src/Internal/RuntimeTypeChecker.php +++ b/src/Internal/RuntimeTypeChecker.php @@ -6,13 +6,13 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\Diagnostic\ErrorMessage; -use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Ast\ScopeCleaner; use TypePHP\Internal\Checker\GeneratorChecker; use TypePHP\Internal\Checker\InlineChecker; use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Checker\ReturnChecker; +use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Util\Config; use TypePHP\Internal\Validator\TypeValidatorRegistry; diff --git a/src/Internal/Util/Config.php b/src/Internal/Util/Config.php index d3c015c7..ed54e266 100644 --- a/src/Internal/Util/Config.php +++ b/src/Internal/Util/Config.php @@ -4,16 +4,15 @@ namespace TypePHP\Internal\Util; -use TypePHP\Internal\Docblock\ContractParser; -use TypePHP\Internal\Resolver\HierarchyResolver; use TypePHP\Extension\ExtensionInterface; -use TypePHP\Internal\Util\ExtensionManager; use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Checker\ReturnChecker; -use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Io\CacheManager; use TypePHP\Internal\Io\StreamWrapper; +use TypePHP\Internal\Resolver\HierarchyResolver; +use TypePHP\Internal\Resolver\SpecialTypeResolver; /** * Global configuration manager for loading and dynamically overriding settings. diff --git a/src/Internal/Util/PathMatcher.php b/src/Internal/Util/PathMatcher.php index 084f1836..bc871ea0 100644 --- a/src/Internal/Util/PathMatcher.php +++ b/src/Internal/Util/PathMatcher.php @@ -6,7 +6,7 @@ use TypePHP\Internal\Io\CacheManager; -require_once __DIR__ . '/CacheManager.php'; +require_once __DIR__ . '/../Io/CacheManager.php'; /** * Centralized utility for path normalization, glob compilation, vendor isolation, and specificity matching. diff --git a/src/Internal/Validator/ArrayValidator.php b/src/Internal/Validator/ArrayValidator.php index d7447cc2..aefcd13b 100644 --- a/src/Internal/Validator/ArrayValidator.php +++ b/src/Internal/Validator/ArrayValidator.php @@ -8,10 +8,10 @@ use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use Traversable; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; +use TypePHP\Internal\Util\Config; /** * Validates array and Traversable collection instances against ArrayTypeNode ASTs (Type[]). diff --git a/src/Internal/Validator/GenericValidator.php b/src/Internal/Validator/GenericValidator.php index 743565f7..ada71763 100644 --- a/src/Internal/Validator/GenericValidator.php +++ b/src/Internal/Validator/GenericValidator.php @@ -14,12 +14,12 @@ use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\Util\ClassNameValidator; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; -use TypePHP\Internal\RuntimeTypeChecker; use TypePHP\Internal\Diagnostic\TypeFormatter; +use TypePHP\Internal\RuntimeTypeChecker; +use TypePHP\Internal\Util\ClassNameValidator; +use TypePHP\Internal\Util\Config; /** * @internal Validates values against generic AST structures (int ranges, class-string, list, array, object generics, key-of, value-of, int-mask, int-mask-of). diff --git a/src/Internal/Validator/IdentifierValidator.php b/src/Internal/Validator/IdentifierValidator.php index add622bc..baef6959 100644 --- a/src/Internal/Validator/IdentifierValidator.php +++ b/src/Internal/Validator/IdentifierValidator.php @@ -6,10 +6,10 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\Util\ClassNameValidator; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; +use TypePHP\Internal\Util\ClassNameValidator; use TypePHP\Internal\Wrapper\CallableWrapper; /** diff --git a/src/Internal/Wrapper/CallableWrapper.php b/src/Internal/Wrapper/CallableWrapper.php index 63d9aa91..f3e7c870 100644 --- a/src/Internal/Wrapper/CallableWrapper.php +++ b/src/Internal/Wrapper/CallableWrapper.php @@ -12,13 +12,13 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use ReflectionFunction; use TypeError; -use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Exception\TypeError as TypePHPTypeError; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\TypeFormatter; -use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Validator\TypeValidatorRegistry; /** diff --git a/src/Internal/Wrapper/IterableWrapper.php b/src/Internal/Wrapper/IterableWrapper.php index ba5a8fb9..7cab7634 100644 --- a/src/Internal/Wrapper/IterableWrapper.php +++ b/src/Internal/Wrapper/IterableWrapper.php @@ -9,12 +9,12 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Exception\TypeError as TypePHPTypeError; use TypePHP\Internal\Diagnostic\ErrorFactory; -use TypePHP\Internal\Resolver\SpecialTypeResolver; +use TypePHP\Internal\Docblock\ContractParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; +use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Validator\TypeValidatorRegistry; /** diff --git a/src/TypePHP.php b/src/TypePHP.php index b4d9af6b..6111698e 100644 --- a/src/TypePHP.php +++ b/src/TypePHP.php @@ -4,9 +4,9 @@ namespace TypePHP; -use TypePHP\Internal\Util\Config; -use TypePHP\Internal\Io\StreamWrapper; use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Io\StreamWrapper; +use TypePHP\Internal\Util\Config; final class TypePHP { diff --git a/tests/Contract/VendorIsolationPathTest.php b/tests/Contract/VendorIsolationPathTest.php index 150d3ec3..d3fa9dd5 100644 --- a/tests/Contract/VendorIsolationPathTest.php +++ b/tests/Contract/VendorIsolationPathTest.php @@ -3,8 +3,8 @@ declare(strict_types=1); use TypePHP\Contract\FileFilter; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Io\StreamWrapper; +use TypePHP\Internal\Util\Config; describe('Vendor Path Isolation & Whitelisting (Shopware Doctrine DBAL Reproduction)', function () { beforeEach(function () { diff --git a/tests/Extension/ExtensionManagerTest.php b/tests/Extension/ExtensionManagerTest.php index 58af018f..93fa4837 100644 --- a/tests/Extension/ExtensionManagerTest.php +++ b/tests/Extension/ExtensionManagerTest.php @@ -5,8 +5,8 @@ namespace TypePHP\Tests\Extension; use TypePHP\Contract\FileFilter; -use TypePHP\Internal\Util\ExtensionManager; use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\ExtensionManager; use TypePHP\Tests\Fixtures\Extensions\SampleRegisteredExtension; describe('ExtensionManager Unit Tests', function () { diff --git a/tests/Internal/RuntimeTypeCheckerTest.php b/tests/Internal/RuntimeTypeCheckerTest.php index e92a8e3f..22b7ac87 100644 --- a/tests/Internal/RuntimeTypeCheckerTest.php +++ b/tests/Internal/RuntimeTypeCheckerTest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\RuntimeTypeChecker; +use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Types\ConfiguredProperty; describe('RuntimeTypeChecker Unit Tests', function () { diff --git a/tests/Internal/StreamWrapperTest.php b/tests/Internal/StreamWrapperTest.php index 921af438..40d9fd7a 100644 --- a/tests/Internal/StreamWrapperTest.php +++ b/tests/Internal/StreamWrapperTest.php @@ -3,8 +3,8 @@ declare(strict_types=1); use TypePHP\Contract\FileFilter; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Io\StreamWrapper; +use TypePHP\Internal\Util\Config; describe('StreamWrapper Unit Tests', function () { beforeEach(function () { diff --git a/tests/RuntimeChecker/InlineCheckerTest.php b/tests/RuntimeChecker/InlineCheckerTest.php index 48f0ec37..236ab5e0 100644 --- a/tests/RuntimeChecker/InlineCheckerTest.php +++ b/tests/RuntimeChecker/InlineCheckerTest.php @@ -3,16 +3,16 @@ declare(strict_types=1); use TypePHP\Internal\Checker\InlineChecker; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Generics\TemplateManager; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Validator\TypeValidatorRegistry; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Generics\GenericCollection; use TypePHP\Tests\Fixtures\Generics\HookedCollection; use TypePHP\Tests\Fixtures\Types\ConfiguredProperty; use TypePHP\TypePHP; -use TypePHP\Internal\Validator\TypeValidatorRegistry; describe('InlineChecker Unit Tests', function () { beforeEach(function () { diff --git a/tests/RuntimeChecker/ParamCheckerTest.php b/tests/RuntimeChecker/ParamCheckerTest.php index a52f998a..0fa87efc 100644 --- a/tests/RuntimeChecker/ParamCheckerTest.php +++ b/tests/RuntimeChecker/ParamCheckerTest.php @@ -3,15 +3,15 @@ declare(strict_types=1); use TypePHP\Internal\Checker\ParamChecker; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Validator\TypeValidatorRegistry; use TypePHP\Tests\Fixtures\Callables\GenericCallableService; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Services\ShiftedParamService; use TypePHP\Tests\Fixtures\Services\UserService; use TypePHP\Tests\Fixtures\Types\ClassStringFactoryContainer; use TypePHP\Tests\Fixtures\Types\MagicMethodFixture; -use TypePHP\Internal\Validator\TypeValidatorRegistry; describe('ParamChecker Unit Tests', function () { beforeEach(function () { diff --git a/tests/RuntimeChecker/ReturnCheckerTest.php b/tests/RuntimeChecker/ReturnCheckerTest.php index 270f6f04..16314906 100644 --- a/tests/RuntimeChecker/ReturnCheckerTest.php +++ b/tests/RuntimeChecker/ReturnCheckerTest.php @@ -3,8 +3,9 @@ declare(strict_types=1); use TypePHP\Internal\Checker\ReturnChecker; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Validator\TypeValidatorRegistry; use TypePHP\Tests\Fixtures\Collections\ConcreteFileCollection; use TypePHP\Tests\Fixtures\Collections\PluginConfiguration; use TypePHP\Tests\Fixtures\Conditionals\ConditionalReturnService; @@ -14,7 +15,6 @@ use TypePHP\Tests\Fixtures\Services\UserEntityFactory; use TypePHP\Tests\Fixtures\Services\UserService; use TypePHP\Tests\Fixtures\Types\MagicMethodFixture; -use TypePHP\Internal\Validator\TypeValidatorRegistry; describe('ReturnChecker Unit Tests', function () { beforeEach(function () { diff --git a/tests/TypeChecking/ArraysAndShapes/ArrayComplexSubtypesTest.php b/tests/TypeChecking/ArraysAndShapes/ArrayComplexSubtypesTest.php index 53a1bd63..5771cecf 100644 --- a/tests/TypeChecking/ArraysAndShapes/ArrayComplexSubtypesTest.php +++ b/tests/TypeChecking/ArraysAndShapes/ArrayComplexSubtypesTest.php @@ -3,7 +3,6 @@ declare(strict_types=1); use TypePHP\Exception\TypeError; -use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\Domain\Animal; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Cat; @@ -16,35 +15,99 @@ class ArraySubtypeBird extends Animal class ArrayTripleInterfaceObject implements Countable, ArrayAccess, Iterator { private array $data = ['a' => 1]; - public function count(): int { return count($this->data); } - public function offsetExists(mixed $offset): bool { return isset($this->data[$offset]); } - public function offsetGet(mixed $offset): mixed { return $this->data[$offset] ?? null; } - public function offsetSet(mixed $offset, mixed $value): void { $this->data[$offset] = $value; } - public function offsetUnset(mixed $offset): void { unset($this->data[$offset]); } - public function rewind(): void { reset($this->data); } - public function current(): mixed { return current($this->data); } - public function key(): mixed { return key($this->data); } - public function next(): void { next($this->data); } - public function valid(): bool { return key($this->data) !== null; } + + public function count(): int + { + return \count($this->data); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed + { + return $this->data[$offset] ?? null; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void + { + unset($this->data[$offset]); + } + + public function rewind(): void + { + reset($this->data); + } + + public function current(): mixed + { + return current($this->data); + } + + public function key(): mixed + { + return key($this->data); + } + + public function next(): void + { + next($this->data); + } + + public function valid(): bool + { + return key($this->data) !== null; + } } class ArrayDoubleInterfaceObject implements Countable, ArrayAccess { private array $data = ['a' => 1]; - public function count(): int { return count($this->data); } - public function offsetExists(mixed $offset): bool { return isset($this->data[$offset]); } - public function offsetGet(mixed $offset): mixed { return $this->data[$offset] ?? null; } - public function offsetSet(mixed $offset, mixed $value): void { $this->data[$offset] = $value; } - public function offsetUnset(mixed $offset): void { unset($this->data[$offset]); } + + public function count(): int + { + return \count($this->data); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed + { + return $this->data[$offset] ?? null; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void + { + unset($this->data[$offset]); + } } class ArrayCountableOnly implements Countable { - public function count(): int { return 1; } + public function count(): int + { + return 1; + } } /** * @param list $animals + * * @return list */ function acceptSupersetAnimalList(array $animals): array @@ -54,6 +117,7 @@ function acceptSupersetAnimalList(array $animals): array /** * @param list $animals + * * @return list */ function acceptSubsetAnimalList(array $animals): array @@ -161,14 +225,16 @@ function acceptNestedAnimalList(array $nested): array $broadArray = [new Dog(), new Cat(), new ArraySubtypeBird()]; expect(fn () => acceptSubsetAnimalList($broadArray)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); test('strictly rejects array containing incompatible element not in union', function () { $incompatibleArray = [new Dog(), new Car()]; expect(fn () => acceptSupersetAnimalList($incompatibleArray)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); }); @@ -192,7 +258,8 @@ function acceptNestedAnimalList(array $nested): array $incompleteList = [new ArrayCountableOnly()]; expect(fn () => acceptIntersectionList($incompleteList)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); }); @@ -206,7 +273,7 @@ function acceptNestedAnimalList(array $nested): array test('allows array with heterogeneous items satisfying different branches of DNF', function () { $mixedDnfList = [ new ArrayDoubleInterfaceObject(), - new ArrayTripleInterfaceObject(), + new ArrayTripleInterfaceObject(), ]; expect(acceptDnfList($mixedDnfList))->toBe($mixedDnfList); @@ -215,11 +282,12 @@ function acceptNestedAnimalList(array $nested): array test('strictly rejects array containing an object that fails all DNF branches', function () { $badList = [ new ArrayDoubleInterfaceObject(), - new ArrayCountableOnly(), + new ArrayCountableOnly(), ]; expect(fn () => acceptDnfList($badList)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); }); @@ -240,7 +308,8 @@ function acceptNestedAnimalList(array $nested): array ]; expect(fn () => acceptNestedAnimalList($nestedBad)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); }); -}); \ No newline at end of file +}); diff --git a/tests/TypeChecking/Boundaries/NormalUnionAndIntersectionSubtypesTest.php b/tests/TypeChecking/Boundaries/NormalUnionAndIntersectionSubtypesTest.php index f632927f..738022e4 100644 --- a/tests/TypeChecking/Boundaries/NormalUnionAndIntersectionSubtypesTest.php +++ b/tests/TypeChecking/Boundaries/NormalUnionAndIntersectionSubtypesTest.php @@ -18,17 +18,60 @@ class NormalQuadObject implements Countable, ArrayAccess, Iterator, Stringable { private array $data = ['key' => 'value']; - public function count(): int { return count($this->data); } - public function offsetExists(mixed $offset): bool { return isset($this->data[$offset]); } - public function offsetGet(mixed $offset): mixed { return $this->data[$offset] ?? null; } - public function offsetSet(mixed $offset, mixed $value): void { $this->data[$offset] = $value; } - public function offsetUnset(mixed $offset): void { unset($this->data[$offset]); } - public function rewind(): void { reset($this->data); } - public function current(): mixed { return current($this->data); } - public function key(): mixed { return key($this->data); } - public function next(): void { next($this->data); } - public function valid(): bool { return key($this->data) !== null; } - public function __toString(): string { return 'quad_object'; } + public function count(): int + { + return \count($this->data); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed + { + return $this->data[$offset] ?? null; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void + { + unset($this->data[$offset]); + } + + public function rewind(): void + { + reset($this->data); + } + + public function current(): mixed + { + return current($this->data); + } + + public function key(): mixed + { + return key($this->data); + } + + public function next(): void + { + next($this->data); + } + + public function valid(): bool + { + return key($this->data) !== null; + } + + public function __toString(): string + { + return 'quad_object'; + } } /** @@ -38,11 +81,30 @@ class NormalBranchAObject implements Countable, ArrayAccess { private array $data = ['a' => 1]; - public function count(): int { return count($this->data); } - public function offsetExists(mixed $offset): bool { return isset($this->data[$offset]); } - public function offsetGet(mixed $offset): mixed { return $this->data[$offset] ?? null; } - public function offsetSet(mixed $offset, mixed $value): void { $this->data[$offset] = $value; } - public function offsetUnset(mixed $offset): void { unset($this->data[$offset]); } + public function count(): int + { + return \count($this->data); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed + { + return $this->data[$offset] ?? null; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void + { + unset($this->data[$offset]); + } } /** @@ -52,12 +114,35 @@ class NormalBranchBObject implements Iterator, Stringable { private array $data = ['b' => 2]; - public function rewind(): void { reset($this->data); } - public function current(): mixed { return current($this->data); } - public function key(): mixed { return key($this->data); } - public function next(): void { next($this->data); } - public function valid(): bool { return key($this->data) !== null; } - public function __toString(): string { return 'branch_b_object'; } + public function rewind(): void + { + reset($this->data); + } + + public function current(): mixed + { + return current($this->data); + } + + public function key(): mixed + { + return key($this->data); + } + + public function next(): void + { + next($this->data); + } + + public function valid(): bool + { + return key($this->data) !== null; + } + + public function __toString(): string + { + return 'branch_b_object'; + } } /** @@ -67,13 +152,23 @@ public function __toString(): string { return 'branch_b_object'; } */ class NormalCrossOverObject implements Countable, Stringable { - public function count(): int { return 1; } - public function __toString(): string { return 'crossover_object'; } + public function count(): int + { + return 1; + } + + public function __toString(): string + { + return 'crossover_object'; + } } class NormalSingleCountable implements Countable { - public function count(): int { return 1; } + public function count(): int + { + return 1; + } } /** @@ -81,11 +176,15 @@ public function count(): int { return 1; } */ class NormalSpecialDog extends Dog implements Countable { - public function count(): int { return 5; } + public function count(): int + { + return 5; + } } /** * @param Dog|Cat|NormalBird $animal + * * @return Dog|Cat|NormalBird */ function processNormalUnionAnimal(Animal $animal): Animal @@ -95,6 +194,7 @@ function processNormalUnionAnimal(Animal $animal): Animal /** * @param 'admin'|'editor'|'viewer'|'guest' $role + * * @return 'admin'|'editor'|'viewer'|'guest' */ function processNormalUnionLiteralRole(string $role): string @@ -104,6 +204,7 @@ function processNormalUnionLiteralRole(string $role): string /** * @param 1|2|3|4|5 $number + * * @return 1|2|3|4|5 */ function processNormalUnionLiteralNumber(int $number): int @@ -113,6 +214,7 @@ function processNormalUnionLiteralNumber(int $number): int /** * @param positive-int|non-empty-string $idOrCode + * * @return positive-int|non-empty-string */ function processNormalUnionRefinements(mixed $idOrCode): mixed @@ -122,6 +224,7 @@ function processNormalUnionRefinements(mixed $idOrCode): mixed /** * @param Countable&ArrayAccess $collection + * * @return Countable&ArrayAccess */ function processNormalIntersection(object $collection): object @@ -131,6 +234,7 @@ function processNormalIntersection(object $collection): object /** * @param Dog&Countable $pet + * * @return Dog&Countable */ function processNormalClassInterfaceIntersection(object $pet): object @@ -142,6 +246,7 @@ function processNormalClassInterfaceIntersection(object $pet): object * DNF: (Countable & ArrayAccess) | (Iterator & Stringable) * * @param (Countable&ArrayAccess)|(Iterator&Stringable) $dnf + * * @return (Countable&ArrayAccess)|(Iterator&Stringable) */ function processNormalDnf(object $dnf): object @@ -208,19 +313,24 @@ function processNormalDnf(object $dnf): object test('strictly rejects value not present in union', function () { expect(fn () => processNormalUnionAnimal(new Car())) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; expect(fn () => processNormalUnionLiteralRole('superadmin')) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; expect(fn () => processNormalUnionLiteralNumber(99)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; expect(fn () => processNormalUnionRefinements(-50)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; expect(fn () => processNormalUnionRefinements('')) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); }); @@ -248,15 +358,18 @@ function processNormalDnf(object $dnf): object test('strictly rejects object missing one required interface of the intersection', function () { expect(fn () => processNormalIntersection(new NormalSingleCountable())) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); test('strictly rejects object failing class or interface part of class-interface intersection', function () { expect(fn () => processNormalClassInterfaceIntersection(new Dog())) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; expect(fn () => processNormalClassInterfaceIntersection(new NormalSingleCountable())) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); }); @@ -292,14 +405,16 @@ function processNormalDnf(object $dnf): object $crossOver = new NormalCrossOverObject(); expect(fn () => processNormalDnf($crossOver)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); test('strictly rejects object satisfying only a single interface of one branch', function () { $single = new NormalSingleCountable(); expect(fn () => processNormalDnf($single)) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); test('strictly rejects completely unrelated object', function () { @@ -307,4 +422,4 @@ function processNormalDnf(object $dnf): object ->toThrow(TypeError::class); }); }); -}); \ No newline at end of file +}); diff --git a/tests/TypeChecking/Conditionals/ListSubtypeOfArrayConditionalTest.php b/tests/TypeChecking/Conditionals/ListSubtypeOfArrayConditionalTest.php index 0070d385..69993082 100644 --- a/tests/TypeChecking/Conditionals/ListSubtypeOfArrayConditionalTest.php +++ b/tests/TypeChecking/Conditionals/ListSubtypeOfArrayConditionalTest.php @@ -29,4 +29,4 @@ function testListIsArrayConditional(mixed $match, mixed $returnVal): mixed expect($result)->toBe(['key1' => 'val1', 'key2' => 'val2']); }); -}); \ No newline at end of file +}); diff --git a/tests/TypeChecking/Conditionals/MutatedParamConditionalReturnTest.php b/tests/TypeChecking/Conditionals/MutatedParamConditionalReturnTest.php index 66905405..6f85a20d 100644 --- a/tests/TypeChecking/Conditionals/MutatedParamConditionalReturnTest.php +++ b/tests/TypeChecking/Conditionals/MutatedParamConditionalReturnTest.php @@ -39,4 +39,4 @@ function testMutatedParameterConditional(int $length): string expect($result)->toBe(''); }); -}); \ No newline at end of file +}); diff --git a/tests/TypeChecking/Conditionals/NullableTemplateConditionalReturnTest.php b/tests/TypeChecking/Conditionals/NullableTemplateConditionalReturnTest.php index a692a9f7..e1dbd24f 100644 --- a/tests/TypeChecking/Conditionals/NullableTemplateConditionalReturnTest.php +++ b/tests/TypeChecking/Conditionals/NullableTemplateConditionalReturnTest.php @@ -34,4 +34,4 @@ function testNullableTemplateConditional(?string $match = null, mixed $returnVal expect($result)->toBe('matched_id_string'); }); -}); \ No newline at end of file +}); diff --git a/tests/TypeChecking/Generics/ComplexUnionAndIntersectionSubtypesTest.php b/tests/TypeChecking/Generics/ComplexUnionAndIntersectionSubtypesTest.php index 2cac0e56..16270be7 100644 --- a/tests/TypeChecking/Generics/ComplexUnionAndIntersectionSubtypesTest.php +++ b/tests/TypeChecking/Generics/ComplexUnionAndIntersectionSubtypesTest.php @@ -8,8 +8,12 @@ use TypePHP\Tests\Fixtures\Domain\Cat; use TypePHP\Tests\Fixtures\Domain\Dog; -class Bird extends Animal {} -class Fish extends Animal {} +class Bird extends Animal +{ +} +class Fish extends Animal +{ +} /** * Fixture representing an object that implements THREE interfaces @@ -17,26 +21,86 @@ class Fish extends Animal {} class TripleInterfaceObject implements Countable, ArrayAccess, Iterator { private array $data = ['a' => 1]; - public function count(): int { return count($this->data); } - public function offsetExists(mixed $offset): bool { return isset($this->data[$offset]); } - public function offsetGet(mixed $offset): mixed { return $this->data[$offset] ?? null; } - public function offsetSet(mixed $offset, mixed $value): void { $this->data[$offset] = $value; } - public function offsetUnset(mixed $offset): void { unset($this->data[$offset]); } - public function rewind(): void { reset($this->data); } - public function current(): mixed { return current($this->data); } - public function key(): mixed { return key($this->data); } - public function next(): void { next($this->data); } - public function valid(): bool { return key($this->data) !== null; } + + public function count(): int + { + return \count($this->data); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed + { + return $this->data[$offset] ?? null; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void + { + unset($this->data[$offset]); + } + + public function rewind(): void + { + reset($this->data); + } + + public function current(): mixed + { + return current($this->data); + } + + public function key(): mixed + { + return key($this->data); + } + + public function next(): void + { + next($this->data); + } + + public function valid(): bool + { + return key($this->data) !== null; + } } class DoubleInterfaceObject implements Countable, ArrayAccess { private array $data = ['a' => 1]; - public function count(): int { return count($this->data); } - public function offsetExists(mixed $offset): bool { return isset($this->data[$offset]); } - public function offsetGet(mixed $offset): mixed { return $this->data[$offset] ?? null; } - public function offsetSet(mixed $offset, mixed $value): void { $this->data[$offset] = $value; } - public function offsetUnset(mixed $offset): void { unset($this->data[$offset]); } + + public function count(): int + { + return \count($this->data); + } + + public function offsetExists(mixed $offset): bool + { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed + { + return $this->data[$offset] ?? null; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void + { + unset($this->data[$offset]); + } } /** @@ -44,7 +108,9 @@ public function offsetUnset(mixed $offset): void { unset($this->data[$offset]); */ class TypeSetHolder { - /** @var array */ + /** + * @var array + */ public array $items = []; } @@ -150,4 +216,4 @@ class TypeSetHolder })->toThrow(TypeError::class); }); }); -}); \ No newline at end of file +}); diff --git a/tests/TypeChecking/Generics/GenericUnionSubsetVarianceTest.php b/tests/TypeChecking/Generics/GenericUnionSubsetVarianceTest.php index 465cecfe..cb9a6e3a 100644 --- a/tests/TypeChecking/Generics/GenericUnionSubsetVarianceTest.php +++ b/tests/TypeChecking/Generics/GenericUnionSubsetVarianceTest.php @@ -2,17 +2,27 @@ declare(strict_types=1); -class StmtA {} -class StmtB {} -class StmtC {} -class StmtUnrelated {} +class StmtA +{ +} +class StmtB +{ +} +class StmtC +{ +} +class StmtUnrelated +{ +} /** * @template T */ class GenericUnionHolderFixture { - /** @var array */ + /** + * @var array + */ public array $items = []; } @@ -39,6 +49,6 @@ class GenericUnionHolderFixture expect(function () use (&$container, $incompatibleContainer) { $container = $incompatibleContainer; - })->toThrow(\TypeError::class); + })->toThrow(TypeError::class); }); -}); \ No newline at end of file +}); diff --git a/tests/Unit/ValidatorsTest.php b/tests/Unit/ValidatorsTest.php index 168c022c..2c1dd875 100644 --- a/tests/Unit/ValidatorsTest.php +++ b/tests/Unit/ValidatorsTest.php @@ -9,6 +9,7 @@ use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; use TypePHP\Internal\Diagnostic\ErrorMessage; +use TypePHP\Internal\Validator\TypeValidatorRegistry; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Cat; use TypePHP\Tests\Fixtures\Domain\Dog; @@ -24,7 +25,6 @@ use TypePHP\Tests\Fixtures\Types\StatusEnum; use TypePHP\Tests\Fixtures\Types\UserObjectShape; use TypePHP\Tests\Fixtures\Types\WildcardConstantFixture; -use TypePHP\Internal\Validator\TypeValidatorRegistry; beforeEach(function () { $this->registry = new TypeValidatorRegistry(); diff --git a/tests/Visitor/FunctionContractInjectorTest.php b/tests/Visitor/FunctionContractInjectorTest.php index 407aa11d..850cdbf2 100644 --- a/tests/Visitor/FunctionContractInjectorTest.php +++ b/tests/Visitor/FunctionContractInjectorTest.php @@ -4,8 +4,8 @@ use PhpParser\Comment\Doc; use PhpParser\Node; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Ast\FunctionContractInjector; +use TypePHP\Internal\Util\Config; describe('FunctionContractInjector Unit Tests', function () { beforeEach(function () { diff --git a/tests/Visitor/PropertyHookInjectorTest.php b/tests/Visitor/PropertyHookInjectorTest.php index 8528a085..e61fb9bc 100644 --- a/tests/Visitor/PropertyHookInjectorTest.php +++ b/tests/Visitor/PropertyHookInjectorTest.php @@ -8,8 +8,8 @@ use PhpParser\Comment\Doc; use PhpParser\Node; -use TypePHP\Internal\Util\Config; use TypePHP\Internal\Ast\PropertyHookInjector; +use TypePHP\Internal\Util\Config; describe('PropertyHookInjector Unit Tests', function () { beforeEach(function () { From 9ebd31a148ac7dccc1a38e67aa039ee6ad7384e3 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 16:52:51 +0800 Subject: [PATCH 06/31] fix phpstan errors --- src/Internal/Ast/ScopeManager.php | 2 +- src/Internal/Io/CacheManager.php | 2 +- tests/Internal/DocblockNormalizerTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Internal/Ast/ScopeManager.php b/src/Internal/Ast/ScopeManager.php index 96127410..ea3ea2bb 100644 --- a/src/Internal/Ast/ScopeManager.php +++ b/src/Internal/Ast/ScopeManager.php @@ -7,7 +7,7 @@ use PhpParser\Node; use PHPStan\PhpDocParser\Parser\TokenIterator; use TypePHP\Internal\Docblock\DocblockExtractor; -use TypePHP\Internal\Dockblock\DocblockNormalizer; +use TypePHP\Internal\Docblock\DocblockNormalizer; /** * @internal Manages lexical scope stack frames and extracts local @var variable annotations. diff --git a/src/Internal/Io/CacheManager.php b/src/Internal/Io/CacheManager.php index e580dca2..c067495f 100644 --- a/src/Internal/Io/CacheManager.php +++ b/src/Internal/Io/CacheManager.php @@ -4,8 +4,8 @@ namespace TypePHP\Internal\Io; -use TypePHP\Contract\FileFilter; use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\FileFilter; /** * @internal diff --git a/tests/Internal/DocblockNormalizerTest.php b/tests/Internal/DocblockNormalizerTest.php index 4585a27a..650201d9 100644 --- a/tests/Internal/DocblockNormalizerTest.php +++ b/tests/Internal/DocblockNormalizerTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Dockblock\DocblockNormalizer; +use TypePHP\Internal\Docblock\DocblockNormalizer; describe('DocblockNormalizer', function () { test('returns docblock string unchanged when no special keywords or curly braces are present', function () { From ed875c43b4daee1f9e65eeccb0792d8c2becc9ca Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 17:22:59 +0800 Subject: [PATCH 07/31] Refactor internal directory patterns and update path normalization logic --- src/Internal/Diagnostic/ErrorFactory.php | 5 ----- src/Internal/Util/PathMatcher.php | 8 +------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/Internal/Diagnostic/ErrorFactory.php b/src/Internal/Diagnostic/ErrorFactory.php index bac3bd49..3898544f 100644 --- a/src/Internal/Diagnostic/ErrorFactory.php +++ b/src/Internal/Diagnostic/ErrorFactory.php @@ -15,11 +15,6 @@ final class ErrorFactory { private const INTERNAL_DIR_PATTERNS = [ 'src/Internal/', - 'src/Wrapper/', - 'src/Validator/', - 'src/Resolver/', - 'src/Contract/', - 'src/Command/', 'bin/typephp', ]; diff --git a/src/Internal/Util/PathMatcher.php b/src/Internal/Util/PathMatcher.php index bc871ea0..9e5e1146 100644 --- a/src/Internal/Util/PathMatcher.php +++ b/src/Internal/Util/PathMatcher.php @@ -190,7 +190,7 @@ public static function isCachePath(string $normalizedPath): bool public static function isLibraryInternal(string $normalizedPath): bool { if (self::$cachedLibSrcDir === null) { - $parentDir = realpath(__DIR__ . '/..'); + $parentDir = realpath(dirname(__DIR__, 2)); self::$cachedLibSrcDir = $parentDir !== false ? rtrim(self::normalizePath($parentDir), '/') . '/' : ''; } @@ -210,14 +210,8 @@ public static function isLibraryInternal(string $normalizedPath): bool if (str_starts_with($lowerCanon, $lowerLibSrcDir)) { $internalDirs = [ $lowerLibSrcDir . 'internal/', - $lowerLibSrcDir . 'contract/', - $lowerLibSrcDir . 'command/', - $lowerLibSrcDir . 'validator/', - $lowerLibSrcDir . 'wrapper/', - $lowerLibSrcDir . 'resolver/', $lowerLibSrcDir . 'extension/', $lowerLibSrcDir . 'exception/', - $lowerLibSrcDir . 'compiler/', $lowerLibSrcDir . 'typephp.php', $lowerLibSrcDir . 'bootstrap.php', ]; From 0f85bf427ff57a0e3e9162a84243322016041be6 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 17:34:32 +0800 Subject: [PATCH 08/31] fix failing test --- tests/Contract/FileFilterTest.php | 2 +- tests/Contract/PackagePathInclusionTest.php | 6 +--- tests/Contract/VendorIsolationPathTest.php | 2 +- tests/Extension/ExtensionManagerTest.php | 2 +- tests/Internal/PathMatcherTest.php | 33 ++++++++++++--------- tests/Internal/StreamWrapperTest.php | 14 ++++----- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/tests/Contract/FileFilterTest.php b/tests/Contract/FileFilterTest.php index 4db5422f..61556f26 100644 --- a/tests/Contract/FileFilterTest.php +++ b/tests/Contract/FileFilterTest.php @@ -2,8 +2,8 @@ declare(strict_types=1); -use TypePHP\Contract\FileFilter; use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\FileFilter; describe('FileFilter Unit Tests', function () { test('returns false for null, empty, or false file paths', function () { diff --git a/tests/Contract/PackagePathInclusionTest.php b/tests/Contract/PackagePathInclusionTest.php index 5da00b97..3e93215a 100644 --- a/tests/Contract/PackagePathInclusionTest.php +++ b/tests/Contract/PackagePathInclusionTest.php @@ -4,21 +4,17 @@ namespace TypePHP\Tests\Contract; -use TypePHP\Contract\FileFilter; use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Util\PathMatcher; describe('Packages and Monorepo Path Inclusion (packages/**/src/**)', function () { beforeEach(function () { Config::reset(); - FileFilter::reset(); - PathMatcher::reset(); }); afterEach(function () { Config::reset(); - FileFilter::reset(); - PathMatcher::reset(); }); test('correctly includes package source files with packages/**/src/** glob', function () { diff --git a/tests/Contract/VendorIsolationPathTest.php b/tests/Contract/VendorIsolationPathTest.php index d3fa9dd5..2f3f6ab2 100644 --- a/tests/Contract/VendorIsolationPathTest.php +++ b/tests/Contract/VendorIsolationPathTest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -use TypePHP\Contract\FileFilter; use TypePHP\Internal\Io\StreamWrapper; use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\FileFilter; describe('Vendor Path Isolation & Whitelisting (Shopware Doctrine DBAL Reproduction)', function () { beforeEach(function () { diff --git a/tests/Extension/ExtensionManagerTest.php b/tests/Extension/ExtensionManagerTest.php index 93fa4837..0c07a690 100644 --- a/tests/Extension/ExtensionManagerTest.php +++ b/tests/Extension/ExtensionManagerTest.php @@ -4,7 +4,7 @@ namespace TypePHP\Tests\Extension; -use TypePHP\Contract\FileFilter; +use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Util\Config; use TypePHP\Internal\Util\ExtensionManager; use TypePHP\Tests\Fixtures\Extensions\SampleRegisteredExtension; diff --git a/tests/Internal/PathMatcherTest.php b/tests/Internal/PathMatcherTest.php index 245a54e2..194e5be5 100644 --- a/tests/Internal/PathMatcherTest.php +++ b/tests/Internal/PathMatcherTest.php @@ -46,8 +46,7 @@ test('returns unchanged path when no dots or traversals exist', function () { expect(PathMatcher::canonicalizePath('src/Services/UserService.php')) - ->toBe('src/Services/UserService.php') - ; + ->toBe('src/Services/UserService.php'); }); test('collapses relative directory traversals (..) and current directory dots (.)', function () { @@ -111,25 +110,31 @@ test('identifies TypePHP internal engine directories correctly', function () { $projectRoot = PathMatcher::normalizePath(Config::getProjectRoot()); - $internalFile = $projectRoot . '/src/Internal/RuntimeTypeChecker.php'; - $contractFile = $projectRoot . '/src/Contract/FileFilter.php'; - $commandFile = $projectRoot . '/src/Command/RunCommand.php'; - $validatorFile = $projectRoot . '/src/Validator/ArrayValidator.php'; - $wrapperFile = $projectRoot . '/src/Wrapper/CallableWrapper.php'; - $resolverFile = $projectRoot . '/src/Resolver/SpecialTypeResolver.php'; - $extensionFile = $projectRoot . '/src/Extension/ExtensionManager.php'; + $internalFile = $projectRoot . '/src/Internal/RuntimeTypeChecker.php'; + $utilFile = $projectRoot . '/src/Internal/Util/FileFilter.php'; + $cliFile = $projectRoot . '/src/Internal/Cli/RunCommand.php'; + $validatorFile = $projectRoot . '/src/Internal/Validator/ArrayValidator.php'; + $wrapperFile = $projectRoot . '/src/Internal/Wrapper/CallableWrapper.php'; + $resolverFile = $projectRoot . '/src/Internal/Resolver/SpecialTypeResolver.php'; + $docblockFile = $projectRoot . '/src/Internal/Docblock/DocblockExtractor.php'; + $genericsFile = $projectRoot . '/src/Internal/Generics/TemplateManager.php'; + $ioFile = $projectRoot . '/src/Internal/Io/StreamWrapper.php'; + $extensionFile = $projectRoot . '/src/Extension/ExtensionInterface.php'; $exceptionFile = $projectRoot . '/src/Exception/TypeError.php'; - $entryFile = $projectRoot . '/src/TypePHP.php'; + $entryFile = $projectRoot . '/src/TypePHP.php'; $bootstrapFile = $projectRoot . '/src/bootstrap.php'; - $mockAppFile = $projectRoot . '/src/Service.php'; - $externalFile = '/var/www/app/Models/User.php'; + $mockAppFile = $projectRoot . '/src/Service.php'; + $externalFile = '/var/www/app/Models/User.php'; expect(PathMatcher::isLibraryInternal($internalFile))->toBeTrue() - ->and(PathMatcher::isLibraryInternal($contractFile))->toBeTrue() - ->and(PathMatcher::isLibraryInternal($commandFile))->toBeTrue() + ->and(PathMatcher::isLibraryInternal($utilFile))->toBeTrue() + ->and(PathMatcher::isLibraryInternal($cliFile))->toBeTrue() ->and(PathMatcher::isLibraryInternal($validatorFile))->toBeTrue() ->and(PathMatcher::isLibraryInternal($wrapperFile))->toBeTrue() ->and(PathMatcher::isLibraryInternal($resolverFile))->toBeTrue() + ->and(PathMatcher::isLibraryInternal($docblockFile))->toBeTrue() + ->and(PathMatcher::isLibraryInternal($genericsFile))->toBeTrue() + ->and(PathMatcher::isLibraryInternal($ioFile))->toBeTrue() ->and(PathMatcher::isLibraryInternal($extensionFile))->toBeTrue() ->and(PathMatcher::isLibraryInternal($exceptionFile))->toBeTrue() ->and(PathMatcher::isLibraryInternal($entryFile))->toBeTrue() diff --git a/tests/Internal/StreamWrapperTest.php b/tests/Internal/StreamWrapperTest.php index 40d9fd7a..eb1c0161 100644 --- a/tests/Internal/StreamWrapperTest.php +++ b/tests/Internal/StreamWrapperTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Contract\FileFilter; +use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Io\StreamWrapper; use TypePHP\Internal\Util\Config; @@ -131,7 +131,7 @@ function testIgnoredFileFunc(int $id): int ->and($lstatResult)->toBeArray() ; - $ref = new ReflectionClass(StreamWrapper::class); + $ref = new \ReflectionClass(StreamWrapper::class); $prop = $ref->getProperty('statCache'); $cache = $prop->getValue(); @@ -164,7 +164,7 @@ function testIgnoredFileFunc(int $id): int $stat = $wrapper->url_stat($txtFile, 0); expect($stat)->toBeArray(); - $ref = new ReflectionClass(StreamWrapper::class); + $ref = new \ReflectionClass(StreamWrapper::class); $prop = $ref->getProperty('statCache'); $cache = $prop->getValue(); @@ -193,7 +193,7 @@ function testIgnoredFileFunc(int $id): int ->and($miss2)->toBeFalse() ; - $ref = new ReflectionClass(StreamWrapper::class); + $ref = new \ReflectionClass(StreamWrapper::class); $negProp = $ref->getProperty('staticNegativeStatCache'); $negCache = $negProp->getValue(); @@ -208,7 +208,7 @@ function testIgnoredFileFunc(int $id): int $miss = $wrapper->url_stat($missingAppTempFile, 0); expect($miss)->toBeFalse(); - $ref = new ReflectionClass(StreamWrapper::class); + $ref = new \ReflectionClass(StreamWrapper::class); $negProp = $ref->getProperty('staticNegativeStatCache'); $negCache = $negProp->getValue(); @@ -228,7 +228,7 @@ function testIgnoredFileFunc(int $id): int $normFile = str_replace('\\', '/', $tempFile); - $ref = new ReflectionClass(StreamWrapper::class); + $ref = new \ReflectionClass(StreamWrapper::class); $prop = $ref->getProperty('statCache'); expect($prop->getValue())->toHaveKey($normFile . ':stat'); @@ -467,7 +467,7 @@ function sampleAction(int $id): string expect(\App\Test\sampleAction(42))->toBe('id_42'); expect(fn () => \App\Test\sampleAction(-5)) - ->toThrow(TypeError::class, 'positive-int') + ->toThrow(\TypeError::class, 'positive-int') ; } finally { if (file_exists($testFile)) { From b18b344d987e8d4368f85e46794f0e17bf482f16 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 17:50:35 +0800 Subject: [PATCH 09/31] Fix class trait use documentation initialization in SpecialTypeResolver --- src/Internal/Resolver/SpecialTypeResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Internal/Resolver/SpecialTypeResolver.php b/src/Internal/Resolver/SpecialTypeResolver.php index c6d525e8..0117676c 100644 --- a/src/Internal/Resolver/SpecialTypeResolver.php +++ b/src/Internal/Resolver/SpecialTypeResolver.php @@ -1101,7 +1101,7 @@ public static function parseFileMetadata(string $fileName, string $source): void if (($token->id === T_CLASS || $token->id === T_INTERFACE || $token->id === T_TRAIT || (\defined('T_ENUM') && $token->id === T_ENUM)) && isset($tokens[$i + 2]) && $tokens[$i + 2]->id === T_STRING) { $className = $tokens[$i + 2]->text; $currentClass = $namespace !== '' ? $namespace . '\\' . $className : $className; - self::$classTraitUseDocs[$currentClass] ??= []; + self::$classTraitUseDocs[$currentClass] = []; continue; } From b3ad6b5c956daefa6edc08a4346b4ca9deb2427c Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 17:58:41 +0800 Subject: [PATCH 10/31] Reorganize Test files --- tests/{Visitor => Internal/Ast}/FunctionContractInjectorTest.php | 0 tests/{Visitor => Internal/Ast}/NodeBuilderTest.php | 0 tests/{Visitor => Internal/Ast}/PropertyHookInjectorTest.php | 0 tests/{Visitor => Internal/Ast}/ScopeManagerTest.php | 0 tests/Internal/{ => Ast}/TypeFormatterTest.php | 0 .../{RuntimeChecker => Internal/Checker}/GeneratorCheckerTest.php | 0 tests/{RuntimeChecker => Internal/Checker}/InlineCheckerTest.php | 0 tests/{RuntimeChecker => Internal/Checker}/ParamCheckerTest.php | 0 tests/{RuntimeChecker => Internal/Checker}/ReturnCheckerTest.php | 0 tests/Internal/{ => Diagnostic}/ErrorFactoryTest.php | 0 tests/Internal/{ => Docblock}/ContractParserTest.php | 0 tests/Internal/{ => Docblock}/DocblockNormalizerTest.php | 0 tests/{Resolver => Internal/Generics}/TemplateManagerTest.php | 0 tests/{Resolver => Internal/Generics}/TemplateSubstitutorTest.php | 0 tests/Internal/{ => Io}/CacheManagerTest.php | 0 tests/Internal/{ => Io}/StreamWrapperTest.php | 0 tests/{ => Internal}/Resolver/SpecialTypeResolverTest.php | 0 tests/Internal/{ => Util}/ClassNameValidatorTest.php | 0 tests/Internal/{ => Util}/ConfigTest.php | 0 tests/Internal/{ => Util}/PathMatcherTest.php | 0 tests/Internal/{ => Util}/StubManagerTest.php | 0 tests/{ => Internal}/Wrapper/CallableWrapperTest.php | 0 tests/{ => Internal}/Wrapper/IteratorProxyTest.php | 0 23 files changed, 0 insertions(+), 0 deletions(-) rename tests/{Visitor => Internal/Ast}/FunctionContractInjectorTest.php (100%) rename tests/{Visitor => Internal/Ast}/NodeBuilderTest.php (100%) rename tests/{Visitor => Internal/Ast}/PropertyHookInjectorTest.php (100%) rename tests/{Visitor => Internal/Ast}/ScopeManagerTest.php (100%) rename tests/Internal/{ => Ast}/TypeFormatterTest.php (100%) rename tests/{RuntimeChecker => Internal/Checker}/GeneratorCheckerTest.php (100%) rename tests/{RuntimeChecker => Internal/Checker}/InlineCheckerTest.php (100%) rename tests/{RuntimeChecker => Internal/Checker}/ParamCheckerTest.php (100%) rename tests/{RuntimeChecker => Internal/Checker}/ReturnCheckerTest.php (100%) rename tests/Internal/{ => Diagnostic}/ErrorFactoryTest.php (100%) rename tests/Internal/{ => Docblock}/ContractParserTest.php (100%) rename tests/Internal/{ => Docblock}/DocblockNormalizerTest.php (100%) rename tests/{Resolver => Internal/Generics}/TemplateManagerTest.php (100%) rename tests/{Resolver => Internal/Generics}/TemplateSubstitutorTest.php (100%) rename tests/Internal/{ => Io}/CacheManagerTest.php (100%) rename tests/Internal/{ => Io}/StreamWrapperTest.php (100%) rename tests/{ => Internal}/Resolver/SpecialTypeResolverTest.php (100%) rename tests/Internal/{ => Util}/ClassNameValidatorTest.php (100%) rename tests/Internal/{ => Util}/ConfigTest.php (100%) rename tests/Internal/{ => Util}/PathMatcherTest.php (100%) rename tests/Internal/{ => Util}/StubManagerTest.php (100%) rename tests/{ => Internal}/Wrapper/CallableWrapperTest.php (100%) rename tests/{ => Internal}/Wrapper/IteratorProxyTest.php (100%) diff --git a/tests/Visitor/FunctionContractInjectorTest.php b/tests/Internal/Ast/FunctionContractInjectorTest.php similarity index 100% rename from tests/Visitor/FunctionContractInjectorTest.php rename to tests/Internal/Ast/FunctionContractInjectorTest.php diff --git a/tests/Visitor/NodeBuilderTest.php b/tests/Internal/Ast/NodeBuilderTest.php similarity index 100% rename from tests/Visitor/NodeBuilderTest.php rename to tests/Internal/Ast/NodeBuilderTest.php diff --git a/tests/Visitor/PropertyHookInjectorTest.php b/tests/Internal/Ast/PropertyHookInjectorTest.php similarity index 100% rename from tests/Visitor/PropertyHookInjectorTest.php rename to tests/Internal/Ast/PropertyHookInjectorTest.php diff --git a/tests/Visitor/ScopeManagerTest.php b/tests/Internal/Ast/ScopeManagerTest.php similarity index 100% rename from tests/Visitor/ScopeManagerTest.php rename to tests/Internal/Ast/ScopeManagerTest.php diff --git a/tests/Internal/TypeFormatterTest.php b/tests/Internal/Ast/TypeFormatterTest.php similarity index 100% rename from tests/Internal/TypeFormatterTest.php rename to tests/Internal/Ast/TypeFormatterTest.php diff --git a/tests/RuntimeChecker/GeneratorCheckerTest.php b/tests/Internal/Checker/GeneratorCheckerTest.php similarity index 100% rename from tests/RuntimeChecker/GeneratorCheckerTest.php rename to tests/Internal/Checker/GeneratorCheckerTest.php diff --git a/tests/RuntimeChecker/InlineCheckerTest.php b/tests/Internal/Checker/InlineCheckerTest.php similarity index 100% rename from tests/RuntimeChecker/InlineCheckerTest.php rename to tests/Internal/Checker/InlineCheckerTest.php diff --git a/tests/RuntimeChecker/ParamCheckerTest.php b/tests/Internal/Checker/ParamCheckerTest.php similarity index 100% rename from tests/RuntimeChecker/ParamCheckerTest.php rename to tests/Internal/Checker/ParamCheckerTest.php diff --git a/tests/RuntimeChecker/ReturnCheckerTest.php b/tests/Internal/Checker/ReturnCheckerTest.php similarity index 100% rename from tests/RuntimeChecker/ReturnCheckerTest.php rename to tests/Internal/Checker/ReturnCheckerTest.php diff --git a/tests/Internal/ErrorFactoryTest.php b/tests/Internal/Diagnostic/ErrorFactoryTest.php similarity index 100% rename from tests/Internal/ErrorFactoryTest.php rename to tests/Internal/Diagnostic/ErrorFactoryTest.php diff --git a/tests/Internal/ContractParserTest.php b/tests/Internal/Docblock/ContractParserTest.php similarity index 100% rename from tests/Internal/ContractParserTest.php rename to tests/Internal/Docblock/ContractParserTest.php diff --git a/tests/Internal/DocblockNormalizerTest.php b/tests/Internal/Docblock/DocblockNormalizerTest.php similarity index 100% rename from tests/Internal/DocblockNormalizerTest.php rename to tests/Internal/Docblock/DocblockNormalizerTest.php diff --git a/tests/Resolver/TemplateManagerTest.php b/tests/Internal/Generics/TemplateManagerTest.php similarity index 100% rename from tests/Resolver/TemplateManagerTest.php rename to tests/Internal/Generics/TemplateManagerTest.php diff --git a/tests/Resolver/TemplateSubstitutorTest.php b/tests/Internal/Generics/TemplateSubstitutorTest.php similarity index 100% rename from tests/Resolver/TemplateSubstitutorTest.php rename to tests/Internal/Generics/TemplateSubstitutorTest.php diff --git a/tests/Internal/CacheManagerTest.php b/tests/Internal/Io/CacheManagerTest.php similarity index 100% rename from tests/Internal/CacheManagerTest.php rename to tests/Internal/Io/CacheManagerTest.php diff --git a/tests/Internal/StreamWrapperTest.php b/tests/Internal/Io/StreamWrapperTest.php similarity index 100% rename from tests/Internal/StreamWrapperTest.php rename to tests/Internal/Io/StreamWrapperTest.php diff --git a/tests/Resolver/SpecialTypeResolverTest.php b/tests/Internal/Resolver/SpecialTypeResolverTest.php similarity index 100% rename from tests/Resolver/SpecialTypeResolverTest.php rename to tests/Internal/Resolver/SpecialTypeResolverTest.php diff --git a/tests/Internal/ClassNameValidatorTest.php b/tests/Internal/Util/ClassNameValidatorTest.php similarity index 100% rename from tests/Internal/ClassNameValidatorTest.php rename to tests/Internal/Util/ClassNameValidatorTest.php diff --git a/tests/Internal/ConfigTest.php b/tests/Internal/Util/ConfigTest.php similarity index 100% rename from tests/Internal/ConfigTest.php rename to tests/Internal/Util/ConfigTest.php diff --git a/tests/Internal/PathMatcherTest.php b/tests/Internal/Util/PathMatcherTest.php similarity index 100% rename from tests/Internal/PathMatcherTest.php rename to tests/Internal/Util/PathMatcherTest.php diff --git a/tests/Internal/StubManagerTest.php b/tests/Internal/Util/StubManagerTest.php similarity index 100% rename from tests/Internal/StubManagerTest.php rename to tests/Internal/Util/StubManagerTest.php diff --git a/tests/Wrapper/CallableWrapperTest.php b/tests/Internal/Wrapper/CallableWrapperTest.php similarity index 100% rename from tests/Wrapper/CallableWrapperTest.php rename to tests/Internal/Wrapper/CallableWrapperTest.php diff --git a/tests/Wrapper/IteratorProxyTest.php b/tests/Internal/Wrapper/IteratorProxyTest.php similarity index 100% rename from tests/Wrapper/IteratorProxyTest.php rename to tests/Internal/Wrapper/IteratorProxyTest.php From 4973b02354edd1bd1a9fa9be0004c3d278fe4c0d Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 18:01:06 +0800 Subject: [PATCH 11/31] Add unit tests for CommandRunner functionality --- tests/{Command => Internal/Cli}/CommandRunnerTest.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{Command => Internal/Cli}/CommandRunnerTest.php (100%) diff --git a/tests/Command/CommandRunnerTest.php b/tests/Internal/Cli/CommandRunnerTest.php similarity index 100% rename from tests/Command/CommandRunnerTest.php rename to tests/Internal/Cli/CommandRunnerTest.php From 247baadd6555219ce58f35c48985e5836f7181f3 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 23:06:15 +0800 Subject: [PATCH 12/31] Enhance StreamWrapper functionality and add tests for string literal preservation --- src/Internal/Io/StreamWrapper.php | 73 +++++++++++++++++++---- tests/Internal/Io/StreamWrapperTest.php | 7 +-- tests/Unit/LineNumberPreservationTest.php | 51 ++++++++++++++++ 3 files changed, 116 insertions(+), 15 deletions(-) diff --git a/src/Internal/Io/StreamWrapper.php b/src/Internal/Io/StreamWrapper.php index 02b06dbb..bc9ebd70 100644 --- a/src/Internal/Io/StreamWrapper.php +++ b/src/Internal/Io/StreamWrapper.php @@ -172,8 +172,7 @@ public static function transformSource(string $source, string $filePath = ''): s $printer = new TypePHPPrinter(); $transformed = $printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens); - - $transformed = preg_replace('/(?:\/\/(.*?)|#(.*?))(?=[ \t]*\r?\n[ \t]*\/\*__TYPEPHP_INJECTED_START__\*\/)/', '/*$1$2 */', $transformed) ?? $transformed; + $transformed = self::neutralizeTrailingLineComments($transformed); $transformed = preg_replace('/[ \t]*\r?\n[ \t]*\/\*__TYPEPHP_INJECTED_START__\*\//', ' /*__TYPEPHP_INJECTED_START__*/', $transformed) ?? $transformed; $transformedLineCount = substr_count($transformed, "\n"); @@ -224,14 +223,14 @@ public function stream_open(string $path, string $mode, int $options, ?string &$ self::unregister(); - $exists = (bool) self::silent(static fn () => file_exists($path)); - $resolvedPath = $exists ? self::silent(static fn () => realpath($path)) : false; + $exists = (bool) self::silent(static fn() => file_exists($path)); + $resolvedPath = $exists ? self::silent(static fn() => realpath($path)) : false; if (! $exists || $resolvedPath === false || ! self::isApplicationFile($path, $resolvedPath)) { $target = ($resolvedPath !== false) ? $resolvedPath : $path; /** @var resource|false $handle */ $handle = self::silent( - fn () => ($this->context !== null) + fn() => ($this->context !== null) ? fopen($target, $mode, false, $this->context) : fopen($target, $mode) ); @@ -275,7 +274,7 @@ private function openDirectHandle(string $targetFile, string $mode, int $options self::unregister(); /** @var resource|false $handle */ $handle = self::silent( - fn () => ($this->context !== null) + fn() => ($this->context !== null) ? fopen($targetFile, $mode, $useIncludePath, $this->context) : fopen($targetFile, $mode, $useIncludePath) ); @@ -430,7 +429,7 @@ public function url_stat(string $path, int $flags): array|false self::unregister(); /** @var array|false $result */ - $result = self::silent(static fn () => $isLink ? @lstat($path) : @stat($path)); + $result = self::silent(static fn() => $isLink ? @lstat($path) : @stat($path)); self::register(); if ($result !== false) { @@ -467,11 +466,11 @@ public function stream_metadata(string $path, int $option, mixed $value): bool $valueArray = \is_array($value) ? $value : []; $time = $valueArray[0] ?? time(); $atime = $valueArray[1] ?? $time; - $result = (bool) self::silent(fn () => @touch($path, (int) $time, (int) $atime)); + $result = (bool) self::silent(fn() => @touch($path, (int) $time, (int) $atime)); } elseif ($option === STREAM_META_ACCESS) { /** @var int $mode */ $mode = \is_int($value) ? $value : 0777; - $result = (bool) self::silent(fn () => @chmod($path, $mode)); + $result = (bool) self::silent(fn() => @chmod($path, $mode)); } self::register(); @@ -483,7 +482,7 @@ public function dir_opendir(string $path, int $options): bool self::unregister(); /** @var resource|false $dh */ $dh = self::silent( - fn () => ($this->context !== null) + fn() => ($this->context !== null) ? @opendir($path, $this->context) : @opendir($path) ); @@ -610,7 +609,7 @@ public function rename(string $pathFrom, string $pathTo): bool */ private static function silent(callable $callback): mixed { - set_error_handler(static fn () => true); + set_error_handler(static fn() => true); try { return $callback(); @@ -709,6 +708,58 @@ private function openCachedStream(string $resolvedPath, string $mode): bool return $this->handle !== null; } + /** + * Safely neutralizes trailing single-line comments (// or #) preceding an injected check + * into block comments (/* ... *\/) without corrupting string literals containing '//' or '#'. + */ + private static function neutralizeTrailingLineComments(string $code): string + { + if (! str_contains($code, '/*__TYPEPHP_INJECTED_START__*/')) { + return $code; + } + + try { + $tokens = \PhpToken::tokenize($code); + $count = \count($tokens); + $result = ''; + + for ($i = 0; $i < $count; $i++) { + $token = $tokens[$i]; + + if ($token->id === T_COMMENT && (str_starts_with($token->text, '//') || str_starts_with($token->text, '#'))) { + $isPrecedingInjection = false; + + for ($j = $i + 1; $j < $count; $j++) { + $next = $tokens[$j]; + if ($next->id === T_WHITESPACE) { + continue; + } + if ($next->id === T_COMMENT && str_starts_with($next->text, '/*__TYPEPHP_INJECTED_START__*/')) { + $isPrecedingInjection = true; + } + + break; + } + + if ($isPrecedingInjection) { + $commentText = rtrim($token->text, "\r\n"); + $trailingNewlines = substr($token->text, \strlen($commentText)); + $cleaned = ltrim($commentText, '/# '); + $result .= '/* ' . $cleaned . ' */' . $trailingNewlines; + + continue; + } + } + + $result .= $token->text; + } + + return $result; + } catch (\Throwable $e) { + return $code; + } + } + /** * Scans top-level AST statements for namespace, use imports, and trait use declarations to seed SpecialTypeResolver. * diff --git a/tests/Internal/Io/StreamWrapperTest.php b/tests/Internal/Io/StreamWrapperTest.php index eb1c0161..0766b24d 100644 --- a/tests/Internal/Io/StreamWrapperTest.php +++ b/tests/Internal/Io/StreamWrapperTest.php @@ -302,7 +302,7 @@ function testIgnoredFileFunc(int $id): int test('bypasses AST transformation on non-PHP files', function () { $wrapper = new StreamWrapper(); $openedPath = null; - $jsonFile = __DIR__ . '/../../composer.json'; + $jsonFile = dirname(__DIR__, 3) . '/composer.json'; $success = $wrapper->stream_open($jsonFile, 'r', 0, $openedPath); expect($success)->toBeTrue(); @@ -466,9 +466,8 @@ function sampleAction(int $id): string expect(\App\Test\sampleAction(42))->toBe('id_42'); - expect(fn () => \App\Test\sampleAction(-5)) - ->toThrow(\TypeError::class, 'positive-int') - ; + expect(fn() => \App\Test\sampleAction(-5)) + ->toThrow(\TypeError::class, 'positive-int'); } finally { if (file_exists($testFile)) { @unlink($testFile); diff --git a/tests/Unit/LineNumberPreservationTest.php b/tests/Unit/LineNumberPreservationTest.php index e5cdd2f6..c55b77e6 100644 --- a/tests/Unit/LineNumberPreservationTest.php +++ b/tests/Unit/LineNumberPreservationTest.php @@ -157,4 +157,55 @@ function testTrailingCommentFunc(int $id): int ->and($transformed)->toContain('RuntimeTypeChecker::checkReturn') ; }); + + test('does not corrupt URLs containing double slashes in string literals', function () { + $source = <<<'PHP' +toContain("'https://example.test/path'") + ->and($transformed)->not()->toContain('https:/*') + ; + + $tokens = token_get_all($transformed); + expect($tokens)->toBeArray(); + }); + + test('does not corrupt strings containing hashtags in string literals', function () { + $source = <<<'PHP' +toContain("'#FF0000'") + ->and($transformed)->not()->toContain('/*') + ; + }); }); From 880bc1f12b72a847e1626ea837368c664dd96987 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sat, 5 Sep 2026 23:36:27 +0800 Subject: [PATCH 13/31] Major performance optimization --- src/Internal/Checker/ParamChecker.php | 5 + src/Internal/Docblock/DocblockExtractor.php | 48 +++-- src/Internal/Generics/TemplateManager.php | 49 ++--- src/Internal/Io/StreamWrapper.php | 169 +++++++++++------- src/Internal/Resolver/SpecialTypeResolver.php | 2 +- src/Internal/Util/PathMatcher.php | 2 +- src/Internal/Util/StubManager.php | 4 +- tests/Extension/ExtensionManagerTest.php | 2 +- tests/Internal/Io/StreamWrapperTest.php | 19 +- tests/Internal/Util/PathMatcherTest.php | 25 +-- ...NormalUnionAndIntersectionSubtypesTest.php | 3 +- 11 files changed, 197 insertions(+), 131 deletions(-) diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index 91b5a891..e204c4fe 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -62,6 +62,11 @@ public static function checkParams( $effectiveFunction = self::resolveEffectiveFunction($function, $thisOrClass, $thisObj); } + // Fast-path: If no arguments were passed and it's not a magic __call dispatch, exit immediately + if ($vars === [] && ! str_ends_with($effectiveFunction, '::__call') && ! str_ends_with($effectiveFunction, '::__callStatic')) { + return null; + } + $magicError = self::handleMagicCall($effectiveFunction, $vars, $thisObj, $registry); if ($magicError !== null) { return $magicError; diff --git a/src/Internal/Docblock/DocblockExtractor.php b/src/Internal/Docblock/DocblockExtractor.php index ccdf4cc4..e9f291f1 100644 --- a/src/Internal/Docblock/DocblockExtractor.php +++ b/src/Internal/Docblock/DocblockExtractor.php @@ -33,6 +33,12 @@ final class DocblockExtractor */ private static array $docParseCache = []; + private static ?PhpDocParser $phpDocParser = null; + + private static ?TypeParser $typeParser = null; + + private static ?Lexer $lexer = null; + /** * Resets the parsed docblock cache. Useful for test isolation. */ @@ -48,20 +54,42 @@ public static function reset(): void */ public static function getParserComponents(): array { - /** @var PhpDocParser|null $phpDocParser */ - static $phpDocParser = null; - /** @var Lexer|null $lexer */ - static $lexer = null; + self::initParserComponents(); + + /** @var PhpDocParser $docParser */ + $docParser = self::$phpDocParser; + /** @var Lexer $lexer */ + $lexer = self::$lexer; + + return [$docParser, $lexer]; + } + + /** + * Returns shared static instances of PHPStan's TypeParser and Lexer. + * + * @return array{TypeParser, Lexer} + */ + public static function getTypeParserComponents(): array + { + self::initParserComponents(); + + /** @var TypeParser $typeParser */ + $typeParser = self::$typeParser; + /** @var Lexer $lexer */ + $lexer = self::$lexer; - if ($phpDocParser === null || $lexer === null) { + return [$typeParser, $lexer]; + } + + private static function initParserComponents(): void + { + if (self::$phpDocParser === null || self::$typeParser === null || self::$lexer === null) { $config = new ParserConfig(usedAttributes: []); - $lexer = new Lexer($config); + self::$lexer = new Lexer($config); $constExprParser = new ConstExprParser($config); - $typeParser = new TypeParser($config, $constExprParser); - $phpDocParser = new PhpDocParser($config, $typeParser, $constExprParser); + self::$typeParser = new TypeParser($config, $constExprParser); + self::$phpDocParser = new PhpDocParser($config, self::$typeParser, $constExprParser); } - - return [$phpDocParser, $lexer]; } /** diff --git a/src/Internal/Generics/TemplateManager.php b/src/Internal/Generics/TemplateManager.php index a44b94e6..623e72a3 100644 --- a/src/Internal/Generics/TemplateManager.php +++ b/src/Internal/Generics/TemplateManager.php @@ -13,11 +13,7 @@ use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use PHPStan\PhpDocParser\Lexer\Lexer; -use PHPStan\PhpDocParser\Parser\ConstExprParser; use PHPStan\PhpDocParser\Parser\TokenIterator; -use PHPStan\PhpDocParser\Parser\TypeParser; -use PHPStan\PhpDocParser\ParserConfig; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Docblock\ContractParser; @@ -64,6 +60,13 @@ final class TemplateManager */ private static array $classInheritedBindingsCache = []; + /** + * In-memory cache for subclass hierarchy (is_a) lookups. + * + * @var array + */ + private static array $subclassCache = []; + /** * Temporary storage for an original object instance being cloned. */ @@ -310,6 +313,7 @@ public static function reset(): void self::$callStackBindings = []; self::$classHierarchyTemplatesCache = []; self::$classInheritedBindingsCache = []; + self::$subclassCache = []; self::$pendingCloneSource = null; } @@ -444,7 +448,7 @@ public static function getBoundTemplatesForInstance(object $instance): array } /** - * Retrieves all declared template variances ('covariant', 'contravariant', 'invariant') for an object instance. + * Retrieves all declared template variances ('covariant', 'contravariant', or 'invariant') for an object instance. * * @return array */ @@ -1122,22 +1126,29 @@ private static function checkNestedGenericVariance(GenericTypeNode $existing, Ge private static function isSubclass(string $sub, string $super): bool { + $cacheKey = $sub . '|' . $super; + if (isset(self::$subclassCache[$cacheKey])) { + return self::$subclassCache[$cacheKey]; + } + $baseSub = ($pos = strpos($sub, '<')) !== false ? substr($sub, 0, $pos) : $sub; $baseSuper = ($pos = strpos($super, '<')) !== false ? substr($super, 0, $pos) : $super; $baseSub = ltrim(trim($baseSub), '\\'); $baseSuper = ltrim(trim($baseSuper), '\\'); + $result = false; + if ( ClassNameValidator::isValid($baseSub) && ClassNameValidator::isValid($baseSuper) && (class_exists($baseSub) || interface_exists($baseSub) || trait_exists($baseSub) || enum_exists($baseSub)) && (class_exists($baseSuper) || interface_exists($baseSuper) || trait_exists($baseSuper) || enum_exists($baseSuper)) ) { - return is_a($baseSub, $baseSuper, true); + $result = is_a($baseSub, $baseSuper, true); } - return false; + return self::$subclassCache[$cacheKey] = $result; } /** @@ -1146,7 +1157,7 @@ private static function isSubclass(string $sub, string $super): bool public static function bindInstance(object $instance, string $typeString, string $file = ''): object { try { - [$typeParser, $lexer] = self::getTypeParserComponents(); + [$typeParser, $lexer] = DocblockExtractor::getTypeParserComponents(); $tokens = new TokenIterator($lexer->tokenize($typeString)); $typeNode = $typeParser->parse($tokens); @@ -1243,26 +1254,4 @@ private static function resolveTypeNodeAst(TypeNode $n, \ReflectionClass $ref): return $n; } - - /** - * Returns shared static instances of PHPStan's TypeParser and Lexer. - * - * @return array{TypeParser, Lexer} - */ - private static function getTypeParserComponents(): array - { - /** @var TypeParser|null $typeParser */ - static $typeParser = null; - /** @var Lexer|null $lexer */ - static $lexer = null; - - if ($typeParser === null || $lexer === null) { - $configParser = new ParserConfig(usedAttributes: []); - $lexer = new Lexer($configParser); - $constExprParser = new ConstExprParser($configParser); - $typeParser = new TypeParser($configParser, $constExprParser); - } - - return [$typeParser, $lexer]; - } } diff --git a/src/Internal/Io/StreamWrapper.php b/src/Internal/Io/StreamWrapper.php index bc9ebd70..b411501e 100644 --- a/src/Internal/Io/StreamWrapper.php +++ b/src/Internal/Io/StreamWrapper.php @@ -8,6 +8,7 @@ use PhpParser\NodeTraverser; use PhpParser\NodeVisitor\CloningVisitor; +use PhpParser\Parser; use PhpParser\ParserFactory; use TypePHP\Internal\Ast\ContractVisitor; use TypePHP\Internal\Ast\TypePHPPrinter; @@ -49,6 +50,21 @@ final class StreamWrapper implements StreamWrapperInterface private static bool $cacheEnabled = true; + /** + * Reusable AST parser singleton. + */ + private static ?Parser $parser = null; + + /** + * Reusable AST printer singleton. + */ + private static ?TypePHPPrinter $printer = null; + + /** + * Reusable AST cloning visitor singleton. + */ + private static ?CloningVisitor $cloningVisitor = null; + /** * In-memory cache for positive url_stat results. * @@ -84,6 +100,30 @@ final class StreamWrapper implements StreamWrapperInterface 'token_get_all' => true, ]; + /** + * Returns a shared singleton instance of the PHP-Parser parser. + */ + public static function getParser(): Parser + { + return self::$parser ??= (new ParserFactory())->createForNewestSupportedVersion(); + } + + /** + * Returns a shared singleton instance of the TypePHP format-preserving printer. + */ + public static function getPrinter(): TypePHPPrinter + { + return self::$printer ??= new TypePHPPrinter(); + } + + /** + * Returns a shared singleton instance of the AST CloningVisitor. + */ + public static function getCloningVisitor(): CloningVisitor + { + return self::$cloningVisitor ??= new CloningVisitor(); + } + /** * Resets all internal in-memory caches and path matchers. */ @@ -144,7 +184,7 @@ public static function transformSource(string $source, string $filePath = ''): s $originalLineCount = substr_count($source, "\n"); - $parser = (new ParserFactory())->createForNewestSupportedVersion(); + $parser = self::getParser(); try { $oldStmts = $parser->parse($source); @@ -160,7 +200,7 @@ public static function transformSource(string $source, string $filePath = ''): s $oldTokens = $parser->getTokens(); $traverser1 = new NodeTraverser(); - $traverser1->addVisitor(new CloningVisitor()); + $traverser1->addVisitor(self::getCloningVisitor()); /** @var array<\PhpParser\Node\Stmt> $nodesToTraverse */ $nodesToTraverse = $oldStmts; @@ -170,8 +210,9 @@ public static function transformSource(string $source, string $filePath = ''): s $traverser2->addVisitor(new ContractVisitor()); $newStmts = $traverser2->traverse($newStmts); - $printer = new TypePHPPrinter(); + $printer = self::getPrinter(); $transformed = $printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens); + $transformed = self::neutralizeTrailingLineComments($transformed); $transformed = preg_replace('/[ \t]*\r?\n[ \t]*\/\*__TYPEPHP_INJECTED_START__\*\//', ' /*__TYPEPHP_INJECTED_START__*/', $transformed) ?? $transformed; @@ -197,6 +238,58 @@ public static function transformSource(string $source, string $filePath = ''): s return str_replace(['/*__TYPEPHP_INJECTED_START__*/', '/*__TYPEPHP_INJECTED_END__*/'], '', $transformed); } + /** + * Safely neutralizes trailing single-line comments (// or #) preceding an injected check + * into block comments without corrupting string literals containing '//' or '#'. + */ + private static function neutralizeTrailingLineComments(string $code): string + { + if (! str_contains($code, '/*__TYPEPHP_INJECTED_START__*/')) { + return $code; + } + + try { + $tokens = \PhpToken::tokenize($code); + $count = \count($tokens); + $result = ''; + + for ($i = 0; $i < $count; $i++) { + $token = $tokens[$i]; + + if ($token->id === T_COMMENT && (str_starts_with($token->text, '//') || str_starts_with($token->text, '#'))) { + $isPrecedingInjection = false; + + for ($j = $i + 1; $j < $count; $j++) { + $next = $tokens[$j]; + if ($next->id === T_WHITESPACE) { + continue; + } + if ($next->id === T_COMMENT && str_starts_with($next->text, '/*__TYPEPHP_INJECTED_START__*/')) { + $isPrecedingInjection = true; + } + + break; + } + + if ($isPrecedingInjection) { + $commentText = rtrim($token->text, "\r\n"); + $trailingNewlines = substr($token->text, \strlen($commentText)); + $cleaned = ltrim($commentText, '/# '); + $result .= '/* ' . $cleaned . ' */' . $trailingNewlines; + + continue; + } + } + + $result .= $token->text; + } + + return $result; + } catch (\Throwable $e) { + return $code; + } + } + /** * Opens a file stream using a multi-stage validation pipeline: * 1. Rejects non-include operations, non-read modes, and non-PHP files directly. @@ -223,14 +316,14 @@ public function stream_open(string $path, string $mode, int $options, ?string &$ self::unregister(); - $exists = (bool) self::silent(static fn() => file_exists($path)); - $resolvedPath = $exists ? self::silent(static fn() => realpath($path)) : false; + $exists = (bool) self::silent(static fn () => file_exists($path)); + $resolvedPath = $exists ? self::silent(static fn () => realpath($path)) : false; if (! $exists || $resolvedPath === false || ! self::isApplicationFile($path, $resolvedPath)) { $target = ($resolvedPath !== false) ? $resolvedPath : $path; /** @var resource|false $handle */ $handle = self::silent( - fn() => ($this->context !== null) + fn () => ($this->context !== null) ? fopen($target, $mode, false, $this->context) : fopen($target, $mode) ); @@ -274,7 +367,7 @@ private function openDirectHandle(string $targetFile, string $mode, int $options self::unregister(); /** @var resource|false $handle */ $handle = self::silent( - fn() => ($this->context !== null) + fn () => ($this->context !== null) ? fopen($targetFile, $mode, $useIncludePath, $this->context) : fopen($targetFile, $mode, $useIncludePath) ); @@ -429,7 +522,7 @@ public function url_stat(string $path, int $flags): array|false self::unregister(); /** @var array|false $result */ - $result = self::silent(static fn() => $isLink ? @lstat($path) : @stat($path)); + $result = self::silent(static fn () => $isLink ? @lstat($path) : @stat($path)); self::register(); if ($result !== false) { @@ -466,11 +559,11 @@ public function stream_metadata(string $path, int $option, mixed $value): bool $valueArray = \is_array($value) ? $value : []; $time = $valueArray[0] ?? time(); $atime = $valueArray[1] ?? $time; - $result = (bool) self::silent(fn() => @touch($path, (int) $time, (int) $atime)); + $result = (bool) self::silent(fn () => @touch($path, (int) $time, (int) $atime)); } elseif ($option === STREAM_META_ACCESS) { /** @var int $mode */ $mode = \is_int($value) ? $value : 0777; - $result = (bool) self::silent(fn() => @chmod($path, $mode)); + $result = (bool) self::silent(fn () => @chmod($path, $mode)); } self::register(); @@ -482,7 +575,7 @@ public function dir_opendir(string $path, int $options): bool self::unregister(); /** @var resource|false $dh */ $dh = self::silent( - fn() => ($this->context !== null) + fn () => ($this->context !== null) ? @opendir($path, $this->context) : @opendir($path) ); @@ -609,7 +702,7 @@ public function rename(string $pathFrom, string $pathTo): bool */ private static function silent(callable $callback): mixed { - set_error_handler(static fn() => true); + set_error_handler(static fn () => true); try { return $callback(); @@ -708,58 +801,6 @@ private function openCachedStream(string $resolvedPath, string $mode): bool return $this->handle !== null; } - /** - * Safely neutralizes trailing single-line comments (// or #) preceding an injected check - * into block comments (/* ... *\/) without corrupting string literals containing '//' or '#'. - */ - private static function neutralizeTrailingLineComments(string $code): string - { - if (! str_contains($code, '/*__TYPEPHP_INJECTED_START__*/')) { - return $code; - } - - try { - $tokens = \PhpToken::tokenize($code); - $count = \count($tokens); - $result = ''; - - for ($i = 0; $i < $count; $i++) { - $token = $tokens[$i]; - - if ($token->id === T_COMMENT && (str_starts_with($token->text, '//') || str_starts_with($token->text, '#'))) { - $isPrecedingInjection = false; - - for ($j = $i + 1; $j < $count; $j++) { - $next = $tokens[$j]; - if ($next->id === T_WHITESPACE) { - continue; - } - if ($next->id === T_COMMENT && str_starts_with($next->text, '/*__TYPEPHP_INJECTED_START__*/')) { - $isPrecedingInjection = true; - } - - break; - } - - if ($isPrecedingInjection) { - $commentText = rtrim($token->text, "\r\n"); - $trailingNewlines = substr($token->text, \strlen($commentText)); - $cleaned = ltrim($commentText, '/# '); - $result .= '/* ' . $cleaned . ' */' . $trailingNewlines; - - continue; - } - } - - $result .= $token->text; - } - - return $result; - } catch (\Throwable $e) { - return $code; - } - } - /** * Scans top-level AST statements for namespace, use imports, and trait use declarations to seed SpecialTypeResolver. * diff --git a/src/Internal/Resolver/SpecialTypeResolver.php b/src/Internal/Resolver/SpecialTypeResolver.php index 0117676c..6d9e5a84 100644 --- a/src/Internal/Resolver/SpecialTypeResolver.php +++ b/src/Internal/Resolver/SpecialTypeResolver.php @@ -1101,7 +1101,7 @@ public static function parseFileMetadata(string $fileName, string $source): void if (($token->id === T_CLASS || $token->id === T_INTERFACE || $token->id === T_TRAIT || (\defined('T_ENUM') && $token->id === T_ENUM)) && isset($tokens[$i + 2]) && $tokens[$i + 2]->id === T_STRING) { $className = $tokens[$i + 2]->text; $currentClass = $namespace !== '' ? $namespace . '\\' . $className : $className; - self::$classTraitUseDocs[$currentClass] = []; + self::$classTraitUseDocs[$currentClass] = []; continue; } diff --git a/src/Internal/Util/PathMatcher.php b/src/Internal/Util/PathMatcher.php index 9e5e1146..b9bcf431 100644 --- a/src/Internal/Util/PathMatcher.php +++ b/src/Internal/Util/PathMatcher.php @@ -190,7 +190,7 @@ public static function isCachePath(string $normalizedPath): bool public static function isLibraryInternal(string $normalizedPath): bool { if (self::$cachedLibSrcDir === null) { - $parentDir = realpath(dirname(__DIR__, 2)); + $parentDir = realpath(\dirname(__DIR__, 2)); self::$cachedLibSrcDir = $parentDir !== false ? rtrim(self::normalizePath($parentDir), '/') . '/' : ''; } diff --git a/src/Internal/Util/StubManager.php b/src/Internal/Util/StubManager.php index db28ad94..25a497e9 100644 --- a/src/Internal/Util/StubManager.php +++ b/src/Internal/Util/StubManager.php @@ -6,11 +6,11 @@ use FilesystemIterator; use PhpParser\Node; -use PhpParser\ParserFactory; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use SplFileInfo; use Throwable; +use TypePHP\Internal\Io\StreamWrapper; /** * @internal Indexes and resolves DocBlock stub overrides for third-party classes, methods, properties, and functions. @@ -136,7 +136,7 @@ public static function hasFunctionStub(string $functionName): bool private static function loadStubFiles(array $globs): void { $projectRoot = Config::getProjectRoot(); - $parser = (new ParserFactory())->createForNewestSupportedVersion(); + $parser = StreamWrapper::getParser(); foreach ($globs as $pattern) { $files = self::resolveStubFiles($pattern, $projectRoot); diff --git a/tests/Extension/ExtensionManagerTest.php b/tests/Extension/ExtensionManagerTest.php index 0c07a690..936b42f2 100644 --- a/tests/Extension/ExtensionManagerTest.php +++ b/tests/Extension/ExtensionManagerTest.php @@ -4,9 +4,9 @@ namespace TypePHP\Tests\Extension; -use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Util\Config; use TypePHP\Internal\Util\ExtensionManager; +use TypePHP\Internal\Util\FileFilter; use TypePHP\Tests\Fixtures\Extensions\SampleRegisteredExtension; describe('ExtensionManager Unit Tests', function () { diff --git a/tests/Internal/Io/StreamWrapperTest.php b/tests/Internal/Io/StreamWrapperTest.php index 0766b24d..6533a545 100644 --- a/tests/Internal/Io/StreamWrapperTest.php +++ b/tests/Internal/Io/StreamWrapperTest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -use TypePHP\Internal\Util\FileFilter; use TypePHP\Internal\Io\StreamWrapper; use TypePHP\Internal\Util\Config; +use TypePHP\Internal\Util\FileFilter; describe('StreamWrapper Unit Tests', function () { beforeEach(function () { @@ -131,7 +131,7 @@ function testIgnoredFileFunc(int $id): int ->and($lstatResult)->toBeArray() ; - $ref = new \ReflectionClass(StreamWrapper::class); + $ref = new ReflectionClass(StreamWrapper::class); $prop = $ref->getProperty('statCache'); $cache = $prop->getValue(); @@ -164,7 +164,7 @@ function testIgnoredFileFunc(int $id): int $stat = $wrapper->url_stat($txtFile, 0); expect($stat)->toBeArray(); - $ref = new \ReflectionClass(StreamWrapper::class); + $ref = new ReflectionClass(StreamWrapper::class); $prop = $ref->getProperty('statCache'); $cache = $prop->getValue(); @@ -193,7 +193,7 @@ function testIgnoredFileFunc(int $id): int ->and($miss2)->toBeFalse() ; - $ref = new \ReflectionClass(StreamWrapper::class); + $ref = new ReflectionClass(StreamWrapper::class); $negProp = $ref->getProperty('staticNegativeStatCache'); $negCache = $negProp->getValue(); @@ -208,7 +208,7 @@ function testIgnoredFileFunc(int $id): int $miss = $wrapper->url_stat($missingAppTempFile, 0); expect($miss)->toBeFalse(); - $ref = new \ReflectionClass(StreamWrapper::class); + $ref = new ReflectionClass(StreamWrapper::class); $negProp = $ref->getProperty('staticNegativeStatCache'); $negCache = $negProp->getValue(); @@ -228,7 +228,7 @@ function testIgnoredFileFunc(int $id): int $normFile = str_replace('\\', '/', $tempFile); - $ref = new \ReflectionClass(StreamWrapper::class); + $ref = new ReflectionClass(StreamWrapper::class); $prop = $ref->getProperty('statCache'); expect($prop->getValue())->toHaveKey($normFile . ':stat'); @@ -302,7 +302,7 @@ function testIgnoredFileFunc(int $id): int test('bypasses AST transformation on non-PHP files', function () { $wrapper = new StreamWrapper(); $openedPath = null; - $jsonFile = dirname(__DIR__, 3) . '/composer.json'; + $jsonFile = \dirname(__DIR__, 3) . '/composer.json'; $success = $wrapper->stream_open($jsonFile, 'r', 0, $openedPath); expect($success)->toBeTrue(); @@ -466,8 +466,9 @@ function sampleAction(int $id): string expect(\App\Test\sampleAction(42))->toBe('id_42'); - expect(fn() => \App\Test\sampleAction(-5)) - ->toThrow(\TypeError::class, 'positive-int'); + expect(fn () => \App\Test\sampleAction(-5)) + ->toThrow(TypeError::class, 'positive-int') + ; } finally { if (file_exists($testFile)) { @unlink($testFile); diff --git a/tests/Internal/Util/PathMatcherTest.php b/tests/Internal/Util/PathMatcherTest.php index 194e5be5..ab49b93b 100644 --- a/tests/Internal/Util/PathMatcherTest.php +++ b/tests/Internal/Util/PathMatcherTest.php @@ -46,7 +46,8 @@ test('returns unchanged path when no dots or traversals exist', function () { expect(PathMatcher::canonicalizePath('src/Services/UserService.php')) - ->toBe('src/Services/UserService.php'); + ->toBe('src/Services/UserService.php') + ; }); test('collapses relative directory traversals (..) and current directory dots (.)', function () { @@ -110,21 +111,21 @@ test('identifies TypePHP internal engine directories correctly', function () { $projectRoot = PathMatcher::normalizePath(Config::getProjectRoot()); - $internalFile = $projectRoot . '/src/Internal/RuntimeTypeChecker.php'; - $utilFile = $projectRoot . '/src/Internal/Util/FileFilter.php'; - $cliFile = $projectRoot . '/src/Internal/Cli/RunCommand.php'; + $internalFile = $projectRoot . '/src/Internal/RuntimeTypeChecker.php'; + $utilFile = $projectRoot . '/src/Internal/Util/FileFilter.php'; + $cliFile = $projectRoot . '/src/Internal/Cli/RunCommand.php'; $validatorFile = $projectRoot . '/src/Internal/Validator/ArrayValidator.php'; - $wrapperFile = $projectRoot . '/src/Internal/Wrapper/CallableWrapper.php'; - $resolverFile = $projectRoot . '/src/Internal/Resolver/SpecialTypeResolver.php'; - $docblockFile = $projectRoot . '/src/Internal/Docblock/DocblockExtractor.php'; - $genericsFile = $projectRoot . '/src/Internal/Generics/TemplateManager.php'; - $ioFile = $projectRoot . '/src/Internal/Io/StreamWrapper.php'; + $wrapperFile = $projectRoot . '/src/Internal/Wrapper/CallableWrapper.php'; + $resolverFile = $projectRoot . '/src/Internal/Resolver/SpecialTypeResolver.php'; + $docblockFile = $projectRoot . '/src/Internal/Docblock/DocblockExtractor.php'; + $genericsFile = $projectRoot . '/src/Internal/Generics/TemplateManager.php'; + $ioFile = $projectRoot . '/src/Internal/Io/StreamWrapper.php'; $extensionFile = $projectRoot . '/src/Extension/ExtensionInterface.php'; $exceptionFile = $projectRoot . '/src/Exception/TypeError.php'; - $entryFile = $projectRoot . '/src/TypePHP.php'; + $entryFile = $projectRoot . '/src/TypePHP.php'; $bootstrapFile = $projectRoot . '/src/bootstrap.php'; - $mockAppFile = $projectRoot . '/src/Service.php'; - $externalFile = '/var/www/app/Models/User.php'; + $mockAppFile = $projectRoot . '/src/Service.php'; + $externalFile = '/var/www/app/Models/User.php'; expect(PathMatcher::isLibraryInternal($internalFile))->toBeTrue() ->and(PathMatcher::isLibraryInternal($utilFile))->toBeTrue() diff --git a/tests/TypeChecking/Boundaries/NormalUnionAndIntersectionSubtypesTest.php b/tests/TypeChecking/Boundaries/NormalUnionAndIntersectionSubtypesTest.php index 738022e4..6f95438b 100644 --- a/tests/TypeChecking/Boundaries/NormalUnionAndIntersectionSubtypesTest.php +++ b/tests/TypeChecking/Boundaries/NormalUnionAndIntersectionSubtypesTest.php @@ -419,7 +419,8 @@ function processNormalDnf(object $dnf): object test('strictly rejects completely unrelated object', function () { expect(fn () => processNormalDnf(new Car())) - ->toThrow(TypeError::class); + ->toThrow(TypeError::class) + ; }); }); }); From 5caa02f3f0e96ea9d41506c51bb8746e4f01d94b Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 00:06:01 +0800 Subject: [PATCH 14/31] Enhance DocblockNormalizer and SpecialTypeResolver with additional checks; refactor TypeValidatorRegistry for improved validation structure --- src/Internal/Docblock/DocblockNormalizer.php | 4 ++ src/Internal/Resolver/SpecialTypeResolver.php | 7 +++ .../Validator/TypeValidatorRegistry.php | 59 +++++++++++-------- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/Internal/Docblock/DocblockNormalizer.php b/src/Internal/Docblock/DocblockNormalizer.php index d59247fc..f89893db 100644 --- a/src/Internal/Docblock/DocblockNormalizer.php +++ b/src/Internal/Docblock/DocblockNormalizer.php @@ -29,6 +29,10 @@ final class DocblockNormalizer */ public static function normalize(string $doc): string { + if (! str_contains($doc, '@')) { + return $doc; + } + if (str_contains($doc, '-type') && str_contains($doc, '=')) { $doc = preg_replace('/(@(?:phpstan|psalm)-type\s+[a-zA-Z0-9_\x80-\xff]+)\s*=\s*/', '$1 ', $doc) ?? $doc; } diff --git a/src/Internal/Resolver/SpecialTypeResolver.php b/src/Internal/Resolver/SpecialTypeResolver.php index 6d9e5a84..c5903184 100644 --- a/src/Internal/Resolver/SpecialTypeResolver.php +++ b/src/Internal/Resolver/SpecialTypeResolver.php @@ -174,6 +174,13 @@ public static function checkThisIdentity(TypeNode $returnTypeNode, mixed $value, */ public static function resolve(TypeNode $node, \ReflectionClass|\ReflectionFunction|\ReflectionMethod|string $context, ?object $thisObj = null): TypeNode { + if ($node instanceof IdentifierTypeNode) { + $lower = strtolower($node->name); + if (isset(self::BUILTIN_TYPE_KEYWORDS[$lower]) && $lower !== 'self' && $lower !== 'parent' && $lower !== 'static' && $lower !== '$this') { + return $node; + } + } + $ref = self::getReflectionContext($context); $declaringClass = $ref instanceof \ReflectionMethod ? $ref->getDeclaringClass()->getName() : ($ref instanceof \ReflectionClass ? $ref->getName() : null); diff --git a/src/Internal/Validator/TypeValidatorRegistry.php b/src/Internal/Validator/TypeValidatorRegistry.php index c99f9875..8ca9a8ac 100644 --- a/src/Internal/Validator/TypeValidatorRegistry.php +++ b/src/Internal/Validator/TypeValidatorRegistry.php @@ -23,10 +23,21 @@ final class TypeValidatorRegistry { private IdentifierValidator $identifierValidator; - /** - * @var array - */ - private array $validators = []; + private GenericValidator $genericValidator; + + private UnionValidator $unionValidator; + + private IntersectionValidator $intersectionValidator; + + private NullableValidator $nullableValidator; + + private ArrayValidator $arrayValidator; + + private ArrayShapeValidator $arrayShapeValidator; + + private ObjectShapeValidator $objectShapeValidator; + + private ConstValidator $constValidator; /** * WeakMap memoizing previously validated object instances against TypeNode signatures. @@ -46,17 +57,14 @@ public static function reset(): void public function __construct() { $this->identifierValidator = new IdentifierValidator(); - $this->validators = [ - IdentifierTypeNode::class => $this->identifierValidator, - GenericTypeNode::class => new GenericValidator(), - UnionTypeNode::class => new UnionValidator(), - IntersectionTypeNode::class => new IntersectionValidator(), - NullableTypeNode::class => new NullableValidator(), - ArrayTypeNode::class => new ArrayValidator(), - ArrayShapeNode::class => new ArrayShapeValidator(), - ObjectShapeNode::class => new ObjectShapeValidator(), - ConstTypeNode::class => new ConstValidator(), - ]; + $this->genericValidator = new GenericValidator(); + $this->unionValidator = new UnionValidator(); + $this->intersectionValidator = new IntersectionValidator(); + $this->nullableValidator = new NullableValidator(); + $this->arrayValidator = new ArrayValidator(); + $this->arrayShapeValidator = new ArrayShapeValidator(); + $this->objectShapeValidator = new ObjectShapeValidator(); + $this->constValidator = new ConstValidator(); } /** @@ -77,15 +85,18 @@ public function validate(mixed $value, TypeNode $node, string $context = ''): ?E } } - if ($node instanceof IdentifierTypeNode) { - $err = $this->identifierValidator->validate($value, $node, $context, $this); - } else { - $validator = $this->validators[\get_class($node)] ?? null; - if ($validator === null) { - return null; - } - $err = $validator->validate($value, $node, $context, $this); - } + $err = match ($node::class) { + IdentifierTypeNode::class => $this->identifierValidator->validate($value, $node, $context, $this), + GenericTypeNode::class => $this->genericValidator->validate($value, $node, $context, $this), + UnionTypeNode::class => $this->unionValidator->validate($value, $node, $context, $this), + NullableTypeNode::class => $this->nullableValidator->validate($value, $node, $context, $this), + ArrayTypeNode::class => $this->arrayValidator->validate($value, $node, $context, $this), + ArrayShapeNode::class => $this->arrayShapeValidator->validate($value, $node, $context, $this), + ObjectShapeNode::class => $this->objectShapeValidator->validate($value, $node, $context, $this), + IntersectionTypeNode::class => $this->intersectionValidator->validate($value, $node, $context, $this), + ConstTypeNode::class => $this->constValidator->validate($value, $node, $context, $this), + default => null, + }; if ($err === null && $isObj && $nodeKey !== null) { $cache = self::$validatedObjectCache[$value] ?? []; From 2cb2830f03b3c6668021b404a7f7dd73f46e3f71 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 00:08:58 +0800 Subject: [PATCH 15/31] Rename ContractParser to DocblockParser --- src/Internal/Checker/GeneratorChecker.php | 4 +- src/Internal/Checker/InlineChecker.php | 12 +-- src/Internal/Checker/ParamChecker.php | 14 ++-- src/Internal/Checker/ReturnChecker.php | 6 +- src/Internal/Docblock/DocblockExtractor.php | 2 +- ...{ContractParser.php => DocblockParser.php} | 2 +- src/Internal/Generics/TemplateManager.php | 4 +- src/Internal/RuntimeTypeChecker.php | 4 +- src/Internal/Util/Config.php | 6 +- src/Internal/Wrapper/CallableWrapper.php | 4 +- src/Internal/Wrapper/IterableWrapper.php | 4 +- .../Ast/FunctionContractInjectorTest.php | 2 +- .../Internal/Docblock/ContractParserTest.php | 80 +++++++++---------- .../Boundaries/ParamContractsTest.php | 4 +- .../ConstructorPropertyTypeMismatchTest.php | 4 +- 15 files changed, 76 insertions(+), 76 deletions(-) rename src/Internal/Docblock/{ContractParser.php => DocblockParser.php} (99%) diff --git a/src/Internal/Checker/GeneratorChecker.php b/src/Internal/Checker/GeneratorChecker.php index 631873c3..74ef9fdb 100644 --- a/src/Internal/Checker/GeneratorChecker.php +++ b/src/Internal/Checker/GeneratorChecker.php @@ -8,7 +8,7 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Internal\Resolver\SpecialTypeResolver; @@ -86,7 +86,7 @@ public static function checkYield( */ private static function resolveGeneratorReturnType(string $function, object|string|null $thisOrClass): ?TypeNode { - $contract = ContractParser::parse($function); + $contract = DocblockParser::parse($function); $returnTypeNode = $contract['return'] ?? null; if ($returnTypeNode === null) { diff --git a/src/Internal/Checker/InlineChecker.php b/src/Internal/Checker/InlineChecker.php index d8c86305..5ae4b488 100644 --- a/src/Internal/Checker/InlineChecker.php +++ b/src/Internal/Checker/InlineChecker.php @@ -24,7 +24,7 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Docblock\DocblockNormalizer; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; @@ -213,7 +213,7 @@ public static function checkProperty(mixed $value, mixed $objectOrClass, string $className = \is_string($objectOrClass) ? $objectOrClass : \get_class($objectOrClass); - $typeNode = ContractParser::parseProperty($className, $propName); + $typeNode = DocblockParser::parseProperty($className, $propName); if ($typeNode === null) { return $value; } @@ -377,7 +377,7 @@ private static function resolveFunctionContext(TypeNode $typeNode, string $funct $refFunc = new \ReflectionFunction($functionName); $typeNode = SpecialTypeResolver::resolve($typeNode, $refFunc); - $contract = ContractParser::parse($functionName); + $contract = DocblockParser::parse($functionName); $declaredTemplates = $contract['templates'] ?? []; $aliases = $contract['aliases'] ?? []; $boundTemplates = TemplateManager::getBoundTemplates($functionName, null, $declaredTemplates); @@ -413,13 +413,13 @@ private static function resolveClassContext( $refClass = new \ReflectionClass($className); $typeNode = SpecialTypeResolver::resolve($typeNode, $refClass); - $classAliases = ContractParser::parseClassAliases($className); + $classAliases = DocblockParser::parseClassAliases($className); $targetFunc = ($methodName !== '{closure}' && $methodName !== null) ? $className . '::' . $methodName : $className . '::__construct'; - $contract = ContractParser::parse($targetFunc); + $contract = DocblockParser::parse($targetFunc); $declaredTemplates = $contract['allTemplates'] ?? ($contract['classTemplates'] ?? []); $boundTemplates = TemplateManager::getBoundTemplates($targetFunc, $thisObj, $declaredTemplates); @@ -442,7 +442,7 @@ private static function resolveClassContext( private static function substitutePropertyGenerics(TypeNode $typeNode, object $object, string $className): TypeNode { $constructorTarget = $className . '::__construct'; - $contract = ContractParser::parse($constructorTarget); + $contract = DocblockParser::parse($constructorTarget); $allTemplates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])]; $boundTemplates = TemplateManager::getBoundTemplates('none', $object, $allTemplates); diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index e204c4fe..e165e004 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -16,7 +16,7 @@ use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; use TypePHP\Internal\Diagnostic\TypeFormatter; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Internal\Resolver\HierarchyResolver; @@ -72,7 +72,7 @@ public static function checkParams( return $magicError; } - $contract = ContractParser::parse($effectiveFunction); + $contract = DocblockParser::parse($effectiveFunction); if (! $contract['hasParamContract']) { return null; @@ -223,7 +223,7 @@ private static function handleMagicCall( } $className = explode('::', $effectiveFunction, 2)[0]; - $magicContract = ContractParser::parseMagicMethod($className, $magicMethodName); + $magicContract = DocblockParser::parseMagicMethod($className, $magicMethodName); if ($magicContract === null) { return null; @@ -271,7 +271,7 @@ private static function inferTemplatesFromClosures( return; } - $contract = ContractParser::parse($effectiveFunction); + $contract = DocblockParser::parse($effectiveFunction); $classTemplates = $contract['classTemplates'] ?? []; foreach ($callableNodes as $cParamName => $cTypeNode) { @@ -514,7 +514,7 @@ private static function bindTemplateIfUnbound( ?object $thisObj, array $templates ): void { - $contract = ContractParser::parse($effectiveFunction); + $contract = DocblockParser::parse($effectiveFunction); $classTemplates = $contract['classTemplates'] ?? []; $isClassLevelTemplate = isset($classTemplates[$templateName]); $targetObj = $isClassLevelTemplate ? $thisObj : null; @@ -705,7 +705,7 @@ private static function resolveClassStringTemplate( $templateName = $innerType->name; $templateNode = $templates[$templateName]; - $contract = ContractParser::parse($function); + $contract = DocblockParser::parse($function); $classTemplates = $contract['classTemplates'] ?? []; $isClassLevelTemplate = isset($classTemplates[$templateName]); $targetObj = $isClassLevelTemplate ? $thisObj : null; @@ -829,7 +829,7 @@ private static function resolveTemplateParam( $isVariadic = $typeNode instanceof ArrayTypeNode; $isNullable = ($typeNode instanceof NullableTypeNode) || ($typeNode instanceof UnionTypeNode && self::typeContainsNull($typeNode)); - $contract = ContractParser::parse($function); + $contract = DocblockParser::parse($function); $classTemplates = $contract['classTemplates'] ?? []; $isClassLevelTemplate = isset($classTemplates[$templateName]); $targetObj = $isClassLevelTemplate ? $thisObj : null; diff --git a/src/Internal/Checker/ReturnChecker.php b/src/Internal/Checker/ReturnChecker.php index f31dda8c..506e7568 100644 --- a/src/Internal/Checker/ReturnChecker.php +++ b/src/Internal/Checker/ReturnChecker.php @@ -13,7 +13,7 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use ReflectionClass; use Traversable; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Internal\Resolver\HierarchyResolver; @@ -71,7 +71,7 @@ public static function checkReturn( return $magicResult; } - $contract = ContractParser::parse($effectiveFunction); + $contract = DocblockParser::parse($effectiveFunction); if (! ($contract['hasReturnContract'] ?? ($contract['return'] !== null))) { return $value; @@ -185,7 +185,7 @@ private static function handleMagicReturn( } $className = explode('::', $effectiveFunction, 2)[0]; - $magicContract = ContractParser::parseMagicMethod($className, $magicMethodName); + $magicContract = DocblockParser::parseMagicMethod($className, $magicMethodName); if ($magicContract === null || $magicContract['return'] === null) { return null; diff --git a/src/Internal/Docblock/DocblockExtractor.php b/src/Internal/Docblock/DocblockExtractor.php index e9f291f1..9f767593 100644 --- a/src/Internal/Docblock/DocblockExtractor.php +++ b/src/Internal/Docblock/DocblockExtractor.php @@ -385,7 +385,7 @@ public static function extractAliases( } foreach ($aliases as $name => $type) { - $aliases[$name] = ContractParser::substituteAliases($type, $aliases); + $aliases[$name] = DocblockParser::substituteAliases($type, $aliases); } } diff --git a/src/Internal/Docblock/ContractParser.php b/src/Internal/Docblock/DocblockParser.php similarity index 99% rename from src/Internal/Docblock/ContractParser.php rename to src/Internal/Docblock/DocblockParser.php index f3ebced7..34e74d22 100644 --- a/src/Internal/Docblock/ContractParser.php +++ b/src/Internal/Docblock/DocblockParser.php @@ -32,7 +32,7 @@ /** * @internal Main orchestrator parsing and caching PHPDoc contracts (@param, @return, @template, @phpstan-type, @var, stubs). */ -final class ContractParser +final class DocblockParser { /** * Cache for resolved contract metadata. diff --git a/src/Internal/Generics/TemplateManager.php b/src/Internal/Generics/TemplateManager.php index 623e72a3..fb2ebf20 100644 --- a/src/Internal/Generics/TemplateManager.php +++ b/src/Internal/Generics/TemplateManager.php @@ -16,7 +16,7 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Docblock\DocblockExtractor; use TypePHP\Internal\Resolver\HierarchyResolver; use TypePHP\Internal\Resolver\SpecialTypeResolver; @@ -413,7 +413,7 @@ public static function getBoundTemplates(string $function, ?object $thisObj, arr $topFrame = end(self::$callStackBindings[$function]); if ($topFrame !== false) { if ($thisObj !== null) { - $contract = ContractParser::parse($function); + $contract = DocblockParser::parse($function); $methodTemplates = $contract['templates'] ?? []; foreach ($topFrame as $tName => $tNode) { if (isset($methodTemplates[$tName])) { diff --git a/src/Internal/RuntimeTypeChecker.php b/src/Internal/RuntimeTypeChecker.php index bd60f2f3..ad031b66 100644 --- a/src/Internal/RuntimeTypeChecker.php +++ b/src/Internal/RuntimeTypeChecker.php @@ -12,7 +12,7 @@ use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Checker\ReturnChecker; use TypePHP\Internal\Diagnostic\ErrorMessage; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Util\Config; use TypePHP\Internal\Validator\TypeValidatorRegistry; @@ -86,7 +86,7 @@ public static function setupScope(string $function, array $vars, object|string|n $err = ParamChecker::checkParams($function, $vars, $thisOrClass, self::getRegistry(), $effectiveFunction); - $contract = ContractParser::parse($effectiveFunction); + $contract = DocblockParser::parse($effectiveFunction); $methodTemplates = $contract['templates'] ?? []; $hasMethodTemplates = \count($methodTemplates) > 0; diff --git a/src/Internal/Util/Config.php b/src/Internal/Util/Config.php index ed54e266..bf9baa47 100644 --- a/src/Internal/Util/Config.php +++ b/src/Internal/Util/Config.php @@ -7,7 +7,7 @@ use TypePHP\Extension\ExtensionInterface; use TypePHP\Internal\Checker\ParamChecker; use TypePHP\Internal\Checker\ReturnChecker; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Io\CacheManager; use TypePHP\Internal\Io\StreamWrapper; @@ -295,7 +295,7 @@ public static function set(array $config): void self::$cachedConfig = $mergedConfig; self::syncFlags($mergedConfig); - ContractParser::reset(); + DocblockParser::reset(); ParamChecker::reset(); ReturnChecker::reset(); FileFilter::reset(); @@ -354,7 +354,7 @@ public static function reset(): void self::$respectNativeNullability = true; self::$arrayValidation = 'full'; - ContractParser::reset(); + DocblockParser::reset(); ParamChecker::reset(); ReturnChecker::reset(); TemplateManager::reset(); diff --git a/src/Internal/Wrapper/CallableWrapper.php b/src/Internal/Wrapper/CallableWrapper.php index f3e7c870..56c6e530 100644 --- a/src/Internal/Wrapper/CallableWrapper.php +++ b/src/Internal/Wrapper/CallableWrapper.php @@ -15,7 +15,7 @@ use TypePHP\Exception\TypeError as TypePHPTypeError; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\TypeFormatter; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Internal\Resolver\SpecialTypeResolver; @@ -70,7 +70,7 @@ public static function isCallable(mixed $value): bool */ public static function wrap(string $function, string $paramName, mixed $callable, TypeValidatorRegistry $registry, object|string|null $thisOrClass = null): mixed { - $contract = ContractParser::parse($function); + $contract = DocblockParser::parse($function); $typeNode = ($paramName === 'return') ? ($contract['return'] ?? null) : ($contract['types'][$paramName] ?? null); $aliases = $contract['aliases'] ?? []; $templates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])]; diff --git a/src/Internal/Wrapper/IterableWrapper.php b/src/Internal/Wrapper/IterableWrapper.php index 7cab7634..016ef828 100644 --- a/src/Internal/Wrapper/IterableWrapper.php +++ b/src/Internal/Wrapper/IterableWrapper.php @@ -11,7 +11,7 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode; use TypePHP\Exception\TypeError as TypePHPTypeError; use TypePHP\Internal\Diagnostic\ErrorFactory; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Internal\Resolver\SpecialTypeResolver; @@ -37,7 +37,7 @@ public static function wrap(string $function, string $paramName, mixed $iterable return $iterable; } - $contract = ContractParser::parse($function); + $contract = DocblockParser::parse($function); $typeNode = ($paramName === 'return') ? ($contract['return'] ?? null) : ($contract['types'][$paramName] ?? null); if ($typeNode === null) { diff --git a/tests/Internal/Ast/FunctionContractInjectorTest.php b/tests/Internal/Ast/FunctionContractInjectorTest.php index 850cdbf2..2f6c8eac 100644 --- a/tests/Internal/Ast/FunctionContractInjectorTest.php +++ b/tests/Internal/Ast/FunctionContractInjectorTest.php @@ -273,7 +273,7 @@ public function dd(): never }); describe('Ignore Tag Suppression (@typephp-ignore)', function () { - test('injects setupScope hook so @typephp-ignore can be resolved dynamically at runtime by ContractParser', function () { + test('injects setupScope hook so @typephp-ignore can be resolved dynamically at runtime by DocblockParser', function () { $doc = new Doc("/**\n * @typephp-ignore\n * @param positive-int \$id\n */"); $method = new Node\Stmt\ClassMethod('ignoredMethod', [ diff --git a/tests/Internal/Docblock/ContractParserTest.php b/tests/Internal/Docblock/ContractParserTest.php index 25c706f4..752d7e68 100644 --- a/tests/Internal/Docblock/ContractParserTest.php +++ b/tests/Internal/Docblock/ContractParserTest.php @@ -17,7 +17,7 @@ use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode; use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Util\Config; use TypePHP\Tests\Fixtures\IgnoreTags\IgnoredMethod; use TypePHP\Tests\Fixtures\Services\ChildMagicMethodService; @@ -30,23 +30,23 @@ use TypePHP\Tests\Fixtures\Types\NestedAliasService; use TypePHP\Tests\Fixtures\Types\NonCpmStrings; -describe('ContractParser Unit Tests', function () { +describe('DocblockParser Unit Tests', function () { beforeEach(function () { Config::reset(); - ContractParser::reset(); + DocblockParser::reset(); }); afterEach(function () { Config::reset(); - ContractParser::reset(); + DocblockParser::reset(); }); describe('Function and Method Parsing (parse)', function () { test('parses class method contracts and caches results', function () { $target = UserService::class . '::find'; - $contract1 = ContractParser::parse($target); - $contract2 = ContractParser::parse($target); + $contract1 = DocblockParser::parse($target); + $contract2 = DocblockParser::parse($target); expect($contract1)->toBeArray() ->and($contract1['types'])->toHaveKey('id') @@ -58,7 +58,7 @@ test('parses standalone global/namespaced functions', function () { $target = 'TypePHP\Tests\Fixtures\Functions\calculateDiscount'; - $contract = ContractParser::parse($target); + $contract = DocblockParser::parse($target); expect($contract['types'])->toHaveKey('price') ->and($contract['types'])->toHaveKey('percentage') @@ -69,7 +69,7 @@ }); test('returns empty contract array for non-existent classes or functions', function () { - $contract = ContractParser::parse('NonExistentClass12345::method'); + $contract = DocblockParser::parse('NonExistentClass12345::method'); expect($contract['types'])->toBeEmpty() ->and($contract['templates'])->toBeEmpty() @@ -81,7 +81,7 @@ test('returns class-level templates and aliases when class has no requested method', function () { $target = NestedAliasService::class . '::nonExistentMethod'; - $contract = ContractParser::parse($target); + $contract = DocblockParser::parse($target); expect($contract['types'])->toBeEmpty() ->and($contract['aliases'])->toHaveKey('LocalId') @@ -91,7 +91,7 @@ test('falls back to property @var docblock for constructor property promotion', function () { $target = NonCpmStrings::class . '::__construct'; - $contract = ContractParser::parse($target); + $contract = DocblockParser::parse($target); expect($contract['types'])->toHaveKey('strings') ->and($contract['types']['strings'])->toBeInstanceOf(ArrayTypeNode::class) @@ -101,10 +101,10 @@ describe('Property Contract Parsing (parseProperty)', function () { test('parses instance and static property @var docblocks', function () { - $instanceProp = ContractParser::parseProperty(ConfiguredProperty::class, 'numbers'); + $instanceProp = DocblockParser::parseProperty(ConfiguredProperty::class, 'numbers'); expect($instanceProp)->toBeInstanceOf(ArrayTypeNode::class); - $staticProp = ContractParser::parseProperty(ConfiguredProperty::class, 'staticTitle'); + $staticProp = DocblockParser::parseProperty(ConfiguredProperty::class, 'staticTitle'); expect($staticProp)->toBeInstanceOf(IdentifierTypeNode::class) ->and($staticProp->name)->toBe('string') ; @@ -117,7 +117,7 @@ return; } - $readOnlyProp = ContractParser::parseProperty(HookedInterfaceImplementation::class, 'readOnlyProp'); + $readOnlyProp = DocblockParser::parseProperty(HookedInterfaceImplementation::class, 'readOnlyProp'); expect($readOnlyProp)->not()->toBeNull() ->and((string) $readOnlyProp)->toBe('positive-int') @@ -125,18 +125,18 @@ }); test('parses class-level magic @property docblocks', function () { - $magicScore = ContractParser::parseProperty(MagicPropertyFixture::class, 'magicScore'); + $magicScore = DocblockParser::parseProperty(MagicPropertyFixture::class, 'magicScore'); expect((string) $magicScore)->toBe('positive-int'); - $magicName = ContractParser::parseProperty(MagicPropertyFixture::class, 'magicName'); + $magicName = DocblockParser::parseProperty(MagicPropertyFixture::class, 'magicName'); expect((string) $magicName)->toBe('non-empty-string'); - $magicTags = ContractParser::parseProperty(MagicPropertyFixture::class, 'magicTags'); + $magicTags = DocblockParser::parseProperty(MagicPropertyFixture::class, 'magicTags'); expect((string) $magicTags)->toBe('list'); }); test('inherits magic @property docblocks across inheritance hierarchy', function () { - $inheritedRole = ContractParser::parseProperty(ChildMagicPropertyFixture::class, 'magicRole'); + $inheritedRole = DocblockParser::parseProperty(ChildMagicPropertyFixture::class, 'magicRole'); expect($inheritedRole)->not()->toBeNull() ->and((string) $inheritedRole)->toContain('admin') @@ -144,12 +144,12 @@ }); test('returns null for un-annotated properties or non-existent classes', function () { - expect(ContractParser::parseProperty('NonExistentClass123', 'prop'))->toBeNull(); - expect(ContractParser::parseProperty(ConfiguredProperty::class, 'nonExistentProperty'))->toBeNull(); + expect(DocblockParser::parseProperty('NonExistentClass123', 'prop'))->toBeNull(); + expect(DocblockParser::parseProperty(ConfiguredProperty::class, 'nonExistentProperty'))->toBeNull(); }); test('returns null for properties marked with @typephp-ignore', function () { - $ignored = ContractParser::parseProperty(IgnoredMethod::class, 'ignoredProperty'); + $ignored = DocblockParser::parseProperty(IgnoredMethod::class, 'ignoredProperty'); expect($ignored)->toBeNull(); }); @@ -157,7 +157,7 @@ describe('Magic Method Parsing (parseMagicMethod)', function () { test('parses dynamic @method annotations with variadics and optional parameters', function () { - $method = ContractParser::parseMagicMethod(MagicMethodFixture::class, 'processId'); + $method = DocblockParser::parseMagicMethod(MagicMethodFixture::class, 'processId'); expect($method)->not()->toBeNull() ->and((string) $method['return'])->toBe('positive-int') @@ -166,30 +166,30 @@ ->and((string) $method['parameters'][0]['type'])->toBe('positive-int') ; - $variadicMethod = ContractParser::parseMagicMethod(MagicMethodFixture::class, 'fetchList'); + $variadicMethod = DocblockParser::parseMagicMethod(MagicMethodFixture::class, 'fetchList'); expect($variadicMethod['parameters'][0]['isVariadic'])->toBeTrue(); }); test('inherits magic @method annotations from parent classes, interfaces, and traits', function () { - $parentMethod = ContractParser::parseMagicMethod(ChildMagicMethodService::class, 'parentMethod'); + $parentMethod = DocblockParser::parseMagicMethod(ChildMagicMethodService::class, 'parentMethod'); expect($parentMethod)->not()->toBeNull(); - $interfaceMethod = ContractParser::parseMagicMethod(ChildMagicMethodService::class, 'interfaceMethod'); + $interfaceMethod = DocblockParser::parseMagicMethod(ChildMagicMethodService::class, 'interfaceMethod'); expect($interfaceMethod)->not()->toBeNull(); - $traitMethod = ContractParser::parseMagicMethod(ChildMagicMethodService::class, 'traitMethod'); + $traitMethod = DocblockParser::parseMagicMethod(ChildMagicMethodService::class, 'traitMethod'); expect($traitMethod)->not()->toBeNull(); }); test('returns null for non-existent magic methods or non-existent classes', function () { - expect(ContractParser::parseMagicMethod('NonExistentClass123', 'method'))->toBeNull(); - expect(ContractParser::parseMagicMethod(MagicMethodFixture::class, 'nonExistentMagicMethod'))->toBeNull(); + expect(DocblockParser::parseMagicMethod('NonExistentClass123', 'method'))->toBeNull(); + expect(DocblockParser::parseMagicMethod(MagicMethodFixture::class, 'nonExistentMagicMethod'))->toBeNull(); }); }); describe('Class Aliases (parseClassAliases)', function () { test('parses and returns all local type aliases for a class', function () { - $aliases = ContractParser::parseClassAliases(NestedAliasService::class); + $aliases = DocblockParser::parseClassAliases(NestedAliasService::class); expect($aliases)->toHaveKey('LocalId') ->and($aliases)->toHaveKey('LocalStatus') @@ -199,7 +199,7 @@ }); test('returns empty array for non-existent classes', function () { - expect(ContractParser::parseClassAliases('NonExistentClass123'))->toBe([]); + expect(DocblockParser::parseClassAliases('NonExistentClass123'))->toBe([]); }); }); @@ -214,12 +214,12 @@ test('substitutes aliases in IdentifierTypeNode', function () { $node = new IdentifierTypeNode('UserId'); - $result = ContractParser::substituteAliases($node, $this->aliases); + $result = DocblockParser::substituteAliases($node, $this->aliases); expect((string) $result)->toBe('positive-int'); $unaliased = new IdentifierTypeNode('string'); - expect(ContractParser::substituteAliases($unaliased, $this->aliases))->toBe($unaliased); + expect(DocblockParser::substituteAliases($unaliased, $this->aliases))->toBe($unaliased); }); test('substitutes parameter and return aliases in CallableTypeNode', function () { @@ -230,7 +230,7 @@ [] ); - $result = ContractParser::substituteAliases($callableNode, $this->aliases); + $result = DocblockParser::substituteAliases($callableNode, $this->aliases); expect($result)->toBeInstanceOf(CallableTypeNode::class) ->and((string) $result)->toContain('positive-int') @@ -240,7 +240,7 @@ test('substitutes target and offset aliases in OffsetAccessTypeNode', function () { $offsetNode = new OffsetAccessTypeNode(new IdentifierTypeNode('UserId'), new IdentifierTypeNode('UserName')); - $result = ContractParser::substituteAliases($offsetNode, $this->aliases); + $result = DocblockParser::substituteAliases($offsetNode, $this->aliases); expect($result)->toBeInstanceOf(OffsetAccessTypeNode::class) ->and((string) $result->type)->toBe('positive-int') @@ -250,7 +250,7 @@ test('substitutes inner type aliases in ArrayTypeNode (UserId[] -> positive-int[])', function () { $arrNode = new ArrayTypeNode(new IdentifierTypeNode('UserId')); - $result = ContractParser::substituteAliases($arrNode, $this->aliases); + $result = DocblockParser::substituteAliases($arrNode, $this->aliases); expect($result)->toBeInstanceOf(ArrayTypeNode::class) ->and((string) $result)->toBe('positive-int[]') @@ -259,7 +259,7 @@ test('substitutes base and generic argument aliases in GenericTypeNode (Collection)', function () { $genericNode = new GenericTypeNode(new IdentifierTypeNode('Collection'), [new IdentifierTypeNode('UserId')]); - $result = ContractParser::substituteAliases($genericNode, $this->aliases); + $result = DocblockParser::substituteAliases($genericNode, $this->aliases); expect($result)->toBeInstanceOf(GenericTypeNode::class) ->and((string) $result)->toContain('positive-int') @@ -268,7 +268,7 @@ test('substitutes inner type aliases in NullableTypeNode (?UserId -> ?positive-int)', function () { $nullableNode = new NullableTypeNode(new IdentifierTypeNode('UserId')); - $result = ContractParser::substituteAliases($nullableNode, $this->aliases); + $result = DocblockParser::substituteAliases($nullableNode, $this->aliases); expect($result)->toBeInstanceOf(NullableTypeNode::class) ->and((string) $result)->toBe('?positive-int') @@ -277,7 +277,7 @@ test('substitutes member type aliases in UnionTypeNode (UserId|UserName)', function () { $unionNode = new UnionTypeNode([new IdentifierTypeNode('UserId'), new IdentifierTypeNode('UserName')]); - $result = ContractParser::substituteAliases($unionNode, $this->aliases); + $result = DocblockParser::substituteAliases($unionNode, $this->aliases); expect($result)->toBeInstanceOf(UnionTypeNode::class) ->and((string) $result)->toContain('positive-int') @@ -287,7 +287,7 @@ test('substitutes member type aliases in IntersectionTypeNode (UserId&UserName)', function () { $intersectionNode = new IntersectionTypeNode([new IdentifierTypeNode('UserId'), new IdentifierTypeNode('UserName')]); - $result = ContractParser::substituteAliases($intersectionNode, $this->aliases); + $result = DocblockParser::substituteAliases($intersectionNode, $this->aliases); expect($result)->toBeInstanceOf(IntersectionTypeNode::class) ->and((string) $result)->toContain('positive-int') @@ -301,7 +301,7 @@ new ArrayShapeItemNode(new ConstExprStringNode('id', ConstExprStringNode::SINGLE_QUOTED), false, new IdentifierTypeNode('UserId')), ], $unsealed); - $result = ContractParser::substituteAliases($shapeNode, $this->aliases); + $result = DocblockParser::substituteAliases($shapeNode, $this->aliases); expect($result)->toBeInstanceOf(ArrayShapeNode::class) ->and((string) $result->items[0]->valueType)->toBe('positive-int') @@ -316,7 +316,7 @@ new ObjectShapeItemNode(new IdentifierTypeNode('name'), false, new IdentifierTypeNode('UserName')), ]); - $result = ContractParser::substituteAliases($objShapeNode, $this->aliases); + $result = DocblockParser::substituteAliases($objShapeNode, $this->aliases); expect($result)->toBeInstanceOf(ObjectShapeNode::class) ->and((string) $result->items[0]->valueType)->toBe('positive-int') diff --git a/tests/TypeChecking/Boundaries/ParamContractsTest.php b/tests/TypeChecking/Boundaries/ParamContractsTest.php index 34d2f03f..7aa25efa 100644 --- a/tests/TypeChecking/Boundaries/ParamContractsTest.php +++ b/tests/TypeChecking/Boundaries/ParamContractsTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use TypePHP\Internal\Docblock\ContractParser; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Tests\Fixtures\Domain\Car; use TypePHP\Tests\Fixtures\Domain\Dog; use TypePHP\Tests\Fixtures\Services\VariadicPropertyService; @@ -114,7 +114,7 @@ function testPureMixedParamFunction(mixed $data, mixed $meta): bool }); test('filters out pure mixed parameters so hasParamContract is false', function () { - $contract = ContractParser::parse('testPureMixedParamFunction'); + $contract = DocblockParser::parse('testPureMixedParamFunction'); expect($contract['types'])->toBeEmpty() ->and($contract['hasParamContract'])->toBeFalse() diff --git a/tests/TypeChecking/InheritanceAndAttributes/ConstructorPropertyTypeMismatchTest.php b/tests/TypeChecking/InheritanceAndAttributes/ConstructorPropertyTypeMismatchTest.php index 2c975b16..71e1cb0d 100644 --- a/tests/TypeChecking/InheritanceAndAttributes/ConstructorPropertyTypeMismatchTest.php +++ b/tests/TypeChecking/InheritanceAndAttributes/ConstructorPropertyTypeMismatchTest.php @@ -36,8 +36,8 @@ public function __construct(int $userId) ; }); - test('ContractParser::parse resolves property aliases for constructor parameters', function () { - $contract = TypePHP\Internal\Docblock\ContractParser::parse(ConstructorPromotionWithAlias::class . '::__construct'); + test('DocblockParser::parse resolves property aliases for constructor parameters', function () { + $contract = TypePHP\Internal\Docblock\DocblockParser::parse(ConstructorPromotionWithAlias::class . '::__construct'); expect((string) $contract['types']['userId'])->toBe('positive-int'); }); From 13e0073893001909e383940dab8db9fc1be3d3a5 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 00:19:15 +0800 Subject: [PATCH 16/31] bump php doc parser version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9f941620..02a4dfef 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ ], "require": { "php": "^8.1", - "phpstan/phpdoc-parser": "^2.0", + "phpstan/phpdoc-parser": "^2.3", "nikic/php-parser": "^5.3" }, "require-dev": { From 716fad5691fcb173f97c8b1b8b96eb61541c977d Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 00:50:48 +0800 Subject: [PATCH 17/31] Update phpstan/phpdoc-parser version to ^2.3.5 in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 02a4dfef..94637225 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ ], "require": { "php": "^8.1", - "phpstan/phpdoc-parser": "^2.3", + "phpstan/phpdoc-parser": "^2.3.5", "nikic/php-parser": "^5.3" }, "require-dev": { From 7285d2b3e7be9e3cc23d08177cc0fcc7ea0921d8 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 01:07:24 +0800 Subject: [PATCH 18/31] trace failing 8.2 ci test --- .github/workflows/ci.yml | 10 +------ src/Internal/Checker/ParamChecker.php | 13 ++++++-- src/Internal/Io/StreamWrapper.php | 30 ++++++++++++------- .../ClassConstKeyShapeTest.php | 14 ++++++--- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b02aa11a..0cf39d46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,15 +46,7 @@ jobs: run: php bin/typephp cache:warm - name: Run Runtime Type Checking Engine Suite (Pest) - run: ./vendor/bin/pest tests/TypeChecking --compact - - - name: Run Full Test Suite with Coverage (Pest) - run: ./vendor/bin/pest --coverage-clover=clover.xml --compact - if: matrix.os == 'ubuntu-latest' && matrix.php == '8.4' - - - name: Run Full Test Suite (Pest) - run: ./vendor/bin/pest --compact - if: "! (matrix.os == 'ubuntu-latest' && matrix.php == '8.4')" + run: ./vendor/bin/pest tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php tests/TypeChecking/ArraysAndShapes/OffsetAccessTest.php --verbose - name: Upload Coverage to Codecov uses: codecov/codecov-action@v5 diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index e165e004..a4417f97 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -74,6 +74,15 @@ public static function checkParams( $contract = DocblockParser::parse($effectiveFunction); + if (str_contains($effectiveFunction, 'ConstKeyContainer') || str_contains($effectiveFunction, 'OffsetAccessContainer')) { + fwrite(STDERR, "[PARAM_CHECKER] $effectiveFunction\n"); + fwrite(STDERR, " - hasParamContract: " . ($contract['hasParamContract'] ? 'true' : 'false') . "\n"); + fwrite(STDERR, " - types count: " . count($contract['types']) . "\n"); + foreach ($contract['types'] as $pName => $tNode) { + fwrite(STDERR, " - param '$pName' AST class: " . get_class($tNode) . " => (string): " . (string) $tNode . "\n"); + } + } + if (! $contract['hasParamContract']) { return null; } @@ -87,8 +96,8 @@ public static function checkParams( foreach ($contract['types'] as $paramName => $typeNode) { if (\array_key_exists($paramName, $vars)) { $err = $registry->validate($vars[$paramName], $typeNode, $effectiveFunction . '(): Argument $' . $paramName); - if ($err !== null) { - return $err; + if (str_contains($effectiveFunction, 'ConstKeyContainer') || str_contains($effectiveFunction, 'OffsetAccessContainer')) { + fwrite(STDERR, " - validate result: " . ($err ? 'ERROR: ' . $err->getMessage() : 'NULL (PASSED)') . "\n"); } } } diff --git a/src/Internal/Io/StreamWrapper.php b/src/Internal/Io/StreamWrapper.php index b411501e..503d1d9d 100644 --- a/src/Internal/Io/StreamWrapper.php +++ b/src/Internal/Io/StreamWrapper.php @@ -301,8 +301,8 @@ public function stream_open(string $path, string $mode, int $options, ?string &$ { $isInclude = ($options & self::STREAM_OPEN_FOR_INCLUDE) !== 0; - if (! $isInclude || ($mode !== 'r' && $mode !== 'rb' && $mode !== 'rt') || ! str_ends_with(strtolower($path), '.php') || ! Config::isEnabled()) { - return $this->openDirectHandle($path, $mode, $options); + if (str_contains($path, 'ConstKeyContainer') || str_contains($path, 'OffsetAccessContainer')) { + fwrite(STDERR, "[STREAM_OPEN] path: $path, isInclude: " . ($isInclude ? 'yes' : 'no') . ", isEnabled: " . (Config::isEnabled() ? 'yes' : 'no') . "\n"); } $normalizedRaw = str_replace('\\', '/', $path); @@ -316,14 +316,14 @@ public function stream_open(string $path, string $mode, int $options, ?string &$ self::unregister(); - $exists = (bool) self::silent(static fn () => file_exists($path)); - $resolvedPath = $exists ? self::silent(static fn () => realpath($path)) : false; + $exists = (bool) self::silent(static fn() => file_exists($path)); + $resolvedPath = $exists ? self::silent(static fn() => realpath($path)) : false; if (! $exists || $resolvedPath === false || ! self::isApplicationFile($path, $resolvedPath)) { $target = ($resolvedPath !== false) ? $resolvedPath : $path; /** @var resource|false $handle */ $handle = self::silent( - fn () => ($this->context !== null) + fn() => ($this->context !== null) ? fopen($target, $mode, false, $this->context) : fopen($target, $mode) ); @@ -367,7 +367,7 @@ private function openDirectHandle(string $targetFile, string $mode, int $options self::unregister(); /** @var resource|false $handle */ $handle = self::silent( - fn () => ($this->context !== null) + fn() => ($this->context !== null) ? fopen($targetFile, $mode, $useIncludePath, $this->context) : fopen($targetFile, $mode, $useIncludePath) ); @@ -522,7 +522,7 @@ public function url_stat(string $path, int $flags): array|false self::unregister(); /** @var array|false $result */ - $result = self::silent(static fn () => $isLink ? @lstat($path) : @stat($path)); + $result = self::silent(static fn() => $isLink ? @lstat($path) : @stat($path)); self::register(); if ($result !== false) { @@ -559,11 +559,11 @@ public function stream_metadata(string $path, int $option, mixed $value): bool $valueArray = \is_array($value) ? $value : []; $time = $valueArray[0] ?? time(); $atime = $valueArray[1] ?? $time; - $result = (bool) self::silent(fn () => @touch($path, (int) $time, (int) $atime)); + $result = (bool) self::silent(fn() => @touch($path, (int) $time, (int) $atime)); } elseif ($option === STREAM_META_ACCESS) { /** @var int $mode */ $mode = \is_int($value) ? $value : 0777; - $result = (bool) self::silent(fn () => @chmod($path, $mode)); + $result = (bool) self::silent(fn() => @chmod($path, $mode)); } self::register(); @@ -575,7 +575,7 @@ public function dir_opendir(string $path, int $options): bool self::unregister(); /** @var resource|false $dh */ $dh = self::silent( - fn () => ($this->context !== null) + fn() => ($this->context !== null) ? @opendir($path, $this->context) : @opendir($path) ); @@ -702,7 +702,7 @@ public function rename(string $pathFrom, string $pathTo): bool */ private static function silent(callable $callback): mixed { - set_error_handler(static fn () => true); + set_error_handler(static fn() => true); try { return $callback(); @@ -754,6 +754,10 @@ private static function isApplicationFile(string $path, string|false $resolvedPa */ private function openMemoryStream(string $resolvedPath): bool { + if (str_contains($resolvedPath, 'ConstKeyContainer') || str_contains($resolvedPath, 'OffsetAccessContainer')) { + fwrite(STDERR, "[TRANSFORM] Transforming $resolvedPath\n"); + } + $source = file_get_contents($resolvedPath); if ($source === false) { return false; @@ -776,6 +780,10 @@ private function openMemoryStream(string $resolvedPath): bool */ private function openCachedStream(string $resolvedPath, string $mode): bool { + if (str_contains($resolvedPath, 'ConstKeyContainer') || str_contains($resolvedPath, 'OffsetAccessContainer')) { + fwrite(STDERR, "[TRANSFORM] Transforming $resolvedPath\n"); + } + $cachedFile = CacheManager::getCachedFilePath($resolvedPath); if (! CacheManager::ensureSecureCacheDir()) { diff --git a/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php b/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php index 2d99d902..b6f036b3 100644 --- a/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php +++ b/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php @@ -35,7 +35,14 @@ public function process(array $payload): bool test('throws TypeError when array shape item with class constant key violates type contract', function () { $container = new ConstKeyContainer(); - expect(fn () => $container->process([ + fwrite(STDERR, "[TEST_START] Calling process() with invalid user_id = -5\n"); + $result = $container->process([ + 'user_id' => -5, + 'user_role' => 'admin', + ]); + fwrite(STDERR, "[TEST_END] process() returned without throwing! Return: " . var_export($result, true) . "\n"); + + expect(fn() => $container->process([ 'user_id' => -5, 'user_role' => 'admin', ]))->toThrow(TypeError::class, "['user_id'] must be of type positive-int"); @@ -44,9 +51,8 @@ public function process(array $payload): bool test('throws TypeError when array shape references a non-existent class constant key', function () { $container = new MissingConstKeyContainer(); - expect(fn () => $container->process(['user_id' => 42])) - ->toThrow(TypeError::class, "is missing required key 'self::NON_EXISTENT_KEY'") - ; + expect(fn() => $container->process(['user_id' => 42])) + ->toThrow(TypeError::class, "is missing required key 'self::NON_EXISTENT_KEY'"); }); test('resolves PHP 8.2+ trait constants inside array shapes', function () { From 744bd28be7d6ca860899eb825c7fa44b4875cd6e Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 01:08:32 +0800 Subject: [PATCH 19/31] Remove redundant --verbose flag from Pest runtime type checking command --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cf39d46..dc3ef55f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: run: php bin/typephp cache:warm - name: Run Runtime Type Checking Engine Suite (Pest) - run: ./vendor/bin/pest tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php tests/TypeChecking/ArraysAndShapes/OffsetAccessTest.php --verbose + run: ./vendor/bin/pest tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php tests/TypeChecking/ArraysAndShapes/OffsetAccessTest.php - name: Upload Coverage to Codecov uses: codecov/codecov-action@v5 From 651eb35e507b3675bce5d43e5cbfd63cf3e86a20 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 01:24:47 +0800 Subject: [PATCH 20/31] Refactor Node name usage to use FullyQualified for consistency --- src/Internal/Ast/ContractVisitor.php | 10 +++-- src/Internal/Ast/FunctionContractInjector.php | 42 +++++++++---------- src/Internal/Ast/NodeBuilder.php | 12 +++--- src/Internal/Ast/PropertyHookInjector.php | 12 +++--- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/Internal/Ast/ContractVisitor.php b/src/Internal/Ast/ContractVisitor.php index 6850a476..eec3028d 100644 --- a/src/Internal/Ast/ContractVisitor.php +++ b/src/Internal/Ast/ContractVisitor.php @@ -27,7 +27,8 @@ public function __construct() */ public function enterNode(Node $node): ?array { - if ($node instanceof Node\Stmt\Function_ + if ( + $node instanceof Node\Stmt\Function_ || $node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Expr\Closure || $node instanceof Node\Expr\ArrowFunction @@ -161,12 +162,12 @@ public function leaveNode(Node $node): Node|null $node->setAttribute('typephp_wrapped', value: true); return new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::cloneInstance'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::cloneInstance'), [ new Node\Arg( new Node\Expr\Clone_( new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::prepareClone'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::prepareClone'), [new Node\Arg($node->expr)] ) ) @@ -176,7 +177,8 @@ public function leaveNode(Node $node): Node|null ); } - if ($node instanceof Node\Stmt\Function_ + if ( + $node instanceof Node\Stmt\Function_ || $node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Expr\Closure || $node instanceof Node\Expr\ArrowFunction diff --git a/src/Internal/Ast/FunctionContractInjector.php b/src/Internal/Ast/FunctionContractInjector.php index ccbb506a..015781bd 100644 --- a/src/Internal/Ast/FunctionContractInjector.php +++ b/src/Internal/Ast/FunctionContractInjector.php @@ -204,7 +204,7 @@ private static function buildSetupScopeStmt(array $params, Node\Expr $thisArg): ); $checkCall = new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::setupScope'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::setupScope'), [ new Node\Arg(new Node\Scalar\MagicConst\Method()), new Node\Arg($argsExpr), @@ -217,7 +217,7 @@ private static function buildSetupScopeStmt(array $params, Node\Expr $thisArg): $ifStmt = new Node\Stmt\If_( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpErr'), $checkCall), - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorMessage') ), ['stmts' => [$throwStmt]] ); @@ -242,7 +242,7 @@ private static function buildCallableParamWrappers(array $params, string $docTex new Node\Expr\Assign( new Node\Expr\Variable($paramName), new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::wrapCallable'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::wrapCallable'), [ new Node\Arg(new Node\Scalar\MagicConst\Method()), new Node\Arg(new Node\Scalar\String_($paramName)), @@ -275,7 +275,7 @@ private static function buildIterableParamWrappers(array $params, string $docTex new Node\Expr\Assign( new Node\Expr\Variable($paramName), new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::wrapIterable'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::wrapIterable'), [ new Node\Arg(new Node\Scalar\MagicConst\Method()), new Node\Arg(new Node\Scalar\String_($paramName)), @@ -373,12 +373,12 @@ public static function buildTypeErrorThrowStmt(Node\Expr $errorVar): Node\Stmt\E return new Node\Stmt\Expression( new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( new Node\Expr\New_( - new Node\Name('\TypePHP\Exception\TypeError'), + new Node\Name\FullyQualified('TypePHP\Exception\TypeError'), [ new Node\Arg( new Node\Expr\MethodCall($errorVar, 'getMessage') @@ -399,7 +399,7 @@ public static function buildReturnCheckCall(Node\Expr $exprToWrap, Node\Expr $th : new Node\Expr\Array_(); return new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::checkReturn'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::checkReturn'), [ new Node\Arg(new Node\Scalar\MagicConst\Method()), new Node\Arg($exprToWrap), @@ -417,7 +417,7 @@ public static function buildVoidReturnGuard(Node\Expr\FuncCall $checkCall): arra $ifStmt = new Node\Stmt\If_( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpRet'), $checkCall), - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorMessage') ), ['stmts' => [self::buildTypeErrorThrowStmt(new Node\Expr\Variable('__typephpRet'))]] ); @@ -434,16 +434,16 @@ public static function buildTernaryReturnExpr(Node\Expr\FuncCall $checkCall): No return new Node\Expr\Ternary( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpRet'), $checkCall), - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( new Node\Expr\New_( - new Node\Name('\TypePHP\Exception\TypeError'), + new Node\Name\FullyQualified('TypePHP\Exception\TypeError'), [ new Node\Arg( new Node\Expr\MethodCall(new Node\Expr\Variable('__typephpRet'), 'getMessage') @@ -461,7 +461,7 @@ public static function buildTernaryReturnExpr(Node\Expr\FuncCall $checkCall): No public static function buildWrappedYieldNode(Node\Expr\Yield_ $n, Node\Expr $thisArg): Node\Expr\Ternary { $checkYieldCall = new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::checkYield'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::checkYield'), [ new Node\Arg(new Node\Scalar\MagicConst\Method()), new Node\Arg($n->key ?? new Node\Expr\ConstFetch(new Node\Name('null'))), @@ -473,16 +473,16 @@ public static function buildWrappedYieldNode(Node\Expr\Yield_ $n, Node\Expr $thi $n->value = new Node\Expr\Ternary( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpYld'), $checkYieldCall), - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( new Node\Expr\New_( - new Node\Name('\TypePHP\Exception\TypeError'), + new Node\Name\FullyQualified('TypePHP\Exception\TypeError'), [ new Node\Arg( new Node\Expr\MethodCall(new Node\Expr\Variable('__typephpYld'), 'getMessage') @@ -498,7 +498,7 @@ public static function buildWrappedYieldNode(Node\Expr\Yield_ $n, Node\Expr $thi ); $checkSendCall = new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::checkSend'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::checkSend'), [ new Node\Arg(new Node\Scalar\MagicConst\Method()), new Node\Arg($n), @@ -509,16 +509,16 @@ public static function buildWrappedYieldNode(Node\Expr\Yield_ $n, Node\Expr $thi return new Node\Expr\Ternary( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpSnd'), $checkSendCall), - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( new Node\Expr\New_( - new Node\Name('\TypePHP\Exception\TypeError'), + new Node\Name\FullyQualified('TypePHP\Exception\TypeError'), [ new Node\Arg( new Node\Expr\MethodCall(new Node\Expr\Variable('__typephpSnd'), 'getMessage') @@ -570,7 +570,7 @@ public function enterNode(Node $n): int|Node|null $n->setAttribute('typephp_wrapped', true); $n->expr = new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::wrapIterable'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::wrapIterable'), [ new Node\Arg(new Node\Scalar\MagicConst\Method()), new Node\Arg(new Node\Scalar\String_('return')), @@ -649,4 +649,4 @@ public function enterNode(Node $n): int|array|null return $newStmts; } -} +} \ No newline at end of file diff --git a/src/Internal/Ast/NodeBuilder.php b/src/Internal/Ast/NodeBuilder.php index b754903c..5e758829 100644 --- a/src/Internal/Ast/NodeBuilder.php +++ b/src/Internal/Ast/NodeBuilder.php @@ -14,7 +14,7 @@ final class NodeBuilder public static function createPropertyCheckCall(Node\Expr $valueExpr, Node\Expr $objectOrClassExpr, string $propertyName): Node\Expr\FuncCall { return new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::checkProperty'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::checkProperty'), [ new Node\Arg($valueExpr), new Node\Arg($objectOrClassExpr), @@ -27,7 +27,7 @@ public static function createPropertyCheckCall(Node\Expr $valueExpr, Node\Expr $ public static function createVariableCheckCall(Node\Expr $valueExpr, string $typeString, string $varName): Node\Expr\FuncCall { return new Node\Expr\FuncCall( - new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::checkVariable'), + new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::checkVariable'), [ new Node\Arg($valueExpr), new Node\Arg(new Node\Scalar\String_($typeString)), @@ -42,7 +42,7 @@ public static function createTernaryThrowExpr(Node\Expr\FuncCall $checkCall, int $args = [ new Node\Arg( new Node\Expr\New_( - new Node\Name('\TypePHP\Exception\TypeError'), + new Node\Name\FullyQualified('TypePHP\Exception\TypeError'), [ new Node\Arg( new Node\Expr\MethodCall( @@ -65,11 +65,11 @@ public static function createTernaryThrowExpr(Node\Expr\FuncCall $checkCall, int new Node\Expr\Variable('__typephpVal'), $checkCall ), - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', $args ) @@ -77,4 +77,4 @@ public static function createTernaryThrowExpr(Node\Expr\FuncCall $checkCall, int new Node\Expr\Variable('__typephpVal') ); } -} +} \ No newline at end of file diff --git a/src/Internal/Ast/PropertyHookInjector.php b/src/Internal/Ast/PropertyHookInjector.php index 01d15632..5f4d1c75 100644 --- a/src/Internal/Ast/PropertyHookInjector.php +++ b/src/Internal/Ast/PropertyHookInjector.php @@ -90,16 +90,16 @@ private static function buildExpressionSetHookTernary(Node\Expr\FuncCall $checkC return new Node\Expr\Ternary( new Node\Expr\Instanceof_( new Node\Expr\Assign(new Node\Expr\Variable('__typephpVal'), $checkCall), - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorMessage') + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorMessage') ), new Node\Expr\Throw_( new Node\Expr\StaticCall( - new Node\Name('\TypePHP\Internal\Diagnostic\ErrorFactory'), + new Node\Name\FullyQualified('TypePHP\Internal\Diagnostic\ErrorFactory'), 'prepareException', [ new Node\Arg( new Node\Expr\New_( - new Node\Name('\TypePHP\Exception\TypeError'), + new Node\Name\FullyQualified('TypePHP\Exception\TypeError'), [ new Node\Arg( new Node\Expr\MethodCall(new Node\Expr\Variable('__typephpVal'), 'getMessage') @@ -122,10 +122,8 @@ private static function buildExpressionSetHookTernary(Node\Expr\FuncCall $checkC private static function wrapHookReturnStatements(array $stmts, string $propertyName): array { $traverser = new NodeTraverser(); - $traverser->addVisitor(new class ($propertyName) extends NodeVisitorAbstract { - public function __construct(private string $propertyName) - { - } + $traverser->addVisitor(new class($propertyName) extends NodeVisitorAbstract { + public function __construct(private string $propertyName) {} public function enterNode(Node $node): int|null { From a9b0f5f8afc092906c5f601003b6bc8b30b6434c Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 01:40:30 +0800 Subject: [PATCH 21/31] Enhance debugging output in ClassConstKeyShapeTest and StreamWrapper for better traceability --- src/Internal/Io/StreamWrapper.php | 8 +++++++- .../ArraysAndShapes/ClassConstKeyShapeTest.php | 13 +++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Internal/Io/StreamWrapper.php b/src/Internal/Io/StreamWrapper.php index 503d1d9d..83aa67d9 100644 --- a/src/Internal/Io/StreamWrapper.php +++ b/src/Internal/Io/StreamWrapper.php @@ -235,7 +235,13 @@ public static function transformSource(string $source, string $filePath = ''): s $transformed = preg_replace('/\/\*__TYPEPHP_INJECTED_END__\*\/[ \t]*\r?\n[ \t]*/', '/*__TYPEPHP_INJECTED_END__*/ ', $transformed, $drift) ?? $transformed; } - return str_replace(['/*__TYPEPHP_INJECTED_START__*/', '/*__TYPEPHP_INJECTED_END__*/'], '', $transformed); + $finalCode = str_replace(['/*__TYPEPHP_INJECTED_START__*/', '/*__TYPEPHP_INJECTED_END__*/'], '', $transformed); + + if (str_contains($filePath, 'ConstKeyContainer')) { + fwrite(STDERR, "=== TRANSFORMED ConstKeyContainer.php ===\n" . $finalCode . "\n=========================================\n"); + } + + return $finalCode; } /** diff --git a/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php b/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php index b6f036b3..283ea1ec 100644 --- a/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php +++ b/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php @@ -35,12 +35,13 @@ public function process(array $payload): bool test('throws TypeError when array shape item with class constant key violates type contract', function () { $container = new ConstKeyContainer(); - fwrite(STDERR, "[TEST_START] Calling process() with invalid user_id = -5\n"); - $result = $container->process([ - 'user_id' => -5, - 'user_role' => 'admin', - ]); - fwrite(STDERR, "[TEST_END] process() returned without throwing! Return: " . var_export($result, true) . "\n"); + $manualCheck = \TypePHP\Internal\RuntimeTypeChecker::setupScope( + 'TypePHP\Tests\Fixtures\Types\ConstKeyContainer::process', + ['payload' => ['user_id' => -5, 'user_role' => 'admin']], + $container + ); + fwrite(STDERR, "[DEBUG] setupScope returned class: " . (is_object($manualCheck) ? get_class($manualCheck) : var_export($manualCheck, true)) . "\n"); + fwrite(STDERR, "[DEBUG] instanceof ErrorMessage: " . var_export($manualCheck instanceof \TypePHP\Internal\Diagnostic\ErrorMessage, true) . "\n"); expect(fn() => $container->process([ 'user_id' => -5, From da5274b918d7d411609c97c341933abf02bfe1ea Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 01:44:36 +0800 Subject: [PATCH 22/31] Refactor ParamChecker to return validation error immediately instead of logging --- src/Internal/Checker/ParamChecker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index a4417f97..dd5799cc 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -96,8 +96,8 @@ public static function checkParams( foreach ($contract['types'] as $paramName => $typeNode) { if (\array_key_exists($paramName, $vars)) { $err = $registry->validate($vars[$paramName], $typeNode, $effectiveFunction . '(): Argument $' . $paramName); - if (str_contains($effectiveFunction, 'ConstKeyContainer') || str_contains($effectiveFunction, 'OffsetAccessContainer')) { - fwrite(STDERR, " - validate result: " . ($err ? 'ERROR: ' . $err->getMessage() : 'NULL (PASSED)') . "\n"); + if ($err !== null) { + return $err; } } } From cb6e8d3c59e79a3518ecd8bdc990fb3a45a40d5d Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 01:44:49 +0800 Subject: [PATCH 23/31] Remove manual debug checks from TypeError test in ClassConstKeyShapeTest --- .../ArraysAndShapes/ClassConstKeyShapeTest.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php b/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php index 283ea1ec..973dfc53 100644 --- a/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php +++ b/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php @@ -35,14 +35,6 @@ public function process(array $payload): bool test('throws TypeError when array shape item with class constant key violates type contract', function () { $container = new ConstKeyContainer(); - $manualCheck = \TypePHP\Internal\RuntimeTypeChecker::setupScope( - 'TypePHP\Tests\Fixtures\Types\ConstKeyContainer::process', - ['payload' => ['user_id' => -5, 'user_role' => 'admin']], - $container - ); - fwrite(STDERR, "[DEBUG] setupScope returned class: " . (is_object($manualCheck) ? get_class($manualCheck) : var_export($manualCheck, true)) . "\n"); - fwrite(STDERR, "[DEBUG] instanceof ErrorMessage: " . var_export($manualCheck instanceof \TypePHP\Internal\Diagnostic\ErrorMessage, true) . "\n"); - expect(fn() => $container->process([ 'user_id' => -5, 'user_role' => 'admin', From fa717b715d53f8cf26b9eed1561ae86822452995 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 01:56:57 +0800 Subject: [PATCH 24/31] Fix formatting and remove redundant debug statements across multiple files --- src/Internal/Ast/FunctionContractInjector.php | 2 +- src/Internal/Ast/NodeBuilder.php | 2 +- src/Internal/Ast/PropertyHookInjector.php | 6 ++- src/Internal/Checker/InlineChecker.php | 2 +- src/Internal/Checker/ParamChecker.php | 9 ----- src/Internal/Generics/TemplateManager.php | 2 +- src/Internal/Io/StreamWrapper.php | 38 ++++++------------- .../ClassConstKeyShapeTest.php | 7 ++-- 8 files changed, 24 insertions(+), 44 deletions(-) diff --git a/src/Internal/Ast/FunctionContractInjector.php b/src/Internal/Ast/FunctionContractInjector.php index 015781bd..a26161a9 100644 --- a/src/Internal/Ast/FunctionContractInjector.php +++ b/src/Internal/Ast/FunctionContractInjector.php @@ -649,4 +649,4 @@ public function enterNode(Node $n): int|array|null return $newStmts; } -} \ No newline at end of file +} diff --git a/src/Internal/Ast/NodeBuilder.php b/src/Internal/Ast/NodeBuilder.php index 5e758829..04a066d1 100644 --- a/src/Internal/Ast/NodeBuilder.php +++ b/src/Internal/Ast/NodeBuilder.php @@ -77,4 +77,4 @@ public static function createTernaryThrowExpr(Node\Expr\FuncCall $checkCall, int new Node\Expr\Variable('__typephpVal') ); } -} \ No newline at end of file +} diff --git a/src/Internal/Ast/PropertyHookInjector.php b/src/Internal/Ast/PropertyHookInjector.php index 5f4d1c75..93f62784 100644 --- a/src/Internal/Ast/PropertyHookInjector.php +++ b/src/Internal/Ast/PropertyHookInjector.php @@ -122,8 +122,10 @@ private static function buildExpressionSetHookTernary(Node\Expr\FuncCall $checkC private static function wrapHookReturnStatements(array $stmts, string $propertyName): array { $traverser = new NodeTraverser(); - $traverser->addVisitor(new class($propertyName) extends NodeVisitorAbstract { - public function __construct(private string $propertyName) {} + $traverser->addVisitor(new class ($propertyName) extends NodeVisitorAbstract { + public function __construct(private string $propertyName) + { + } public function enterNode(Node $node): int|null { diff --git a/src/Internal/Checker/InlineChecker.php b/src/Internal/Checker/InlineChecker.php index 5ae4b488..9f275d9f 100644 --- a/src/Internal/Checker/InlineChecker.php +++ b/src/Internal/Checker/InlineChecker.php @@ -24,8 +24,8 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; use PHPStan\PhpDocParser\ParserConfig; -use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Docblock\DocblockNormalizer; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Generics\TemplateManager; use TypePHP\Internal\Generics\TemplateSubstitutor; use TypePHP\Internal\Resolver\SpecialTypeResolver; diff --git a/src/Internal/Checker/ParamChecker.php b/src/Internal/Checker/ParamChecker.php index dd5799cc..e165e004 100644 --- a/src/Internal/Checker/ParamChecker.php +++ b/src/Internal/Checker/ParamChecker.php @@ -74,15 +74,6 @@ public static function checkParams( $contract = DocblockParser::parse($effectiveFunction); - if (str_contains($effectiveFunction, 'ConstKeyContainer') || str_contains($effectiveFunction, 'OffsetAccessContainer')) { - fwrite(STDERR, "[PARAM_CHECKER] $effectiveFunction\n"); - fwrite(STDERR, " - hasParamContract: " . ($contract['hasParamContract'] ? 'true' : 'false') . "\n"); - fwrite(STDERR, " - types count: " . count($contract['types']) . "\n"); - foreach ($contract['types'] as $pName => $tNode) { - fwrite(STDERR, " - param '$pName' AST class: " . get_class($tNode) . " => (string): " . (string) $tNode . "\n"); - } - } - if (! $contract['hasParamContract']) { return null; } diff --git a/src/Internal/Generics/TemplateManager.php b/src/Internal/Generics/TemplateManager.php index fb2ebf20..d8324103 100644 --- a/src/Internal/Generics/TemplateManager.php +++ b/src/Internal/Generics/TemplateManager.php @@ -16,8 +16,8 @@ use PHPStan\PhpDocParser\Parser\TokenIterator; use TypePHP\Internal\Diagnostic\ErrorFactory; use TypePHP\Internal\Diagnostic\ErrorMessage; -use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Docblock\DocblockExtractor; +use TypePHP\Internal\Docblock\DocblockParser; use TypePHP\Internal\Resolver\HierarchyResolver; use TypePHP\Internal\Resolver\SpecialTypeResolver; use TypePHP\Internal\Util\ClassNameValidator; diff --git a/src/Internal/Io/StreamWrapper.php b/src/Internal/Io/StreamWrapper.php index 83aa67d9..b411501e 100644 --- a/src/Internal/Io/StreamWrapper.php +++ b/src/Internal/Io/StreamWrapper.php @@ -235,13 +235,7 @@ public static function transformSource(string $source, string $filePath = ''): s $transformed = preg_replace('/\/\*__TYPEPHP_INJECTED_END__\*\/[ \t]*\r?\n[ \t]*/', '/*__TYPEPHP_INJECTED_END__*/ ', $transformed, $drift) ?? $transformed; } - $finalCode = str_replace(['/*__TYPEPHP_INJECTED_START__*/', '/*__TYPEPHP_INJECTED_END__*/'], '', $transformed); - - if (str_contains($filePath, 'ConstKeyContainer')) { - fwrite(STDERR, "=== TRANSFORMED ConstKeyContainer.php ===\n" . $finalCode . "\n=========================================\n"); - } - - return $finalCode; + return str_replace(['/*__TYPEPHP_INJECTED_START__*/', '/*__TYPEPHP_INJECTED_END__*/'], '', $transformed); } /** @@ -307,8 +301,8 @@ public function stream_open(string $path, string $mode, int $options, ?string &$ { $isInclude = ($options & self::STREAM_OPEN_FOR_INCLUDE) !== 0; - if (str_contains($path, 'ConstKeyContainer') || str_contains($path, 'OffsetAccessContainer')) { - fwrite(STDERR, "[STREAM_OPEN] path: $path, isInclude: " . ($isInclude ? 'yes' : 'no') . ", isEnabled: " . (Config::isEnabled() ? 'yes' : 'no') . "\n"); + if (! $isInclude || ($mode !== 'r' && $mode !== 'rb' && $mode !== 'rt') || ! str_ends_with(strtolower($path), '.php') || ! Config::isEnabled()) { + return $this->openDirectHandle($path, $mode, $options); } $normalizedRaw = str_replace('\\', '/', $path); @@ -322,14 +316,14 @@ public function stream_open(string $path, string $mode, int $options, ?string &$ self::unregister(); - $exists = (bool) self::silent(static fn() => file_exists($path)); - $resolvedPath = $exists ? self::silent(static fn() => realpath($path)) : false; + $exists = (bool) self::silent(static fn () => file_exists($path)); + $resolvedPath = $exists ? self::silent(static fn () => realpath($path)) : false; if (! $exists || $resolvedPath === false || ! self::isApplicationFile($path, $resolvedPath)) { $target = ($resolvedPath !== false) ? $resolvedPath : $path; /** @var resource|false $handle */ $handle = self::silent( - fn() => ($this->context !== null) + fn () => ($this->context !== null) ? fopen($target, $mode, false, $this->context) : fopen($target, $mode) ); @@ -373,7 +367,7 @@ private function openDirectHandle(string $targetFile, string $mode, int $options self::unregister(); /** @var resource|false $handle */ $handle = self::silent( - fn() => ($this->context !== null) + fn () => ($this->context !== null) ? fopen($targetFile, $mode, $useIncludePath, $this->context) : fopen($targetFile, $mode, $useIncludePath) ); @@ -528,7 +522,7 @@ public function url_stat(string $path, int $flags): array|false self::unregister(); /** @var array|false $result */ - $result = self::silent(static fn() => $isLink ? @lstat($path) : @stat($path)); + $result = self::silent(static fn () => $isLink ? @lstat($path) : @stat($path)); self::register(); if ($result !== false) { @@ -565,11 +559,11 @@ public function stream_metadata(string $path, int $option, mixed $value): bool $valueArray = \is_array($value) ? $value : []; $time = $valueArray[0] ?? time(); $atime = $valueArray[1] ?? $time; - $result = (bool) self::silent(fn() => @touch($path, (int) $time, (int) $atime)); + $result = (bool) self::silent(fn () => @touch($path, (int) $time, (int) $atime)); } elseif ($option === STREAM_META_ACCESS) { /** @var int $mode */ $mode = \is_int($value) ? $value : 0777; - $result = (bool) self::silent(fn() => @chmod($path, $mode)); + $result = (bool) self::silent(fn () => @chmod($path, $mode)); } self::register(); @@ -581,7 +575,7 @@ public function dir_opendir(string $path, int $options): bool self::unregister(); /** @var resource|false $dh */ $dh = self::silent( - fn() => ($this->context !== null) + fn () => ($this->context !== null) ? @opendir($path, $this->context) : @opendir($path) ); @@ -708,7 +702,7 @@ public function rename(string $pathFrom, string $pathTo): bool */ private static function silent(callable $callback): mixed { - set_error_handler(static fn() => true); + set_error_handler(static fn () => true); try { return $callback(); @@ -760,10 +754,6 @@ private static function isApplicationFile(string $path, string|false $resolvedPa */ private function openMemoryStream(string $resolvedPath): bool { - if (str_contains($resolvedPath, 'ConstKeyContainer') || str_contains($resolvedPath, 'OffsetAccessContainer')) { - fwrite(STDERR, "[TRANSFORM] Transforming $resolvedPath\n"); - } - $source = file_get_contents($resolvedPath); if ($source === false) { return false; @@ -786,10 +776,6 @@ private function openMemoryStream(string $resolvedPath): bool */ private function openCachedStream(string $resolvedPath, string $mode): bool { - if (str_contains($resolvedPath, 'ConstKeyContainer') || str_contains($resolvedPath, 'OffsetAccessContainer')) { - fwrite(STDERR, "[TRANSFORM] Transforming $resolvedPath\n"); - } - $cachedFile = CacheManager::getCachedFilePath($resolvedPath); if (! CacheManager::ensureSecureCacheDir()) { diff --git a/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php b/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php index 973dfc53..2d99d902 100644 --- a/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php +++ b/tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php @@ -35,7 +35,7 @@ public function process(array $payload): bool test('throws TypeError when array shape item with class constant key violates type contract', function () { $container = new ConstKeyContainer(); - expect(fn() => $container->process([ + expect(fn () => $container->process([ 'user_id' => -5, 'user_role' => 'admin', ]))->toThrow(TypeError::class, "['user_id'] must be of type positive-int"); @@ -44,8 +44,9 @@ public function process(array $payload): bool test('throws TypeError when array shape references a non-existent class constant key', function () { $container = new MissingConstKeyContainer(); - expect(fn() => $container->process(['user_id' => 42])) - ->toThrow(TypeError::class, "is missing required key 'self::NON_EXISTENT_KEY'"); + expect(fn () => $container->process(['user_id' => 42])) + ->toThrow(TypeError::class, "is missing required key 'self::NON_EXISTENT_KEY'") + ; }); test('resolves PHP 8.2+ trait constants inside array shapes', function () { From c62b88c2d939aaad6903d2441bf5d969279503aa Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 02:00:00 +0800 Subject: [PATCH 25/31] Update CI workflow to run full test suite with coverage and adjust PHPStan parser version --- .github/workflows/ci.yml | 10 +++++++++- composer.json | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc3ef55f..b02aa11a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,15 @@ jobs: run: php bin/typephp cache:warm - name: Run Runtime Type Checking Engine Suite (Pest) - run: ./vendor/bin/pest tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php tests/TypeChecking/ArraysAndShapes/OffsetAccessTest.php + run: ./vendor/bin/pest tests/TypeChecking --compact + + - name: Run Full Test Suite with Coverage (Pest) + run: ./vendor/bin/pest --coverage-clover=clover.xml --compact + if: matrix.os == 'ubuntu-latest' && matrix.php == '8.4' + + - name: Run Full Test Suite (Pest) + run: ./vendor/bin/pest --compact + if: "! (matrix.os == 'ubuntu-latest' && matrix.php == '8.4')" - name: Upload Coverage to Codecov uses: codecov/codecov-action@v5 diff --git a/composer.json b/composer.json index 94637225..9f941620 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ ], "require": { "php": "^8.1", - "phpstan/phpdoc-parser": "^2.3.5", + "phpstan/phpdoc-parser": "^2.0", "nikic/php-parser": "^5.3" }, "require-dev": { From 811f14b0db0058fa30a99473b6a08d87635cc6e3 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 02:09:47 +0800 Subject: [PATCH 26/31] Update phpdoc-parser version and fix namespace usage in NodeBuilder --- composer.json | 2 +- src/Internal/Ast/NodeBuilder.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 9f941620..94637225 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ ], "require": { "php": "^8.1", - "phpstan/phpdoc-parser": "^2.0", + "phpstan/phpdoc-parser": "^2.3.5", "nikic/php-parser": "^5.3" }, "require-dev": { diff --git a/src/Internal/Ast/NodeBuilder.php b/src/Internal/Ast/NodeBuilder.php index 04a066d1..42c3518a 100644 --- a/src/Internal/Ast/NodeBuilder.php +++ b/src/Internal/Ast/NodeBuilder.php @@ -14,7 +14,7 @@ final class NodeBuilder public static function createPropertyCheckCall(Node\Expr $valueExpr, Node\Expr $objectOrClassExpr, string $propertyName): Node\Expr\FuncCall { return new Node\Expr\FuncCall( - new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::checkProperty'), + new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::checkProperty'), [ new Node\Arg($valueExpr), new Node\Arg($objectOrClassExpr), @@ -27,7 +27,7 @@ public static function createPropertyCheckCall(Node\Expr $valueExpr, Node\Expr $ public static function createVariableCheckCall(Node\Expr $valueExpr, string $typeString, string $varName): Node\Expr\FuncCall { return new Node\Expr\FuncCall( - new Node\Name\FullyQualified('TypePHP\Internal\RuntimeTypeChecker::checkVariable'), + new Node\Name('\TypePHP\Internal\RuntimeTypeChecker::checkVariable'), [ new Node\Arg($valueExpr), new Node\Arg(new Node\Scalar\String_($typeString)), @@ -77,4 +77,4 @@ public static function createTernaryThrowExpr(Node\Expr\FuncCall $checkCall, int new Node\Expr\Variable('__typephpVal') ); } -} +} \ No newline at end of file From 86a0f937a7e60e1c2e73528016d1deeab68cc903 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 02:13:38 +0800 Subject: [PATCH 27/31] Update nikic/php-parser version to ^5.8 in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 94637225..9195e867 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require": { "php": "^8.1", "phpstan/phpdoc-parser": "^2.3.5", - "nikic/php-parser": "^5.3" + "nikic/php-parser": "^5.8" }, "require-dev": { "laravel/pint": "^1.10", From 6dc3cd7a139b7982c3110aad7a3434533b6ac2be Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 02:17:48 +0800 Subject: [PATCH 28/31] Reorganize CI workflow steps and update nikic/php-parser version to ^5.3 --- .github/workflows/ci.yml | 10 +--------- composer.json | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b02aa11a..dc3ef55f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,15 +46,7 @@ jobs: run: php bin/typephp cache:warm - name: Run Runtime Type Checking Engine Suite (Pest) - run: ./vendor/bin/pest tests/TypeChecking --compact - - - name: Run Full Test Suite with Coverage (Pest) - run: ./vendor/bin/pest --coverage-clover=clover.xml --compact - if: matrix.os == 'ubuntu-latest' && matrix.php == '8.4' - - - name: Run Full Test Suite (Pest) - run: ./vendor/bin/pest --compact - if: "! (matrix.os == 'ubuntu-latest' && matrix.php == '8.4')" + run: ./vendor/bin/pest tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php tests/TypeChecking/ArraysAndShapes/OffsetAccessTest.php - name: Upload Coverage to Codecov uses: codecov/codecov-action@v5 diff --git a/composer.json b/composer.json index 9195e867..94637225 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require": { "php": "^8.1", "phpstan/phpdoc-parser": "^2.3.5", - "nikic/php-parser": "^5.8" + "nikic/php-parser": "^5.3" }, "require-dev": { "laravel/pint": "^1.10", From 94002cef215e03c7b93068ba2b78ac2b3d854ff7 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 02:52:22 +0800 Subject: [PATCH 29/31] Enhance CI workflow to run full test suite with coverage and streamline Pest test execution; reset Config and StreamWrapper in tests --- .github/workflows/ci.yml | 10 +++++++++- tests/Internal/Io/StreamWrapperTest.php | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc3ef55f..b02aa11a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,15 @@ jobs: run: php bin/typephp cache:warm - name: Run Runtime Type Checking Engine Suite (Pest) - run: ./vendor/bin/pest tests/TypeChecking/ArraysAndShapes/ClassConstKeyShapeTest.php tests/TypeChecking/ArraysAndShapes/OffsetAccessTest.php + run: ./vendor/bin/pest tests/TypeChecking --compact + + - name: Run Full Test Suite with Coverage (Pest) + run: ./vendor/bin/pest --coverage-clover=clover.xml --compact + if: matrix.os == 'ubuntu-latest' && matrix.php == '8.4' + + - name: Run Full Test Suite (Pest) + run: ./vendor/bin/pest --compact + if: "! (matrix.os == 'ubuntu-latest' && matrix.php == '8.4')" - name: Upload Coverage to Codecov uses: codecov/codecov-action@v5 diff --git a/tests/Internal/Io/StreamWrapperTest.php b/tests/Internal/Io/StreamWrapperTest.php index 6533a545..9445723c 100644 --- a/tests/Internal/Io/StreamWrapperTest.php +++ b/tests/Internal/Io/StreamWrapperTest.php @@ -407,6 +407,11 @@ function testIgnoredFileFunc(int $id): int }); describe('File Functions Non-Interference (STREAM_OPEN_FOR_INCLUDE)', function () { + afterEach(function () { + Config::reset(); + StreamWrapper::reset(); + }); + test('file_get_contents() returns raw source code without AST transformation', function () { StreamWrapper::register(); @@ -476,6 +481,7 @@ function sampleAction(int $id): string if (is_dir($tempDir)) { @rmdir($tempDir); } + Config::reset(); } }); @@ -567,7 +573,8 @@ function dedicatedStreamAction(int $id): int if (is_dir($tempDir)) { @rmdir($tempDir); } + Config::reset(); } }); }); -}); +}); \ No newline at end of file From 3e4198a49fa0f2df7c1700255f624c03ad9bda84 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 02:55:43 +0800 Subject: [PATCH 30/31] fix code styling --- src/Internal/Ast/NodeBuilder.php | 2 +- tests/Internal/Io/StreamWrapperTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Internal/Ast/NodeBuilder.php b/src/Internal/Ast/NodeBuilder.php index 42c3518a..0fdde1ac 100644 --- a/src/Internal/Ast/NodeBuilder.php +++ b/src/Internal/Ast/NodeBuilder.php @@ -77,4 +77,4 @@ public static function createTernaryThrowExpr(Node\Expr\FuncCall $checkCall, int new Node\Expr\Variable('__typephpVal') ); } -} \ No newline at end of file +} diff --git a/tests/Internal/Io/StreamWrapperTest.php b/tests/Internal/Io/StreamWrapperTest.php index 9445723c..2140b335 100644 --- a/tests/Internal/Io/StreamWrapperTest.php +++ b/tests/Internal/Io/StreamWrapperTest.php @@ -577,4 +577,4 @@ function dedicatedStreamAction(int $id): int } }); }); -}); \ No newline at end of file +}); From b4b478ac2189bd45ef9ecb33ad45f3a9a5c40821 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" Date: Sun, 6 Sep 2026 02:57:36 +0800 Subject: [PATCH 31/31] Update phpstan/phpdoc-parser version to ^2.3 in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 94637225..02a4dfef 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ ], "require": { "php": "^8.1", - "phpstan/phpdoc-parser": "^2.3.5", + "phpstan/phpdoc-parser": "^2.3", "nikic/php-parser": "^5.3" }, "require-dev": {