From 37def942b477aca6a0c6898bc93cdd26ff16a7eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Aug 2024 02:15:42 +0000 Subject: [PATCH] chore(deps-dev): Bump nextcloud/coding-standard from 1.2.1 to 1.2.3 Bumps [nextcloud/coding-standard](https://github.com/nextcloud/coding-standard) from 1.2.1 to 1.2.3. - [Release notes](https://github.com/nextcloud/coding-standard/releases) - [Changelog](https://github.com/nextcloud/coding-standard/blob/master/CHANGELOG.md) - [Commits](https://github.com/nextcloud/coding-standard/compare/v1.2.1...v1.2.3) --- updated-dependencies: - dependency-name: nextcloud/coding-standard dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 24 +- generate-spec | 416 ++++++++++---------- merge-specs | 136 +++---- src/ControllerMethod.php | 42 +- src/Helpers.php | 70 ++-- src/Logger.php | 4 +- src/LoggerException.php | 2 +- src/LoggerLevel.php | 8 +- src/OpenApiType.php | 108 ++--- src/ResponseType.php | 80 ++-- src/Route.php | 2 +- src/StatusCodes.php | 128 +++--- tests/lib/Controller/SettingsController.php | 6 +- 13 files changed, 513 insertions(+), 513 deletions(-) diff --git a/composer.lock b/composer.lock index d0893ec..a77590a 100644 --- a/composer.lock +++ b/composer.lock @@ -185,16 +185,16 @@ "packages-dev": [ { "name": "nextcloud/coding-standard", - "version": "v1.2.1", + "version": "v1.2.3", "source": { "type": "git", "url": "https://github.com/nextcloud/coding-standard.git", - "reference": "cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e" + "reference": "bc9c53a5306114b60c4363057aff9c2ed10a54da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e", - "reference": "cf5f18d989ec62fb4cdc7fc92a36baf34b3d829e", + "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/bc9c53a5306114b60c4363057aff9c2ed10a54da", + "reference": "bc9c53a5306114b60c4363057aff9c2ed10a54da", "shasum": "" }, "require": { @@ -220,9 +220,9 @@ "description": "Nextcloud coding standards for the php cs fixer", "support": { "issues": "https://github.com/nextcloud/coding-standard/issues", - "source": "https://github.com/nextcloud/coding-standard/tree/v1.2.1" + "source": "https://github.com/nextcloud/coding-standard/tree/v1.2.3" }, - "time": "2024-02-01T14:54:37+00:00" + "time": "2024-08-23T14:32:32+00:00" }, { "name": "nextcloud/ocp", @@ -271,16 +271,16 @@ }, { "name": "php-cs-fixer/shim", - "version": "v3.41.1", + "version": "v3.62.0", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/shim.git", - "reference": "01cea2dca727100537bd63e28e06e49a475b54e9" + "reference": "7a91d5ce45c486f5b445d95901228507a02f60ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/01cea2dca727100537bd63e28e06e49a475b54e9", - "reference": "01cea2dca727100537bd63e28e06e49a475b54e9", + "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/7a91d5ce45c486f5b445d95901228507a02f60ae", + "reference": "7a91d5ce45c486f5b445d95901228507a02f60ae", "shasum": "" }, "require": { @@ -317,9 +317,9 @@ "description": "A tool to automatically fix PHP code style", "support": { "issues": "https://github.com/PHP-CS-Fixer/shim/issues", - "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.41.1" + "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.62.0" }, - "time": "2023-12-10T19:59:57+00:00" + "time": "2024-08-07T17:03:46+00:00" }, { "name": "psr/clock", diff --git a/generate-spec b/generate-spec index ec62ce2..8ab0011 100755 --- a/generate-spec +++ b/generate-spec @@ -3,7 +3,7 @@ namespace OpenAPIExtractor; -foreach ([__DIR__ . "/../../autoload.php", __DIR__ . "/vendor/autoload.php"] as $file) { +foreach ([__DIR__ . '/../../autoload.php', __DIR__ . '/vendor/autoload.php'] as $file) { if (file_exists($file)) { require_once $file; break; @@ -34,19 +34,19 @@ use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use stdClass; -$command = new Command("generate-spec", "Extract OpenAPI specs from the Nextcloud source code"); +$command = new Command('generate-spec', 'Extract OpenAPI specs from the Nextcloud source code'); $command - ->arguments("dir out") + ->arguments('dir out') ->option('--first-status-code', 'Only output the first status code') ->option('--first-content-type', 'Only output the first content type') ->option('--allow-missing-docs', 'Allow missing documentation fields') ->option('--no-tags', 'Use no tags') ->option('--openapi-version', 'OpenAPI version to use', null, '3.0.3') ->option('--verbose', 'Verbose logging') - ->parse($_SERVER["argv"]); + ->parse($_SERVER['argv']); -$dir = $command->dir ?? ""; -$out = $command->out ?? ""; +$dir = $command->dir ?? ''; +$out = $command->out ?? ''; $firstStatusCode = $command->firstStatusCode ?? false; $firstContentType = $command->firstContentType ?? false; $allowMissingDocs = $command->allowMissingDocs ?? false; @@ -54,11 +54,11 @@ $useTags = $command->tags ?? true; Logger::$verbose = $command->verbose ?? false; $openapiVersion = $command->openapiVersion ?? '3.0.3'; -if ($dir == "") { - $dir = "."; +if ($dir == '') { + $dir = '.'; } -if ($out == "") { - $out = "openapi.json"; +if ($out == '') { + $out = 'openapi.json'; } $astParser = (new ParserFactory())->createForNewestSupportedVersion(); @@ -69,12 +69,12 @@ $constExprParser = new ConstExprParser(); $typeParser = new TypeParser($constExprParser); $phpDocParser = new PhpDocParser($typeParser, $constExprParser); -$infoXMLPath = $dir . "/appinfo/info.xml"; +$infoXMLPath = $dir . '/appinfo/info.xml'; if (file_exists($infoXMLPath)) { $xml = simplexml_load_string(file_get_contents($infoXMLPath)); if ($xml === false) { - Logger::panic("appinfo", "info.xml file at " . $infoXMLPath . " is not parsable"); + Logger::panic('appinfo', 'info.xml file at ' . $infoXMLPath . ' is not parsable'); } $appIsCore = false; @@ -88,51 +88,51 @@ if (file_exists($infoXMLPath)) { $appVersion = (string)$xml->version; $appLicence = (string)$xml->licence; } else { - $versionPHPPath = $dir . "/../version.php"; + $versionPHPPath = $dir . '/../version.php'; if (!file_exists($versionPHPPath)) { - Logger::panic("appinfo", "Neither " . $infoXMLPath . " nor " . $versionPHPPath . " exists"); + Logger::panic('appinfo', 'Neither ' . $infoXMLPath . ' nor ' . $versionPHPPath . ' exists'); } // Includes https://github.com/nextcloud/server/blob/master/version.php when running inside https://github.com/nextcloud/server/tree/master/core include($versionPHPPath); if (!isset($OC_VersionString)) { - Logger::panic("appinfo", "Unable to figure out core version"); + Logger::panic('appinfo', 'Unable to figure out core version'); } $appIsCore = true; - $appID = "core"; - $readableAppID = "Core"; - $appSummary = "Core functionality of Nextcloud"; + $appID = 'core'; + $readableAppID = 'Core'; + $appSummary = 'Core functionality of Nextcloud'; $appVersion = $OC_VersionString; - $appLicence = "agpl"; + $appLicence = 'agpl'; } -$sourceDir = $appIsCore ? $dir : $dir . "/lib"; -$appinfoDir = $appIsCore ? $dir : $dir . "/appinfo"; +$sourceDir = $appIsCore ? $dir : $dir . '/lib'; +$appinfoDir = $appIsCore ? $dir : $dir . '/appinfo'; $openapi = [ - "openapi" => $openapiVersion, - "info" => [ - "title" => $appID, - "version" => "0.0.1", // This marks the document version and not the implementation version - "description" => $appSummary, - "license" => Helpers::license($openapiVersion, $appLicence), + 'openapi' => $openapiVersion, + 'info' => [ + 'title' => $appID, + 'version' => '0.0.1', // This marks the document version and not the implementation version + 'description' => $appSummary, + 'license' => Helpers::license($openapiVersion, $appLicence), ], - "components" => [ - "securitySchemes" => Helpers::securitySchemes(), - "schemas" => [], + 'components' => [ + 'securitySchemes' => Helpers::securitySchemes(), + 'schemas' => [], ], - "paths" => [], + 'paths' => [], ]; -Logger::info("app", "Extracting OpenAPI spec for " . $appID . " " . $appVersion); +Logger::info('app', 'Extracting OpenAPI spec for ' . $appID . ' ' . $appVersion); $schemas = []; $tags = []; $definitions = []; -$definitionsPath = $sourceDir . "/ResponseDefinitions.php"; +$definitionsPath = $sourceDir . '/ResponseDefinitions.php'; if (file_exists($definitionsPath)) { foreach ($nodeFinder->findInstanceOf($astParser->parse(file_get_contents($definitionsPath)), Class_::class) as $node) { $doc = $node->getDocComment()?->getText(); @@ -141,7 +141,7 @@ if (file_exists($definitionsPath)) { foreach ($docNodes as $docNode) { if ($docNode instanceof PhpDocTagNode && $docNode->value instanceof TypeAliasTagValueNode) { if (!str_starts_with($docNode->value->alias, $readableAppID)) { - Logger::error("Response definitions", "Type alias '" . $docNode->value->alias . "' has to start with '" . $readableAppID . "'"); + Logger::error('Response definitions', "Type alias '" . $docNode->value->alias . "' has to start with '" . $readableAppID . "'"); } $definitions[$docNode->value->alias] = $docNode->value->type; } @@ -149,10 +149,10 @@ if (file_exists($definitionsPath)) { } } foreach (array_keys($definitions) as $name) { - $schemas[Helpers::cleanSchemaName($name)] = OpenApiType::resolve("Response definitions", $definitions, $definitions[$name])->toArray(); + $schemas[Helpers::cleanSchemaName($name)] = OpenApiType::resolve('Response definitions', $definitions, $definitions[$name])->toArray(); } } else { - Logger::debug("Response definitions", "No response definitions were loaded"); + Logger::debug('Response definitions', 'No response definitions were loaded'); } $capabilities = null; @@ -166,7 +166,7 @@ foreach ($capabilitiesDirs as $dir) { $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)); foreach ($iterator as $file) { $path = $file->getPathname(); - if (str_ends_with($path, "Capabilities.php")) { + if (str_ends_with($path, 'Capabilities.php')) { $capabilitiesFiles[] = $path; } } @@ -177,8 +177,8 @@ foreach ($capabilitiesFiles as $path) { * @var Class_ $node */ foreach ($nodeFinder->findInstanceOf($astParser->parse(file_get_contents($path)), Class_::class) as $node) { - $implementsCapability = count(array_filter($node->implements, fn (Name $name) => $name->getLast() == "ICapability")) > 0; - $implementsPublicCapability = count(array_filter($node->implements, fn (Name $name) => $name->getLast() == "IPublicCapability")) > 0; + $implementsCapability = count(array_filter($node->implements, fn (Name $name) => $name->getLast() == 'ICapability')) > 0; + $implementsPublicCapability = count(array_filter($node->implements, fn (Name $name) => $name->getLast() == 'IPublicCapability')) > 0; if (!$implementsCapability && !$implementsPublicCapability) { continue; } @@ -186,19 +186,19 @@ foreach ($capabilitiesFiles as $path) { $capabilitiesMethod = null; /** @var ClassMethod $classMethod */ foreach ($nodeFinder->findInstanceOf($node->stmts, ClassMethod::class) as $classMethod) { - if ($classMethod->name == "getCapabilities") { + if ($classMethod->name == 'getCapabilities') { $capabilitiesMethod = $classMethod; break; } } if ($capabilitiesMethod == null) { - Logger::error($path, "Unable to read capabilities method"); + Logger::error($path, 'Unable to read capabilities method'); continue; } $doc = $capabilitiesMethod->getDocComment()?->getText(); if ($doc == null) { - Logger::error($path, "Unable to read capabilities docs"); + Logger::error($path, 'Unable to read capabilities docs'); continue; } @@ -211,7 +211,7 @@ foreach ($capabilitiesFiles as $path) { } } if ($type == null) { - Logger::error($path, "No return value"); + Logger::error($path, 'No return value'); continue; } @@ -225,25 +225,25 @@ foreach ($capabilitiesFiles as $path) { } } if ($capabilities != null) { - $schemas["Capabilities"] = $capabilities; + $schemas['Capabilities'] = $capabilities; } if ($publicCapabilities != null) { - $schemas["PublicCapabilities"] = $publicCapabilities; + $schemas['PublicCapabilities'] = $publicCapabilities; } if ($capabilities == null && $publicCapabilities == null) { - Logger::debug("Capabilities", "No capabilities were loaded"); + Logger::debug('Capabilities', 'No capabilities were loaded'); } -$parsedRoutes = file_exists($appinfoDir . "/routes.php") ? Route::parseRoutes($appinfoDir . "/routes.php") : []; +$parsedRoutes = file_exists($appinfoDir . '/routes.php') ? Route::parseRoutes($appinfoDir . '/routes.php') : []; $controllers = []; -$controllersDir = $sourceDir . "/Controller"; +$controllersDir = $sourceDir . '/Controller'; if (file_exists($controllersDir)) { $dir = new DirectoryIterator($controllersDir); $controllerFiles = []; foreach ($dir as $file) { $filePath = $file->getPathname(); - if (!str_ends_with($filePath, "Controller.php")) { + if (!str_ends_with($filePath, 'Controller.php')) { continue; } $controllerFiles[] = $filePath; @@ -251,7 +251,7 @@ if (file_exists($controllersDir)) { sort($controllerFiles); foreach ($controllerFiles as $filePath) { - $controllers[basename($filePath, "Controller.php")] = $astParser->parse(file_get_contents($filePath)); + $controllers[basename($filePath, 'Controller.php')] = $astParser->parse(file_get_contents($filePath)); } } @@ -323,51 +323,51 @@ foreach ($controllers as $controllerName => $stmts) { } if (count($parsedRoutes) === 0) { - Logger::warning("Routes", "No routes were loaded"); + Logger::warning('Routes', 'No routes were loaded'); } $operationIds = []; foreach ($parsedRoutes as $key => $value) { - $isOCS = $key === "ocs"; - $isIndex = $key === "routes"; + $isOCS = $key === 'ocs'; + $isIndex = $key === 'routes'; if (!$isOCS && !$isIndex) { continue; } foreach ($value as $route) { - $routeName = $route["name"]; - - $postfix = array_key_exists("postfix", $route) ? $route["postfix"] : null; - $verb = array_key_exists("verb", $route) ? $route["verb"] : "GET"; - $requirements = array_key_exists("requirements", $route) ? $route["requirements"] : []; - $defaults = array_key_exists("defaults", $route) ? $route["defaults"] : []; - $root = array_key_exists("root", $route) ? $route["root"] : ($appIsCore ? "" : "/apps/" . $appID); - $url = $route["url"]; - if (!str_starts_with($url, "/")) { - $url = "/" . $url; + $routeName = $route['name']; + + $postfix = array_key_exists('postfix', $route) ? $route['postfix'] : null; + $verb = array_key_exists('verb', $route) ? $route['verb'] : 'GET'; + $requirements = array_key_exists('requirements', $route) ? $route['requirements'] : []; + $defaults = array_key_exists('defaults', $route) ? $route['defaults'] : []; + $root = array_key_exists('root', $route) ? $route['root'] : ($appIsCore ? '' : '/apps/' . $appID); + $url = $route['url']; + if (!str_starts_with($url, '/')) { + $url = '/' . $url; } - if (str_ends_with($url, "/")) { + if (str_ends_with($url, '/')) { $url = substr($url, 0, -1); } if ($isIndex) { - $url = "/index.php" . $root . $url; + $url = '/index.php' . $root . $url; } if ($isOCS) { - $url = "/ocs/v2.php" . $root . $url; + $url = '/ocs/v2.php' . $root . $url; } - $methodName = lcfirst(str_replace("_", "", ucwords(explode("#", $routeName)[1], "_"))); - if ($methodName == "preflightedCors") { + $methodName = lcfirst(str_replace('_', '', ucwords(explode('#', $routeName)[1], '_'))); + if ($methodName == 'preflightedCors') { continue; } - $controllerName = ucfirst(str_replace("_", "", ucwords(explode("#", $routeName)[0], "_"))); + $controllerName = ucfirst(str_replace('_', '', ucwords(explode('#', $routeName)[0], '_'))); $controllerClass = null; /** @var Class_ $class */ foreach ($nodeFinder->findInstanceOf($controllers[$controllerName] ?? [], Class_::class) as $class) { - if ($class->name == $controllerName . "Controller") { + if ($class->name == $controllerName . 'Controller') { $controllerClass = $class; break; } @@ -378,7 +378,7 @@ foreach ($parsedRoutes as $key => $value) { } $controllerScopes = Helpers::getOpenAPIAttributeScopes($controllerClass, $routeName); - if (Helpers::classMethodHasAnnotationOrAttribute($controllerClass, "IgnoreOpenAPI")) { + if (Helpers::classMethodHasAnnotationOrAttribute($controllerClass, 'IgnoreOpenAPI')) { if (count($controllerScopes) === 0 || (in_array('ignore', $controllerScopes, true) && count($controllerScopes) === 1)) { Logger::debug($routeName, "Controller '" . $controllerName . "' ignored because of IgnoreOpenAPI attribute"); continue; @@ -396,16 +396,16 @@ foreach ($parsedRoutes as $key => $value) { Logger::panic($routeName, "Controller '" . $controllerName . "' is marked as ignore but also has other scopes"); } - $tagName = implode("_", array_map(fn (string $s) => strtolower($s), Helpers::splitOnUppercaseFollowedByNonUppercase($controllerName))); + $tagName = implode('_', array_map(fn (string $s) => strtolower($s), Helpers::splitOnUppercaseFollowedByNonUppercase($controllerName))); $doc = $controllerClass->getDocComment()?->getText(); - if ($doc != null && count(array_filter($tags, fn (array $tag) => $tag["name"] == $tagName)) == 0) { + if ($doc != null && count(array_filter($tags, fn (array $tag) => $tag['name'] == $tagName)) == 0) { $classDescription = []; $docNodes = $phpDocParser->parse(new TokenIterator($lexer->tokenize($doc)))->children; foreach ($docNodes as $docNode) { if ($docNode instanceof PhpDocTextNode) { $block = Helpers::cleanDocComment($docNode->text); - if ($block == "") { + if ($block == '') { continue; } $classDescription[] = $block; @@ -414,8 +414,8 @@ foreach ($parsedRoutes as $key => $value) { if (count($classDescription) > 0) { $tags[] = [ - "name" => $tagName, - "description" => join("\n", $classDescription), + 'name' => $tagName, + 'description' => join("\n", $classDescription), ]; } } @@ -432,37 +432,37 @@ foreach ($parsedRoutes as $key => $value) { Logger::panic($routeName, 'Missing controller method'); } - $isCSRFRequired = !Helpers::classMethodHasAnnotationOrAttribute($methodFunction, "NoCSRFRequired"); + $isCSRFRequired = !Helpers::classMethodHasAnnotationOrAttribute($methodFunction, 'NoCSRFRequired'); if ($isCSRFRequired && !$isOCS) { - Logger::debug($routeName, "Route ignored because of required CSRF in a non-OCS controller"); + Logger::debug($routeName, 'Route ignored because of required CSRF in a non-OCS controller'); continue; } - $isCORS = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, "CORS"); - $isPublic = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, "PublicPage"); - $isAdmin = !Helpers::classMethodHasAnnotationOrAttribute($methodFunction, "NoAdminRequired") && !$isPublic; - $isDeprecated = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, "deprecated"); - $isIgnored = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, "IgnoreOpenAPI"); - $isPasswordConfirmation = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, "PasswordConfirmationRequired"); - $isExApp = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, "ExAppRequired"); + $isCORS = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, 'CORS'); + $isPublic = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, 'PublicPage'); + $isAdmin = !Helpers::classMethodHasAnnotationOrAttribute($methodFunction, 'NoAdminRequired') && !$isPublic; + $isDeprecated = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, 'deprecated'); + $isIgnored = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, 'IgnoreOpenAPI'); + $isPasswordConfirmation = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, 'PasswordConfirmationRequired'); + $isExApp = Helpers::classMethodHasAnnotationOrAttribute($methodFunction, 'ExAppRequired'); $scopes = Helpers::getOpenAPIAttributeScopes($classMethod, $routeName); if ($isIgnored) { if (count($scopes) === 0 || (in_array('ignore', $scopes, true) && count($scopes) === 1)) { - Logger::debug($routeName, "Route ignored because of IgnoreOpenAPI attribute"); + Logger::debug($routeName, 'Route ignored because of IgnoreOpenAPI attribute'); continue; } - Logger::panic($routeName, "Route is marked as ignore but also has other scopes"); + Logger::panic($routeName, 'Route is marked as ignore but also has other scopes'); } if (in_array('ignore', $scopes, true)) { if (count($scopes) === 1) { - Logger::debug($routeName, "Route ignored because of OpenAPI attribute"); + Logger::debug($routeName, 'Route ignored because of OpenAPI attribute'); continue; } - Logger::panic($routeName, "Route is marked as ignore but also has other scopes"); + Logger::panic($routeName, 'Route is marked as ignore but also has other scopes'); } if (empty($scopes)) { @@ -479,30 +479,30 @@ foreach ($parsedRoutes as $key => $value) { $routeTags = Helpers::getOpenAPIAttributeTagsByScope($classMethod, $routeName, $tagName, reset($scopes)); - if ($isOCS && !array_key_exists("OCSMeta", $schemas)) { - $schemas["OCSMeta"] = [ - "type" => "object", - "required" => [ - "status", - "statuscode", + if ($isOCS && !array_key_exists('OCSMeta', $schemas)) { + $schemas['OCSMeta'] = [ + 'type' => 'object', + 'required' => [ + 'status', + 'statuscode', ], - "properties" => [ - "status" => ["type" => "string"], - "statuscode" => ["type" => "integer"], - "message" => ["type" => "string"], - "totalitems" => ["type" => "string"], - "itemsperpage" => ["type" => "string"], + 'properties' => [ + 'status' => ['type' => 'string'], + 'statuscode' => ['type' => 'integer'], + 'message' => ['type' => 'string'], + 'totalitems' => ['type' => 'string'], + 'itemsperpage' => ['type' => 'string'], ], ]; } $classMethodInfo = ControllerMethod::parse($routeName, $definitions, $methodFunction, $isAdmin, $isDeprecated, $isPasswordConfirmation); if (count($classMethodInfo->returns) > 0) { - Logger::error($routeName, "Returns an invalid response"); + Logger::error($routeName, 'Returns an invalid response'); continue; } if (count($classMethodInfo->responses) == 0) { - Logger::error($routeName, "Returns no responses"); + Logger::error($routeName, 'Returns no responses'); continue; } @@ -522,7 +522,7 @@ foreach ($parsedRoutes as $key => $value) { $missingDocStatusCodes = array_unique(array_filter(array_diff($codeStatusCodes, $docStatusCodes), fn (int $code) => $code < 500)); if (count($missingDocStatusCodes) > 0) { - Logger::error($routeName, "Returns undocumented status codes: " . implode(", ", $missingDocStatusCodes)); + Logger::error($routeName, 'Returns undocumented status codes: ' . implode(', ', $missingDocStatusCodes)); continue; } @@ -533,7 +533,7 @@ foreach ($parsedRoutes as $key => $value) { if ($postfix !== null) { $operationId[] = $postfix; } - $operationId = strtolower(implode("-", $operationId)); + $operationId = strtolower(implode('-', $operationId)); if (in_array($operationId, $operationIds, true)) { Logger::panic($routeName, 'Route is not unique! If you want to have two routes pointing to the same controller method you must specify a postfix on at least one of the routes.'); @@ -558,7 +558,7 @@ foreach ($parsedRoutes as $key => $value) { ); } - Logger::debug($routeName, "Route generated"); + Logger::debug($routeName, 'Route generated'); } } @@ -582,7 +582,7 @@ foreach ($routes as $scope => $scopeRoutes) { $pathParameters = []; $urlParameters = []; - preg_match_all("/{[^}]*}/", $route->url, $urlParameters); + preg_match_all('/{[^}]*}/', $route->url, $urlParameters); $urlParameters = array_map(fn (string $name) => substr($name, 1, -1), $urlParameters[0]); foreach ($urlParameters as $urlParameter) { @@ -598,56 +598,56 @@ foreach ($routes as $scope => $scopeRoutes) { } $schema = $parameter->type->toArray(true); - $description = $parameter?->docType != null && $parameter->docType->description != "" ? Helpers::cleanDocComment($parameter->docType->description) : null; + $description = $parameter?->docType != null && $parameter->docType->description != '' ? Helpers::cleanDocComment($parameter->docType->description) : null; } else { $schema = [ - "type" => "string", + 'type' => 'string', ]; $description = null; } if ($requirement != null) { - if (!str_starts_with($requirement, "^")) { - $requirement = "^" . $requirement; + if (!str_starts_with($requirement, '^')) { + $requirement = '^' . $requirement; } - if (!str_ends_with($requirement, "$")) { - $requirement = $requirement . "$"; + if (!str_ends_with($requirement, '$')) { + $requirement = $requirement . '$'; } } - if ($schema["type"] == "string") { - if ($urlParameter == "apiVersion") { + if ($schema['type'] == 'string') { + if ($urlParameter == 'apiVersion') { if ($requirement == null) { - Logger::error($route->name, "Missing requirement for apiVersion"); + Logger::error($route->name, 'Missing requirement for apiVersion'); continue; } preg_match("/^\^\(([v0-9-.|]*)\)\\$$/m", $requirement, $matches); if (count($matches) == 2) { - $enum = explode("|", $matches[1]); + $enum = explode('|', $matches[1]); } else { - Logger::error($route->name, "Invalid requirement for apiVersion"); + Logger::error($route->name, 'Invalid requirement for apiVersion'); continue; } - $schema["enum"] = $enum; - $schema["default"] = end($enum); + $schema['enum'] = $enum; + $schema['default'] = end($enum); } elseif ($requirement != null) { - $schema["pattern"] = $requirement; + $schema['pattern'] = $requirement; } } if (array_key_exists($urlParameter, $route->defaults)) { - $schema["default"] = $route->defaults[$urlParameter]; + $schema['default'] = $route->defaults[$urlParameter]; } $parameter = [ - "name" => $urlParameter, - "in" => "path", + 'name' => $urlParameter, + 'in' => 'path', ]; if ($description !== null) { - $parameter["description"] = $description; + $parameter['description'] = $description; } - $parameter["required"] = true; - $parameter["schema"] = $schema; + $parameter['required'] = true; + $parameter['schema'] = $schema; $pathParameters[] = $parameter; } @@ -657,7 +657,7 @@ foreach ($routes as $scope => $scopeRoutes) { foreach ($route->controllerMethod->parameters as $parameter) { $alreadyInPath = false; foreach ($pathParameters as $pathParameter) { - if ($pathParameter["name"] == $parameter->name) { + if ($pathParameter['name'] == $parameter->name) { $alreadyInPath = true; break; } @@ -701,12 +701,12 @@ foreach ($routes as $scope => $scopeRoutes) { $mergedContentTypeResponses[$contentType] = []; } else { $schema = Helpers::cleanEmptyResponseArray($contentTypeResponses[0]->type->toArray()); - $mergedContentTypeResponses[$contentType] = ["schema" => Helpers::wrapOCSResponse($route, $contentTypeResponses[0], $schema)]; + $mergedContentTypeResponses[$contentType] = ['schema' => Helpers::wrapOCSResponse($route, $contentTypeResponses[0], $schema)]; } } else { $mergedContentTypeResponses[$contentType] = [ - "schema" => [ - [$hasEmpty ? "anyOf" : "oneOf" => array_map(function (ControllerMethodResponse $response) use ($route) { + 'schema' => [ + [$hasEmpty ? 'anyOf' : 'oneOf' => array_map(function (ControllerMethodResponse $response) use ($route) { $schema = Helpers::cleanEmptyResponseArray($response->type->toArray()); return Helpers::wrapOCSResponse($route, $response, $schema); }, $uniqueResponses)], @@ -716,21 +716,21 @@ foreach ($routes as $scope => $scopeRoutes) { } $response = [ - "description" => array_key_exists($statusCode, $route->controllerMethod->responseDescription) ? $route->controllerMethod->responseDescription[$statusCode] : "", + 'description' => array_key_exists($statusCode, $route->controllerMethod->responseDescription) ? $route->controllerMethod->responseDescription[$statusCode] : '', ]; if (count($headers) > 0) { - $response["headers"] = array_combine( + $response['headers'] = array_combine( array_keys($headers), array_map( fn (OpenApiType $type) => [ - "schema" => $type->toArray(), + 'schema' => $type->toArray(), ], array_values($headers), ), ); } if (count($mergedContentTypeResponses) > 0) { - $response["content"] = $mergedContentTypeResponses; + $response['content'] = $mergedContentTypeResponses; } $mergedResponses[$statusCode] = $response; } @@ -742,30 +742,30 @@ foreach ($routes as $scope => $scopeRoutes) { } if (!$route->isCORS) { // Bearer auth is not allowed on CORS routes - $security[] = ["bearer_auth" => []]; + $security[] = ['bearer_auth' => []]; } if (!$route->isCSRFRequired || $route->isOCS) { // Add basic auth last, so it's only fallback if bearer is available - $security[] = ["basic_auth" => []]; + $security[] = ['basic_auth' => []]; } $operation = [ - "operationId" => $route->operationId, + 'operationId' => $route->operationId, ]; if ($route->controllerMethod->summary !== null) { - $operation["summary"] = $route->controllerMethod->summary; + $operation['summary'] = $route->controllerMethod->summary; } if (count($route->controllerMethod->description) > 0) { - $operation["description"] = implode("\n", $route->controllerMethod->description); + $operation['description'] = implode("\n", $route->controllerMethod->description); } if ($route->controllerMethod->isDeprecated) { - $operation["deprecated"] = true; + $operation['deprecated'] = true; } if ($useTags) { - $operation["tags"] = $route->tags; + $operation['tags'] = $route->tags; } if (count($security) > 0) { - $operation["security"] = $security; + $operation['security'] = $security; } if (count($bodyParameters) > 0) { @@ -781,21 +781,21 @@ foreach ($routes as $scope => $scopeRoutes) { $required = count($requiredBodyParameters) > 0; $schema = [ - "type" => "object", + 'type' => 'object', ]; if ($required) { - $schema["required"] = $requiredBodyParameters; + $schema['required'] = $requiredBodyParameters; } - $schema["properties"] = []; + $schema['properties'] = []; foreach ($bodyParameters as $bodyParameter) { - $schema["properties"][$bodyParameter->name] = $bodyParameter->type->toArray(); + $schema['properties'][$bodyParameter->name] = $bodyParameter->type->toArray(); } - $operation["requestBody"] = [ - "required" => $required, - "content" => [ - "application/json" => [ - "schema" => $schema, + $operation['requestBody'] = [ + 'required' => $required, + 'content' => [ + 'application/json' => [ + 'schema' => $schema, ], ], ]; @@ -804,42 +804,42 @@ foreach ($routes as $scope => $scopeRoutes) { $parameters = $pathParameters; foreach ($queryParameters as $queryParameter) { $parameter = [ - "name" => $queryParameter->name . ($queryParameter->type->type === "array" ? "[]" : ""), - "in" => "query", + 'name' => $queryParameter->name . ($queryParameter->type->type === 'array' ? '[]' : ''), + 'in' => 'query', ]; - if ($queryParameter->docType !== null && $queryParameter->docType->description !== "") { - $parameter["description"] = Helpers::cleanDocComment($queryParameter->docType->description); + if ($queryParameter->docType !== null && $queryParameter->docType->description !== '') { + $parameter['description'] = Helpers::cleanDocComment($queryParameter->docType->description); } if (!$queryParameter->type->nullable && !$queryParameter->type->hasDefaultValue) { - $parameter["required"] = true; + $parameter['required'] = true; } - $parameter["schema"] = $queryParameter->type->toArray(true); + $parameter['schema'] = $queryParameter->type->toArray(true); $parameters[] = $parameter; } if ($route->isOCS) { $parameters[] = [ - "name" => "OCS-APIRequest", - "in" => "header", - "description" => "Required to be true for the API request to pass", - "required" => true, - "schema" => [ - "type" => "boolean", - "default" => true, + 'name' => 'OCS-APIRequest', + 'in' => 'header', + 'description' => 'Required to be true for the API request to pass', + 'required' => true, + 'schema' => [ + 'type' => 'boolean', + 'default' => true, ], ]; } if (count($parameters) > 0) { - $operation["parameters"] = $parameters; + $operation['parameters'] = $parameters; } - $operation["responses"] = $mergedResponses; + $operation['responses'] = $mergedResponses; $scopePaths[$scope] ??= []; $scopePaths[$scope][$route->url] ??= []; - if (!array_key_exists($route->url, $openapi["paths"])) { - $openapi["paths"][$route->url] = []; + if (!array_key_exists($route->url, $openapi['paths'])) { + $openapi['paths'][$route->url] = []; } $verb = strtolower($route->verb); @@ -852,55 +852,55 @@ foreach ($routes as $scope => $scopeRoutes) { } if ($appIsCore) { - $schemas["Status"] = [ - "type" => "object", - "required" => [ - "installed", - "maintenance", - "needsDbUpgrade", - "version", - "versionstring", - "edition", - "productname", - "extendedSupport" + $schemas['Status'] = [ + 'type' => 'object', + 'required' => [ + 'installed', + 'maintenance', + 'needsDbUpgrade', + 'version', + 'versionstring', + 'edition', + 'productname', + 'extendedSupport' ], - "properties" => [ - "installed" => [ - "type" => "boolean", + 'properties' => [ + 'installed' => [ + 'type' => 'boolean', ], - "maintenance" => [ - "type" => "boolean", + 'maintenance' => [ + 'type' => 'boolean', ], - "needsDbUpgrade" => [ - "type" => "boolean", + 'needsDbUpgrade' => [ + 'type' => 'boolean', ], - "version" => [ - "type" => "string", + 'version' => [ + 'type' => 'string', ], - "versionstring" => [ - "type" => "string", + 'versionstring' => [ + 'type' => 'string', ], - "edition" => [ - "type" => "string", + 'edition' => [ + 'type' => 'string', ], - "productname" => [ - "type" => "string", + 'productname' => [ + 'type' => 'string', ], - "extendedSupport" => [ - "type" => "boolean", + 'extendedSupport' => [ + 'type' => 'boolean', ], ], ]; $scopePaths['default']['/status.php'] = [ - "get" => [ - "operationId" => "get-status", - "responses" => [ + 'get' => [ + 'operationId' => 'get-status', + 'responses' => [ 200 => [ - "description" => "Status returned", - "content" => [ - "application/json" => [ - "schema" => [ - "\$ref" => "#/components/schemas/Status" + 'description' => 'Status returned', + 'content' => [ + 'application/json' => [ + 'schema' => [ + '$ref' => '#/components/schemas/Status' ], ], ], @@ -911,13 +911,13 @@ if ($appIsCore) { } if (count($schemas) == 0 && count($routes) == 0) { - Logger::error("app", "No spec generated"); + Logger::error('app', 'No spec generated'); } ksort($schemas); if ($useTags) { - $openapi["tags"] = $tags; + $openapi['tags'] = $tags; } $hasSingleScope = count($scopePaths) <= 1; @@ -974,7 +974,7 @@ foreach ($scopePaths as $scope => $paths) { $schemaName = substr($usedSchema, strlen('#/components/schemas/')); if (!isset($schemas[$schemaName])) { - Logger::error("app", "Schema $schemaName used by scope $scope is not defined"); + Logger::error('app', "Schema $schemaName used by scope $scope is not defined"); } $newRefs = Helpers::collectUsedRefs($schemas[$schemaName]); diff --git a/merge-specs b/merge-specs index 5c75043..e52486d 100755 --- a/merge-specs +++ b/merge-specs @@ -3,7 +3,7 @@ namespace OpenAPIExtractor; -foreach ([__DIR__ . "/../../autoload.php", __DIR__ . "/vendor/autoload.php"] as $file) { +foreach ([__DIR__ . '/../../autoload.php', __DIR__ . '/vendor/autoload.php'] as $file) { if (file_exists($file)) { require_once $file; break; @@ -13,23 +13,23 @@ foreach ([__DIR__ . "/../../autoload.php", __DIR__ . "/vendor/autoload.php"] as use Ahc\Cli\Input\Command; use stdClass; -$command = new Command("merge-specs", "Merge multiple Nextcloud OpenAPI specs into one"); +$command = new Command('merge-specs', 'Merge multiple Nextcloud OpenAPI specs into one'); $command - ->option("--merged ") - ->option("--core ") + ->option('--merged ') + ->option('--core ') ->option('--openapi-version', 'OpenAPI version to use', null, '3.0.3') ->option('--first-status-code', 'Only output the first status code') - ->argument("<[specs...]>") - ->parse($_SERVER["argv"]); + ->argument('<[specs...]>') + ->parse($_SERVER['argv']); /** * @var string $mergedSpecPath */ -$mergedSpecPath = $command->values()[""]; +$mergedSpecPath = $command->values()['']; /** * @var string $coreSpecPath */ -$coreSpecPath = $command->values()[""]; +$coreSpecPath = $command->values()['']; $openapiVersion = $command->openapiVersion ?? '3.0.3'; $firstStatusCode = $command->firstStatusCode ?? false; /** @@ -42,27 +42,27 @@ $coreSpec = loadSpec($coreSpecPath); $capabilities = collectCapabilities($coreSpec); $data = [ - "openapi" => $openapiVersion, - "info" => [ - "title" => "nextcloud", - "description" => "Nextcloud APIs", - "license" => Helpers::license($openapiVersion, "agpl"), - "version" => "0.0.1", + 'openapi' => $openapiVersion, + 'info' => [ + 'title' => 'nextcloud', + 'description' => 'Nextcloud APIs', + 'license' => Helpers::license($openapiVersion, 'agpl'), + 'version' => '0.0.1', ], - "security" => [ + 'security' => [ [ - "basic_auth" => [], + 'basic_auth' => [], ], [ - "bearer_auth" => [], + 'bearer_auth' => [], ], ], - "tags" => rewriteTags($coreSpec), - "components" => [ - "securitySchemes" => Helpers::securitySchemes(), - "schemas" => rewriteSchemaNames($coreSpec), + 'tags' => rewriteTags($coreSpec), + 'components' => [ + 'securitySchemes' => Helpers::securitySchemes(), + 'schemas' => rewriteSchemaNames($coreSpec), ], - "paths" => rewriteOperations($coreSpec), + 'paths' => rewriteOperations($coreSpec), ]; foreach ($otherSpecPaths as $specPath) { @@ -70,39 +70,39 @@ foreach ($otherSpecPaths as $specPath) { continue; } $spec = loadSpec($specPath); - $data["components"]["schemas"] = array_merge($data["components"]["schemas"], rewriteSchemaNames($spec)); - $data["tags"] = array_merge($data["tags"], rewriteTags($spec)); - $data["paths"] = array_merge($data["paths"], rewriteOperations($spec)); + $data['components']['schemas'] = array_merge($data['components']['schemas'], rewriteSchemaNames($spec)); + $data['tags'] = array_merge($data['tags'], rewriteTags($spec)); + $data['paths'] = array_merge($data['paths'], rewriteOperations($spec)); $capabilities = array_merge($capabilities, collectCapabilities($spec)); } $data -["paths"] -["/ocs/v2.php/cloud/capabilities"] -["get"] -["responses"] -["200"] -["content"] -["application/json"] -["schema"] -["properties"] -["ocs"] -["properties"] -["data"] -["properties"] -["capabilities"] -["anyOf"] - = array_map(fn (string $capability) => ["\$ref" => "#/components/schemas/" . $capability], $capabilities); +['paths'] +['/ocs/v2.php/cloud/capabilities'] +['get'] +['responses'] +['200'] +['content'] +['application/json'] +['schema'] +['properties'] +['ocs'] +['properties'] +['data'] +['properties'] +['capabilities'] +['anyOf'] + = array_map(fn (string $capability) => ['$ref' => '#/components/schemas/' . $capability], $capabilities); function loadSpec(string $path): array { return rewriteRefs(json_decode(file_get_contents($path), true)); } function rewriteRefs(array $spec): array { - $readableAppID = Helpers::generateReadableAppID($spec["info"]["title"]); + $readableAppID = Helpers::generateReadableAppID($spec['info']['title']); array_walk_recursive($spec, function (mixed &$item, string $key) use ($readableAppID) { if ($key === '$ref' && $item !== '#/components/schemas/OCSMeta') { - $item = str_replace("#/components/schemas/", "#/components/schemas/" . $readableAppID, $item); + $item = str_replace('#/components/schemas/', '#/components/schemas/' . $readableAppID, $item); } }); return $spec; @@ -110,9 +110,9 @@ function rewriteRefs(array $spec): array { function collectCapabilities(array $spec): array { $capabilities = []; - $readableAppID = Helpers::generateReadableAppID($spec["info"]["title"]); - foreach (array_keys($spec["components"]["schemas"]) as $name) { - if ($name == "Capabilities" || $name == "PublicCapabilities") { + $readableAppID = Helpers::generateReadableAppID($spec['info']['title']); + foreach (array_keys($spec['components']['schemas']) as $name) { + if ($name == 'Capabilities' || $name == 'PublicCapabilities') { $capabilities[] = $readableAppID . $name; } } @@ -121,53 +121,53 @@ function collectCapabilities(array $spec): array { } function rewriteSchemaNames(array $spec): array { - $schemas = $spec["components"]["schemas"]; - $readableAppID = Helpers::generateReadableAppID($spec["info"]["title"]); + $schemas = $spec['components']['schemas']; + $readableAppID = Helpers::generateReadableAppID($spec['info']['title']); return array_combine( - array_map(fn (string $key) => $key == "OCSMeta" ? $key : $readableAppID . $key, array_keys($schemas)), + array_map(fn (string $key) => $key == 'OCSMeta' ? $key : $readableAppID . $key, array_keys($schemas)), array_values($schemas), ); } function rewriteTags(array $spec): array { return array_map(function (array $tag) use ($spec) { - $tag["name"] = $spec["info"]["title"] . "/" . $tag["name"]; + $tag['name'] = $spec['info']['title'] . '/' . $tag['name']; return $tag; - }, $spec["tags"]); + }, $spec['tags']); } function rewriteOperations(array $spec): array { global $firstStatusCode; - foreach (array_keys($spec["paths"]) as $path) { - foreach (array_keys($spec["paths"][$path]) as $method) { - if (!in_array($method, ["delete", "get", "post", "put", "patch", "options"])) { + foreach (array_keys($spec['paths']) as $path) { + foreach (array_keys($spec['paths'][$path]) as $method) { + if (!in_array($method, ['delete', 'get', 'post', 'put', 'patch', 'options'])) { continue; } - $operation = &$spec["paths"][$path][$method]; - if (array_key_exists("operationId", $operation)) { - $operation["operationId"] = $spec["info"]["title"] . "-" . $operation["operationId"]; + $operation = &$spec['paths'][$path][$method]; + if (array_key_exists('operationId', $operation)) { + $operation['operationId'] = $spec['info']['title'] . '-' . $operation['operationId']; } - if (array_key_exists("tags", $operation)) { - $operation["tags"] = array_map(fn (string $tag) => $spec["info"]["title"] . "/" . $tag, $operation["tags"]); + if (array_key_exists('tags', $operation)) { + $operation['tags'] = array_map(fn (string $tag) => $spec['info']['title'] . '/' . $tag, $operation['tags']); } else { - $operation["tags"] = [$spec["info"]["title"]]; + $operation['tags'] = [$spec['info']['title']]; } - if ($firstStatusCode && array_key_exists("responses", $operation)) { + if ($firstStatusCode && array_key_exists('responses', $operation)) { /** @var string $value */ - $value = array_key_first($operation["responses"]); - $operation["responses"] = [$value => $operation["responses"][$value]]; + $value = array_key_first($operation['responses']); + $operation['responses'] = [$value => $operation['responses'][$value]]; } - if (array_key_exists("security", $operation)) { - for ($i = 0; $i < count($operation["security"]); $i++) { - if (count($operation["security"][$i]) == 0) { - $operation["security"][$i] = new stdClass(); // When reading {} will be converted to [], so we have to fix it + if (array_key_exists('security', $operation)) { + for ($i = 0; $i < count($operation['security']); $i++) { + if (count($operation['security'][$i]) == 0) { + $operation['security'][$i] = new stdClass(); // When reading {} will be converted to [], so we have to fix it } } } } } - return $spec["paths"]; + return $spec['paths']; } file_put_contents($mergedSpecPath, json_encode($data, Helpers::jsonFlags()) . "\n"); diff --git a/src/ControllerMethod.php b/src/ControllerMethod.php index 4db0871..e06cebc 100644 --- a/src/ControllerMethod.php +++ b/src/ControllerMethod.php @@ -41,10 +41,10 @@ public static function parse(string $context, array $definitions, ClassMethod $m foreach ($docNodes as $docNode) { if ($docNode instanceof PhpDocTextNode) { $block = Helpers::cleanDocComment($docNode->text); - if ($block == "") { + if ($block == '') { continue; } - $pattern = "/([0-9]{3}): /"; + $pattern = '/([0-9]{3}): /'; if (preg_match($pattern, $block)) { $parts = preg_split($pattern, $block, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); for ($i = 0; $i < count($parts); $i += 2) { @@ -77,16 +77,16 @@ public static function parse(string $context, array $definitions, ClassMethod $m $type = $docNode->value->type; $statusCode = StatusCodes::resolveException($context . ': @throws', $type); if ($statusCode != null) { - if (!$allowMissingDocs && $docNode->value->description == "" && $statusCode < 500) { + if (!$allowMissingDocs && $docNode->value->description == '' && $statusCode < 500) { Logger::error($context, "Missing description for exception '" . $type . "'"); } else { $responseDescriptions[$statusCode] = $docNode->value->description; } if (str_starts_with($type->name, 'OCS') && str_ends_with($type->name, 'Exception')) { - $responses[] = new ControllerMethodResponse($docNode->value->type, $statusCode, "application/json", new OpenApiType(context: $context, type: "array", maxItems: 0), null); + $responses[] = new ControllerMethodResponse($docNode->value->type, $statusCode, 'application/json', new OpenApiType(context: $context, type: 'array', maxItems: 0), null); } else { - $responses[] = new ControllerMethodResponse($docNode->value->type, $statusCode, "text/plain", new OpenApiType(context: $context, type: "string"), null); + $responses[] = new ControllerMethodResponse($docNode->value->type, $statusCode, 'text/plain', new OpenApiType(context: $context, type: 'string'), null); } } } @@ -96,8 +96,8 @@ public static function parse(string $context, array $definitions, ClassMethod $m if (!$allowMissingDocs) { foreach (array_unique(array_map(fn (ControllerMethodResponse $response) => $response->statusCode, array_filter($responses, fn (?ControllerMethodResponse $response) => $response != null))) as $statusCode) { - if ($statusCode < 500 && (!array_key_exists($statusCode, $responseDescriptions) || $responseDescriptions[$statusCode] == "")) { - Logger::error($context, "Missing description for status code " . $statusCode); + if ($statusCode < 500 && (!array_key_exists($statusCode, $responseDescriptions) || $responseDescriptions[$statusCode] == '')) { + Logger::error($context, 'Missing description for status code ' . $statusCode); } } } @@ -112,12 +112,12 @@ public static function parse(string $context, array $definitions, ClassMethod $m $docParameterName = substr($docParameter->parameterName, 1); if ($docParameterName == $methodParameterName) { - if ($docParameterType == "@param") { + if ($docParameterType == '@param') { $paramTag = $docParameter; - } elseif ($docParameterType == "@psalm-param") { + } elseif ($docParameterType == '@psalm-param') { $psalmParamTag = $docParameter; } else { - Logger::panic($context . ': @param', "Unknown param type " . $docParameterType); + Logger::panic($context . ': @param', 'Unknown param type ' . $docParameterType); } } } @@ -126,12 +126,12 @@ public static function parse(string $context, array $definitions, ClassMethod $m if ($paramTag !== null && $psalmParamTag !== null) { // Use all the type information from @psalm-param because it is more specific, // but pull the description from @param and @psalm-param because usually only one of them has it. - if ($psalmParamTag->description !== "") { + if ($psalmParamTag->description !== '') { $description = $psalmParamTag->description; - } elseif ($paramTag->description !== "") { + } elseif ($paramTag->description !== '') { $description = $paramTag->description; } else { - $description = ""; + $description = ''; } try { @@ -147,7 +147,7 @@ public static function parse(string $context, array $definitions, ClassMethod $m ), ); } catch (LoggerException $e) { - Logger::debug($context, "Unable to parse parameter " . $methodParameterName . ": " . $e->message . "\n" . $e->getTraceAsString()); + Logger::debug($context, 'Unable to parse parameter ' . $methodParameterName . ': ' . $e->message . "\n" . $e->getTraceAsString()); // Fallback to the @param annotation $type = OpenApiType::resolve( $context . ': @param: ' . $psalmParamTag->parameterName, @@ -176,8 +176,8 @@ public static function parse(string $context, array $definitions, ClassMethod $m continue; } - if (!$allowMissingDocs && $param->type->description == "") { - Logger::error($context . ': @param: ' . $methodParameterName, "Missing description"); + if (!$allowMissingDocs && $param->type->description == '') { + Logger::error($context . ': @param: ' . $methodParameterName, 'Missing description'); continue; } @@ -185,15 +185,15 @@ public static function parse(string $context, array $definitions, ClassMethod $m } if (!$allowMissingDocs && count($methodDescription) == 0) { - Logger::error($context, "Missing method description"); + Logger::error($context, 'Missing method description'); } if ($isAdmin) { - $methodDescription[] = "This endpoint requires admin access"; + $methodDescription[] = 'This endpoint requires admin access'; } if ($isPasswordConfirmation) { - $methodDescription[] = "This endpoint requires password confirmation"; + $methodDescription[] = 'This endpoint requires password confirmation'; } if (count($methodDescription) == 1) { @@ -204,8 +204,8 @@ public static function parse(string $context, array $definitions, ClassMethod $m $methodDescription = array_slice($methodDescription, 1); } - if ($methodSummary != null && preg_match("/[.,!?:-]$/", $methodSummary)) { - Logger::warning($context, "Summary ends with a punctuation mark"); + if ($methodSummary != null && preg_match('/[.,!?:-]$/', $methodSummary)) { + Logger::warning($context, 'Summary ends with a punctuation mark'); } return new ControllerMethod($parameters, $responses, $returns, $responseDescriptions, $methodDescription, $methodSummary, $isDeprecated); diff --git a/src/Helpers.php b/src/Helpers.php index bfd3058..5aabdca 100644 --- a/src/Helpers.php +++ b/src/Helpers.php @@ -21,33 +21,33 @@ class Helpers { public const OPENAPI_ATTRIBUTE_CLASSNAME = 'OpenAPI'; public static function generateReadableAppID(string $appID): string { - return implode("", array_map(fn (string $s) => ucfirst($s), explode("_", $appID))); + return implode('', array_map(fn (string $s) => ucfirst($s), explode('_', $appID))); } public static function securitySchemes(): array { return [ - "basic_auth" => [ - "type" => "http", - "scheme" => "basic", + 'basic_auth' => [ + 'type' => 'http', + 'scheme' => 'basic', ], - "bearer_auth" => [ - "type" => "http", - "scheme" => "bearer", + 'bearer_auth' => [ + 'type' => 'http', + 'scheme' => 'bearer', ], ]; } public static function license(string $openapiVersion, string $license): array { $identifier = match ($license) { - "agpl" => "AGPL-3.0-only", - default => Logger::panic("license", "Unable to convert " . $license . " to SPDX identifier"), + 'agpl' => 'AGPL-3.0-only', + default => Logger::panic('license', 'Unable to convert ' . $license . ' to SPDX identifier'), }; $out = [ - "name" => "agpl", + 'name' => 'agpl', ]; - if (version_compare($openapiVersion, "3.1.0", ">=")) { - $out["identifier"] = $identifier; + if (version_compare($openapiVersion, '3.1.0', '>=')) { + $out['identifier'] = $identifier; } return $out; } @@ -57,7 +57,7 @@ public static function jsonFlags(): int { } public static function cleanDocComment(string $comment): string { - return trim(preg_replace("/\s+/", " ", $comment)); + return trim(preg_replace("/\s+/", ' ', $comment)); } public static function splitOnUppercaseFollowedByNonUppercase(string $str): array { @@ -68,7 +68,7 @@ public static function mergeSchemas(array $schemas): mixed { if (!in_array(true, array_map(fn ($schema) => is_array($schema), $schemas))) { $results = array_values(array_unique($schemas)); if (count($results) > 1) { - throw new Exception("Incompatibles types: " . join(", ", $results)); + throw new Exception('Incompatibles types: ' . join(', ', $results)); } return $results[0]; } @@ -82,14 +82,14 @@ public static function mergeSchemas(array $schemas): mixed { $result = []; /** @var string $key */ foreach ($keys as $key) { - if ($key == "required") { + if ($key == 'required') { $required = []; foreach ($schemas as $schema) { - if (array_key_exists("required", $schema)) { - $required = array_merge($required, $schema["required"]); + if (array_key_exists('required', $schema)) { + $required = array_merge($required, $schema['required']); } } - $result["required"] = array_unique($required); + $result['required'] = array_unique($required); continue; } @@ -110,22 +110,22 @@ public static function wrapOCSResponse(Route $route, ControllerMethodResponse $r && ($response->className === 'DataResponse' || (str_starts_with($response->className, 'OCS') && str_ends_with($response->className, 'Exception')))) { return [ - "type" => "object", - "required" => [ - "ocs", + 'type' => 'object', + 'required' => [ + 'ocs', ], - "properties" => [ - "ocs" => [ - "type" => "object", - "required" => [ - "meta", - "data", + 'properties' => [ + 'ocs' => [ + 'type' => 'object', + 'required' => [ + 'meta', + 'data', ], - "properties" => [ - "meta" => [ - "\$ref" => "#/components/schemas/OCSMeta", + 'properties' => [ + 'meta' => [ + '$ref' => '#/components/schemas/OCSMeta', ], - "data" => $schema, + 'data' => $schema, ], ], ], @@ -145,7 +145,7 @@ public static function cleanEmptyResponseArray(array $schema): array|stdClass { public static function classMethodHasAnnotationOrAttribute(ClassMethod|Class_|Node $node, string $annotation): bool { $doc = $node->getDocComment()?->getText(); - if ($doc !== null && str_contains($doc, "@" . $annotation)) { + if ($doc !== null && str_contains($doc, '@' . $annotation)) { return true; } @@ -206,7 +206,7 @@ public static function getOpenAPIAttributeScopes(ClassMethod|Class_|Node $node, } foreach ($attr->args as $key => $arg) { - $scope = self::getScopeNameFromAttributeArgument($arg, (int) $key, $routeName); + $scope = self::getScopeNameFromAttributeArgument($arg, (int)$key, $routeName); if ($scope !== null) { $scopes[] = $scope; } @@ -233,7 +233,7 @@ public static function getOpenAPIAttributeTagsByScope(ClassMethod|Class_|Node $n $foundTags = []; $foundScopeName = null; foreach ($attr->args as $key => $arg) { - $foundScopeName = self::getScopeNameFromAttributeArgument($arg, (int) $key, $routeName); + $foundScopeName = self::getScopeNameFromAttributeArgument($arg, (int)$key, $routeName); if ($arg->name?->name !== 'tags' && ($arg->name !== null || $key !== 1)) { continue; @@ -246,7 +246,7 @@ public static function getOpenAPIAttributeTagsByScope(ClassMethod|Class_|Node $n foreach ($arg->value->items as $item) { if ($item?->value instanceof String_) { $tag = $item->value->value; - $pattern = "/^[0-9a-zA-Z_-]+$/"; + $pattern = '/^[0-9a-zA-Z_-]+$/'; if (!preg_match($pattern, $tag)) { Logger::error($routeName, 'Tag "' . $tag . '" has to match pattern "' . $pattern . '"'); } diff --git a/src/Logger.php b/src/Logger.php index 24f68b9..9d31b8f 100644 --- a/src/Logger.php +++ b/src/Logger.php @@ -12,12 +12,12 @@ protected static function log(LoggerLevel $level, string $context, string $text) protected static function format(LoggerLevel $level, string $context, string $text): string { $colorCode = match ($level) { - LoggerLevel::Debug => "", + LoggerLevel::Debug => '', LoggerLevel::Info => "\e[32m", LoggerLevel::Warning => "\e[33m", LoggerLevel::Error => "\e[91m", }; - return $colorCode . $level->value . ": " . $context . ": " . $text . "\n\e[0m"; + return $colorCode . $level->value . ': ' . $context . ': ' . $text . "\n\e[0m"; } public static function debug(string $context, string $text): void { diff --git a/src/LoggerException.php b/src/LoggerException.php index 37e5c47..f79ba5a 100644 --- a/src/LoggerException.php +++ b/src/LoggerException.php @@ -15,6 +15,6 @@ public function __construct( } public function __toString(): string { - return $this->level->value . ": " . $this->context . ": " . $this->message; + return $this->level->value . ': ' . $this->context . ': ' . $this->message; } } diff --git a/src/LoggerLevel.php b/src/LoggerLevel.php index 3a25f36..5e94856 100644 --- a/src/LoggerLevel.php +++ b/src/LoggerLevel.php @@ -3,8 +3,8 @@ namespace OpenAPIExtractor; enum LoggerLevel: string { - case Debug = "Debug"; - case Info = "Info"; - case Warning = "Warning"; - case Error = "Error"; + case Debug = 'Debug'; + case Info = 'Info'; + case Warning = 'Warning'; + case Error = 'Error'; } diff --git a/src/OpenApiType.php b/src/OpenApiType.php index 0eea15b..a7ce617 100644 --- a/src/OpenApiType.php +++ b/src/OpenApiType.php @@ -82,74 +82,74 @@ enum: [0, 1], $values = []; if ($this->ref !== null) { - $values["\$ref"] = $this->ref; + $values['$ref'] = $this->ref; } if ($this->type !== null) { - $values["type"] = $this->type; + $values['type'] = $this->type; } if ($this->format !== null) { - $values["format"] = $this->format; + $values['format'] = $this->format; } if ($this->nullable) { - $values["nullable"] = true; + $values['nullable'] = true; } if ($this->hasDefaultValue && $this->defaultValue !== null) { if ($this->type === 'object' && empty($this->defaultValue)) { - $values["default"] = new stdClass(); + $values['default'] = new stdClass(); } else { - $values["default"] = $this->defaultValue; + $values['default'] = $this->defaultValue; } } if ($this->enum !== null) { - $values["enum"] = $this->enum; + $values['enum'] = $this->enum; } - if ($this->description !== null && $this->description !== "" && !$isParameter) { - $values["description"] = Helpers::cleanDocComment($this->description); + if ($this->description !== null && $this->description !== '' && !$isParameter) { + $values['description'] = Helpers::cleanDocComment($this->description); } if ($this->items !== null) { - $values["items"] = $this->items->toArray(); + $values['items'] = $this->items->toArray(); } if ($this->minLength !== null) { - $values["minLength"] = $this->minLength; + $values['minLength'] = $this->minLength; } if ($this->maxLength !== null) { - $values["maxLength"] = $this->maxLength; + $values['maxLength'] = $this->maxLength; } if ($this->minimum !== null) { - $values["minimum"] = $this->minimum; + $values['minimum'] = $this->minimum; } if ($this->maximum !== null) { - $values["maximum"] = $this->maximum; + $values['maximum'] = $this->maximum; } if ($this->minItems !== null) { - $values["minItems"] = $this->minItems; + $values['minItems'] = $this->minItems; } if ($this->maxItems !== null) { - $values["maxItems"] = $this->maxItems; + $values['maxItems'] = $this->maxItems; } if ($this->required !== null) { - $values["required"] = $this->required; + $values['required'] = $this->required; } if ($this->properties !== null && count($this->properties) > 0) { - $values["properties"] = array_combine(array_keys($this->properties), + $values['properties'] = array_combine(array_keys($this->properties), array_map(static fn (OpenApiType $property) => $property->toArray(), array_values($this->properties)), ); } if ($this->additionalProperties !== null) { if ($this->additionalProperties instanceof OpenApiType) { - $values["additionalProperties"] = $this->additionalProperties->toArray(); + $values['additionalProperties'] = $this->additionalProperties->toArray(); } else { - $values["additionalProperties"] = $this->additionalProperties; + $values['additionalProperties'] = $this->additionalProperties; } } if ($this->oneOf !== null) { - $values["oneOf"] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->oneOf); + $values['oneOf'] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->oneOf); } if ($this->anyOf !== null) { - $values["anyOf"] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->anyOf); + $values['anyOf'] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->anyOf); } if ($this->allOf !== null) { - $values["allOf"] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->allOf); + $values['allOf'] = array_map(fn (OpenApiType $type) => $type->toArray(), $this->allOf); } return count($values) > 0 ? $values : new stdClass(); @@ -175,8 +175,8 @@ public static function resolve(string $context, array $definitions, ParamTagValu items: self::resolve($context . ': items', $definitions, $node->type), ); } - if ($node instanceof GenericTypeNode && ($node->type->name == "array" || $node->type->name == "list") && count($node->genericTypes) == 1) { - if ($node->genericTypes[0] instanceof IdentifierTypeNode && $node->genericTypes[0]->name == "empty") { + if ($node instanceof GenericTypeNode && ($node->type->name == 'array' || $node->type->name == 'list') && count($node->genericTypes) == 1) { + if ($node->genericTypes[0] instanceof IdentifierTypeNode && $node->genericTypes[0]->name == 'empty') { return new OpenApiType( context: $context, type: 'array', @@ -212,8 +212,8 @@ public static function resolve(string $context, array $definitions, ParamTagValu ); } - if ($node instanceof GenericTypeNode && $node->type->name === "array" && count($node->genericTypes) === 2 && $node->genericTypes[0] instanceof IdentifierTypeNode) { - if ($node->genericTypes[0]->name === "string") { + if ($node instanceof GenericTypeNode && $node->type->name === 'array' && count($node->genericTypes) === 2 && $node->genericTypes[0] instanceof IdentifierTypeNode) { + if ($node->genericTypes[0]->name === 'string') { return new OpenApiType( context: $context, type: 'object', @@ -224,7 +224,7 @@ public static function resolve(string $context, array $definitions, ParamTagValu Logger::panic($context, "JSON objects can only be indexed by 'string' but got '" . $node->genericTypes[0]->name . "'"); } - if ($node instanceof GenericTypeNode && $node->type->name == "int" && count($node->genericTypes) == 2) { + if ($node instanceof GenericTypeNode && $node->type->name == 'int' && count($node->genericTypes) == 2) { $min = null; $max = null; if ($node->genericTypes[0] instanceof ConstTypeNode) { @@ -235,8 +235,8 @@ public static function resolve(string $context, array $definitions, ParamTagValu } return new OpenApiType( context: $context, - type: "integer", - format: "int64", + type: 'integer', + format: 'int64', minimum: $min, maximum: $max, ); @@ -282,15 +282,15 @@ enum: $values, // Not a valid enum return new OpenApiType( context: $context, - type: "integer", - format: "int64", + type: 'integer', + format: 'int64', ); } return new OpenApiType( context: $context, - type: "integer", - format: "int64", + type: 'integer', + format: 'int64', enum: $values, ); } @@ -300,11 +300,11 @@ enum: $values, $items = []; foreach ($node->types as $type) { - if (($type instanceof IdentifierTypeNode || $type instanceof Identifier) && $type->name == "null") { + if (($type instanceof IdentifierTypeNode || $type instanceof Identifier) && $type->name == 'null') { $nullable = true; continue; } - if (($type instanceof IdentifierTypeNode || $type instanceof Identifier) && $type->name == "mixed") { + if (($type instanceof IdentifierTypeNode || $type instanceof Identifier) && $type->name == 'mixed') { Logger::error($context, "Unions and intersections should not contain 'mixed'"); } $items[] = self::resolve($context, $definitions, $type); @@ -414,34 +414,34 @@ private static function mergeEnums(string $context, array $types): array { } private static function resolveIdentifier(string $context, array $definitions, string $name): OpenApiType { - if ($name == "array") { + if ($name == 'array') { Logger::error($context, "Instead of 'array' use:\n'new stdClass()' for empty objects\n'array' for non-empty objects\n'array' for empty lists\n'array' for lists"); } - if (str_starts_with($name, "\\")) { + if (str_starts_with($name, '\\')) { $name = substr($name, 1); } return match ($name) { - "string", "non-falsy-string", "numeric-string" => new OpenApiType(context: $context, type: "string"), - "non-empty-string" => new OpenApiType(context: $context, type: "string", minLength: 1), - "int", "integer" => new OpenApiType(context: $context, type: "integer", format: "int64"), - "non-negative-int" => new OpenApiType(context: $context, type: "integer", format: "int64", minimum: 0), - "positive-int" => new OpenApiType(context: $context, type: "integer", format: "int64", minimum: 1), - "negative-int" => new OpenApiType(context: $context, type: "integer", format: "int64", maximum: -1), - "non-positive-int" => new OpenApiType(context: $context, type: "integer", format: "int64", maximum: 0), - "bool", "boolean" => new OpenApiType(context: $context, type: "boolean"), - "true" => new OpenApiType(context: $context, type: "boolean", enum: [true]), - "false" => new OpenApiType(context: $context, type: "boolean", enum: [false]), - "numeric" => new OpenApiType(context: $context, type: "number"), + 'string', 'non-falsy-string', 'numeric-string' => new OpenApiType(context: $context, type: 'string'), + 'non-empty-string' => new OpenApiType(context: $context, type: 'string', minLength: 1), + 'int', 'integer' => new OpenApiType(context: $context, type: 'integer', format: 'int64'), + 'non-negative-int' => new OpenApiType(context: $context, type: 'integer', format: 'int64', minimum: 0), + 'positive-int' => new OpenApiType(context: $context, type: 'integer', format: 'int64', minimum: 1), + 'negative-int' => new OpenApiType(context: $context, type: 'integer', format: 'int64', maximum: -1), + 'non-positive-int' => new OpenApiType(context: $context, type: 'integer', format: 'int64', maximum: 0), + 'bool', 'boolean' => new OpenApiType(context: $context, type: 'boolean'), + 'true' => new OpenApiType(context: $context, type: 'boolean', enum: [true]), + 'false' => new OpenApiType(context: $context, type: 'boolean', enum: [false]), + 'numeric' => new OpenApiType(context: $context, type: 'number'), // https://www.php.net/manual/en/language.types.float.php: Both float and double are always stored with double precision - "float", "double" => new OpenApiType(context: $context, type: "number", format: "double"), - "mixed", "empty", "array" => new OpenApiType(context: $context, type: "object"), - "object", "stdClass" => new OpenApiType(context: $context, type: "object", additionalProperties: true), - "null" => new OpenApiType(context: $context, nullable: true), + 'float', 'double' => new OpenApiType(context: $context, type: 'number', format: 'double'), + 'mixed', 'empty', 'array' => new OpenApiType(context: $context, type: 'object'), + 'object', 'stdClass' => new OpenApiType(context: $context, type: 'object', additionalProperties: true), + 'null' => new OpenApiType(context: $context, nullable: true), default => (function () use ($context, $definitions, $name) { if (array_key_exists($name, $definitions)) { return new OpenApiType( context: $context, - ref: "#/components/schemas/" . Helpers::cleanSchemaName($name), + ref: '#/components/schemas/' . Helpers::cleanSchemaName($name), ); } Logger::panic($context, "Unable to resolve OpenAPI type for identifier '" . $name . "'"); diff --git a/src/ResponseType.php b/src/ResponseType.php index d9fcaf2..5d83c12 100644 --- a/src/ResponseType.php +++ b/src/ResponseType.php @@ -23,11 +23,11 @@ public function __construct( /** @return ResponseType[] */ public static function getAll(): array { $context = 'Response Types'; - $stringType = new OpenApiType(context: $context, type: "string"); - $binaryType = new OpenApiType(context: $context, type: "string", format: "binary"); + $stringType = new OpenApiType(context: $context, type: 'string'); + $binaryType = new OpenApiType(context: $context, type: 'string', format: 'binary'); return [ new ResponseType( - "DataDisplayResponse", + 'DataDisplayResponse', false, false, null, @@ -35,7 +35,7 @@ public static function getAll(): array { null, ), new ResponseType( - "DataDownloadResponse", + 'DataDownloadResponse', true, false, null, @@ -43,15 +43,15 @@ public static function getAll(): array { null, ), new ResponseType( - "DataResponse", + 'DataResponse', false, true, - "application/json", + 'application/json', $stringType, null, ), new ResponseType( - "DownloadResponse", + 'DownloadResponse', true, false, null, @@ -59,7 +59,7 @@ public static function getAll(): array { null, ), new ResponseType( - "FileDisplayResponse", + 'FileDisplayResponse', false, false, null, @@ -67,39 +67,39 @@ public static function getAll(): array { null, ), new ResponseType( - "JSONResponse", + 'JSONResponse', false, true, - "application/json", + 'application/json', $stringType, null, ), new ResponseType( - "NotFoundResponse", + 'NotFoundResponse', false, false, - "text/html", + 'text/html', $stringType, null, ), new ResponseType( - "RedirectResponse", + 'RedirectResponse', false, false, null, null, - ["Location" => $stringType], + ['Location' => $stringType], ), new ResponseType( - "RedirectToDefaultAppResponse", + 'RedirectToDefaultAppResponse', false, false, null, null, - ["Location" => $stringType], + ['Location' => $stringType], ), new ResponseType( - "Response", + 'Response', false, false, null, @@ -107,15 +107,15 @@ public static function getAll(): array { null, ), new ResponseType( - "StandaloneTemplateResponse", + 'StandaloneTemplateResponse', false, false, - "text/html", + 'text/html', $stringType, null, ), new ResponseType( - "StreamResponse", + 'StreamResponse', false, false, null, @@ -123,31 +123,31 @@ public static function getAll(): array { null, ), new ResponseType( - "TemplateResponse", + 'TemplateResponse', false, false, - "text/html", + 'text/html', $stringType, null, ), new ResponseType( - "TextPlainResponse", + 'TextPlainResponse', false, false, - "text/plain", + 'text/plain', $stringType, null, ), new ResponseType( - "TooManyRequestsResponse", + 'TooManyRequestsResponse', false, false, - "text/html", + 'text/html', $stringType, null, ), new ResponseType( - "ZipResponse", + 'ZipResponse', false, false, null, @@ -182,12 +182,12 @@ public static function resolve(string $context, TypeNode $obj): array { $className = $obj->type->name; $args = $obj->genericTypes; } else { - Logger::panic($context, "Failed to get class name for " . $obj); + Logger::panic($context, 'Failed to get class name for ' . $obj); } - $classNameParts = explode("\\", $className); + $classNameParts = explode('\\', $className); $className = end($classNameParts); - if ($className == "void") { + if ($className == 'void') { $responses[] = null; } else { if (count(array_filter($responseTypes, fn ($responseType) => $responseType->className == $className)) == 0) { @@ -199,7 +199,7 @@ public static function resolve(string $context, TypeNode $obj): array { // +2 for status code and headers which are always present $expectedArgs = count(array_filter([$responseType->hasContentTypeTemplate, $responseType->hasTypeTemplate], fn ($value) => $value)) + 2; if (count($args) != $expectedArgs) { - Logger::error($context, "'" . $className . "' needs " . $expectedArgs . " parameters"); + Logger::error($context, "'" . $className . "' needs " . $expectedArgs . ' parameters'); continue; } @@ -209,12 +209,12 @@ public static function resolve(string $context, TypeNode $obj): array { if ($responseType->hasContentTypeTemplate) { if ($args[$i] instanceof ConstTypeNode) { $contentTypes = [$args[$i]->constExpr->value]; - } elseif ($args[$i] instanceof IdentifierTypeNode && $args[$i]->name == "string") { - $contentTypes = ["*/*"]; + } elseif ($args[$i] instanceof IdentifierTypeNode && $args[$i]->name == 'string') { + $contentTypes = ['*/*']; } elseif ($args[$i] instanceof UnionTypeNode) { $contentTypes = array_map(fn ($arg) => $arg->constExpr->value, $args[$i]->types); } else { - Logger::panic($context, "Unable to parse content type from " . get_class($args[$i])); + Logger::panic($context, 'Unable to parse content type from ' . get_class($args[$i])); } $i++; } else { @@ -230,16 +230,16 @@ public static function resolve(string $context, TypeNode $obj): array { $headersType = OpenApiType::resolve($context, $definitions, $args[$i]); if ($headersType->additionalProperties !== null) { - Logger::error($context, "Use array{} instead of array for empty headers"); + Logger::error($context, 'Use array{} instead of array for empty headers'); } $headers = $headersType->properties ?? []; if ($responseType->defaultHeaders != null) { $headers = array_merge($responseType->defaultHeaders, $headers); } - if (array_key_exists("Content-Type", $headers)) { + if (array_key_exists('Content-Type', $headers)) { /** @var OpenApiType $value */ - $values = $headers["Content-Type"]; + $values = $headers['Content-Type']; if ($values->oneOf != null) { $values = $values->oneOf; } else { @@ -247,16 +247,16 @@ public static function resolve(string $context, TypeNode $obj): array { } foreach ($values as $value) { - if ($value->type == "string" && $value->enum != null) { + if ($value->type == 'string' && $value->enum != null) { $contentTypes = array_merge($contentTypes, $value->enum); } } // Content-Type is an illegal response header - unset($headers["Content-Type"]); + unset($headers['Content-Type']); } - $contentTypes = $contentTypes !== [] ? $contentTypes : [$type != null ? "*/*" : null]; + $contentTypes = $contentTypes !== [] ? $contentTypes : [$type != null ? '*/*' : null]; foreach ($statusCodes as $statusCode) { if ($statusCode === 204 || $statusCode === 304) { diff --git a/src/Route.php b/src/Route.php index ea511ec..e2afb7c 100644 --- a/src/Route.php +++ b/src/Route.php @@ -37,7 +37,7 @@ public static function parseRoutes(string $path): array { } private static function includeRoutes(string $code): array { - $tmpPath = tempnam(sys_get_temp_dir(), "routes-"); + $tmpPath = tempnam(sys_get_temp_dir(), 'routes-'); file_put_contents($tmpPath, $code); $routes = include($tmpPath); unlink($tmpPath); diff --git a/src/StatusCodes.php b/src/StatusCodes.php index 31aea5e..f7710ea 100644 --- a/src/StatusCodes.php +++ b/src/StatusCodes.php @@ -36,78 +36,78 @@ public static function resolveType(string $context, ConstTypeNode|UnionTypeNode| private static function statusEnumToCode(string $context, string $name): int { return match ($name) { - "STATUS_CONTINUE" => 100, - "STATUS_SWITCHING_PROTOCOLS" => 101, - "STATUS_PROCESSING" => 102, - "STATUS_OK" => 200, - "STATUS_CREATED" => 201, - "STATUS_ACCEPTED" => 202, - "STATUS_NON_AUTHORATIVE_INFORMATION" => 203, - "STATUS_NO_CONTENT" => 204, - "STATUS_RESET_CONTENT" => 205, - "STATUS_PARTIAL_CONTENT" => 206, - "STATUS_MULTI_STATUS" => 207, - "STATUS_ALREADY_REPORTED" => 208, - "STATUS_IM_USED" => 226, - "STATUS_MULTIPLE_CHOICES" => 300, - "STATUS_MOVED_PERMANENTLY" => 301, - "STATUS_FOUND" => 302, - "STATUS_SEE_OTHER" => 303, - "STATUS_NOT_MODIFIED" => 304, - "STATUS_USE_PROXY" => 305, - "STATUS_RESERVED" => 306, - "STATUS_TEMPORARY_REDIRECT" => 307, - "STATUS_BAD_REQUEST" => 400, - "STATUS_UNAUTHORIZED" => 401, - "STATUS_PAYMENT_REQUIRED" => 402, - "STATUS_FORBIDDEN" => 403, - "STATUS_NOT_FOUND" => 404, - "STATUS_METHOD_NOT_ALLOWED" => 405, - "STATUS_NOT_ACCEPTABLE" => 406, - "STATUS_PROXY_AUTHENTICATION_REQUIRED" => 407, - "STATUS_REQUEST_TIMEOUT" => 408, - "STATUS_CONFLICT" => 409, - "STATUS_GONE" => 410, - "STATUS_LENGTH_REQUIRED" => 411, - "STATUS_PRECONDITION_FAILED" => 412, - "STATUS_REQUEST_ENTITY_TOO_LARGE" => 413, - "STATUS_REQUEST_URI_TOO_LONG" => 414, - "STATUS_UNSUPPORTED_MEDIA_TYPE" => 415, - "STATUS_REQUEST_RANGE_NOT_SATISFIABLE" => 416, - "STATUS_EXPECTATION_FAILED" => 417, - "STATUS_IM_A_TEAPOT" => 418, - "STATUS_UNPROCESSABLE_ENTITY" => 422, - "STATUS_LOCKED" => 423, - "STATUS_FAILED_DEPENDENCY" => 424, - "STATUS_UPGRADE_REQUIRED" => 426, - "STATUS_PRECONDITION_REQUIRED" => 428, - "STATUS_TOO_MANY_REQUESTS" => 429, - "STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE" => 431, - "STATUS_INTERNAL_SERVER_ERROR" => 500, - "STATUS_NOT_IMPLEMENTED" => 501, - "STATUS_BAD_GATEWAY" => 502, - "STATUS_SERVICE_UNAVAILABLE" => 503, - "STATUS_GATEWAY_TIMEOUT" => 504, - "STATUS_HTTP_VERSION_NOT_SUPPORTED" => 505, - "STATUS_VARIANT_ALSO_NEGOTIATES" => 506, - "STATUS_INSUFFICIENT_STORAGE" => 507, - "STATUS_LOOP_DETECTED" => 508, - "STATUS_BANDWIDTH_LIMIT_EXCEEDED" => 509, - "STATUS_NOT_EXTENDED" => 510, - "STATUS_NETWORK_AUTHENTICATION_REQUIRED" => 511, + 'STATUS_CONTINUE' => 100, + 'STATUS_SWITCHING_PROTOCOLS' => 101, + 'STATUS_PROCESSING' => 102, + 'STATUS_OK' => 200, + 'STATUS_CREATED' => 201, + 'STATUS_ACCEPTED' => 202, + 'STATUS_NON_AUTHORATIVE_INFORMATION' => 203, + 'STATUS_NO_CONTENT' => 204, + 'STATUS_RESET_CONTENT' => 205, + 'STATUS_PARTIAL_CONTENT' => 206, + 'STATUS_MULTI_STATUS' => 207, + 'STATUS_ALREADY_REPORTED' => 208, + 'STATUS_IM_USED' => 226, + 'STATUS_MULTIPLE_CHOICES' => 300, + 'STATUS_MOVED_PERMANENTLY' => 301, + 'STATUS_FOUND' => 302, + 'STATUS_SEE_OTHER' => 303, + 'STATUS_NOT_MODIFIED' => 304, + 'STATUS_USE_PROXY' => 305, + 'STATUS_RESERVED' => 306, + 'STATUS_TEMPORARY_REDIRECT' => 307, + 'STATUS_BAD_REQUEST' => 400, + 'STATUS_UNAUTHORIZED' => 401, + 'STATUS_PAYMENT_REQUIRED' => 402, + 'STATUS_FORBIDDEN' => 403, + 'STATUS_NOT_FOUND' => 404, + 'STATUS_METHOD_NOT_ALLOWED' => 405, + 'STATUS_NOT_ACCEPTABLE' => 406, + 'STATUS_PROXY_AUTHENTICATION_REQUIRED' => 407, + 'STATUS_REQUEST_TIMEOUT' => 408, + 'STATUS_CONFLICT' => 409, + 'STATUS_GONE' => 410, + 'STATUS_LENGTH_REQUIRED' => 411, + 'STATUS_PRECONDITION_FAILED' => 412, + 'STATUS_REQUEST_ENTITY_TOO_LARGE' => 413, + 'STATUS_REQUEST_URI_TOO_LONG' => 414, + 'STATUS_UNSUPPORTED_MEDIA_TYPE' => 415, + 'STATUS_REQUEST_RANGE_NOT_SATISFIABLE' => 416, + 'STATUS_EXPECTATION_FAILED' => 417, + 'STATUS_IM_A_TEAPOT' => 418, + 'STATUS_UNPROCESSABLE_ENTITY' => 422, + 'STATUS_LOCKED' => 423, + 'STATUS_FAILED_DEPENDENCY' => 424, + 'STATUS_UPGRADE_REQUIRED' => 426, + 'STATUS_PRECONDITION_REQUIRED' => 428, + 'STATUS_TOO_MANY_REQUESTS' => 429, + 'STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE' => 431, + 'STATUS_INTERNAL_SERVER_ERROR' => 500, + 'STATUS_NOT_IMPLEMENTED' => 501, + 'STATUS_BAD_GATEWAY' => 502, + 'STATUS_SERVICE_UNAVAILABLE' => 503, + 'STATUS_GATEWAY_TIMEOUT' => 504, + 'STATUS_HTTP_VERSION_NOT_SUPPORTED' => 505, + 'STATUS_VARIANT_ALSO_NEGOTIATES' => 506, + 'STATUS_INSUFFICIENT_STORAGE' => 507, + 'STATUS_LOOP_DETECTED' => 508, + 'STATUS_BANDWIDTH_LIMIT_EXCEEDED' => 509, + 'STATUS_NOT_EXTENDED' => 510, + 'STATUS_NETWORK_AUTHENTICATION_REQUIRED' => 511, default => Logger::panic($context, "Unknown status code '" . $name . "'"), }; } public static function resolveException(string $context, string $name): ?int { - if (!str_starts_with($name, "OCS")) { + if (!str_starts_with($name, 'OCS')) { return 500; } return match ($name) { - "OCSException" => null, - "OCSBadRequestException" => 400, - "OCSForbiddenException" => 403, - "OCSNotFoundException" => 404, + 'OCSException' => null, + 'OCSBadRequestException' => 400, + 'OCSForbiddenException' => 403, + 'OCSNotFoundException' => 404, default => Logger::panic($context, "Unknown exception '" . $name . "'"), }; } diff --git a/tests/lib/Controller/SettingsController.php b/tests/lib/Controller/SettingsController.php index 2d1dcc4..3d5dab7 100644 --- a/tests/lib/Controller/SettingsController.php +++ b/tests/lib/Controller/SettingsController.php @@ -577,9 +577,9 @@ public function objectDefaults(array $empty = [], array $values = ['key' => 'val * whitespace * * @param int $value and this one - * has - * even - * more whitespace + * has + * even + * more whitespace * @return DataResponse}, array{}> * * 200: OK