diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php index 3a934275..ff154fba 100644 --- a/packages/documentator/src/Commands/Preprocess.php +++ b/packages/documentator/src/Commands/Preprocess.php @@ -3,19 +3,29 @@ namespace LastDragon_ru\LaraASP\Documentator\Commands; use Illuminate\Console\Command; +use LastDragon_ru\LaraASP\Core\Application\ContainerResolver; use LastDragon_ru\LaraASP\Core\Path\DirectoryPath; use LastDragon_ru\LaraASP\Core\Path\FilePath; use LastDragon_ru\LaraASP\Core\Utils\Cast; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\Move; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Heading\Renumber; use LastDragon_ru\LaraASP\Documentator\Package; -use LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Factory; use LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Task; +use LastDragon_ru\LaraASP\Documentator\Processor\InstanceFactory; use LastDragon_ru\LaraASP\Documentator\Processor\Processor; use LastDragon_ru\LaraASP\Documentator\Processor\Result; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\CodeLinks\Task as CodeLinksTask; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Contracts\Instruction; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Contracts\Parameters; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeArtisan\Instruction as PreprocessIncludeArtisan; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeDocBlock\Instruction as PreprocessIncludeDocBlock; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeDocumentList\Instruction as PreprocessIncludeDocumentList; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeExample\Instruction as PreprocessIncludeExample; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeExec\Instruction as PreprocessIncludeExec; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeFile\Instruction as PreprocessIncludeFile; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeGraphqlDirective\Instruction as PreprocessIncludeGraphqlDirective; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludePackageList\Instruction as PreprocessIncludePackageList; +use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeTemplate\Instruction as PreprocessIncludeTemplate; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Task as PreprocessTask; use LastDragon_ru\LaraASP\Documentator\Utils\PhpDoc; use LastDragon_ru\LaraASP\Documentator\Utils\PhpDocumentFactory; @@ -80,7 +90,7 @@ class Preprocess extends Command { private ?PhpDocumentFactory $phpDocumentFactory = null; public function __construct( - protected readonly Factory $factory, + protected readonly ContainerResolver $container, ) { parent::__construct(); } @@ -108,12 +118,42 @@ public function __invoke(Formatter $formatter): void { $this->output->writeln($line, OutputInterface::OUTPUT_NORMAL | $resultVerbosity); }; - $duration = ($this->factory)()->run($path, $exclude, $listener); + $duration = $this->processor()->exclude($exclude)->run($path, $listener); $this->output->newLine(); $this->output->writeln("DONE ({$formatter->duration($duration)})"); } + private function processor(): Processor { + $processor = new Processor($this->container); + + foreach ($this->tasks() as $task) { + $processor->task($task); + } + + return $processor; + } + + /** + * @return list|Task|class-string> + */ + protected function tasks(): array { + return [ + new InstanceFactory(PreprocessTask::class, static function (PreprocessTask $task): void { + $task->addInstruction(PreprocessIncludeFile::class); + $task->addInstruction(PreprocessIncludeExec::class); + $task->addInstruction(PreprocessIncludeExample::class); + $task->addInstruction(PreprocessIncludeArtisan::class); + $task->addInstruction(PreprocessIncludeTemplate::class); + $task->addInstruction(PreprocessIncludeDocBlock::class); + $task->addInstruction(PreprocessIncludePackageList::class); + $task->addInstruction(PreprocessIncludeDocumentList::class); + $task->addInstruction(PreprocessIncludeGraphqlDirective::class); + }), + CodeLinksTask::class, + ]; + } + #[Override] public function getProcessedHelp(): string { try { @@ -129,7 +169,7 @@ protected function getProcessedHelpTasks(int $level): string { $help = ''; $heading = str_repeat('#', $level); $default = '_No description provided_.'; - $processor = ($this->factory)(); + $processor = $this->processor(); foreach ($processor->tasks() as $index => $task) { $description = trim($this->getProcessedHelpTaskDescription($task, $level + 1)); diff --git a/packages/documentator/src/Commands/PreprocessTest.php b/packages/documentator/src/Commands/PreprocessTest.php index a583b795..2e447e46 100644 --- a/packages/documentator/src/Commands/PreprocessTest.php +++ b/packages/documentator/src/Commands/PreprocessTest.php @@ -2,7 +2,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Commands; -use LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Factory; +use LastDragon_ru\LaraASP\Core\Application\ContainerResolver; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Context; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Contracts\Instruction; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Contracts\Parameters; @@ -19,8 +19,7 @@ #[CoversClass(Preprocess::class)] final class PreprocessTest extends TestCase { public function testGetProcessedHelpTaskPreprocessInstructions(): void { - $factory = Mockery::mock(Factory::class); - $task = Mockery::mock(PreprocessTask::class); + $task = Mockery::mock(PreprocessTask::class); $task->shouldAllowMockingProtectedMethods(); $task ->shouldReceive('getInstructions') @@ -31,7 +30,8 @@ public function testGetProcessedHelpTaskPreprocessInstructions(): void { PreprocessTest__InstructionNotSerializable::class, ]); - $command = new class($factory) extends Preprocess { + $container = $this->app()->make(ContainerResolver::class); + $command = new class($container) extends Preprocess { #[Override] public function getProcessedHelpTaskPreprocessInstructions(PreprocessTask $task, int $level): string { return parent::getProcessedHelpTaskPreprocessInstructions($task, $level); @@ -84,8 +84,8 @@ public function getProcessedHelpTaskPreprocessInstructions(PreprocessTask $task, } public function testGetProcessedHelpTaskPreprocessInstructionTarget(): void { - $factory = Mockery::mock(Factory::class); - $command = new class($factory) extends Preprocess { + $container = $this->app()->make(ContainerResolver::class); + $command = new class($container) extends Preprocess { #[Override] public function getProcessedHelpTaskPreprocessInstructionTarget( string $instruction, @@ -114,8 +114,8 @@ public function getProcessedHelpTaskPreprocessInstructionTarget( } public function testGetProcessedHelpTaskPreprocessParameters(): void { - $factory = Mockery::mock(Factory::class); - $command = new class($factory) extends Preprocess { + $container = $this->app()->make(ContainerResolver::class); + $command = new class($container) extends Preprocess { #[Override] public function getProcessedHelpTaskPreprocessParameters( string $instruction, @@ -148,8 +148,8 @@ public function getProcessedHelpTaskPreprocessParameters( } public function testGetProcessedHelpTaskPreprocessParametersNoParameters(): void { - $factory = Mockery::mock(Factory::class); - $command = new class($factory) extends Preprocess { + $container = $this->app()->make(ContainerResolver::class); + $command = new class($container) extends Preprocess { #[Override] public function getProcessedHelpTaskPreprocessParameters( string $instruction, @@ -170,8 +170,8 @@ public function getProcessedHelpTaskPreprocessParameters( } public function testGetProcessedHelpTaskPreprocessParametersNotSerializable(): void { - $factory = Mockery::mock(Factory::class); - $command = new class($factory) extends Preprocess { + $container = $this->app()->make(ContainerResolver::class); + $command = new class($container) extends Preprocess { #[Override] public function getProcessedHelpTaskPreprocessParameters( string $instruction, diff --git a/packages/documentator/src/PackageProvider.php b/packages/documentator/src/PackageProvider.php index a92789eb..21424a84 100644 --- a/packages/documentator/src/PackageProvider.php +++ b/packages/documentator/src/PackageProvider.php @@ -9,8 +9,6 @@ use LastDragon_ru\LaraASP\Documentator\Commands\Requirements; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Markdown as MarkdownContract; use LastDragon_ru\LaraASP\Documentator\Markdown\Markdown; -use LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Factory as ProcessorFactoryContract; -use LastDragon_ru\LaraASP\Documentator\Processor\Factory as ProcessorFactory; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\CodeLinks\Contracts\LinkFactory as LinkFactoryContract; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\CodeLinks\Links\Factory as LinkFactory; use Override; @@ -22,7 +20,6 @@ class PackageProvider extends ServiceProvider { public function register(): void { parent::register(); - $this->app->scopedIf(ProcessorFactoryContract::class, ProcessorFactory::class); $this->app->scopedIf(LinkFactoryContract::class, LinkFactory::class); $this->app->scopedIf(MarkdownContract::class, Markdown::class); } diff --git a/packages/documentator/src/Processor/Contracts/Factory.php b/packages/documentator/src/Processor/Contracts/Factory.php deleted file mode 100644 index 9431fd99..00000000 --- a/packages/documentator/src/Processor/Contracts/Factory.php +++ /dev/null @@ -1,9 +0,0 @@ -, mixed, bool>|bool|null - * fixme(documentator): The correct type is `Generator, V, bool>|bool|null` + * @return Generator, mixed, bool>|bool + * fixme(documentator): The correct type is `Generator, V, bool>|bool` * but it is not yet supported by phpstan (see https://github.com/phpstan/phpstan/issues/4245) */ - public function __invoke(Directory $root, File $file): Generator|bool|null; + public function __invoke(Directory $root, File $file): Generator|bool; } diff --git a/packages/documentator/src/Processor/Dependencies/DirectoryIteratorTest.php b/packages/documentator/src/Processor/Dependencies/DirectoryIteratorTest.php index 8ad7992e..767b6644 100644 --- a/packages/documentator/src/Processor/Dependencies/DirectoryIteratorTest.php +++ b/packages/documentator/src/Processor/Dependencies/DirectoryIteratorTest.php @@ -23,7 +23,7 @@ final class DirectoryIteratorTest extends TestCase { public function testToString(): void { $path = (new DirectoryPath(__DIR__))->getNormalizedPath(); - $directory = new Directory($path, false); + $directory = new Directory($path); self::assertEquals('path/to/directory', (string) (new DirectoryIterator('path/to/directory'))); self::assertEquals((string) $directory, (string) (new DirectoryIterator($directory))); @@ -33,11 +33,11 @@ public function testToString(): void { public function testInvoke(): void { $fs = new FileSystem(); $path = (new DirectoryPath(self::getTestData()->path('')))->getNormalizedPath(); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $absolute = new DirectoryIterator($path); $relative = new DirectoryIterator(basename((string) $path)); - $directory = new DirectoryIterator(new Directory($path, false)); + $directory = new DirectoryIterator(new Directory($path)); $formatter = static function (Directory $directory) use ($path): string { return (string) $path->getRelativePath($directory->getPath()); }; @@ -57,8 +57,8 @@ public function testInvoke(): void { public function testInvokeNotFound(): void { $fs = new FileSystem(); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $path = 'path/to/directory'; self::expectException(DependencyNotFound::class); diff --git a/packages/documentator/src/Processor/Dependencies/DirectoryReferenceTest.php b/packages/documentator/src/Processor/Dependencies/DirectoryReferenceTest.php index 15d42e0b..28bca035 100644 --- a/packages/documentator/src/Processor/Dependencies/DirectoryReferenceTest.php +++ b/packages/documentator/src/Processor/Dependencies/DirectoryReferenceTest.php @@ -20,7 +20,7 @@ final class DirectoryReferenceTest extends TestCase { public function testToString(): void { $path = (new DirectoryPath(__DIR__))->getNormalizedPath(); - $directory = new Directory($path, false); + $directory = new Directory($path); self::assertEquals('path/to/directory', (string) (new DirectoryReference('path/to/directory'))); self::assertEquals((string) $directory, (string) (new DirectoryReference($directory))); @@ -30,9 +30,9 @@ public function testToString(): void { public function testInvoke(): void { $fs = new FileSystem(); $dir = (new DirectoryPath(__DIR__))->getNormalizedPath(); - $root = new Directory($dir, false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); - $another = new Directory($dir, false); + $root = new Directory($dir); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); + $another = new Directory($dir); $dirpath = new DirectoryReference($dir); $absolute = new DirectoryReference(__DIR__); $relative = new DirectoryReference('.'); @@ -46,8 +46,8 @@ public function testInvoke(): void { public function testInvokeNotFound(): void { $fs = new FileSystem(); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $path = 'path/to/directory'; self::expectException(DependencyNotFound::class); diff --git a/packages/documentator/src/Processor/Dependencies/FileIteratorTest.php b/packages/documentator/src/Processor/Dependencies/FileIteratorTest.php index ef4c2028..855dfe36 100644 --- a/packages/documentator/src/Processor/Dependencies/FileIteratorTest.php +++ b/packages/documentator/src/Processor/Dependencies/FileIteratorTest.php @@ -23,7 +23,7 @@ final class FileIteratorTest extends TestCase { public function testToString(): void { $path = (new DirectoryPath(__DIR__))->getNormalizedPath(); - $directory = new Directory($path, false); + $directory = new Directory($path); self::assertEquals('path/to/directory', (string) (new FileIterator('path/to/directory'))); self::assertEquals((string) $directory, (string) (new FileIterator($directory))); @@ -33,12 +33,12 @@ public function testToString(): void { public function testInvoke(): void { $fs = new FileSystem(); $path = (new DirectoryPath(self::getTestData()->path('')))->getNormalizedPath(); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $pattern = '*.txt'; $absolute = new FileIterator($path, $pattern); $relative = new FileIterator(basename((string) $path), $pattern); - $directory = new FileIterator(new Directory($path, false), $pattern); + $directory = new FileIterator(new Directory($path), $pattern); $formatter = static function (File $file) use ($path): string { return (string) $path->getRelativePath($file->getPath()); }; @@ -59,8 +59,8 @@ public function testInvoke(): void { public function testInvokeNotFound(): void { $fs = new FileSystem(); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $path = 'path/to/directory'; self::expectException(DependencyNotFound::class); diff --git a/packages/documentator/src/Processor/Dependencies/FileReferenceTest.php b/packages/documentator/src/Processor/Dependencies/FileReferenceTest.php index 23885615..cae6d855 100644 --- a/packages/documentator/src/Processor/Dependencies/FileReferenceTest.php +++ b/packages/documentator/src/Processor/Dependencies/FileReferenceTest.php @@ -21,7 +21,7 @@ final class FileReferenceTest extends TestCase { public function testToString(): void { $path = (new FilePath(__FILE__))->getNormalizedPath(); - $file = new File($path, false); + $file = new File($path); self::assertEquals('path/to/file', (string) (new FileReference('path/to/file'))); self::assertEquals((string) $file, (string) (new FileReference($file))); @@ -30,10 +30,10 @@ public function testToString(): void { public function testInvoke(): void { $fs = new FileSystem(); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); $path = (new FilePath(__FILE__))->getNormalizedPath(); - $file = new File($path, false); - $another = new File($path, false); + $file = new File($path); + $another = new File($path); $absolute = new FileReference(__FILE__); $relative = new FileReference(basename(__FILE__)); $filepath = new FileReference($path); @@ -47,8 +47,8 @@ public function testInvoke(): void { public function testInvokeNotFound(): void { $fs = new FileSystem(); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $path = 'path/to/file'; self::expectException(DependencyNotFound::class); diff --git a/packages/documentator/src/Processor/Dependencies/OptionalTest.php b/packages/documentator/src/Processor/Dependencies/OptionalTest.php index c6f31221..93d2f155 100644 --- a/packages/documentator/src/Processor/Dependencies/OptionalTest.php +++ b/packages/documentator/src/Processor/Dependencies/OptionalTest.php @@ -25,8 +25,8 @@ public function testToString(): void { public function testInvoke(): void { $dependency = new FileReference(__FILE__); $optional = new Optional($dependency); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); $fs = new FileSystem(); self::assertEquals($file, $dependency($fs, $root, $file)); @@ -36,8 +36,8 @@ public function testInvoke(): void { public function testInvokeNotFound(): void { $dependency = new FileReference('path/to/file'); $optional = new Optional($dependency); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); $fs = new FileSystem(); self::assertNull($optional($fs, $root, $file)); diff --git a/packages/documentator/src/Processor/Executor.php b/packages/documentator/src/Processor/Executor.php index 175ab6f0..adf3020a 100644 --- a/packages/documentator/src/Processor/Executor.php +++ b/packages/documentator/src/Processor/Executor.php @@ -107,17 +107,10 @@ private function runFile(File $file): float { foreach ($tasks as $task) { try { // Run + $result = false; $generator = $task($this->root, $file); - // Postponed? - if ($generator === null) { - $paused += $this->runIterator(); - $generator = $task($this->root, $file) ?? false; - } - // Dependencies? - $result = false; - if ($generator instanceof Generator) { while ($generator->valid()) { $dependency = $generator->current(); diff --git a/packages/documentator/src/Processor/Factory.php b/packages/documentator/src/Processor/Factory.php deleted file mode 100644 index e56c422d..00000000 --- a/packages/documentator/src/Processor/Factory.php +++ /dev/null @@ -1,59 +0,0 @@ -container); - - foreach ($this->tasks() as $task => $configurator) { - $processor->task($task, $configurator); - } - - return $processor; - } - - /** - * @return array, Closure(Task): void|null> - */ - protected function tasks(): array { - return [ - PreprocessTask::class => static function (PreprocessTask $task): void { - $task->addInstruction(PreprocessIncludeFile::class); - $task->addInstruction(PreprocessIncludeExec::class); - $task->addInstruction(PreprocessIncludeExample::class); - $task->addInstruction(PreprocessIncludeArtisan::class); - $task->addInstruction(PreprocessIncludeTemplate::class); - $task->addInstruction(PreprocessIncludeDocBlock::class); - $task->addInstruction(PreprocessIncludePackageList::class); - $task->addInstruction(PreprocessIncludeDocumentList::class); - $task->addInstruction(PreprocessIncludeGraphqlDirective::class); - }, - CodeLinksTask::class => null, - ]; - } -} diff --git a/packages/documentator/src/Processor/FileSystem/Directory.php b/packages/documentator/src/Processor/FileSystem/Directory.php index d5a0ca9a..f3c6b267 100644 --- a/packages/documentator/src/Processor/FileSystem/Directory.php +++ b/packages/documentator/src/Processor/FileSystem/Directory.php @@ -10,14 +10,12 @@ use Stringable; use function is_dir; -use function is_writable; use function sprintf; use function str_starts_with; class Directory implements Stringable { public function __construct( private readonly DirectoryPath $path, - private readonly bool $writable, ) { if (!$this->path->isNormalized()) { throw new InvalidArgumentException( @@ -55,10 +53,6 @@ public function getName(): string { return $this->path->getName(); } - public function isWritable(): bool { - return $this->writable && is_writable((string) $this->path); - } - public function isInside(self|File|Path $path): bool { $path = $path instanceof Path ? $path : $path->getPath(); $path = (string) $this->path->getPath($path); diff --git a/packages/documentator/src/Processor/FileSystem/DirectoryTest.php b/packages/documentator/src/Processor/FileSystem/DirectoryTest.php index bd905934..92ae4679 100644 --- a/packages/documentator/src/Processor/FileSystem/DirectoryTest.php +++ b/packages/documentator/src/Processor/FileSystem/DirectoryTest.php @@ -17,7 +17,7 @@ final class DirectoryTest extends TestCase { public function testConstruct(): void { $path = (new DirectoryPath(__DIR__))->getNormalizedPath(); - $directory = new Directory($path, false); + $directory = new Directory($path); self::assertEquals($path, $directory->getPath()); self::assertEquals((string) $path, (string) $directory->getPath()); @@ -27,14 +27,14 @@ public function testConstructNotNormalized(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('Path must be normalized, `/../path` given.'); - new Directory(new DirectoryPath('/../path'), false); + new Directory(new DirectoryPath('/../path')); } public function testConstructNotAbsolute(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('Path must be absolute, `../path` given.'); - new Directory(new DirectoryPath('../path'), false); + new Directory(new DirectoryPath('../path')); } public function testConstructNotDirectory(): void { @@ -43,14 +43,14 @@ public function testConstructNotDirectory(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage(sprintf('The `%s` is not a directory.', $path)); - new Directory($path, false); + new Directory($path); } public function testIsInside(): void { $a = (new FilePath(self::getTestData()->path('a/a.txt'))); $b = $a->getPath(new DirectoryPath('../../..')); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); - $directory = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), true); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); + $directory = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); self::assertTrue($directory->isInside($a)); self::assertFalse($directory->isInside($b)); @@ -60,9 +60,9 @@ public function testIsInside(): void { public function testGetRelativePath(): void { $path = (new FilePath(self::getTestData()->path('a/a.txt')))->getNormalizedPath(); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); - $parent = new Directory($path->getDirectoryPath(), false); - $directory = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), true); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); + $parent = new Directory($path->getDirectoryPath()); + $directory = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); self::assertEquals('DirectoryTest/a', (string) $directory->getRelativePath($parent)); self::assertEquals('DirectoryTest.php', (string) $directory->getRelativePath($file)); diff --git a/packages/documentator/src/Processor/FileSystem/File.php b/packages/documentator/src/Processor/FileSystem/File.php index b23e5411..cf5d1a09 100644 --- a/packages/documentator/src/Processor/FileSystem/File.php +++ b/packages/documentator/src/Processor/FileSystem/File.php @@ -15,12 +15,11 @@ use function array_key_exists; use function file_get_contents; use function is_file; -use function is_writable; use function sprintf; class File implements Stringable { - private ?string $content = null; - private bool $modified = false; + private ?string $content = null; + private bool $modified = false; /** * @var array>, mixed> @@ -29,7 +28,6 @@ class File implements Stringable { public function __construct( private readonly FilePath $path, - private readonly bool $writable, ) { if (!$this->path->isNormalized()) { throw new InvalidArgumentException( @@ -71,10 +69,6 @@ public function getExtension(): ?string { return $this->path->getExtension(); } - public function isWritable(): bool { - return $this->writable && is_writable((string) $this->path); - } - public function isModified(): bool { return $this->modified; } @@ -122,7 +116,7 @@ public function getMetadata(Metadata $metadata): mixed { * @param T $path * * @return (T is Path ? new : (T is Directory ? DirectoryPath : FilePath)) - */ + */ public function getRelativePath(Directory|self|Path $path): Path { $path = $path instanceof Path ? $path : $path->getPath(); $path = $this->path->getRelativePath($path); diff --git a/packages/documentator/src/Processor/FileSystem/FileSystem.php b/packages/documentator/src/Processor/FileSystem/FileSystem.php index a9379941..d4fd8bc5 100644 --- a/packages/documentator/src/Processor/FileSystem/FileSystem.php +++ b/packages/documentator/src/Processor/FileSystem/FileSystem.php @@ -4,6 +4,7 @@ use Closure; use Iterator; +use LastDragon_ru\LaraASP\Core\Path\DirectoryPath; use LastDragon_ru\LaraASP\Core\Path\FilePath; use LastDragon_ru\LaraASP\Core\Path\Path; use SplFileInfo; @@ -13,6 +14,7 @@ use function file_put_contents; use function is_dir; use function is_file; +use function mkdir; class FileSystem { /** @@ -20,7 +22,9 @@ class FileSystem { */ private array $cache = []; - public function __construct() { + public function __construct( + private readonly ?DirectoryPath $output = null, + ) { // empty } @@ -35,9 +39,8 @@ public function getFile(Directory $root, SplFileInfo|File|FilePath|string $path) } // Cached? - $pathObject = $root->getPath()->getFilePath($path); - $path = (string) $pathObject; - $file = ($this->cache[$path] ?? null)?->get(); + $path = $root->getPath()->getFilePath($path); + $file = $this->cached($path); if ($file !== null && !($file instanceof File)) { return null; @@ -48,10 +51,8 @@ public function getFile(Directory $root, SplFileInfo|File|FilePath|string $path) } // Create - if (is_file($path)) { - $writable = $root->isWritable() && $root->isInside($pathObject); - $file = new File($pathObject, $writable); - $this->cache[$path] = WeakReference::create($file); + if (is_file((string) $path)) { + $file = $this->cache(new File($path)); } return $file; @@ -69,15 +70,9 @@ public function getDirectory(Directory $root, SplFileInfo|Directory|File|Path|st // empty } - // Self? - if ($path === '.' || $path === '') { - return $root; - } - // Cached? - $pathObject = $root->getPath()->getDirectoryPath($path); - $path = (string) $pathObject; - $directory = ($this->cache[$path] ?? null)?->get(); + $path = $root->getPath()->getDirectoryPath($path); + $directory = $this->cached($path); if ($directory !== null && !($directory instanceof Directory)) { return null; @@ -88,12 +83,8 @@ public function getDirectory(Directory $root, SplFileInfo|Directory|File|Path|st } // Create - if (is_dir($path)) { - $writable = $root->isWritable() && $root->isInside($pathObject); - $directory = !$root->getPath()->isEqual($pathObject) - ? new Directory($pathObject, $writable) - : $root; - $this->cache[$path] = WeakReference::create($directory); + if (is_dir((string) $path)) { + $directory = $this->cache(new Directory($path)); } return $directory; @@ -179,7 +170,52 @@ protected function getIterator( } public function save(File $file): bool { - return !$file->isModified() - || ($file->isWritable() && file_put_contents((string) $file->getPath(), $file->getContent()) !== false); + // Modified? + if (!$file->isModified()) { + return true; + } + + // Inside? + if ($this->output?->isInside($file->getPath()) !== true) { + return false; + } + + // Directory? + $directory = (string) $file->getPath()->getDirectoryPath(); + + if (!is_dir($directory) && !mkdir($directory, recursive: true)) { + return false; + } + + // Save + return file_put_contents((string) $file->getPath(), $file->getContent()) !== false; + } + + /** + * @template T of Directory|File + * + * @param T $object + * + * @return T + */ + private function cache(Directory|File $object): Directory|File { + $this->cache[(string) $object] = WeakReference::create($object); + + return $object; + } + + private function cached(Path $path): Directory|File|null { + $key = (string) $path; + $cached = null; + + if (isset($this->cache[$key])) { + $cached = $this->cache[$key]->get(); + + if ($cached === null) { + unset($this->cache[$key]); + } + } + + return $cached; } } diff --git a/packages/documentator/src/Processor/FileSystem/FileSystemTest.php b/packages/documentator/src/Processor/FileSystem/FileSystemTest.php index c6a6eecd..d16444ed 100644 --- a/packages/documentator/src/Processor/FileSystem/FileSystemTest.php +++ b/packages/documentator/src/Processor/FileSystem/FileSystemTest.php @@ -20,28 +20,26 @@ final class FileSystemTest extends TestCase { public function testGetFile(): void { $fs = new FileSystem(); - $directory = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); + $directory = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); $readonly = $fs->getFile($directory, __FILE__); $relative = $fs->getFile($directory, basename(__FILE__)); $notfound = $fs->getFile($directory, 'not found'); - $writable = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), true); + $writable = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); $internal = $fs->getFile($writable, self::getTestData()->path('c.html')); $external = $fs->getFile($writable, '../Processor.php'); - $file = new File((new FilePath(self::getTestData()->path('c.txt')))->getNormalizedPath(), false); + $file = new File((new FilePath(self::getTestData()->path('c.txt')))->getNormalizedPath()); $fromFile = $fs->getFile($writable, $file); $splFile = new SplFileInfo((string) $file); $fromSplFile = $fs->getFile($writable, $splFile); $fromFilePath = $fs->getFile($writable, $file->getPath()); self::assertNotNull($readonly); - self::assertFalse($readonly->isWritable()); self::assertEquals( (string) (new FilePath(__FILE__))->getNormalizedPath(), (string) $readonly, ); self::assertNotNull($relative); - self::assertFalse($relative->isWritable()); self::assertEquals( (string) (new FilePath(__FILE__))->getNormalizedPath(), (string) $relative, @@ -50,22 +48,18 @@ public function testGetFile(): void { self::assertNull($notfound); self::assertNotNull($internal); - self::assertTrue($internal->isWritable()); self::assertEquals( (string) (new FilePath(self::getTestData()->path('c.html')))->getNormalizedPath(), (string) $internal, ); self::assertNotNull($external); - self::assertFalse($external->isWritable()); self::assertEquals( (string) (new FilePath(__FILE__))->getFilePath('../Processor.php'), (string) $external, ); self::assertNotNull($fromFile); - self::assertFalse($file->isWritable()); - self::assertTrue($fromFile->isWritable()); self::assertEquals($file->getPath(), $fromFile->getPath()); self::assertEquals( (string) (new FilePath(self::getTestData()->path('c.txt')))->getNormalizedPath(), @@ -73,8 +67,6 @@ public function testGetFile(): void { ); self::assertNotNull($fromSplFile); - self::assertFalse($file->isWritable()); - self::assertTrue($fromSplFile->isWritable()); self::assertEquals($file->getPath(), $fromSplFile->getPath()); self::assertEquals( (string) (new FilePath(self::getTestData()->path('c.txt')))->getNormalizedPath(), @@ -82,8 +74,6 @@ public function testGetFile(): void { ); self::assertNotNull($fromFilePath); - self::assertFalse($file->isWritable()); - self::assertTrue($fromFilePath->isWritable()); self::assertEquals($file->getPath(), $fromFilePath->getPath()); self::assertEquals( (string) (new FilePath(self::getTestData()->path('c.txt')))->getNormalizedPath(), @@ -94,19 +84,19 @@ public function testGetFile(): void { public function testGetDirectory(): void { // Prepare $fs = new FileSystem(); - $directory = new Directory((new DirectoryPath(__DIR__))->getParentPath(), false); - $writable = new Directory($directory->getPath(), true); + $directory = new Directory((new DirectoryPath(__DIR__))->getParentPath()); + $writable = new Directory($directory->getPath()); // Self - self::assertSame($directory, $fs->getDirectory($directory, '')); - self::assertSame($directory, $fs->getDirectory($directory, '.')); - self::assertSame($directory, $fs->getDirectory($directory, $directory->getPath())); + self::assertSame( + $fs->getDirectory($directory, '.'), + $fs->getDirectory($directory, ''), + ); // Readonly $readonly = $fs->getDirectory($directory, __DIR__); self::assertNotNull($readonly); - self::assertFalse($readonly->isWritable()); self::assertEquals( (string) (new DirectoryPath(__DIR__))->getNormalizedPath(), (string) $readonly, @@ -116,7 +106,6 @@ public function testGetDirectory(): void { $relative = $fs->getDirectory($directory, basename(__DIR__)); self::assertNotNull($relative); - self::assertFalse($relative->isWritable()); self::assertEquals( (string) (new DirectoryPath(__DIR__))->getNormalizedPath(), (string) $relative, @@ -132,14 +121,12 @@ public function testGetDirectory(): void { $internal = $fs->getDirectory($writable, $internalPath); self::assertNotNull($internal); - self::assertTrue($internal->isWritable()); self::assertEquals($internalPath, (string) $internal); // External $external = $fs->getDirectory($writable, '../Testing'); self::assertNotNull($external); - self::assertFalse($external->isWritable()); self::assertEquals( (string) (new DirectoryPath(__DIR__))->getDirectoryPath('../../Testing'), (string) $external, @@ -147,10 +134,9 @@ public function testGetDirectory(): void { // From File $filePath = (new FilePath(self::getTestData()->path('c.html')))->getNormalizedPath(); - $fromFile = $fs->getDirectory($writable, new File($filePath, true)); + $fromFile = $fs->getDirectory($writable, new File($filePath)); self::assertNotNull($fromFile); - self::assertTrue($fromFile->isWritable()); self::assertEquals( (string) (new DirectoryPath(self::getTestData()->path('')))->getNormalizedPath(), (string) $fromFile, @@ -161,7 +147,6 @@ public function testGetDirectory(): void { $fromFilePath = $fs->getDirectory($writable, $filePath); self::assertNotNull($fromFilePath); - self::assertTrue($fromFilePath->isWritable()); self::assertEquals( (string) (new DirectoryPath(self::getTestData()->path('')))->getNormalizedPath(), (string) $fromFilePath, @@ -172,7 +157,6 @@ public function testGetDirectory(): void { $fromSpl = $fs->getDirectory($writable, $spl); self::assertNotNull($fromSpl); - self::assertTrue($fromSpl->isWritable()); self::assertEquals( (string) (new DirectoryPath($spl->getPathname()))->getNormalizedPath(), (string) $fromSpl, @@ -180,12 +164,10 @@ public function testGetDirectory(): void { // From Directory $directoryPath = (new DirectoryPath(self::getTestData()->path('a/a')))->getNormalizedPath(); - $directory = new Directory($directoryPath, false); + $directory = new Directory($directoryPath); $fromDirectory = $fs->getDirectory($writable, $directory); self::assertNotNull($fromDirectory); - self::assertFalse($directory->isWritable()); - self::assertTrue($fromDirectory->isWritable()); self::assertEquals((string) $directory, (string) $fromDirectory); // From DirectoryPath @@ -193,15 +175,13 @@ public function testGetDirectory(): void { $fromDirectoryPath = $fs->getDirectory($writable, $directoryPath); self::assertNotNull($fromDirectoryPath); - self::assertTrue($writable->isWritable()); - self::assertTrue($fromDirectoryPath->isWritable()); self::assertEquals((string) $directoryPath, (string) $fromDirectoryPath); } public function testGetFilesIterator(): void { $fs = new FileSystem(); $root = (new DirectoryPath(self::getTestData()->path('')))->getNormalizedPath(); - $directory = new Directory($root, false); + $directory = new Directory($root); $map = static function (File $file) use ($directory): string { return (string) $directory->getRelativePath($file); }; @@ -259,7 +239,7 @@ public function testGetFilesIterator(): void { public function testGetDirectoriesIterator(): void { $fs = new FileSystem(); $root = (new DirectoryPath(self::getTestData()->path('')))->getNormalizedPath(); - $directory = new Directory($root, false); + $directory = new Directory($root); $map = static function (Directory $dir) use ($directory): string { return (string) $directory->getRelativePath($dir); }; @@ -305,10 +285,10 @@ public function testGetDirectoriesIterator(): void { ); } - public function testSave(): void { - $fs = new FileSystem(); + public function testSaveInsideRoot(): void { $temp = (new FilePath(self::getTempFile(__FILE__)->getPathname()))->getNormalizedPath(); - $file = new File($temp, true); + $file = new File($temp); + $fs = new FileSystem($temp->getDirectoryPath()); self::assertTrue($fs->save($file)); // because no changes @@ -319,10 +299,10 @@ public function testSave(): void { self::assertEquals(__METHOD__, file_get_contents((string) $temp)); } - public function testSaveReadonly(): void { - $fs = new FileSystem(); + public function testSaveOutsideRoot(): void { + $fs = new FileSystem(new DirectoryPath(__DIR__)); $temp = (new FilePath(self::getTempFile(__FILE__)->getPathname()))->getNormalizedPath(); - $file = new File($temp, false); + $file = new File($temp); self::assertTrue($fs->save($file)); // because no changes @@ -335,7 +315,7 @@ public function testSaveReadonly(): void { public function testCache(): void { $fs = new FileSystem(); - $dir = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); + $dir = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); $file = $fs->getFile($dir, __FILE__); $directory = $fs->getDirectory($dir, __DIR__); diff --git a/packages/documentator/src/Processor/FileSystem/FileTest.php b/packages/documentator/src/Processor/FileSystem/FileTest.php index 25da8f30..5f573166 100644 --- a/packages/documentator/src/Processor/FileSystem/FileTest.php +++ b/packages/documentator/src/Processor/FileSystem/FileTest.php @@ -22,7 +22,7 @@ final class FileTest extends TestCase { public function testConstruct(): void { $path = (new FilePath(__FILE__))->getNormalizedPath(); - $file = new File($path, false); + $file = new File($path); self::assertEquals($path, $file->getPath()); self::assertEquals("{$path}", (string) $file->getPath()); @@ -34,14 +34,14 @@ public function testConstructNotNormalized(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('Path must be normalized, `/../file.txt` given.'); - new File(new FilePath('/../file.txt'), false); + new File(new FilePath('/../file.txt')); } public function testConstructNotAbsolute(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('Path must be absolute, `../file.txt` given.'); - new File(new FilePath('../file.txt'), false); + new File(new FilePath('../file.txt')); } public function testConstructNotFile(): void { @@ -50,12 +50,12 @@ public function testConstructNotFile(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage(sprintf('The `%s` is not a file.', $path)); - new File($path, false); + new File($path); } public function testGetContent(): void { $temp = (new FilePath(self::getTempFile(__FILE__)->getPathname()))->getNormalizedPath(); - $file = new File($temp, false); + $file = new File($temp); $path = (string) $file; self::assertEquals(__FILE__, $file->getContent()); @@ -66,7 +66,7 @@ public function testGetContent(): void { public function testSetContent(): void { $temp = (new FilePath(self::getTempFile(__FILE__)->getPathname()))->getNormalizedPath(); - $file = new File($temp, false); + $file = new File($temp); $path = (string) $file; $meta = new class([1, 2]) implements Metadata { public function __construct( @@ -96,9 +96,9 @@ public function __invoke(File $file): mixed { public function testGetRelativePath(): void { $path = new FilePath('a/a.txt'); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); - $parent = new Directory($file->getPath()->getParentPath()->getParentPath(), false); - $directory = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), true); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); + $parent = new Directory($file->getPath()->getParentPath()->getParentPath()); + $directory = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); self::assertEquals('..', (string) $file->getRelativePath($parent)); self::assertEquals('FileTest.php', (string) $file->getRelativePath($file)); diff --git a/packages/documentator/src/Processor/InstanceFactory.php b/packages/documentator/src/Processor/InstanceFactory.php new file mode 100644 index 00000000..701592bb --- /dev/null +++ b/packages/documentator/src/Processor/InstanceFactory.php @@ -0,0 +1,27 @@ + + */ + public string $class, + /** + * @var Closure(TInstance): void + */ + public Closure $factory, + ) { + // empty + } +} diff --git a/packages/documentator/src/Processor/Metadata/PhpClassCommentTest.php b/packages/documentator/src/Processor/Metadata/PhpClassCommentTest.php index 37d5bfbe..60fa0283 100644 --- a/packages/documentator/src/Processor/Metadata/PhpClassCommentTest.php +++ b/packages/documentator/src/Processor/Metadata/PhpClassCommentTest.php @@ -33,7 +33,6 @@ class A { PHP; $file = new File( (new FilePath(self::getTempFile($content)->getPathname()))->getNormalizedPath(), - false, ); $factory = new PhpClassComment(new PhpClass()); $metadata = $factory($file); @@ -50,7 +49,7 @@ class A { } public function testInvokeNotPhp(): void { - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $factory = new PhpClassComment( new class() extends PhpClass { #[Override] diff --git a/packages/documentator/src/Processor/Metadata/PhpClassMarkdownTest.php b/packages/documentator/src/Processor/Metadata/PhpClassMarkdownTest.php index ba958fcf..8fc4494e 100644 --- a/packages/documentator/src/Processor/Metadata/PhpClassMarkdownTest.php +++ b/packages/documentator/src/Processor/Metadata/PhpClassMarkdownTest.php @@ -34,7 +34,6 @@ class A { PHP; $file = new File( (new FilePath(self::getTempFile($content)->getPathname()))->getNormalizedPath(), - false, ); $factory = new PhpClassMarkdown( $this->app()->make(PhpDocumentFactory::class), @@ -55,7 +54,7 @@ class A { } public function testInvokeEmpty(): void { - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $factory = new PhpClassMarkdown( $this->app()->make(PhpDocumentFactory::class), new PhpClassComment(new PhpClass()), @@ -67,7 +66,7 @@ public function testInvokeEmpty(): void { } public function testInvokeNotPhp(): void { - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $factory = new PhpClassMarkdown( $this->app()->make(PhpDocumentFactory::class), new class(new PhpClass()) extends PhpClassComment { diff --git a/packages/documentator/src/Processor/Metadata/PhpClassTest.php b/packages/documentator/src/Processor/Metadata/PhpClassTest.php index 35e65f23..2d689f81 100644 --- a/packages/documentator/src/Processor/Metadata/PhpClassTest.php +++ b/packages/documentator/src/Processor/Metadata/PhpClassTest.php @@ -13,7 +13,7 @@ #[CoversClass(PhpClass::class)] final class PhpClassTest extends TestCase { public function testInvoke(): void { - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $factory = new PhpClass(); $metadata = $factory($file); @@ -21,7 +21,7 @@ public function testInvoke(): void { } public function testInvokeNotPhp(): void { - $file = new File((new FilePath(__FILE__))->getFilePath('../../../README.md'), false); + $file = new File((new FilePath(__FILE__))->getFilePath('../../../README.md')); $factory = new PhpClass(); $metadata = $factory($file); diff --git a/packages/documentator/src/Processor/Metadata/PhpDocBlockTest.php b/packages/documentator/src/Processor/Metadata/PhpDocBlockTest.php index 69c58c91..efd5a533 100644 --- a/packages/documentator/src/Processor/Metadata/PhpDocBlockTest.php +++ b/packages/documentator/src/Processor/Metadata/PhpDocBlockTest.php @@ -36,7 +36,6 @@ class A { PHP; $file = new File( (new FilePath(self::getTempFile($content)->getPathname()))->getNormalizedPath(), - false, ); $factory = new PhpDocBlock( $this->app()->make(Markdown::class), @@ -58,7 +57,7 @@ class A { } public function testInvokeEmpty(): void { - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $factory = new PhpDocBlock( $this->app()->make(Markdown::class), $this->app()->make(LinkFactory::class), @@ -71,7 +70,7 @@ public function testInvokeEmpty(): void { } public function testInvokeNotPhp(): void { - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $factory = new PhpDocBlock( $this->app()->make(Markdown::class), $this->app()->make(LinkFactory::class), diff --git a/packages/documentator/src/Processor/Processor.php b/packages/documentator/src/Processor/Processor.php index 8494ecad..cccd28d7 100644 --- a/packages/documentator/src/Processor/Processor.php +++ b/packages/documentator/src/Processor/Processor.php @@ -15,6 +15,7 @@ use Symfony\Component\Finder\Glob; use function array_map; +use function array_merge; use function microtime; /** @@ -26,6 +27,11 @@ class Processor { */ private InstanceList $tasks; + /** + * @var array + */ + private array $exclude = []; + public function __construct(ContainerResolver $container) { $this->tasks = new InstanceList($container, $this->key(...)); } @@ -47,37 +53,52 @@ public function tasks(): array { } /** - * @param Task|class-string $task - * @param ($task is object ? null : ?Closure(Task): void) $configurator + * @template T of Task + * + * @param InstanceFactory|T|class-string $task + */ + public function task(InstanceFactory|Task|string $task): static { + if ($task instanceof InstanceFactory) { + $this->tasks->add( + $task->class, // @phpstan-ignore argument.type (https://github.com/phpstan/phpstan/issues/7609) + $task->factory, // @phpstan-ignore argument.type (https://github.com/phpstan/phpstan/issues/7609) + ); + } else { + $this->tasks->add($task); + } + + return $this; + } + + /** + * @param array|string $exclude glob(s) to exclude. */ - public function task(Task|string $task, ?Closure $configurator = null): static { - $this->tasks->add($task, $configurator); + public function exclude(array|string $exclude): static { + $this->exclude = array_merge($this->exclude, (array) $exclude); return $this; } /** - * @param array|string|null $exclude glob(s) to exclude. - * @param Closure(FilePath $path, Result $result, float $duration): void|null $listener + * @param Closure(FilePath $input, Result $result, float $duration): void|null $listener */ public function run( - DirectoryPath|FilePath $path, - array|string|null $exclude = null, + DirectoryPath|FilePath $input, ?Closure $listener = null, ): float { $start = microtime(true); $depth = match (true) { - $path instanceof FilePath => 0, - default => null, + $input instanceof FilePath => 0, + default => null, }; $extensions = match (true) { - $path instanceof FilePath => $path->getName(), - !$this->tasks->has('*') => array_map(static fn ($e) => "*.{$e}", $this->tasks->keys()), - default => null, + $input instanceof FilePath => $input->getName(), + !$this->tasks->has('*') => array_map(static fn ($e) => "*.{$e}", $this->tasks->keys()), + default => null, }; - $exclude = array_map(Glob::toRegex(...), (array) $exclude); - $root = new Directory($path->getDirectoryPath(), true); - $fs = new FileSystem(); + $exclude = array_map(Glob::toRegex(...), $this->exclude); + $root = new Directory($input->getDirectoryPath()); + $fs = new FileSystem($root->getPath()); try { $iterator = $fs->getFilesIterator($root, $extensions, $depth, $exclude); @@ -87,7 +108,7 @@ public function run( } catch (ProcessorError $exception) { throw $exception; } catch (Exception $exception) { - throw new ProcessingFailed($path, $exception); + throw new ProcessingFailed($input, $exception); } return microtime(true) - $start; diff --git a/packages/documentator/src/Processor/ProcessorTest.php b/packages/documentator/src/Processor/ProcessorTest.php index c0b462ee..4f8fbe14 100644 --- a/packages/documentator/src/Processor/ProcessorTest.php +++ b/packages/documentator/src/Processor/ProcessorTest.php @@ -64,9 +64,9 @@ public static function getExtensions(): array { ->task($mock) ->task($taskA) ->task($taskB) + ->exclude(['excluded.txt', '**/**/excluded.txt']) ->run( $root, - ['excluded.txt', '**/**/excluded.txt'], static function (FilePath $path, Result $result) use (&$count, &$events): void { $events[(string) $path] = $result; $count++; @@ -144,13 +144,8 @@ static function (FilePath $path, Result $result) use (&$count, &$events): void { } public function testRunFile(): void { - $task = new ProcessorTest__Task([ - 'c.txt' => [ - 'excluded.txt', - ], - ]); - - $path = (new FilePath(self::getTestData()->path('c.txt')))->getNormalizedPath(); + $task = new ProcessorTest__Task(); + $path = (new FilePath(self::getTestData()->path('excluded.txt')))->getNormalizedPath(); $count = 0; $events = []; @@ -158,7 +153,6 @@ public function testRunFile(): void { ->task($task) ->run( $path, - ['excluded.txt', '**/**/excluded.txt'], static function (FilePath $path, Result $result) use (&$count, &$events): void { $events[(string) $path] = $result; $count++; @@ -167,8 +161,7 @@ static function (FilePath $path, Result $result) use (&$count, &$events): void { self::assertEquals( [ - 'c.txt' => Result::Success, - 'excluded.txt' => Result::Skipped, + 'excluded.txt' => Result::Success, ], $events, ); @@ -176,9 +169,9 @@ static function (FilePath $path, Result $result) use (&$count, &$events): void { self::assertEquals( [ [ - 'c.txt', + 'excluded.txt', [ - 'excluded.txt' => 'excluded.txt', + // empty ], ], ], @@ -186,104 +179,6 @@ static function (FilePath $path, Result $result) use (&$count, &$events): void { ); } - public function testRunPostpone(): void { - $task = new class() implements Task { - /** - * @var array - */ - public array $processed = []; - /** - * @var array - */ - public array $postponed = []; - - /** - * @inheritDoc - */ - #[Override] - public static function getExtensions(): array { - return ['txt', 'htm', 'html']; - } - - /** - * @inheritDoc - */ - #[Override] - public function __invoke(Directory $root, File $file): ?bool { - // Postponed? - $path = (string) $root->getRelativePath($file); - - if ($file->getExtension() === 'html' && !isset($this->postponed[$path])) { - $this->postponed[$path] = true; - - return null; - } - - // Process - $this->processed[] = $path; - - return true; - } - }; - - $root = (new DirectoryPath(self::getTestData()->path('')))->getNormalizedPath(); - $count = 0; - $events = []; - - (new Processor($this->app()->make(ContainerResolver::class))) - ->task($task) - ->run( - $root, - ['excluded.txt', '**/**/excluded.txt'], - static function (FilePath $path, Result $result) use (&$count, &$events): void { - $events[(string) $path] = $result; - $count++; - }, - ); - - self::assertEquals( - [ - 'b/a/ba.txt' => Result::Success, - 'c.txt' => Result::Success, - 'b/b/bb.txt' => Result::Success, - 'a/a.txt' => Result::Success, - 'a/a/aa.txt' => Result::Success, - 'a/b/ab.txt' => Result::Success, - 'b/b.txt' => Result::Success, - 'c.htm' => Result::Success, - 'c.html' => Result::Success, - 'b/b.html' => Result::Success, - 'a/a.html' => Result::Success, - ], - $events, - ); - self::assertCount($count, $events); - self::assertEquals( - [ - 'a/a.txt', - 'a/a/aa.txt', - 'a/b/ab.txt', - 'b/a/ba.txt', - 'b/b.txt', - 'b/b/bb.txt', - 'c.htm', - 'c.txt', - 'c.html', - 'b/b.html', - 'a/a.html', - ], - $task->processed, - ); - self::assertEquals( - [ - 'c.html' => true, - 'b/b.html' => true, - 'a/a.html' => true, - ], - $task->postponed, - ); - } - public function testRunWildcard(): void { $taskA = new class([ 'b.html' => [ @@ -316,9 +211,9 @@ public static function getExtensions(): array { (new Processor($this->app()->make(ContainerResolver::class))) ->task($taskA) ->task($taskB) + ->exclude(['excluded.txt', '**/**/excluded.txt']) ->run( $root, - ['excluded.txt', '**/**/excluded.txt'], static function (FilePath $path, Result $result) use (&$count, &$events): void { $events[(string) $path] = $result; $count++; diff --git a/packages/documentator/src/Processor/Tasks/CodeLinks/TaskTest.php b/packages/documentator/src/Processor/Tasks/CodeLinks/TaskTest.php index 6ef3b505..8359fa89 100644 --- a/packages/documentator/src/Processor/Tasks/CodeLinks/TaskTest.php +++ b/packages/documentator/src/Processor/Tasks/CodeLinks/TaskTest.php @@ -47,8 +47,8 @@ final class TaskTest extends TestCase { #[DataProvider('dataProviderInvoke')] public function testInvoke(Closure|string $expected, string $document): void { $path = (new FilePath(self::getTestData()->path($document)))->getNormalizedPath(); - $file = new File($path, true); - $root = new Directory($path->getDirectoryPath(), true); + $file = new File($path); + $root = new Directory($path->getDirectoryPath()); $task = $this->app()->make(Task::class); if (!is_callable($expected)) { diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeArtisan/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeArtisan/InstructionTest.php index a5f87672..1c9fbcac 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeArtisan/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeArtisan/InstructionTest.php @@ -30,8 +30,8 @@ #[CoversClass(Instruction::class)] final class InstructionTest extends TestCase { public function testInvoke(): void { - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...'); $expected = 'result'; $command = 'command to execute'; @@ -75,8 +75,8 @@ static function (InputInterface $input, OutputInterface $output) use ($expected) } public function testInvokeFailed(): void { - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $node = new class() extends Node { #[Override] public function getDestination(): string { @@ -133,8 +133,8 @@ static function (): int { } public function testGetCommand(): void { - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...'); $command = 'artisan:command $directory {$directory} "{$directory}" $file {$file} "{$file}"'; $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocBlock/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocBlock/InstructionTest.php index b10281ad..5375c349 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocBlock/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocBlock/InstructionTest.php @@ -32,8 +32,8 @@ final class InstructionTest extends TestCase { #[DataProvider('dataProviderProcess')] public function testInvoke(Closure|string $expected, string $file, Parameters $params): void { $path = (new FilePath(self::getTestData()->path($file)))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $target = $file->getName(); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); $instance = $this->app()->make(Instruction::class); diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/InstructionTest.php index 334d4b30..966e38f3 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/InstructionTest.php @@ -30,8 +30,8 @@ final class InstructionTest extends TestCase { public function testInvoke(string $expected, string $path, string $content): void { // Prepare $path = (new FilePath(self::getTestData()->path($path)))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $document = $this->app()->make(Markdown::class)->parse($content, $path); $instruction = (new Query())->where(Query::type(Node::class))->findOne($document->node); diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeExample/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeExample/InstructionTest.php index fc0df9d9..36ddf3ee 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeExample/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeExample/InstructionTest.php @@ -30,8 +30,8 @@ final class InstructionTest extends TestCase { #[DataProvider('dataProviderInvoke')] public function testInvoke(string $expected, string $output): void { $path = (new FilePath(__FILE__))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $params = new Parameters('...'); $target = self::getTestData()->path('Example.md'); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); @@ -56,8 +56,8 @@ public function testInvokeNoRun(): void { self::assertFalse($this->app()->bound(Runner::class)); $path = (new FilePath(self::getTestData()->path('Example.md')))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $params = new Parameters('...'); $target = $file->getName(); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeExec/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeExec/InstructionTest.php index e9d769f6..1fe8a3a8 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeExec/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeExec/InstructionTest.php @@ -23,8 +23,8 @@ #[CoversClass(Instruction::class)] final class InstructionTest extends TestCase { public function testInvoke(): void { - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...'); $expected = 'result'; $command = 'command to execute'; diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeFile/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeFile/InstructionTest.php index cee712a3..c61bf1b6 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeFile/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeFile/InstructionTest.php @@ -27,8 +27,8 @@ final class InstructionTest extends TestCase { // ========================================================================= #[DataProvider('dataProviderInvoke')] public function testInvoke(string $expected, string $source): void { - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...'); $target = self::getTestData()->path($source); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeGraphqlDirective/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeGraphqlDirective/InstructionTest.php index 2caabf06..4fda6b9d 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeGraphqlDirective/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeGraphqlDirective/InstructionTest.php @@ -77,8 +77,8 @@ public function testInvokeNoPrinter(): void { } // Test - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...'); $target = '@test'; $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); @@ -105,8 +105,8 @@ public function testInvokeNoDirective(): void { return (new Printer())->setDirectiveResolver($resolver); }); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...'); $target = '@test'; $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); @@ -124,8 +124,8 @@ public function testInvokeNoDirectiveResolver(): void { return (new Printer())->setDirectiveResolver(null); }); - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...'); $target = '@test'; $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludePackageList/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludePackageList/InstructionTest.php index b4d4cceb..cbbcd68a 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludePackageList/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludePackageList/InstructionTest.php @@ -31,8 +31,8 @@ final class InstructionTest extends TestCase { #[DataProvider('dataProviderProcess')] public function testInvoke(string $expected, string $template, SortOrder $order): void { $path = (new FilePath(self::getTestData()->path('Document.md')))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $target = $root->getDirectoryPath('packages'); $params = new Parameters('...', template: $template, order: $order); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); @@ -52,13 +52,13 @@ public function testInvoke(string $expected, string $template, SortOrder $order) public function testInvokeNoReadme(): void { $fs = new FileSystem(); $path = (new FilePath(self::getTestData()->path('Document.md')))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $target = $root->getDirectoryPath('no readme'); $params = new Parameters('...'); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); $instance = $this->app()->make(Instruction::class); - $package = $fs->getDirectory(new Directory($target, false), 'package'); + $package = $fs->getDirectory(new Directory($target), 'package'); self::assertNotNull($package); self::expectExceptionObject( @@ -71,13 +71,13 @@ public function testInvokeNoReadme(): void { public function testInvokeEmptyReadme(): void { $fs = new FileSystem(); $path = (new FilePath(self::getTestData()->path('Document.md')))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $target = $root->getDirectoryPath('empty readme'); $params = new Parameters('...'); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); $instance = $this->app()->make(Instruction::class); - $package = $fs->getDirectory(new Directory($target, false), 'package'); + $package = $fs->getDirectory(new Directory($target), 'package'); $expected = $fs->getFile($root, 'empty readme/package/README.md'); self::assertNotNull($package); diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeTemplate/InstructionTest.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeTemplate/InstructionTest.php index 3d72415b..f27970fe 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeTemplate/InstructionTest.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeTemplate/InstructionTest.php @@ -33,8 +33,8 @@ final class InstructionTest extends TestCase { */ #[DataProvider('dataProviderInvoke')] public function testInvoke(string $expected, string $source, array $data): void { - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...', $data); $target = self::getTestData()->path($source); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); @@ -52,8 +52,8 @@ public function testInvoke(string $expected, string $source, array $data): void } public function testInvokeNoData(): void { - $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath(), false); - $file = new File((new FilePath(__FILE__))->getNormalizedPath(), false); + $root = new Directory((new DirectoryPath(__DIR__))->getNormalizedPath()); + $file = new File((new FilePath(__FILE__))->getNormalizedPath()); $params = new Parameters('...', []); $target = $file->getPath(); $context = new Context($root, $file, Mockery::mock(Document::class), new Node(), new Nop()); @@ -68,8 +68,8 @@ public function testInvokeNoData(): void { public function testInvokeVariablesUnused(): void { $path = (new FilePath(self::getTestData()->path('.md')))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $params = new Parameters('...', [ 'a' => 'A', 'b' => 'B', @@ -89,8 +89,8 @@ public function testInvokeVariablesUnused(): void { public function testInvokeVariablesMissed(): void { $path = (new FilePath(self::getTestData()->path('.md')))->getNormalizedPath(); - $root = new Directory($path->getDirectoryPath(), false); - $file = new File($path, false); + $root = new Directory($path->getDirectoryPath()); + $file = new File($path); $params = new Parameters('...', [ 'a' => 'A', ]); diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Task.php b/packages/documentator/src/Processor/Tasks/Preprocess/Task.php index 06ed36ec..a6adf1be 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Task.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Task.php @@ -14,6 +14,7 @@ use LastDragon_ru\LaraASP\Documentator\Processor\Exceptions\ProcessorError; use LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\Directory; use LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\File; +use LastDragon_ru\LaraASP\Documentator\Processor\InstanceFactory; use LastDragon_ru\LaraASP\Documentator\Processor\InstanceList; use LastDragon_ru\LaraASP\Documentator\Processor\Metadata\Markdown; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Contracts\Instruction; @@ -87,12 +88,20 @@ public function getInstructions(): array { } /** - * @template I of Instruction<*> + * @template P of Parameters + * @template I of Instruction

