diff --git a/composer.json b/composer.json index cd0cbbb..e5084ee 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "php": "^8.1", "nette/utils": "^3.2 || ^4.0", "nikic/php-parser": "^5.0", - "phpstan/phpdoc-parser": "^1.18.1" + "phpstan/phpdoc-parser": "^2.0.0" }, "require-dev": { "editorconfig-checker/editorconfig-checker": "^10.6.0", @@ -20,7 +20,7 @@ "shipmonk/composer-dependency-analyser": "^1.8.1", "shipmonk/name-collision-detector": "^2.1.1", "shipmonk/phpstan-rules": "^4.0.0", - "slevomat/coding-standard": "^8.15.0" + "slevomat/coding-standard": "dev-master" }, "autoload": { "psr-4": { diff --git a/src/Compiler/Mapper/Array/MapArrayShape.php b/src/Compiler/Mapper/Array/MapArrayShape.php index 232ad6f..36587b7 100644 --- a/src/Compiler/Mapper/Array/MapArrayShape.php +++ b/src/Compiler/Mapper/Array/MapArrayShape.php @@ -5,7 +5,6 @@ use Attribute; use PhpParser\Node\Expr; use PhpParser\Node\Stmt; -use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode; use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; @@ -102,13 +101,15 @@ public function getOutputType(): TypeNode foreach ($this->items as $mapping) { $items[] = new ArrayShapeItemNode( - new ConstExprStringNode($mapping->key), + new IdentifierTypeNode($mapping->key), $mapping->optional, $mapping->mapper->getOutputType(), ); } - return new ArrayShapeNode($items, $this->sealed, ArrayShapeNode::KIND_ARRAY); + return $this->sealed + ? ArrayShapeNode::createSealed($items) + : ArrayShapeNode::createUnsealed($items, null); } /** diff --git a/src/Compiler/MapperFactory/DefaultMapperCompilerFactoryProvider.php b/src/Compiler/MapperFactory/DefaultMapperCompilerFactoryProvider.php index 887f227..5406bcb 100644 --- a/src/Compiler/MapperFactory/DefaultMapperCompilerFactoryProvider.php +++ b/src/Compiler/MapperFactory/DefaultMapperCompilerFactoryProvider.php @@ -6,6 +6,7 @@ use PHPStan\PhpDocParser\Parser\ConstExprParser; use PHPStan\PhpDocParser\Parser\PhpDocParser; use PHPStan\PhpDocParser\Parser\TypeParser; +use PHPStan\PhpDocParser\ParserConfig; class DefaultMapperCompilerFactoryProvider implements MapperCompilerFactoryProvider { @@ -19,20 +20,26 @@ public function get(): MapperCompilerFactory protected function create(): MapperCompilerFactory { - return new DefaultMapperCompilerFactory($this->createPhpDocLexer(), $this->createPhpDocParser()); + $config = $this->createParserConfig(); + return new DefaultMapperCompilerFactory($this->createPhpDocLexer($config), $this->createPhpDocParser($config)); } - protected function createPhpDocLexer(): Lexer + protected function createPhpDocLexer(ParserConfig $config): Lexer { - return new Lexer(); + return new Lexer($config); } - protected function createPhpDocParser(): PhpDocParser + protected function createParserConfig(): ParserConfig { - $phpDocExprParser = new ConstExprParser(unescapeStrings: true); - $phpDocTypeParser = new TypeParser($phpDocExprParser); + return new ParserConfig([]); + } + + protected function createPhpDocParser(ParserConfig $config): PhpDocParser + { + $phpDocExprParser = new ConstExprParser($config); + $phpDocTypeParser = new TypeParser($config, $phpDocExprParser); - return new PhpDocParser($phpDocTypeParser, $phpDocExprParser); + return new PhpDocParser($config, $phpDocTypeParser, $phpDocExprParser); } } diff --git a/src/Compiler/Php/PhpCodeBuilder.php b/src/Compiler/Php/PhpCodeBuilder.php index debcfcb..0246cac 100644 --- a/src/Compiler/Php/PhpCodeBuilder.php +++ b/src/Compiler/Php/PhpCodeBuilder.php @@ -528,7 +528,7 @@ public function mapperClassConstructor(MapperCompiler $mapperCompiler): ClassMet $innerMappersParameter->flags = ClassNode::MODIFIER_PRIVATE | ClassNode::MODIFIER_READONLY; $mapperConstructorBuilder->addParam($innerMappersParameter); - $innerMappersType = new ArrayShapeNode(Arrays::map( + $innerMappersType = ArrayShapeNode::createSealed(Arrays::map( $mapperCompiler->getGenericParameters(), static function (GenericTypeParameter $genericParameter): ArrayShapeItemNode { return new ArrayShapeItemNode( diff --git a/src/Compiler/Type/PhpDocTypeUtils.php b/src/Compiler/Type/PhpDocTypeUtils.php index c71f792..028685a 100644 --- a/src/Compiler/Type/PhpDocTypeUtils.php +++ b/src/Compiler/Type/PhpDocTypeUtils.php @@ -39,6 +39,7 @@ use PHPStan\PhpDocParser\Parser\PhpDocParser; use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; +use PHPStan\PhpDocParser\ParserConfig; use ReflectionClass; use ReflectionIntersectionType; use ReflectionNamedType; @@ -179,7 +180,7 @@ public static function fromValue(mixed $value): TypeNode ); } - return new ArrayShapeNode($items); + return ArrayShapeNode::createSealed($items); } if (is_object($value)) { @@ -947,10 +948,11 @@ private static function getGenericTypeDefinitionFromPhpDoc(string $className): G private static function parsePhpDoc(string $phpDoc): PhpDocNode { - $phpDocLexer = new Lexer(); - $phpDocTypeParser = new TypeParser(); - $phpDocConstExprParser = new ConstExprParser(unescapeStrings: true); - $phpDocParser = new PhpDocParser($phpDocTypeParser, $phpDocConstExprParser); + $config = new ParserConfig([]); + $phpDocLexer = new Lexer($config); + $phpDocConstExprParser = new ConstExprParser($config); + $phpDocTypeParser = new TypeParser($config, $phpDocConstExprParser); + $phpDocParser = new PhpDocParser($config, $phpDocTypeParser, $phpDocConstExprParser); $phpDocTokens = $phpDocLexer->tokenize($phpDoc); return $phpDocParser->parse(new TokenIterator($phpDocTokens)); @@ -1065,7 +1067,7 @@ private static function normalizeType(TypeNode $type): TypeNode } elseif ($item->keyName instanceof IdentifierTypeNode) { $newItems[] = new ArrayShapeItemNode( - keyName: new ConstExprStringNode($item->keyName->name), + keyName: new ConstExprStringNode($item->keyName->name, ConstExprStringNode::SINGLE_QUOTED), optional: $item->optional, valueType: $item->valueType, ); @@ -1075,7 +1077,9 @@ private static function normalizeType(TypeNode $type): TypeNode } } - return new ArrayShapeNode($newItems, $type->sealed, $type->kind); + return $type->sealed + ? ArrayShapeNode::createSealed($newItems, $type->kind) + : ArrayShapeNode::createUnsealed($newItems, null, $type->kind); } if ($type instanceof GenericTypeNode) { diff --git a/tests/Compiler/MapperFactory/DefaultMapperCompilerFactoryTest.php b/tests/Compiler/MapperFactory/DefaultMapperCompilerFactoryTest.php index 2a441d9..dbf9df1 100644 --- a/tests/Compiler/MapperFactory/DefaultMapperCompilerFactoryTest.php +++ b/tests/Compiler/MapperFactory/DefaultMapperCompilerFactoryTest.php @@ -11,6 +11,7 @@ use PHPStan\PhpDocParser\Parser\PhpDocParser; use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; +use PHPStan\PhpDocParser\ParserConfig; use PHPUnit\Framework\Attributes\DataProvider; use ShipMonk\InputMapper\Compiler\Exception\CannotCreateMapperCompilerException; use ShipMonk\InputMapper\Compiler\Mapper\Array\ArrayShapeItemMapping; @@ -71,10 +72,11 @@ class DefaultMapperCompilerFactoryTest extends InputMapperTestCase #[DataProvider('provideCreateOkData')] public function testCreateOk(string $type, array $options, MapperCompiler $expectedMapperCompiler): void { - $phpDocLexer = new Lexer(); - $phpDocExprParser = new ConstExprParser(unescapeStrings: true); - $phpDocTypeParser = new TypeParser($phpDocExprParser); - $phpDocParser = new PhpDocParser($phpDocTypeParser, $phpDocExprParser); + $config = new ParserConfig([]); + $phpDocLexer = new Lexer($config); + $phpDocConstExprParser = new ConstExprParser($config); + $phpDocTypeParser = new TypeParser($config, $phpDocConstExprParser); + $phpDocParser = new PhpDocParser($config, $phpDocTypeParser, $phpDocConstExprParser); $phpDocType = $phpDocTypeParser->parse(new TokenIterator($phpDocLexer->tokenize($type))); $mapperCompilerFactory = new DefaultMapperCompilerFactory($phpDocLexer, $phpDocParser); @@ -435,10 +437,11 @@ className: InputWithRenamedSourceKey::class, #[DataProvider('provideCreateErrorData')] public function testCreateError(string $type, array $options, ?string $expectedMessage = null): void { - $phpDocLexer = new Lexer(); - $phpDocExprParser = new ConstExprParser(unescapeStrings: true); - $phpDocTypeParser = new TypeParser($phpDocExprParser); - $phpDocParser = new PhpDocParser($phpDocTypeParser, $phpDocExprParser); + $config = new ParserConfig([]); + $phpDocLexer = new Lexer($config); + $phpDocConstExprParser = new ConstExprParser($config); + $phpDocTypeParser = new TypeParser($config, $phpDocConstExprParser); + $phpDocParser = new PhpDocParser($config, $phpDocTypeParser, $phpDocConstExprParser); $phpDocType = $phpDocTypeParser->parse(new TokenIterator($phpDocLexer->tokenize($type))); $mapperCompilerFactory = new DefaultMapperCompilerFactory($phpDocLexer, $phpDocParser); @@ -510,10 +513,11 @@ public static function provideCreateErrorData(): iterable public function testCreateWithCustomFactory(): void { - $phpDocLexer = new Lexer(); - $phpDocExprParser = new ConstExprParser(unescapeStrings: true); - $phpDocTypeParser = new TypeParser($phpDocExprParser); - $phpDocParser = new PhpDocParser($phpDocTypeParser, $phpDocExprParser); + $config = new ParserConfig([]); + $phpDocLexer = new Lexer($config); + $phpDocConstExprParser = new ConstExprParser($config); + $phpDocTypeParser = new TypeParser($config, $phpDocConstExprParser); + $phpDocParser = new PhpDocParser($config, $phpDocTypeParser, $phpDocConstExprParser); $carMapperCompiler = new MapObject(CarInput::class, [ 'id' => new MapInt(), diff --git a/tests/Compiler/Type/PhpDocTypeUtilsTest.php b/tests/Compiler/Type/PhpDocTypeUtilsTest.php index 24dfdd3..f551f86 100644 --- a/tests/Compiler/Type/PhpDocTypeUtilsTest.php +++ b/tests/Compiler/Type/PhpDocTypeUtilsTest.php @@ -23,6 +23,7 @@ use PHPStan\PhpDocParser\Parser\ConstExprParser; use PHPStan\PhpDocParser\Parser\TokenIterator; use PHPStan\PhpDocParser\Parser\TypeParser; +use PHPStan\PhpDocParser\ParserConfig; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use ReflectionClass; @@ -279,7 +280,7 @@ public static function provideToNativeTypeData(): iterable ]; yield 'array{int, string}' => [ - new ArrayShapeNode([ + ArrayShapeNode::createSealed([ new ArrayShapeItemNode(keyName: null, optional: false, valueType: new IdentifierTypeNode('int')), new ArrayShapeItemNode(keyName: null, optional: false, valueType: new IdentifierTypeNode('string')), ]), @@ -397,7 +398,7 @@ public static function provideIsNullableData(): iterable ]; yield 'array{int, string}' => [ - new ArrayShapeNode([ + ArrayShapeNode::createSealed([ new ArrayShapeItemNode(keyName: null, optional: false, valueType: new IdentifierTypeNode('int')), new ArrayShapeItemNode(keyName: null, optional: false, valueType: new IdentifierTypeNode('string')), ]), @@ -1609,9 +1610,10 @@ public static function provideInferGenericParameterData(): iterable private function parseType(string $type): TypeNode { - $lexer = new Lexer(); - $constExprParser = new ConstExprParser(unescapeStrings: true); - $typeParser = new TypeParser($constExprParser); + $config = new ParserConfig([]); + $lexer = new Lexer($config); + $constExprParser = new ConstExprParser($config); + $typeParser = new TypeParser($config, $constExprParser); $tokens = new TokenIterator($lexer->tokenize($type)); $typeNode = $typeParser->parse($tokens);