diff --git a/src/Capability/Discovery/SchemaGenerator.php b/src/Capability/Discovery/SchemaGenerator.php index a4efdd6a..80779c70 100644 --- a/src/Capability/Discovery/SchemaGenerator.php +++ b/src/Capability/Discovery/SchemaGenerator.php @@ -677,7 +677,12 @@ private function mapPhpTypeToJsonSchemaType(string $phpTypeString): array return ['array']; } - // PRIORITY 3: Handle unions (recursive) + // PRIORITY 3: Treat PHPStan/Psalm integer ranges as their base type + if (preg_match('/^int\s*<\s*[^<>]+\s*>$/i', $normalizedType)) { + return ['integer']; + } + + // PRIORITY 4: Handle unions (recursive) if (str_contains($normalizedType, '|')) { $types = explode('|', $normalizedType); $jsonTypes = []; @@ -689,7 +694,7 @@ private function mapPhpTypeToJsonSchemaType(string $phpTypeString): array return array_values(array_unique($jsonTypes)); } - // PRIORITY 4: Handle simple built-in types + // PRIORITY 5: Handle simple built-in types return match ($normalizedType) { 'string', 'scalar' => ['string'], '?string' => ['null', 'string'], diff --git a/tests/Unit/Capability/Discovery/SchemaGeneratorFixture.php b/tests/Unit/Capability/Discovery/SchemaGeneratorFixture.php index d6959173..548c5d9b 100644 --- a/tests/Unit/Capability/Discovery/SchemaGeneratorFixture.php +++ b/tests/Unit/Capability/Discovery/SchemaGeneratorFixture.php @@ -226,6 +226,21 @@ public function typeHintDocBlockAndParameterSchema( ): void { } + /** + * PHPStan/Psalm integer ranges should keep their base integer type. + * + * @param int<0, max> $offset Positive offset + * @param int $negative Negative value + * @param int<-5, 10> $bounded Bounded value + */ + public function integerRangeTypes( + #[Schema(minimum: 0)] + int $offset, + int $negative, + int $bounded, + ): void { + } + // ===== ENUM SCENARIOS ===== /** diff --git a/tests/Unit/Capability/Discovery/SchemaGeneratorTest.php b/tests/Unit/Capability/Discovery/SchemaGeneratorTest.php index 0c223cb5..b5dbb09b 100644 --- a/tests/Unit/Capability/Discovery/SchemaGeneratorTest.php +++ b/tests/Unit/Capability/Discovery/SchemaGeneratorTest.php @@ -190,6 +190,16 @@ public function testCombinesPhpTypeHintsDocBlockDescriptionsAndParameterLevelSch $this->assertEqualsCanonicalizing(['username', 'priority'], $schema['required']); } + public function testMapsPhpStanAndPsalmIntegerRangesToBaseIntegerType(): void + { + $method = new \ReflectionMethod(SchemaGeneratorFixture::class, 'integerRangeTypes'); + $schema = $this->schemaGenerator->generate($method); + + $this->assertEquals(['type' => 'integer', 'description' => 'Positive offset', 'minimum' => 0], $schema['properties']['offset']); + $this->assertEquals(['type' => 'integer', 'description' => 'Negative value'], $schema['properties']['negative']); + $this->assertEquals(['type' => 'integer', 'description' => 'Bounded value'], $schema['properties']['bounded']); + } + public function testGeneratesCorrectSchemaForEnumParameters(): void { $method = new \ReflectionMethod(SchemaGeneratorFixture::class, 'enumParameters');