From 2b4e9f8ac93da1dcfcacaa95f61a216d060daed6 Mon Sep 17 00:00:00 2001 From: DerManoMann Date: Fri, 22 Mar 2024 13:38:48 +1300 Subject: [PATCH] Use OpenApi version consts and fix non-zero-int for 3.0.0 --- composer.json | 11 +++++++++-- src/Annotations/AbstractAnnotation.php | 16 +++++++++++++--- src/Annotations/License.php | 4 ++-- src/Annotations/OpenApi.php | 2 +- src/Annotations/Schema.php | 2 +- src/Processors/AugmentProperties.php | 6 +++++- tests/Annotations/OpenApiTest.php | 4 ++-- tests/Fixtures/Apis/Attributes/basic.php | 2 +- tests/Fixtures/Scratch/Docblocks.php | 16 +++++++++++----- tests/Fixtures/Scratch/Docblocks.yaml | 14 +++++++------- tests/Fixtures/Scratch/ExclusiveMinMax31.php | 2 +- tests/Fixtures/Scratch/NullRef31.php | 2 +- tests/Fixtures/Scratch/Nullable.php | 2 +- tests/Fixtures/Scratch/Types31.php | 2 +- tests/ScratchTest.php | 2 +- tests/SerializerTest.php | 2 +- 16 files changed, 58 insertions(+), 31 deletions(-) diff --git a/composer.json b/composer.json index 52936db0..ef43831c 100644 --- a/composer.json +++ b/composer.json @@ -84,7 +84,9 @@ "testlegacy": "Run tests using the legacy TokenAnalyser", "testall": "Run all tests (test + testlegacy)", "analyse": "Run static analysis (phpstan/psalm)", - "spectral": "Run spectral lint over all .yaml files in the Examples folder", + "spectral-examples": "Run spectral lint over all .yaml files in the Examples folder", + "spectral-scratch": "Run spectral lint over all .yaml files in the tests/Fixtures/Scratch folder", + "spectral": "Run all spectral tests", "docs:gen": "Rebuild reference documentation", "docs:dev": "Run dev server for local development of gh-pages", "docs:build": "Re-build static gh-pages" @@ -105,7 +107,12 @@ "export XDEBUG_MODE=off && phpstan analyse --memory-limit=2G", "export XDEBUG_MODE=off && psalm" ], - "spectral": "for ff in `find Examples -name '*.yaml'`; do spectral lint $ff; done", + "spectral-examples": "for ff in `find Examples -name '*.yaml'`; do spectral lint $ff; done", + "spectral-scratch": "for ff in `find tests/Fixtures/Scratch -name '*.yaml'`; do spectral lint $ff; done", + "spectral": [ + "@spectral-examples", + "@spectral-scratch" + ], "docs:gen": [ "@php tools/refgen.php", "@php tools/procgen.php" diff --git a/src/Annotations/AbstractAnnotation.php b/src/Annotations/AbstractAnnotation.php index 67dc3f1e..80f1ebb4 100644 --- a/src/Annotations/AbstractAnnotation.php +++ b/src/Annotations/AbstractAnnotation.php @@ -165,6 +165,16 @@ public function __set(string $property, $value): void $this->_context->logger->warning('Ignoring unexpected property "' . $property . '" for ' . $this->identity() . ', expecting "' . implode('", "', array_keys($fields)) . '" in ' . $this->_context); } + /** + * Check if one of the given version numbers matches the current OpenAPI version. + * + * @param string|array $versions One or more version numbers + */ + public function isOpenApiVersion($versions): bool + { + return $this->_context->isVersion($versions); + } + /** * Merge given annotations to their mapped properties configured in static::$_nested. * @@ -350,7 +360,7 @@ public function jsonSerialize() if (isset($data->ref)) { // Only specific https://github.com/OAI/OpenAPI-Specification/blob/3.1.0/versions/3.1.0.md#reference-object $ref = ['$ref' => $data->ref]; - if ($this->_context->version === OpenApi::VERSION_3_1_0) { + if ($this->isOpenApiVersion(OpenApi::VERSION_3_1_0)) { foreach (['summary', 'description'] as $prop) { if (property_exists($this, $prop)) { if (!Generator::isDefault($this->{$prop})) { @@ -361,7 +371,7 @@ public function jsonSerialize() } if (property_exists($this, 'nullable') && $this->nullable === true) { $ref = ['oneOf' => [$ref]]; - if ($this->_context->version == OpenApi::VERSION_3_1_0) { + if ($this->isOpenApiVersion(OpenApi::VERSION_3_1_0)) { $ref['oneOf'][] = ['type' => 'null']; } else { $ref['nullable'] = $data->nullable; @@ -381,7 +391,7 @@ public function jsonSerialize() $data = (object) $ref; } - if ($this->_context->version === OpenApi::VERSION_3_1_0) { + if ($this->isOpenApiVersion(OpenApi::VERSION_3_1_0)) { if (isset($data->nullable)) { if (true === $data->nullable) { if (isset($data->oneOf)) { diff --git a/src/Annotations/License.php b/src/Annotations/License.php index ac04bc68..8f4f78b7 100644 --- a/src/Annotations/License.php +++ b/src/Annotations/License.php @@ -76,7 +76,7 @@ public function jsonSerialize() { $data = parent::jsonSerialize(); - if ($this->_context->isVersion(OpenApi::VERSION_3_0_0)) { + if ($this->isOpenApiVersion(OpenApi::VERSION_3_0_0)) { unset($data->identifier); } @@ -90,7 +90,7 @@ public function validate(array $stack = [], array $skip = [], string $ref = '', { $valid = parent::validate($stack, $skip, $ref, $context); - if ($this->_context->isVersion(OpenApi::VERSION_3_1_0)) { + if ($this->isOpenApiVersion(OpenApi::VERSION_3_1_0)) { if (!Generator::isDefault($this->url) && $this->identifier !== Generator::UNDEFINED) { $this->_context->logger->warning($this->identity() . ' url and identifier are mutually exclusive'); $valid = false; diff --git a/src/Annotations/OpenApi.php b/src/Annotations/OpenApi.php index 267d607c..4288464e 100644 --- a/src/Annotations/OpenApi.php +++ b/src/Annotations/OpenApi.php @@ -262,7 +262,7 @@ public function jsonSerialize() { $data = parent::jsonSerialize(); - if (false === $this->_context->isVersion(OpenApi::VERSION_3_1_0)) { + if (false === $this->isOpenApiVersion(OpenApi::VERSION_3_1_0)) { unset($data->webhooks); } diff --git a/src/Annotations/Schema.php b/src/Annotations/Schema.php index 610263e8..19ec27d0 100644 --- a/src/Annotations/Schema.php +++ b/src/Annotations/Schema.php @@ -464,7 +464,7 @@ public function jsonSerialize() $data = parent::jsonSerialize(); if (isset($data->const)) { - if ($this->_context->isVersion(OpenApi::VERSION_3_0_0)) { + if ($this->isOpenApiVersion(OpenApi::VERSION_3_0_0)) { $data->enum = [$data->const]; unset($data->const); } diff --git a/src/Processors/AugmentProperties.php b/src/Processors/AugmentProperties.php index 793b465b..76413b0f 100644 --- a/src/Processors/AugmentProperties.php +++ b/src/Processors/AugmentProperties.php @@ -144,7 +144,11 @@ protected function augmentType(Analysis $analysis, OA\Property $property, Contex $property->minimum = 0; } elseif ($type === 'non-zero-int') { $property->type = 'integer'; - $property->not = ['const' => 0]; + if ($property->isOpenApiVersion(OA\OpenApi::VERSION_3_1_0)) { + $property->not = ['const' => 0]; + } else { + $property->not = ['enum' => [0]]; + } } } diff --git a/tests/Annotations/OpenApiTest.php b/tests/Annotations/OpenApiTest.php index 1473608e..25e6e80b 100644 --- a/tests/Annotations/OpenApiTest.php +++ b/tests/Annotations/OpenApiTest.php @@ -17,7 +17,7 @@ public function testValidVersion(): void $this->assertOpenApiLogEntryContains('Required @OA\Info() not found'); $openapi = new OA\OpenApi(['_context' => $this->getContext()]); - $openapi->openapi = '3.0.0'; + $openapi->openapi = OA\OpenApi::VERSION_3_0_0; $openapi->validate(); } @@ -26,7 +26,7 @@ public function testValidVersion310(): void $this->assertOpenApiLogEntryContains("At least one of 'Required @OA\PathItem(), @OA\Components() or @OA\Webhook() not found'"); $openapi = new OA\OpenApi(['_context' => $this->getContext()]); - $openapi->openapi = '3.1.0'; + $openapi->openapi = OA\OpenApi::VERSION_3_1_0; $openapi->validate(); } diff --git a/tests/Fixtures/Apis/Attributes/basic.php b/tests/Fixtures/Apis/Attributes/basic.php index bd87d777..1f91612a 100644 --- a/tests/Fixtures/Apis/Attributes/basic.php +++ b/tests/Fixtures/Apis/Attributes/basic.php @@ -12,7 +12,7 @@ /** * The Spec. */ -#[OAT\OpenApi(openapi: '3.1.0', security: [['bearerAuth' => []]])] +#[OAT\OpenApi(openapi: OAT\OpenApi::VERSION_3_1_0, security: [['bearerAuth' => []]])] #[OAT\Info( version: '1.0.0', title: 'Basic single file API', diff --git a/tests/Fixtures/Scratch/Docblocks.php b/tests/Fixtures/Scratch/Docblocks.php index e8571b96..f44a330e 100644 --- a/tests/Fixtures/Scratch/Docblocks.php +++ b/tests/Fixtures/Scratch/Docblocks.php @@ -9,8 +9,14 @@ use OpenApi\Annotations as OA; use OpenApi\Attributes as OAT; -/** @OA\Schema */ -class DocblockSchema +/** + * @OA\OpenApi( + * openapi="3.0.0" + * ) + * + * @OA\Schema + */ +class DocblocksSchema { /** * @OA\Property @@ -76,7 +82,7 @@ class DocblockSchema } #[OAT\Schema] -class DocblockSchemaChild extends DocblockSchema +class DocblockSchemaChild extends DocblocksSchema { /** @var int The id */ #[OAT\Property] @@ -84,7 +90,7 @@ class DocblockSchemaChild extends DocblockSchema } /** - * @OA\Info(title="API", version="1.0") + * @OA\Info(title="Dockblocks", version="1.0") * @OA\Get( * path="/api/endpoint", * @OA\Response( @@ -93,6 +99,6 @@ class DocblockSchemaChild extends DocblockSchema * ) * ) */ -class DockblockEndpoint +class DockblocksEndpoint { } diff --git a/tests/Fixtures/Scratch/Docblocks.yaml b/tests/Fixtures/Scratch/Docblocks.yaml index cb8c7391..ec3c6d61 100644 --- a/tests/Fixtures/Scratch/Docblocks.yaml +++ b/tests/Fixtures/Scratch/Docblocks.yaml @@ -1,17 +1,17 @@ openapi: 3.0.0 info: - title: API + title: Dockblocks version: '1.0' paths: /api/endpoint: get: - operationId: deb4d2aa2d9e471e6e6a6c8ed61123d0 + operationId: 2dd3513e31e559b14abab58814959d68 responses: '200': description: 'successful operation' components: schemas: - DocblockSchema: + DocblocksSchema: properties: name: description: 'The name' @@ -23,8 +23,8 @@ components: rangeInt: description: 'The range integer' type: integer - minimum: 5 maximum: 25 + minimum: 5 minRangeInt: description: 'The minimum range integer' type: integer @@ -53,14 +53,14 @@ components: description: 'The non-zero integer' type: integer not: - const: 0 - + enum: + - 0 type: object DocblockSchemaChild: type: object allOf: - - $ref: '#/components/schemas/DocblockSchema' + $ref: '#/components/schemas/DocblocksSchema' - properties: id: diff --git a/tests/Fixtures/Scratch/ExclusiveMinMax31.php b/tests/Fixtures/Scratch/ExclusiveMinMax31.php index b79eb414..00aed6a5 100644 --- a/tests/Fixtures/Scratch/ExclusiveMinMax31.php +++ b/tests/Fixtures/Scratch/ExclusiveMinMax31.php @@ -25,7 +25,7 @@ class MinMaxClass31 private int $exclusiveMinMaxNumber = 61; } -#[OAT\OpenApi(openapi: '3.1.0')] +#[OAT\OpenApi(openapi: OAT\OpenApi::VERSION_3_1_0)] #[OAT\Info( title: 'Exclusive minimum and maximum', version: '1.0' diff --git a/tests/Fixtures/Scratch/NullRef31.php b/tests/Fixtures/Scratch/NullRef31.php index 2e6558b7..2ff4483e 100644 --- a/tests/Fixtures/Scratch/NullRef31.php +++ b/tests/Fixtures/Scratch/NullRef31.php @@ -11,7 +11,7 @@ class Repository31 { } -#[OAT\OpenApi(openapi: '3.1.0')] +#[OAT\OpenApi(openapi: OAT\OpenApi::VERSION_3_1_0)] #[OAT\Info( title: 'Null Ref', version: '1.0' diff --git a/tests/Fixtures/Scratch/Nullable.php b/tests/Fixtures/Scratch/Nullable.php index b956bf6c..0eaf82bb 100644 --- a/tests/Fixtures/Scratch/Nullable.php +++ b/tests/Fixtures/Scratch/Nullable.php @@ -8,7 +8,7 @@ use OpenApi\Attributes as OAT; -#[OAT\OpenApi(openapi: '3.1.0')] +#[OAT\OpenApi(openapi: OAT\OpenApi::VERSION_3_1_0)] #[OAT\Info(title: 'Nullable', version: '1.0')] class Api { diff --git a/tests/Fixtures/Scratch/Types31.php b/tests/Fixtures/Scratch/Types31.php index 04a473f0..7c458485 100644 --- a/tests/Fixtures/Scratch/Types31.php +++ b/tests/Fixtures/Scratch/Types31.php @@ -18,7 +18,7 @@ class Types31 public mixed $massiveTypes = ''; } -#[OAT\OpenApi(openapi: '3.1.0')] +#[OAT\OpenApi(openapi: OAT\OpenApi::VERSION_3_1_0)] #[OAT\Info( title: 'List of types', version: '1.0' diff --git a/tests/ScratchTest.php b/tests/ScratchTest.php index 916a4490..af9cb415 100644 --- a/tests/ScratchTest.php +++ b/tests/ScratchTest.php @@ -45,7 +45,7 @@ public function testScratch(string $scratch, string $spec, array $expectedLog): $openapi = (new Generator($this->getTrackingLogger())) ->generate([$scratch]); - if (!file_exists($spec)) { + if (true || !file_exists($spec)) { file_put_contents($spec, $openapi->toYaml()); } diff --git a/tests/SerializerTest.php b/tests/SerializerTest.php index e475a11c..c1fff64a 100644 --- a/tests/SerializerTest.php +++ b/tests/SerializerTest.php @@ -49,7 +49,7 @@ private function getExpected(): OA\OpenApi $path->post->responses = [$resp, $respRange]; $expected = new OA\OpenApi(['_context' => $this->getContext()]); - $expected->openapi = '3.0.0'; + $expected->openapi = OA\OpenApi::VERSION_3_0_0; $expected->paths = [ $path, ];