* Add .gitattributes and .editorconfig
* Add basic fixer to ensure we have a @license docblock
* Add missing dev autoload config
This commit is contained in:
Martin Rademacher 2022-05-20 16:17:19 +12:00 committed by GitHub
parent 117caa0c0c
commit 46c3e4c493
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 289 additions and 157 deletions

13
.editorconfig Normal file
View File

@ -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

12
.gitattributes vendored Normal file
View File

@ -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

View File

@ -1,17 +1,23 @@
<?php
use OpenApi\Tools\CSFixer\LicenseFixer;
$finder = PhpCsFixer\Finder::create()
->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']],

View File

@ -68,6 +68,7 @@
"/tests/Fixtures"
],
"psr-4": {
"OpenApi\\Tools\\": "tools/src/",
"OpenApi\\Tests\\": "tests/",
"AnotherNamespace\\": "tests/Fixtures/AnotherNamespace",
"OpenApi\\Tests\\Fixtures\\Annotations\\": "tests/Fixtures/Annotations"
@ -102,7 +103,7 @@
"psalm"
],
"spectral": "for ff in `find Examples -name '*.yaml'`; do spectral lint $ff; done",
"docs:refgen": "php docs/refgen.php",
"docs:refgen": "php tools/refgen.php",
"docs:dev": "cd docs && npm run dev",
"docs:build": [
"@docs:refgen",

View File

@ -1,5 +1,9 @@
<?php declare(strict_types=1);
/**
* @license Apache 2.0
*/
namespace OpenApi\Processors;
use OpenApi\Analysis;

View File

@ -1,5 +1,9 @@
<?php
/**
* @license Apache 2.0
*/
namespace OpenApi\Processors;
use OpenApi\Annotations\AbstractAnnotation;

20
tools/refgen.php Normal file
View File

@ -0,0 +1,20 @@
<?php declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use OpenApi\Tools\Docs\RefGenerator;
$refgen = new RefGenerator(__DIR__ . '/../');
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($refgen->docPath('reference/' . strtolower($type) . '.md'), ob_get_clean());
}

View File

@ -0,0 +1,28 @@
<?php declare(strict_types=1);
/**
* @license Apache 2.0
*/
namespace OpenApi\Tools\CSFixer;
use PhpCsFixer\Fixer\FixerInterface;
use PhpCsFixer\Tokenizer\Tokens;
abstract class AbstractFixer implements FixerInterface
{
public function isCandidate(Tokens $tokens): bool
{
return true;
}
public function isRisky(): bool
{
return false;
}
public function supports(\SplFileInfo $file): bool
{
return $file->getExtension() == 'php';
}
}

View File

@ -0,0 +1,63 @@
<?php declare(strict_types=1);
/**
* @license Apache 2.0
*/
namespace OpenApi\Tools\CSFixer;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
class LicenseFixer extends AbstractFixer
{
public function fix(\SplFileInfo $file, Tokens $tokens): void
{
foreach ($tokens as $index => $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/');
}
}

View File

@ -1,10 +1,14 @@
<?php declare(strict_types=1);
/**
* @license Apache 2.0
*/
namespace OpenApi\Tools\Docs;
use OpenApi\Analysers\TokenScanner;
use OpenApi\Annotations\AbstractAnnotation;
require_once __DIR__ . '/../vendor/autoload.php';
class RefGenerator
{
const ATTRIBUTES = 'Attributes';
@ -12,15 +16,19 @@ class RefGenerator
const NO_DETAILS_AVAILABLE = 'No details available.';
protected $scanner;
protected $projectRoot;
public function __construct()
public function __construct($projectRoot)
{
$this->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;
@ -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;
@ -165,7 +161,7 @@ EOT;
echo '<dl>' . 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 = ' : <span style="font-family: monospace;">' . $var . '</span>';
@ -229,6 +225,7 @@ EOT;
$parents = array_map(function (string $parent) {
$shortName = $this->shortName($parent);
return '<a href="#' . strtolower($shortName) . '">' . $shortName . '</a>';
}, $fqdn::$_parents);
echo implode(', ', $parents) . PHP_EOL;
@ -240,6 +237,7 @@ EOT;
$nested = array_map(function (string $nested) {
$shortName = $this->shortName($nested);
return '<a href="#' . strtolower($shortName) . '">' . $shortName . '</a>';
}, 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();
}
@ -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());
}