From 97d0467ce71ae7a80a5f94e17528fa55a988c5ee Mon Sep 17 00:00:00 2001 From: Shish Date: Mon, 3 Feb 2025 07:26:08 +0000 Subject: [PATCH] Organise generator into namespaces Trying to make this project as easy to contribute to as possible - smaller modules make it easier to focus on parts relevant to an issue --- CONTRIBUTING.md | 23 +++++------- generator/safe.php | 6 ++-- .../{ => Commands}/FunctionInfoCommand.php | 5 ++- .../src/{ => Commands}/GenerateCommand.php | 19 ++++++---- .../src/{ => Commands}/ScanObjectsCommand.php | 4 ++- .../{ => Generator}/ComposerJsonEditor.php | 2 +- generator/src/{ => Generator}/FileCreator.php | 4 ++- .../src/{ => Generator}/WritePhpFunction.php | 5 ++- .../src/PhpStanFunctions/PhpStanParameter.php | 2 +- .../src/PhpStanFunctions/PhpStanType.php | 4 +-- generator/src/{ => XmlDocParser}/DocPage.php | 4 +-- generator/src/{ => XmlDocParser}/Method.php | 3 +- .../src/{ => XmlDocParser}/Parameter.php | 2 +- generator/src/{ => XmlDocParser}/Scanner.php | 2 +- .../{ => XmlDocParser}/ScannerResponse.php | 2 +- generator/src/{ => XmlDocParser}/Type.php | 2 +- .../ComposerJsonEditorTest.php | 2 +- .../PhpStanFunctions/PhpStanTypeTest.php | 35 +++++++++---------- .../tests/{ => XmlDocParser}/DocPageTest.php | 2 +- .../tests/{ => XmlDocParser}/MethodTest.php | 2 +- .../tests/{ => XmlDocParser}/ScannerTest.php | 4 +-- .../tests/{ => XmlDocParser}/TypeTest.php | 2 +- 22 files changed, 73 insertions(+), 63 deletions(-) rename generator/src/{ => Commands}/FunctionInfoCommand.php (93%) rename generator/src/{ => Commands}/GenerateCommand.php (87%) rename generator/src/{ => Commands}/ScanObjectsCommand.php (91%) rename generator/src/{ => Generator}/ComposerJsonEditor.php (98%) rename generator/src/{ => Generator}/FileCreator.php (98%) rename generator/src/{ => Generator}/WritePhpFunction.php (98%) rename generator/src/{ => XmlDocParser}/DocPage.php (99%) rename generator/src/{ => XmlDocParser}/Method.php (99%) rename generator/src/{ => XmlDocParser}/Parameter.php (99%) rename generator/src/{ => XmlDocParser}/Scanner.php (99%) rename generator/src/{ => XmlDocParser}/ScannerResponse.php (92%) rename generator/src/{ => XmlDocParser}/Type.php (96%) rename generator/tests/{ => Generator}/ComposerJsonEditorTest.php (95%) rename generator/tests/{ => XmlDocParser}/DocPageTest.php (98%) rename generator/tests/{ => XmlDocParser}/MethodTest.php (99%) rename generator/tests/{ => XmlDocParser}/ScannerTest.php (89%) rename generator/tests/{ => XmlDocParser}/TypeTest.php (93%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 45bab206..a181b0a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,20 +17,15 @@ Safe-PHP code is generated automatically from the PHP doc. ### Generator * `safe.php` is the CLI entry point, with a few utility commands, but the - most important one is `generate`, which generates the Safe-PHP code. -* `GenerateCommand` is the class that actually does the generation: - * Call `Scanner` to get a list of all the PHP XML documentation files - (returned in a `ScannerResponse`). - * Use `DocPage` to parse each XML file and extract the relevant - information. - * The "relevant information" is a list of `Method`s, which have - `Parameter`s, which have `Type`s. - * (As well as taking some information from the PHP XML docs, we also - take some type-hint information from PHPStan's type-hint database, - and merge these sources together to get a more complete picture.) - * Given a bunch of `Method` meta-data objects, `FileCreator` will create - files in `generated/` and use `WritePhpFunction` to write safe wrappers - for each function into those files. + most important one is `\Safe\Commands\GenerateCommand`, which does the + generation: + * Use `\Safe\XmlDocParser` to parse the PHP XML documentation + and pull out information about `Method`s, `Parameter`s, and + `Type`s - try to figure out which methods are unsafe. + * Use `\Safe\PhpStanFunctions` to get a bit of extra data from + PHPStan's typehint database, and merge that with the XML info. + * Given this list of unsafe functions, use `\Safe\Generator` to + write a bunch of safe wrappers. ### End-Users diff --git a/generator/safe.php b/generator/safe.php index ff11f4ea..b8601752 100755 --- a/generator/safe.php +++ b/generator/safe.php @@ -4,9 +4,9 @@ require __DIR__.'/vendor/autoload.php'; -use Safe\GenerateCommand; -use Safe\ScanObjectsCommand; -use Safe\FunctionInfoCommand; +use Safe\Commands\FunctionInfoCommand; +use Safe\Commands\GenerateCommand; +use Safe\Commands\ScanObjectsCommand; use Symfony\Component\Console\Application; $application = new Application(); diff --git a/generator/src/FunctionInfoCommand.php b/generator/src/Commands/FunctionInfoCommand.php similarity index 93% rename from generator/src/FunctionInfoCommand.php rename to generator/src/Commands/FunctionInfoCommand.php index 76421d3b..f9e67595 100644 --- a/generator/src/FunctionInfoCommand.php +++ b/generator/src/Commands/FunctionInfoCommand.php @@ -2,8 +2,11 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\Commands; +use Safe\XmlDocParser\Scanner; +use Safe\XmlDocParser\DocPage; +use Safe\Generator\WritePhpFunction; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputArgument; diff --git a/generator/src/GenerateCommand.php b/generator/src/Commands/GenerateCommand.php similarity index 87% rename from generator/src/GenerateCommand.php rename to generator/src/Commands/GenerateCommand.php index 56df43a2..ff6ad7ff 100644 --- a/generator/src/GenerateCommand.php +++ b/generator/src/Commands/GenerateCommand.php @@ -2,7 +2,12 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\Commands; + +use Safe\XmlDocParser\Scanner; +use Safe\XmlDocParser\DocPage; +use Safe\Generator\FileCreator; +use Safe\Generator\ComposerJsonEditor; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -37,9 +42,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('These functions have been ignored and must be dealt with manually: '.\implode(', ', $overloadedFunctions)); $fileCreator = new FileCreator(); - $fileCreator->generatePhpFile($functions, __DIR__ . '/../../generated/'); - $fileCreator->generateFunctionsList($functions, __DIR__ . '/../../generated/functionsList.php'); - $fileCreator->generateRectorFile($functions, __DIR__ . '/../../rector-migrate.php'); + $fileCreator->generatePhpFile($functions, __DIR__ . '/../../../generated/'); + $fileCreator->generateFunctionsList($functions, __DIR__ . '/../../../generated/functionsList.php'); + $fileCreator->generateRectorFile($functions, __DIR__ . '/../../../rector-migrate.php'); $modules = []; @@ -63,7 +68,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function rmGenerated(): void { - $exceptions = \glob(__DIR__.'/../../generated/Exceptions/*.php'); + $exceptions = \glob(__DIR__.'/../../../generated/Exceptions/*.php'); if ($exceptions === false) { throw new \RuntimeException('Failed to require the generated exception files'); } @@ -72,7 +77,7 @@ private function rmGenerated(): void \unlink($exception); } - $files = \glob(__DIR__.'/../../generated/*.php'); + $files = \glob(__DIR__.'/../../../generated/*.php'); if ($files === false) { throw new \RuntimeException('Failed to require the generated files'); } @@ -88,7 +93,7 @@ private function rmGenerated(): void private function runCsFix(OutputInterface $output): void { - $process = new Process(['vendor/bin/phpcbf'], __DIR__.'/../..'); + $process = new Process(['vendor/bin/phpcbf'], __DIR__.'/../../..'); $process->setTimeout(600); $process->run(function ($type, $buffer) use ($output) { if (Process::ERR === $type) { diff --git a/generator/src/ScanObjectsCommand.php b/generator/src/Commands/ScanObjectsCommand.php similarity index 91% rename from generator/src/ScanObjectsCommand.php rename to generator/src/Commands/ScanObjectsCommand.php index 7dd68c8a..74aa2224 100644 --- a/generator/src/ScanObjectsCommand.php +++ b/generator/src/Commands/ScanObjectsCommand.php @@ -2,8 +2,10 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\Commands; +use Safe\XmlDocParser\Scanner; +use Safe\XmlDocParser\DocPage; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/generator/src/ComposerJsonEditor.php b/generator/src/Generator/ComposerJsonEditor.php similarity index 98% rename from generator/src/ComposerJsonEditor.php rename to generator/src/Generator/ComposerJsonEditor.php index a4ad086f..e89321f6 100644 --- a/generator/src/ComposerJsonEditor.php +++ b/generator/src/Generator/ComposerJsonEditor.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\Generator; /** * This class will edit the main composer.json file to add the list of files generated from modules. diff --git a/generator/src/FileCreator.php b/generator/src/Generator/FileCreator.php similarity index 98% rename from generator/src/FileCreator.php rename to generator/src/Generator/FileCreator.php index 5f38af47..30fd6fac 100644 --- a/generator/src/FileCreator.php +++ b/generator/src/Generator/FileCreator.php @@ -2,7 +2,9 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\Generator; + +use Safe\XmlDocParser\Method; use Rector\Config\RectorConfig; use Rector\Renaming\Rector\FuncCall\RenameFunctionRector; diff --git a/generator/src/WritePhpFunction.php b/generator/src/Generator/WritePhpFunction.php similarity index 98% rename from generator/src/WritePhpFunction.php rename to generator/src/Generator/WritePhpFunction.php index b8c59009..19c7fbdb 100644 --- a/generator/src/WritePhpFunction.php +++ b/generator/src/Generator/WritePhpFunction.php @@ -2,7 +2,10 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\Generator; + +use Safe\XmlDocParser\Method; +use Safe\XmlDocParser\Parameter; class WritePhpFunction { diff --git a/generator/src/PhpStanFunctions/PhpStanParameter.php b/generator/src/PhpStanFunctions/PhpStanParameter.php index a10c0c2c..f1c01345 100644 --- a/generator/src/PhpStanFunctions/PhpStanParameter.php +++ b/generator/src/PhpStanFunctions/PhpStanParameter.php @@ -4,7 +4,7 @@ namespace Safe\PhpStanFunctions; -use Safe\Type; +use Safe\XmlDocParser\Type; class PhpStanParameter { diff --git a/generator/src/PhpStanFunctions/PhpStanType.php b/generator/src/PhpStanFunctions/PhpStanType.php index 33ec387c..fdf12ca9 100644 --- a/generator/src/PhpStanFunctions/PhpStanType.php +++ b/generator/src/PhpStanFunctions/PhpStanType.php @@ -4,8 +4,8 @@ namespace Safe\PhpStanFunctions; -use Safe\Method; -use Safe\Type; +use Safe\XmlDocParser\Method; +use Safe\XmlDocParser\Type; /** * This class will parse the type from either parameters or return as given by phpstan and generate appropriate doc-block comments or typehints diff --git a/generator/src/DocPage.php b/generator/src/XmlDocParser/DocPage.php similarity index 99% rename from generator/src/DocPage.php rename to generator/src/XmlDocParser/DocPage.php index 113e4abc..3b6c389b 100644 --- a/generator/src/DocPage.php +++ b/generator/src/XmlDocParser/DocPage.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; use function explode; use function strpos; @@ -15,7 +15,7 @@ public function __construct(private readonly string $path) public static function findDocDir(): string { - return __DIR__ . '/../doc'; + return __DIR__ . '/../../doc'; } public static function findReferenceDir(): string diff --git a/generator/src/Method.php b/generator/src/XmlDocParser/Method.php similarity index 99% rename from generator/src/Method.php rename to generator/src/XmlDocParser/Method.php index 3291dd41..a8381890 100644 --- a/generator/src/Method.php +++ b/generator/src/XmlDocParser/Method.php @@ -2,11 +2,12 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; use Safe\PhpStanFunctions\PhpStanFunction; use Safe\PhpStanFunctions\PhpStanFunctionMapReader; use Safe\PhpStanFunctions\PhpStanType; +use Safe\Generator\FileCreator; class Method { diff --git a/generator/src/Parameter.php b/generator/src/XmlDocParser/Parameter.php similarity index 99% rename from generator/src/Parameter.php rename to generator/src/XmlDocParser/Parameter.php index cefb4e25..23b2e1e4 100644 --- a/generator/src/Parameter.php +++ b/generator/src/XmlDocParser/Parameter.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; use Safe\PhpStanFunctions\PhpStanFunction; use Safe\PhpStanFunctions\PhpStanParameter; diff --git a/generator/src/Scanner.php b/generator/src/XmlDocParser/Scanner.php similarity index 99% rename from generator/src/Scanner.php rename to generator/src/XmlDocParser/Scanner.php index 7acf4e61..09672158 100644 --- a/generator/src/Scanner.php +++ b/generator/src/XmlDocParser/Scanner.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; use function array_merge; use function iterator_to_array; diff --git a/generator/src/ScannerResponse.php b/generator/src/XmlDocParser/ScannerResponse.php similarity index 92% rename from generator/src/ScannerResponse.php rename to generator/src/XmlDocParser/ScannerResponse.php index 8c2e2505..9e3d8f89 100644 --- a/generator/src/ScannerResponse.php +++ b/generator/src/XmlDocParser/ScannerResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; class ScannerResponse { diff --git a/generator/src/Type.php b/generator/src/XmlDocParser/Type.php similarity index 96% rename from generator/src/Type.php rename to generator/src/XmlDocParser/Type.php index 0751dc35..cbc50258 100644 --- a/generator/src/Type.php +++ b/generator/src/XmlDocParser/Type.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; class Type { diff --git a/generator/tests/ComposerJsonEditorTest.php b/generator/tests/Generator/ComposerJsonEditorTest.php similarity index 95% rename from generator/tests/ComposerJsonEditorTest.php rename to generator/tests/Generator/ComposerJsonEditorTest.php index 15cdd33d..b2812293 100644 --- a/generator/tests/ComposerJsonEditorTest.php +++ b/generator/tests/Generator/ComposerJsonEditorTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\Generator; use PHPUnit\Framework\TestCase; diff --git a/generator/tests/PhpStanFunctions/PhpStanTypeTest.php b/generator/tests/PhpStanFunctions/PhpStanTypeTest.php index 79fac21e..92ac521b 100644 --- a/generator/tests/PhpStanFunctions/PhpStanTypeTest.php +++ b/generator/tests/PhpStanFunctions/PhpStanTypeTest.php @@ -4,13 +4,12 @@ namespace Safe\PhpStanFunctions; - use PHPUnit\Framework\TestCase; -use Safe\Method; +use Safe\XmlDocParser\Method; class PhpStanTypeTest extends TestCase { - public function testMixedTypes(): void + public function testMixedTypes(): void { $param = new PhpStanType('array|string|int'); $this->assertEquals('array|string|int', $param->getDocBlockType()); @@ -54,8 +53,8 @@ public function testGenerics(): void $this->assertEquals('array{0:float,1:float,2:float,3:float,4:float,5:float}', $param->getDocBlockType()); $this->assertEquals('array', $param->getSignatureType()); } - - public function testNullable(): void + + public function testNullable(): void { $param = new PhpStanType('array|null'); $this->assertEquals(true, $param->isNullable()); @@ -77,8 +76,8 @@ public function testNullable(): void $this->assertEquals('\HashContext|null', $param->getDocBlockType()); $this->assertEquals('?\HashContext', $param->getSignatureType()); } - - public function testParenthesisOutsideOfCallable(): void + + public function testParenthesisOutsideOfCallable(): void { $param = new PhpStanType('(?int)|(?string)'); $this->assertEquals(true, $param->isNullable()); @@ -93,8 +92,8 @@ public function testFalsable(): void $this->assertEquals('string|false', $param->getDocBlockType()); $this->assertEquals('string', $param->getSignatureType()); } - - public function testResource(): void + + public function testResource(): void { $param = new PhpStanType('resource'); $this->assertEquals('resource', $param->getDocBlockType()); @@ -107,8 +106,8 @@ public function testNamespace(): void $this->assertEquals('\GMP', $param->getDocBlockType()); $this->assertEquals('\GMP', $param->getSignatureType()); } - - public function testVoid(): void + + public function testVoid(): void { $param = new PhpStanType(''); $this->assertEquals('', $param->getDocBlockType()); @@ -122,8 +121,8 @@ public function testVoid(): void $this->assertEquals('void', $param->getDocBlockType()); $this->assertEquals('void', $param->getSignatureType()); } - - public function testOciSpecialCases(): void + + public function testOciSpecialCases(): void { $param = new PhpStanType('OCI-Collection'); $this->assertEquals('\OCI-Collection', $param->getDocBlockType()); @@ -133,14 +132,14 @@ public function testOciSpecialCases(): void $this->assertEquals('\OCI-Lob', $param->getDocBlockType()); $this->assertEquals('', $param->getSignatureType()); } - - public function testErrorTypeInteraction(): void + + public function testErrorTypeInteraction(): void { //bool => void if the method is falsy $param = new PhpStanType('bool'); $this->assertEquals('void', $param->getDocBlockType(Method::FALSY_TYPE)); $this->assertEquals('void', $param->getSignatureType(Method::FALSY_TYPE)); - + //int|false => int if the method is falsy $param = new PhpStanType('int|false'); $this->assertEquals('int', $param->getDocBlockType(Method::FALSY_TYPE)); @@ -155,8 +154,8 @@ public function testErrorTypeInteraction(): void $this->assertEquals('array|null', $param->getDocBlockType(Method::FALSY_TYPE)); $this->assertEquals('?array', $param->getSignatureType(Method::FALSY_TYPE)); } - - public function testDuplicateType(): void + + public function testDuplicateType(): void { $param = new PhpStanType('array|array|array>'); $this->assertEquals('array|array|array>', $param->getDocBlockType()); diff --git a/generator/tests/DocPageTest.php b/generator/tests/XmlDocParser/DocPageTest.php similarity index 98% rename from generator/tests/DocPageTest.php rename to generator/tests/XmlDocParser/DocPageTest.php index 5464591d..744aa467 100644 --- a/generator/tests/DocPageTest.php +++ b/generator/tests/XmlDocParser/DocPageTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; use PHPUnit\Framework\TestCase; diff --git a/generator/tests/MethodTest.php b/generator/tests/XmlDocParser/MethodTest.php similarity index 99% rename from generator/tests/MethodTest.php rename to generator/tests/XmlDocParser/MethodTest.php index 1a63d0ec..44fcdcee 100644 --- a/generator/tests/MethodTest.php +++ b/generator/tests/XmlDocParser/MethodTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; use PHPUnit\Framework\TestCase; use Safe\PhpStanFunctions\PhpStanFunctionMapReader; diff --git a/generator/tests/ScannerTest.php b/generator/tests/XmlDocParser/ScannerTest.php similarity index 89% rename from generator/tests/ScannerTest.php rename to generator/tests/XmlDocParser/ScannerTest.php index f8b08107..f9083758 100644 --- a/generator/tests/ScannerTest.php +++ b/generator/tests/XmlDocParser/ScannerTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; use PHPUnit\Framework\TestCase; @@ -20,7 +20,7 @@ public function testGetMethodsPaths(): void public function testGetFunctionsPaths(): void { - $scanner = new Scanner(DocPage::findReferenceDir()); + $scanner = new Scanner(DocPage::findReferenceDir() . '/'); $paths = $scanner->getMethodsPaths(); $this->assertArrayNotHasKey(DocPage::findReferenceDir() . '/filesystem/functions/chmod.xml', $paths); diff --git a/generator/tests/TypeTest.php b/generator/tests/XmlDocParser/TypeTest.php similarity index 93% rename from generator/tests/TypeTest.php rename to generator/tests/XmlDocParser/TypeTest.php index aecfaa6e..3039af2f 100644 --- a/generator/tests/TypeTest.php +++ b/generator/tests/XmlDocParser/TypeTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Safe; +namespace Safe\XmlDocParser; use PHPUnit\Framework\TestCase;