* - * @param I|class-string $instruction + * @param InstanceFactory|I|class-string $instruction */ - public function addInstruction(Instruction|string $instruction): static { - $this->instructions->add($instruction); // @phpstan-ignore argument.type + public function addInstruction(InstanceFactory|Instruction|string $instruction): static { + if ($instruction instanceof InstanceFactory) { + $this->instructions->add( + $instruction->class, // @phpstan-ignore argument.type (https://github.com/phpstan/phpstan/issues/7609) + $instruction->factory, // @phpstan-ignore argument.type (https://github.com/phpstan/phpstan/issues/7609) + ); + } else { + $this->instructions->add($instruction); + } return $this; } diff --git a/phpstan-baseline-well-known.neon b/phpstan-baseline-well-known.neon index 486b229c..ffb4bb3b 100644 --- a/phpstan-baseline-well-known.neon +++ b/phpstan-baseline-well-known.neon @@ -83,11 +83,3 @@ parameters: message: "#^Class `[^`]+` must be marked by `@internal`\\.$#" paths: - packages/dev/src/PhpStan/ClassMustBeInternal/RuleTest.php - - # Not supported yet (`class-string-map`) - # https://github.com/phpstan/phpstan/discussions/11736 - # https://github.com/phpstan/phpstan/issues/9521 (?) - - - message: "#^Method LastDragon_ru\\\\LaraASP\\\\Documentator\\\\Processor\\\\Factory::tasks\\(\\) should return array, \\(Closure\\(LastDragon_ru\\\\LaraASP\\\\Documentator\\\\Processor\\\\Contracts\\\\Task\\): void\\)\\|null> but returns#" - paths: - - packages/documentator/src/Processor/Factory.php