diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..653a04c7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +; top-most EditorConfig file +root = true + +; Unix-style newlines +[*] +charset = utf-8 +end_of_line = LF +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{php,json,yaml}] +indent_style = space +indent_size = 4 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..de0330e2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +/.* export-ignore +/tools/ export-ignore +/phpstan*.neon export-ignore +/phpunit.xml.dist export-ignore +/psalm*.xml export-ignore +/tests/ export-ignore + +* text=auto eol=lf +*.json text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4 +*.md text whitespace=blank-at-eol,blank-at-eof +*.php text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4 diff=php +*.yml text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4 diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index d4bd85e1..1be9a568 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,17 +1,23 @@ path('src')->name('*.php') ->path('tests')->name('*.php') ->path('Examples')->name('*.php') - //->exclude('tests/Fixtures') + ->path('tools')->name('*.php') ->in(__DIR__) ; return (new PhpCsFixer\Config()) + ->registerCustomFixers([ + new LicenseFixer(), + ]) ->setRules([ '@PSR2' => true, '@DoctrineAnnotation' => true, + 'OpenApi/license' => true, 'array_syntax' => ['syntax' => 'short'], 'no_unused_imports' => true, 'blank_line_before_statement' => ['statements' => ['return']], diff --git a/composer.json b/composer.json index 2fa76fc9..ce82aa05 100644 --- a/composer.json +++ b/composer.json @@ -1,112 +1,113 @@ { - "name": "zircote/swagger-php", - "type": "library", - "license": "Apache-2.0", - "bin": [ - "bin/openapi" - ], - "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations", - "keywords": [ - "json", - "rest", - "api", - "service discovery" - ], - "homepage": "https://github.com/zircote/swagger-php/", - "authors": [ - { - "name": "Robert Allen", - "email": "zircote@gmail.com" + "name": "zircote/swagger-php", + "type": "library", + "license": "Apache-2.0", + "bin": [ + "bin/openapi" + ], + "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations", + "keywords": [ + "json", + "rest", + "api", + "service discovery" + ], + "homepage": "https://github.com/zircote/swagger-php/", + "authors": [ + { + "name": "Robert Allen", + "email": "zircote@gmail.com" + }, + { + "name": "Bob Fanger", + "email": "bfanger@gmail.com", + "homepage": "https://bfanger.nl" + }, + { + "name": "Martin Rademacher", + "email": "mano@radebatz.net", + "homepage": "https://radebatz.net" + } + ], + "config": { + "bin-dir": "bin", + "optimize-autoloader": true, + "sort-packages": true, + "allow-plugins": { + "composer/package-versions-deprecated": true + } }, - { - "name": "Bob Fanger", - "email": "bfanger@gmail.com", - "homepage": "https://bfanger.nl" + "minimum-stability": "stable", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } }, - { - "name": "Martin Rademacher", - "email": "mano@radebatz.net", - "homepage": "https://radebatz.net" + "require": { + "php": ">=7.2", + "ext-json": "*", + "doctrine/annotations": "^1.7", + "psr/log": "^1.1 || ^2.0 || 3.0", + "symfony/finder": ">=2.2", + "symfony/yaml": ">=3.3" + }, + "autoload": { + "psr-4": { + "OpenApi\\": "src" + } + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.11", + "friendsofphp/php-cs-fixer": "^2.17 || ^3.0", + "phpstan/phpstan": "^1.6", + "phpunit/phpunit": ">=8", + "vimeo/psalm": "^4.23" + }, + "autoload-dev": { + "exclude-from-classmap": [ + "/tests/Fixtures" + ], + "psr-4": { + "OpenApi\\Tools\\": "tools/src/", + "OpenApi\\Tests\\": "tests/", + "AnotherNamespace\\": "tests/Fixtures/AnotherNamespace", + "OpenApi\\Tests\\Fixtures\\Annotations\\": "tests/Fixtures/Annotations" + } + }, + "scripts-descriptions": { + "cs": "Fix all codestyle issues", + "lint": "Test codestyle", + "test": "Run all non-legacy and codestyle tests", + "testlegacy": "Run tests using the legacy TokenAnalyser", + "testall": "Run all tests (test + testlegacy)", + "analyse": "Run static analysis (phpstan/psalm)", + "spectral": "Run spectral lint over all .yaml files in the Examples folder", + "docs:refgen": "Rebuild the annotations/attributes reference markup files", + "docs:dev": "Run dev server for local development of gh-pages", + "docs:build": "Re-build static gh-pages" + }, + "scripts": { + "cs": "php-cs-fixer fix --allow-risky=yes", + "lint": "@cs --dry-run", + "test": [ + "phpunit", + "@lint" + ], + "testlegacy": "export PHPUNIT_ANALYSER=legacy && phpunit", + "testall": [ + "@test", + "@testlegacy" + ], + "analyse": [ + "phpstan analyse --memory-limit=2G", + "psalm" + ], + "spectral": "for ff in `find Examples -name '*.yaml'`; do spectral lint $ff; done", + "docs:refgen": "php tools/refgen.php", + "docs:dev": "cd docs && npm run dev", + "docs:build": [ + "@docs:refgen", + "cd docs && npm run build" + ] } - ], - "config": { - "bin-dir": "bin", - "optimize-autoloader": true, - "sort-packages": true, - "allow-plugins": { - "composer/package-versions-deprecated": true - } - }, - "minimum-stability": "stable", - "extra": { - "branch-alias": { - "dev-master": "4.x-dev" - } - }, - "require": { - "php": ">=7.2", - "ext-json": "*", - "doctrine/annotations": "^1.7", - "psr/log": "^1.1 || ^2.0 || 3.0", - "symfony/finder": ">=2.2", - "symfony/yaml": ">=3.3" - }, - "autoload": { - "psr-4": { - "OpenApi\\": "src" - } - }, - "require-dev": { - "composer/package-versions-deprecated": "^1.11", - "friendsofphp/php-cs-fixer": "^2.17 || ^3.0", - "phpstan/phpstan": "^1.6", - "phpunit/phpunit": ">=8", - "vimeo/psalm": "^4.23" - }, - "autoload-dev": { - "exclude-from-classmap": [ - "/tests/Fixtures" - ], - "psr-4": { - "OpenApi\\Tests\\": "tests/", - "AnotherNamespace\\": "tests/Fixtures/AnotherNamespace", - "OpenApi\\Tests\\Fixtures\\Annotations\\": "tests/Fixtures/Annotations" - } - }, - "scripts-descriptions": { - "cs": "Fix all codestyle issues", - "lint": "Test codestyle", - "test": "Run all non-legacy and codestyle tests", - "testlegacy": "Run tests using the legacy TokenAnalyser", - "testall": "Run all tests (test + testlegacy)", - "analyse": "Run static analysis (phpstan/psalm)", - "spectral": "Run spectral lint over all .yaml files in the Examples folder", - "docs:refgen": "Rebuild the annotations/attributes reference markup files", - "docs:dev": "Run dev server for local development of gh-pages", - "docs:build": "Re-build static gh-pages" - }, - "scripts": { - "cs": "php-cs-fixer fix --allow-risky=yes", - "lint": "@cs --dry-run", - "test": [ - "phpunit", - "@lint" - ], - "testlegacy": "export PHPUNIT_ANALYSER=legacy && phpunit", - "testall": [ - "@test", - "@testlegacy" - ], - "analyse": [ - "phpstan analyse --memory-limit=2G", - "psalm" - ], - "spectral": "for ff in `find Examples -name '*.yaml'`; do spectral lint $ff; done", - "docs:refgen": "php docs/refgen.php", - "docs:dev": "cd docs && npm run dev", - "docs:build": [ - "@docs:refgen", - "cd docs && npm run build" - ] - } } diff --git a/src/Processors/CleanUnusedComponents.php b/src/Processors/CleanUnusedComponents.php index bd90ae22..adadf1b5 100644 --- a/src/Processors/CleanUnusedComponents.php +++ b/src/Processors/CleanUnusedComponents.php @@ -1,5 +1,9 @@ types() as $type) { + ob_start(); + + echo $refgen->preamble($type); + foreach ($refgen->classesForType($type) as $name => $details) { + echo $refgen->formatHeader($name, $type); + $method = "format{$type}Details"; + echo $refgen->$method($name, $details['fqdn'], $details['filename']); + } + + file_put_contents($refgen->docPath('reference/' . strtolower($type) . '.md'), ob_get_clean()); +} diff --git a/tools/src/CSFixer/AbstractFixer.php b/tools/src/CSFixer/AbstractFixer.php new file mode 100644 index 00000000..88bae613 --- /dev/null +++ b/tools/src/CSFixer/AbstractFixer.php @@ -0,0 +1,28 @@ +getExtension() == 'php'; + } +} diff --git a/tools/src/CSFixer/LicenseFixer.php b/tools/src/CSFixer/LicenseFixer.php new file mode 100644 index 00000000..a9c83448 --- /dev/null +++ b/tools/src/CSFixer/LicenseFixer.php @@ -0,0 +1,63 @@ + $token) { + if ($token->isComment()) { + if (false !== strpos($token->getContent(), '@license')) { + return; + } + } + } + + $license = <<< EOC +/** + * @license Apache 2.0 + */ +EOC; + + if ($sequence = $tokens->findSequence([[T_NAMESPACE]])) { + $index = array_keys($sequence)[0]; + $tokens->insertAt($index, new Token([ + T_COMMENT, + $license, + ])); + } + } + + public function getDefinition(): FixerDefinitionInterface + { + return new FixerDefinition( + 'All .php files MUST have a @license docblock annotation before namespace / use statement(s)', + [] + ); + } + + public function getName(): string + { + return 'OpenApi/license'; + } + + public function getPriority(): int + { + return 5; + } + + public function supports(\SplFileInfo $file): bool + { + return parent::supports($file) && false !== strpos($file->getPath(), '/src/'); + } +} diff --git a/docs/refgen.php b/tools/src/Docs/RefGenerator.php similarity index 87% rename from docs/refgen.php rename to tools/src/Docs/RefGenerator.php index 5ef6324a..99f62a52 100644 --- a/docs/refgen.php +++ b/tools/src/Docs/RefGenerator.php @@ -1,10 +1,14 @@ scanner = new TokenScanner(); + $this->projectRoot = realpath($projectRoot); + } + + public function docPath(string $relativeName): string + { + return $this->projectRoot . '/docs/' . $relativeName; } - /** - * - */ public function preamble(string $type): string { return <<< EOT @@ -37,13 +45,10 @@ In addition to this page, there are also a number of [examples](https://github.c EOT; } - /** - * - */ public function classesForType(string $type): array { $classes = []; - $dir = new DirectoryIterator(__DIR__ . '/../src/' . $type); + $dir = new \DirectoryIterator($this->projectRoot . '/src/' . $type); foreach ($dir as $entry) { if (!$entry->isFile() || $entry->getExtension() != 'php') { continue; @@ -63,17 +68,11 @@ EOT; return $classes; } - /** - * - */ public function types(): array { return [self::ANNOTATIONS, self::ATTRIBUTES]; } - /** - * - */ public function formatHeader(string $name, string $type): string { return <<< EOT @@ -83,16 +82,13 @@ EOT; EOT; } - /** - * - */ public function formatAttributesDetails(string $name, string $fqdn, string $filename): string { - $rctor = (new ReflectionClass($fqdn))->getMethod('__construct'); + $rctor = (new \ReflectionClass($fqdn))->getMethod('__construct'); ob_start(); - $rc = new ReflectionClass($fqdn); + $rc = new \ReflectionClass($fqdn); $classDocumentation = $this->extractDocumentation($rc->getDocComment()); echo $classDocumentation['content'] . PHP_EOL; @@ -104,7 +100,7 @@ EOT; $parameters = $rctor->getParameters(); if ($parameters) { echo PHP_EOL . '#### Parameters' . PHP_EOL; - echo '---'.PHP_EOL; + echo '---' . PHP_EOL; echo '
' . PHP_EOL; foreach ($parameters as $rp) { @@ -127,7 +123,7 @@ EOT; if ($classDocumentation['see']) { echo PHP_EOL . '#### Reference' . PHP_EOL; - echo '---'.PHP_EOL; + echo '---' . PHP_EOL; foreach ($classDocumentation['see'] as $link) { echo '- ' . $link . PHP_EOL; @@ -148,7 +144,7 @@ EOT; ob_start(); - $rc = new ReflectionClass($fqdn); + $rc = new \ReflectionClass($fqdn); $classDocumentation = $this->extractDocumentation($rc->getDocComment()); echo $classDocumentation['content'] . PHP_EOL; @@ -161,11 +157,11 @@ EOT; if ($properties) { echo PHP_EOL . '#### Properties' . PHP_EOL; - echo '---'.PHP_EOL; + echo '---' . PHP_EOL; echo '
' . PHP_EOL; foreach ($properties as $property) { - $rp = new ReflectionProperty($fqdn, $property); + $rp = new \ReflectionProperty($fqdn, $property); $propertyDocumentation = $this->extractDocumentation($rp->getDocComment()); if ($var = $this->getReflectionType($fqdn, $rp, false, $propertyDocumentation['var'])) { $var = ' : ' . $var . ''; @@ -193,7 +189,7 @@ EOT; if ($classDocumentation['see']) { echo PHP_EOL . '#### Reference' . PHP_EOL; - echo '---'.PHP_EOL; + echo '---' . PHP_EOL; foreach ($classDocumentation['see'] as $link) { echo '- ' . $link . PHP_EOL; @@ -212,7 +208,7 @@ EOT; { $props = []; foreach ($fqdn::$_nested as $details) { - $props[] = ((array)$details)[0]; + $props[] = ((array) $details)[0]; } return $props; @@ -225,10 +221,11 @@ EOT; { if ($fqdn::$_parents) { echo PHP_EOL . '#### Allowed in' . PHP_EOL; - echo '---'.PHP_EOL; + echo '---' . PHP_EOL; $parents = array_map(function (string $parent) { $shortName = $this->shortName($parent); + return '' . $shortName . ''; }, $fqdn::$_parents); echo implode(', ', $parents) . PHP_EOL; @@ -236,10 +233,11 @@ EOT; if ($fqdn::$_nested) { echo PHP_EOL . '#### Nested elements' . PHP_EOL; - echo '---'.PHP_EOL; + echo '---' . PHP_EOL; $nested = array_map(function (string $nested) { $shortName = $this->shortName($nested); + return '' . $shortName . ''; }, array_keys($fqdn::$_nested)); echo implode(', ', $nested) . PHP_EOL; @@ -263,7 +261,7 @@ EOT; $var = []; if ($type = $rp->getType()) { - if ($type instanceof ReflectionUnionType) { + if ($type instanceof \ReflectionUnionType) { foreach ($type->getTypes() as $type) { $var[] = $type->getName(); } @@ -292,7 +290,7 @@ EOT; return ['content' => '', 'see' => [], 'var' => '', 'params' => []]; } - $comment = preg_split('/(\n|\r\n)/', (string)$docblock); + $comment = preg_split('/(\n|\r\n)/', (string) $docblock); $comment[0] = preg_replace('/[ \t]*\\/\*\*/', '', $comment[0]); // strip '/**' $i = count($comment) - 1; @@ -334,20 +332,3 @@ EOT; return ['content' => $content, 'see' => $see, 'var' => $var, 'params' => $params]; } } - - -// ================================================================================ -$refgen = new RefGenerator(); - -foreach ($refgen->types() as $type) { - ob_start(); - - echo $refgen->preamble($type); - foreach ($refgen->classesForType($type) as $name => $details) { - echo $refgen->formatHeader($name, $type); - $method = "format{$type}Details"; - echo $refgen->$method($name, $details['fqdn'], $details['filename']); - } - - file_put_contents(__DIR__ . '/reference/' . strtolower($type) . '.md', ob_get_clean()); -}