diff --git a/.github/workflows/lint-php-cs.yml b/.github/workflows/lint-php-cs.yml new file mode 100644 index 0000000..163706e --- /dev/null +++ b/.github/workflows/lint-php-cs.yml @@ -0,0 +1,40 @@ +# This workflow is provided via the organization template repository +# +# https://github.com/nextcloud/.github +# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization + +name: Lint php-cs + +on: pull_request + +permissions: + contents: read + +concurrency: + group: lint-php-cs-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + + name: php-cs + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Set up php8.2 + uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # v2 + with: + php-version: 8.2 + coverage: none + ini-file: development + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Install dependencies + run: composer i + + - name: Lint + run: composer run cs:check || ( echo 'Please run `composer run cs:fix` to format your code' && exit 1 ) diff --git a/.gitignore b/.gitignore index 92b6c18..e6e6083 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ vendor/ -testdata/ \ No newline at end of file +.php-cs-fixer.cache diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..9373311 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,16 @@ +getFinder() + ->ignoreVCSIgnored(true) + ->notPath('vendor') + ->in(__DIR__) + ->append(['generate-spec', 'merge-specs']); +return $config; diff --git a/composer.json b/composer.json index 18d15f1..4a93196 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,9 @@ "adhocore/cli": "^v1.6", "phpstan/phpdoc-parser": "^1.23" }, + "require-dev": { + "nextcloud/coding-standard": "^1.1" + }, "bin": [ "generate-spec", "merge-specs" @@ -15,5 +18,9 @@ "psr-4": { "OpenAPIExtractor\\": "src" } + }, + "scripts": { + "cs:check": "php-cs-fixer fix --dry-run --diff", + "cs:fix": "php-cs-fixer fix" } } diff --git a/composer.lock b/composer.lock index 2283935..c354fba 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "adcec76930b025adc913b413ba46635a", + "content-hash": "d9ac214eb4d330d564d79433a29f90ba", "packages": [ { "name": "adhocore/cli", @@ -180,15 +180,110 @@ "time": "2023-08-03T16:32:59+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "nextcloud/coding-standard", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/nextcloud/coding-standard.git", + "reference": "55def702fb9a37a219511e1d8c6fe8e37164c1fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/55def702fb9a37a219511e1d8c6fe8e37164c1fb", + "reference": "55def702fb9a37a219511e1d8c6fe8e37164c1fb", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0", + "php-cs-fixer/shim": "^3.17" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nextcloud\\CodingStandard\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christoph Wurst", + "email": "christoph@winzerhof-wurst.at" + } + ], + "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.1.1" + }, + "time": "2023-06-01T12:05:01+00:00" + }, + { + "name": "php-cs-fixer/shim", + "version": "v3.41.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/shim.git", + "reference": "01cea2dca727100537bd63e28e06e49a475b54e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/01cea2dca727100537bd63e28e06e49a475b54e9", + "reference": "01cea2dca727100537bd63e28e06e49a475b54e9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "replace": { + "friendsofphp/php-cs-fixer": "self.version" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer", + "php-cs-fixer.phar" + ], + "type": "application", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz RumiƄski", + "email": "dariusz.ruminski@gmail.com" + } + ], + "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" + }, + "time": "2023-12-10T19:59:57+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { + "php": "^8.1", "ext-simplexml": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/generate-spec b/generate-spec index dab7344..c5ff669 100755 --- a/generate-spec +++ b/generate-spec @@ -168,8 +168,8 @@ foreach ($capabilitiesFiles as $path) { * @var Class_ $node */ foreach ($nodeFinder->findInstanceOf(loadAST($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; } @@ -280,9 +280,9 @@ foreach ($parsedRoutes as $key => $value) { continue; } - $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; @@ -373,8 +373,8 @@ foreach ($parsedRoutes as $key => $value) { } } - $docStatusCodes = array_map(fn(ControllerMethodResponse $response) => $response->statusCode, array_filter($classMethodInfo->responses, fn(?ControllerMethodResponse $response) => $response != null)); - $missingDocStatusCodes = array_unique(array_filter(array_diff($codeStatusCodes, $docStatusCodes), fn(int $code) => $code < 500)); + $docStatusCodes = array_map(fn (ControllerMethodResponse $response) => $response->statusCode, array_filter($classMethodInfo->responses, fn (?ControllerMethodResponse $response) => $response != null)); + $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)); @@ -415,7 +415,7 @@ foreach ($routes as $route) { $urlParameters = []; preg_match_all("/{[^}]*}/", $route->url, $urlParameters); - $urlParameters = array_map(fn(string $name) => substr($name, 1, -1), $urlParameters[0]); + $urlParameters = array_map(fn (string $name) => substr($name, 1, -1), $urlParameters[0]); foreach ($urlParameters as $urlParameter) { $matchingParameters = array_filter($route->controllerMethod->parameters, function (ControllerMethodParameter $param) use ($urlParameter) { @@ -462,7 +462,7 @@ foreach ($routes as $route) { } $schema["enum"] = $enum; $schema["default"] = end($enum); - } else if ($requirement != null) { + } elseif ($requirement != null) { $schema["pattern"] = $requirement; } } @@ -499,25 +499,25 @@ foreach ($routes as $route) { } $mergedResponses = []; - foreach (array_unique(array_map(fn(ControllerMethodResponse $response) => $response->statusCode, array_filter($route->controllerMethod->responses, fn(?ControllerMethodResponse $response) => $response != null))) as $statusCode) { + foreach (array_unique(array_map(fn (ControllerMethodResponse $response) => $response->statusCode, array_filter($route->controllerMethod->responses, fn (?ControllerMethodResponse $response) => $response != null))) as $statusCode) { if ($firstStatusCode && count($mergedResponses) > 0) { break; } - $statusCodeResponses = array_filter($route->controllerMethod->responses, fn(?ControllerMethodResponse $response) => $response != null && $response->statusCode == $statusCode); - $headers = array_merge(...array_map(fn(ControllerMethodResponse $response) => $response->headers ?? [], $statusCodeResponses)); + $statusCodeResponses = array_filter($route->controllerMethod->responses, fn (?ControllerMethodResponse $response) => $response != null && $response->statusCode == $statusCode); + $headers = array_merge(...array_map(fn (ControllerMethodResponse $response) => $response->headers ?? [], $statusCodeResponses)); $mergedContentTypeResponses = []; - foreach (array_unique(array_map(fn(ControllerMethodResponse $response) => $response->contentType, array_filter($statusCodeResponses, fn(ControllerMethodResponse $response) => $response->contentType != null))) as $contentType) { + foreach (array_unique(array_map(fn (ControllerMethodResponse $response) => $response->contentType, array_filter($statusCodeResponses, fn (ControllerMethodResponse $response) => $response->contentType != null))) as $contentType) { if ($firstContentType && count($mergedContentTypeResponses) > 0) { break; } /** @var ControllerMethodResponse[] $contentTypeResponses */ - $contentTypeResponses = array_values(array_filter($statusCodeResponses, fn(ControllerMethodResponse $response) => $response->contentType == $contentType)); + $contentTypeResponses = array_values(array_filter($statusCodeResponses, fn (ControllerMethodResponse $response) => $response->contentType == $contentType)); - $hasEmpty = count(array_filter($contentTypeResponses, fn(ControllerMethodResponse $response) => $response->type == null)) > 0; - $uniqueResponses = array_values(array_intersect_key($contentTypeResponses, array_unique(array_map(fn(ControllerMethodResponse $response) => $response->type->toArray($openapiVersion), array_filter($contentTypeResponses, fn(ControllerMethodResponse $response) => $response->type != null)), SORT_REGULAR))); + $hasEmpty = count(array_filter($contentTypeResponses, fn (ControllerMethodResponse $response) => $response->type == null)) > 0; + $uniqueResponses = array_values(array_intersect_key($contentTypeResponses, array_unique(array_map(fn (ControllerMethodResponse $response) => $response->type->toArray($openapiVersion), array_filter($contentTypeResponses, fn (ControllerMethodResponse $response) => $response->type != null)), SORT_REGULAR))); if (count($uniqueResponses) == 1) { if ($hasEmpty) { $mergedContentTypeResponses[$contentType] = []; @@ -545,7 +545,7 @@ foreach ($routes as $route) { "headers" => array_combine( array_keys($headers), array_map( - fn(OpenApiType $type) => [ + fn (OpenApiType $type) => [ "schema" => $type->toArray($openapiVersion), ], array_values($headers), @@ -559,7 +559,7 @@ foreach ($routes as $route) { } $operationId = [$route->tag]; - $operationId = array_merge($operationId, array_map(fn(string $s) => Helpers::mapVerb(strtolower($s)), Helpers::splitOnUppercaseFollowedByNonUppercase($route->methodName))); + $operationId = array_merge($operationId, array_map(fn (string $s) => Helpers::mapVerb(strtolower($s)), Helpers::splitOnUppercaseFollowedByNonUppercase($route->methodName))); if ($route->postfix != null) { $operationId[] = $route->postfix; } @@ -587,7 +587,7 @@ foreach ($routes as $route) { count($security) > 0 ? ["security" => $security] : [], count($queryParameters) > 0 || count($pathParameters) > 0 || $route->isOCS ? [ "parameters" => array_merge( - array_map(fn(ControllerMethodParameter $parameter) => array_merge( + array_map(fn (ControllerMethodParameter $parameter) => array_merge( [ "name" => $parameter->name . ($parameter->type->type == "array" ? "[]" : ""), "in" => "query", diff --git a/merge-specs b/merge-specs index d38fa8d..db676dd 100755 --- a/merge-specs +++ b/merge-specs @@ -89,7 +89,7 @@ $data ["properties"] ["capabilities"] ["anyOf"] - = array_map(fn(string $capability) => ["\$ref" => "#/components/schemas/" . $capability], $capabilities); + = array_map(fn (string $capability) => ["\$ref" => "#/components/schemas/" . $capability], $capabilities); function loadSpec(string $path): array { return rewriteRefs(json_decode(file_get_contents($path), true)); @@ -121,7 +121,7 @@ function rewriteSchemaNames(array $spec): array { $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), ); } @@ -146,7 +146,7 @@ function rewriteOperations(array $spec): array { $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"]); + $operation["tags"] = array_map(fn (string $tag) => $spec["info"]["title"] . "/" . $tag, $operation["tags"]); } else { $operation["tags"] = [$spec["info"]["title"]]; } diff --git a/src/ControllerMethod.php b/src/ControllerMethod.php index 018f46f..7c138fb 100644 --- a/src/ControllerMethod.php +++ b/src/ControllerMethod.php @@ -2,8 +2,6 @@ namespace OpenAPIExtractor; - -use Exception; use PhpParser\Node\Stmt\ClassMethod; use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode; @@ -23,7 +21,7 @@ class ControllerMethod { public function __construct(public array $parameters, public array $responses, public array $returns, public array $responseDescription, public array $description, public ?string $summary, public bool $isDeprecated) { } - static function parse(string $context, array $definitions, ClassMethod $method, bool $isAdmin, bool $isDeprecated): ControllerMethod { + public static function parse(string $context, array $definitions, ClassMethod $method, bool $isAdmin, bool $isDeprecated): ControllerMethod { global $phpDocParser, $lexer, $allowMissingDocs; $parameters = []; @@ -92,7 +90,7 @@ static function parse(string $context, array $definitions, ClassMethod $method, } if (!$allowMissingDocs) { - foreach (array_unique(array_map(fn(ControllerMethodResponse $response) => $response->statusCode, array_filter($responses, fn(?ControllerMethodResponse $response) => $response != null))) as $statusCode) { + 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); } @@ -111,7 +109,7 @@ static function parse(string $context, array $definitions, ClassMethod $method, if ($docParameterName == $methodParameterName) { if ($docParameterType == "@param") { $paramTag = $docParameter; - } else if ($docParameterType == "@psalm-param") { + } elseif ($docParameterType == "@psalm-param") { $psalmParamTag = $docParameter; } else { Logger::panic($context, "Unknown param type " . $docParameterType); @@ -125,7 +123,7 @@ static function parse(string $context, array $definitions, ClassMethod $method, // but pull the description from @param and @psalm-param because usually only one of them has it. if ($psalmParamTag->description !== "") { $description = $psalmParamTag->description; - } else if ($paramTag->description !== "") { + } elseif ($paramTag->description !== "") { $description = $paramTag->description; } else { $description = ""; @@ -160,13 +158,13 @@ static function parse(string $context, array $definitions, ClassMethod $method, } $param = new ControllerMethodParameter($context, $definitions, $methodParameterName, $methodParameter, $type); - } else if ($psalmParamTag !== null) { + } elseif ($psalmParamTag !== null) { $type = OpenApiType::resolve($context, $definitions, $psalmParamTag); $param = new ControllerMethodParameter($context, $definitions, $methodParameterName, $methodParameter, $type); - } else if ($paramTag !== null) { + } elseif ($paramTag !== null) { $type = OpenApiType::resolve($context, $definitions, $paramTag); $param = new ControllerMethodParameter($context, $definitions, $methodParameterName, $methodParameter, $type); - } else if ($allowMissingDocs) { + } elseif ($allowMissingDocs) { $param = new ControllerMethodParameter($context, $definitions, $methodParameterName, $methodParameter, null); } else { Logger::error($context, "Missing doc parameter for '" . $methodParameterName . "'"); @@ -192,7 +190,7 @@ static function parse(string $context, array $definitions, ClassMethod $method, if (count($methodDescription) == 1) { $methodSummary = $methodDescription[0]; $methodDescription = []; - } else if (count($methodDescription) > 1) { + } elseif (count($methodDescription) > 1) { $methodSummary = $methodDescription[0]; $methodDescription = array_slice($methodDescription, 1); } diff --git a/src/ControllerMethodParameter.php b/src/ControllerMethodParameter.php index d2d1f9d..365f0d6 100644 --- a/src/ControllerMethodParameter.php +++ b/src/ControllerMethodParameter.php @@ -2,7 +2,6 @@ namespace OpenAPIExtractor; - use PhpParser\Node\Expr; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\ArrayItem; @@ -11,7 +10,6 @@ use PhpParser\Node\Param; use PhpParser\Node\Scalar\LNumber; use PhpParser\Node\Scalar\String_; -use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode; class ControllerMethodParameter { public OpenApiType $type; @@ -48,8 +46,8 @@ private static function exprToValue(string $context, Expr $expr): mixed { return -self::exprToValue($context, $expr->expr); } if ($expr instanceof Array_) { - $values = array_map(fn(ArrayItem $item) => self::exprToValue($context, $item), $expr->items); - $filteredValues = array_filter($values, fn(mixed $value) => $value !== null); + $values = array_map(fn (ArrayItem $item) => self::exprToValue($context, $item), $expr->items); + $filteredValues = array_filter($values, fn (mixed $value) => $value !== null); if (count($filteredValues) != count($values)) { return null; } diff --git a/src/ControllerMethodResponse.php b/src/ControllerMethodResponse.php index ce30ccd..1e329e3 100644 --- a/src/ControllerMethodResponse.php +++ b/src/ControllerMethodResponse.php @@ -2,7 +2,6 @@ namespace OpenAPIExtractor; - class ControllerMethodResponse { /** * @param array|null $headers diff --git a/src/Helpers.php b/src/Helpers.php index a29d044..15984cc 100644 --- a/src/Helpers.php +++ b/src/Helpers.php @@ -4,16 +4,16 @@ use Exception; use PhpParser\Node; -use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassMethod; use stdClass; class Helpers { - static function generateReadableAppID(string $appID): string { - return implode("", array_map(fn(string $s) => ucfirst($s), explode("_", $appID))); + public static function generateReadableAppID(string $appID): string { + return implode("", array_map(fn (string $s) => ucfirst($s), explode("_", $appID))); } - static function securitySchemes(): array { + public static function securitySchemes(): array { return [ "basic_auth" => [ "type" => "http", @@ -26,7 +26,7 @@ static function securitySchemes(): array { ]; } - static function license(string $openapiVersion, string $license): array { + 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"), @@ -38,27 +38,27 @@ static function license(string $openapiVersion, string $license): array { ); } - static function jsonFlags(): int { + public static function jsonFlags(): int { return JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES; } - static function cleanDocComment(string $comment): string { + public static function cleanDocComment(string $comment): string { return trim(preg_replace("/\s+/", " ", $comment)); } - static function splitOnUppercaseFollowedByNonUppercase(string $str): array { + public static function splitOnUppercaseFollowedByNonUppercase(string $str): array { return preg_split('/(?=[A-Z][^A-Z])/', $str, -1, PREG_SPLIT_NO_EMPTY); } - static function mapVerb(string $verb): string { + public static function mapVerb(string $verb): string { return match ($verb) { "index" => "list", default => $verb, }; } - static function mergeSchemas(array $schemas) { - if (!in_array(true, array_map(fn($schema) => is_array($schema), $schemas))) { + public static function mergeSchemas(array $schemas) { + 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)); @@ -89,13 +89,13 @@ static function mergeSchemas(array $schemas) { return $schema[$key]; } return null; - }, $schemas), fn($schema) => $schema != null)); + }, $schemas), fn ($schema) => $schema != null)); } return $result; } - static function wrapOCSResponse(Route $route, ControllerMethodResponse $response, array|stdClass $schema): array|stdClass { + public static function wrapOCSResponse(Route $route, ControllerMethodResponse $response, array|stdClass $schema): array|stdClass { if ($route->isOCS && $response->className == "DataResponse") { return [ "type" => "object", @@ -123,7 +123,7 @@ static function wrapOCSResponse(Route $route, ControllerMethodResponse $response return $schema; } - static function cleanEmptyResponseArray(array|stdClass $schema): array|stdClass { + public static function cleanEmptyResponseArray(array|stdClass $schema): array|stdClass { if (key_exists("type", $schema) && $schema["type"] == "array" && key_exists("maxLength", $schema) && $schema["maxLength"] === 0) { return new stdClass(); } @@ -131,7 +131,7 @@ static function cleanEmptyResponseArray(array|stdClass $schema): array|stdClass return $schema; } - static function classMethodHasAnnotationOrAttribute(ClassMethod|Class_|Node $node, string $annotation): bool { + public static function classMethodHasAnnotationOrAttribute(ClassMethod|Class_|Node $node, string $annotation): bool { $doc = $node->getDocComment()?->getText(); if ($doc !== null && str_contains($doc, "@" . $annotation)) { return true; diff --git a/src/Logger.php b/src/Logger.php index 0a45ab6..3d3ca86 100644 --- a/src/Logger.php +++ b/src/Logger.php @@ -3,8 +3,8 @@ namespace OpenAPIExtractor; class Logger { - static bool $exitOnError = true; - static bool $verbose = false; + public static bool $exitOnError = true; + public static bool $verbose = false; protected static function log(LoggerLevel $level, string $context, string $text): void { print(self::format($level, $context, $text)); diff --git a/src/OpenApiType.php b/src/OpenApiType.php index 04ee8db..6b8dea8 100644 --- a/src/OpenApiType.php +++ b/src/OpenApiType.php @@ -53,10 +53,10 @@ public function __construct( public function toArray(string $openapiVersion, bool $isParameter = false): array|stdClass { $asContentString = $isParameter && ( - $this->type == "object" || - $this->ref !== null || - $this->anyOf !== null || - $this->allOf !== null); + $this->type == "object" || + $this->ref !== null || + $this->anyOf !== null || + $this->allOf !== null); if ($asContentString) { return array_merge([ "type" => "string", @@ -84,19 +84,19 @@ public function toArray(string $openapiVersion, bool $isParameter = false): arra $this->required != null ? ["required" => $this->required] : [], $this->properties != null ? ["properties" => array_combine(array_keys($this->properties), - array_map(fn(OpenApiType $property) => $property->toArray($openapiVersion), array_values($this->properties)), + array_map(fn (OpenApiType $property) => $property->toArray($openapiVersion), array_values($this->properties)), )] : [], $this->additionalProperties != null ? [ "additionalProperties" => $this->additionalProperties instanceof OpenApiType ? $this->additionalProperties->toArray($openapiVersion) : $this->additionalProperties, ] : [], - $this->oneOf != null ? ["oneOf" => array_map(fn(OpenApiType $type) => $type->toArray($openapiVersion), $this->oneOf)] : [], - $this->anyOf != null ? ["anyOf" => array_map(fn(OpenApiType $type) => $type->toArray($openapiVersion), $this->anyOf)] : [], - $this->allOf != null ? ["allOf" => array_map(fn(OpenApiType $type) => $type->toArray($openapiVersion), $this->allOf)] : [], + $this->oneOf != null ? ["oneOf" => array_map(fn (OpenApiType $type) => $type->toArray($openapiVersion), $this->oneOf)] : [], + $this->anyOf != null ? ["anyOf" => array_map(fn (OpenApiType $type) => $type->toArray($openapiVersion), $this->anyOf)] : [], + $this->allOf != null ? ["allOf" => array_map(fn (OpenApiType $type) => $type->toArray($openapiVersion), $this->allOf)] : [], ); return count($values) > 0 ? $values : new stdClass(); } - static function resolve(string $context, array $definitions, ParamTagValueNode|NodeAbstract|TypeNode $node): OpenApiType { + public static function resolve(string $context, array $definitions, ParamTagValueNode|NodeAbstract|TypeNode $node): OpenApiType { if ($node instanceof ParamTagValueNode) { $type = self::resolve($context, $definitions, $node->type); $type->description = $node->description; @@ -167,28 +167,28 @@ static function resolve(string $context, array $definitions, ParamTagValueNode|N $isUnion = $node instanceof UnionTypeNode || $node instanceof UnionType; $isIntersection = $node instanceof IntersectionTypeNode || $node instanceof IntersectionType; - if ($isUnion && count($node->types) == count(array_filter($node->types, fn($type) => $type instanceof ConstTypeNode && $type->constExpr instanceof ConstExprStringNode))) { + if ($isUnion && count($node->types) == count(array_filter($node->types, fn ($type) => $type instanceof ConstTypeNode && $type->constExpr instanceof ConstExprStringNode))) { $values = []; /** @var ConstTypeNode $type */ foreach ($node->types as $type) { $values[] = $type->constExpr->value; } - if (count(array_filter($values, fn(string $value) => $value == '')) > 0) { + if (count(array_filter($values, fn (string $value) => $value == '')) > 0) { // Not a valid enum return new OpenApiType(type: "string"); } return new OpenApiType(type: "string", enum: $values); } - if ($isUnion && count($node->types) == count(array_filter($node->types, fn($type) => $type instanceof ConstTypeNode && $type->constExpr instanceof ConstExprIntegerNode))) { + if ($isUnion && count($node->types) == count(array_filter($node->types, fn ($type) => $type instanceof ConstTypeNode && $type->constExpr instanceof ConstExprIntegerNode))) { $values = []; /** @var ConstTypeNode $type */ foreach ($node->types as $type) { $values[] = (int) $type->constExpr->value; } - if (count(array_filter($values, fn(string $value) => $value == '')) > 0) { + if (count(array_filter($values, fn (string $value) => $value == '')) > 0) { // Not a valid enum return new OpenApiType( type: "integer", @@ -276,7 +276,7 @@ private static function mergeEnums(array $types) { } } - return array_merge($nonEnums, array_map(fn(string $type) => new OpenApiType(type: $type, enum: $enums[$type]), array_keys($enums))); + return array_merge($nonEnums, array_map(fn (string $type) => new OpenApiType(type: $type, enum: $enums[$type]), array_keys($enums))); } private static function resolveIdentifier(string $context, array $definitions, string $name): OpenApiType { diff --git a/src/ResponseType.php b/src/ResponseType.php index 2215565..3d00064 100644 --- a/src/ResponseType.php +++ b/src/ResponseType.php @@ -21,7 +21,7 @@ public function __construct( } /** @return ResponseType[] */ - static function getAll(): array { + public static function getAll(): array { $stringType = new OpenApiType(type: "string"); $binaryType = new OpenApiType(type: "string", format: "binary"); return [ @@ -162,7 +162,7 @@ static function getAll(): array { * @return ControllerMethodResponse[] * @throws Exception */ - static function resolve(string $context, TypeNode $obj): array { + public static function resolve(string $context, TypeNode $obj): array { global $definitions; $responseTypes = self::getAll(); @@ -177,7 +177,7 @@ static function resolve(string $context, TypeNode $obj): array { if ($obj instanceof IdentifierTypeNode) { $className = $obj->name; $args = []; - } else if ($obj instanceof GenericTypeNode) { + } elseif ($obj instanceof GenericTypeNode) { $className = $obj->type->name; $args = $obj->genericTypes; } else { @@ -189,14 +189,14 @@ static function resolve(string $context, TypeNode $obj): array { if ($className == "void") { $responses[] = null; } else { - if (count(array_filter($responseTypes, fn($responseType) => $responseType->className == $className)) == 0) { + if (count(array_filter($responseTypes, fn ($responseType) => $responseType->className == $className)) == 0) { Logger::error($context, "Invalid return type '" . $obj . "'"); return []; } foreach ($responseTypes as $responseType) { if ($responseType->className == $className) { // +2 for status code and headers which are always present - $expectedArgs = count(array_filter([$responseType->hasContentTypeTemplate, $responseType->hasTypeTemplate], fn($value) => $value)) + 2; + $expectedArgs = count(array_filter([$responseType->hasContentTypeTemplate, $responseType->hasTypeTemplate], fn ($value) => $value)) + 2; if (count($args) != $expectedArgs) { Logger::error($context, "'" . $className . "' needs " . $expectedArgs . " parameters"); continue; @@ -208,10 +208,10 @@ static function resolve(string $context, TypeNode $obj): array { if ($responseType->hasContentTypeTemplate) { if ($args[$i] instanceof ConstTypeNode) { $contentTypes = [$args[$i]->constExpr->value]; - } else if ($args[$i] instanceof IdentifierTypeNode && $args[$i]->name == "string") { + } elseif ($args[$i] instanceof IdentifierTypeNode && $args[$i]->name == "string") { $contentTypes = ["*/*"]; - } else if ($args[$i] instanceof UnionTypeNode) { - $contentTypes = array_map(fn($arg) => $arg->constExpr->value, $args[$i]->types); + } 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])); } diff --git a/src/Route.php b/src/Route.php index 26d865d..a68dcf8 100644 --- a/src/Route.php +++ b/src/Route.php @@ -20,7 +20,7 @@ public function __construct( ) { } - static function parseRoutes(string $path): array { + public static function parseRoutes(string $path): array { $content = file_get_contents($path); if (str_contains($content, "return ")) { if (str_contains($content, "\$this")) { diff --git a/src/StatusCodes.php b/src/StatusCodes.php index 1dc319b..31aea5e 100644 --- a/src/StatusCodes.php +++ b/src/StatusCodes.php @@ -2,7 +2,6 @@ namespace OpenAPIExtractor; - use Exception; use PhpParser\Node\Arg; use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; @@ -16,7 +15,7 @@ class StatusCodes { * @return int[] * @throws Exception */ - static function resolveType(string $context, ConstTypeNode|UnionTypeNode|Arg $type): array { + public static function resolveType(string $context, ConstTypeNode|UnionTypeNode|Arg $type): array { $statusCodes = []; if ($type instanceof TypeNode) { $nodes = []; @@ -100,7 +99,7 @@ private static function statusEnumToCode(string $context, string $name): int { }; } - static function resolveException(string $context, string $name): ?int { + public static function resolveException(string $context, string $name): ?int { if (!str_starts_with($name, "OCS")) { return 500; }