diff --git a/generate-spec b/generate-spec index 1dfb9e5..24a7884 100755 --- a/generate-spec +++ b/generate-spec @@ -770,7 +770,7 @@ foreach ($scopePaths as $scope => $paths) { } // Queue potential sub-refs for exporting as well - foreach (['allOf', 'oneOf', 'anyOf', 'properties'] as $group) { + foreach (['allOf', 'oneOf', 'anyOf', 'properties', 'additionalProperties'] as $group) { if (isset($schemas[$schemaName][$group])) { foreach ($schemas[$schemaName][$group] as $subType) { $newRefs = Helpers::collectUsedRefs($subType); @@ -783,6 +783,15 @@ foreach ($scopePaths as $scope => $paths) { } } + if (isset($schemas[$schemaName]['items'])) { + $newRefs = Helpers::collectUsedRefs($schemas[$schemaName]['items']); + foreach ($newRefs as $newRef) { + if (!isset($scopedSchemas[substr($newRef, strlen('#/components/schemas/'))])) { + $usedSchemas[] = $newRef; + } + } + } + $scopedSchemas[$schemaName] = $schemas[$schemaName]; } diff --git a/src/Helpers.php b/src/Helpers.php index a5117c4..d5b1df1 100644 --- a/src/Helpers.php +++ b/src/Helpers.php @@ -253,10 +253,12 @@ static function collectUsedRefs(array $data): array { if (isset($data['$ref'])) { $refs[] = [$data['$ref']]; } - if (isset($data['properties'])) { - foreach ($data['properties'] as $property) { - if (is_array($property)) { - $refs[] = self::collectUsedRefs($property); + foreach (['allOf', 'oneOf', 'anyOf', 'properties', 'additionalProperties'] as $group) { + if (isset($data[$group]) && is_array($data[$group])) { + foreach ($data[$group] as $property) { + if (is_array($property)) { + $refs[] = self::collectUsedRefs($property); + } } } } diff --git a/tests/appinfo/routes.php b/tests/appinfo/routes.php index 5d55c70..6827908 100644 --- a/tests/appinfo/routes.php +++ b/tests/appinfo/routes.php @@ -32,6 +32,7 @@ ['name' => 'Settings#adminScope', 'url' => '/api/{apiVersion}/admin', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings#doubleScope', 'url' => '/api/{apiVersion}/double', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings#nestedSchemas', 'url' => '/api/{apiVersion}/nested-schemas', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#listSchemas', 'url' => '/api/{apiVersion}/list-schemas', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings2#defaultAdminScopeOverwritten', 'url' => '/api/{apiVersion}/default-admin-overwritten', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings2#defaultAdminScope', 'url' => '/api/{apiVersion}/default-admin', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], diff --git a/tests/lib/Controller/SettingsController.php b/tests/lib/Controller/SettingsController.php index 81b84fe..3e79b45 100644 --- a/tests/lib/Controller/SettingsController.php +++ b/tests/lib/Controller/SettingsController.php @@ -35,6 +35,7 @@ /** * @psalm-import-type NotificationsPushDevice from ResponseDefinitions * @psalm-import-type NotificationsNotification from ResponseDefinitions + * @psalm-import-type NotificationsCollection from ResponseDefinitions */ #[OpenAPI(scope: OpenAPI::SCOPE_FEDERATION)] class SettingsController extends OCSController { @@ -133,4 +134,18 @@ public function doubleScope(): DataResponse { public function nestedSchemas(): DataResponse { return new DataResponse(); } + + /** + * @NoAdminRequired + * + * Route is ignored because of scope on the controller + * + * @return DataResponse + * + * 200: OK + */ + #[OpenAPI] + public function listSchemas(): DataResponse { + return new DataResponse(); + } } diff --git a/tests/lib/ResponseDefinitions.php b/tests/lib/ResponseDefinitions.php index 80ba8f2..88b1b21 100644 --- a/tests/lib/ResponseDefinitions.php +++ b/tests/lib/ResponseDefinitions.php @@ -27,6 +27,15 @@ namespace OCA\Notifications; /** + * @psalm-type NotificationsItem = array{ + * label: string, + * link: string, + * type: string, + * primary: bool, + * } + * + * @psalm-type NotificationsCollection = list + * * @psalm-type NotificationsNotificationAction = array{ * label: string, * link: string, diff --git a/tests/openapi.json b/tests/openapi.json index efc029b..f0f9153 100644 --- a/tests/openapi.json +++ b/tests/openapi.json @@ -119,6 +119,12 @@ } } }, + "Collection": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Item" + } + }, "NotificationAction": { "type": "object", "required": [ @@ -141,6 +147,29 @@ "type": "boolean" } } + }, + "Item": { + "type": "object", + "required": [ + "label", + "link", + "type", + "primary" + ], + "properties": { + "label": { + "type": "string" + }, + "link": { + "type": "string" + }, + "type": { + "type": "string" + }, + "primary": { + "type": "boolean" + } + } } } }, @@ -363,6 +392,79 @@ } } }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/list-schemas": { + "post": { + "operationId": "settings-list-schemas", + "summary": "Route is ignored because of scope on the controller", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Collection" + } + } + } + } + } + } + } + } + } + } + }, "/ocs/v2.php/apps/notifications/api/{apiVersion}/default-admin-overwritten": { "post": { "operationId": "settings2-default-admin-scope-overwritten",