From 1358544f47134c8ff663ef1267c4ef6077c64b28 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:05:26 +0400 Subject: [PATCH 1/7] A bit better tests. --- .../src/Processor/ProcessorTest.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/documentator/src/Processor/ProcessorTest.php b/packages/documentator/src/Processor/ProcessorTest.php index c0b462ee2..1bfc09f10 100644 --- a/packages/documentator/src/Processor/ProcessorTest.php +++ b/packages/documentator/src/Processor/ProcessorTest.php @@ -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,7 @@ public function testRunFile(): void { ->task($task) ->run( $path, - ['excluded.txt', '**/**/excluded.txt'], + null, static function (FilePath $path, Result $result) use (&$count, &$events): void { $events[(string) $path] = $result; $count++; @@ -167,8 +162,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 +170,9 @@ static function (FilePath $path, Result $result) use (&$count, &$events): void { self::assertEquals( [ [ - 'c.txt', + 'excluded.txt', [ - 'excluded.txt' => 'excluded.txt', + // empty ], ], ], From efca5a72d1cb2d0235e58600e5e1cefc768d637a Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Wed, 11 Dec 2024 19:21:30 +0400 Subject: [PATCH 2/7] `\LastDragon_ru\LaraASP\Documentator\Processor\Processor::run($exclude)` removed, the `\LastDragon_ru\LaraASP\Documentator\Processor\Processor::exclude()` should be used instead. --- .../documentator/src/Commands/Preprocess.php | 2 +- .../documentator/src/Processor/Processor.php | 18 +++++++++++++++--- .../src/Processor/ProcessorTest.php | 7 +++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php index 3a934275e..318f9ad1c 100644 --- a/packages/documentator/src/Commands/Preprocess.php +++ b/packages/documentator/src/Commands/Preprocess.php @@ -108,7 +108,7 @@ public function __invoke(Formatter $formatter): void { $this->output->writeln($line, OutputInterface::OUTPUT_NORMAL | $resultVerbosity); }; - $duration = ($this->factory)()->run($path, $exclude, $listener); + $duration = ($this->factory)()->exclude($exclude)->run($path, $listener); $this->output->newLine(); $this->output->writeln("DONE ({$formatter->duration($duration)})"); diff --git a/packages/documentator/src/Processor/Processor.php b/packages/documentator/src/Processor/Processor.php index 8494ecadd..454bb3f43 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; /** @@ -25,6 +26,10 @@ class Processor { * @var InstanceList */ private InstanceList $tasks; + /** + * @var array + */ + private array $exclude = []; public function __construct(ContainerResolver $container) { $this->tasks = new InstanceList($container, $this->key(...)); @@ -57,12 +62,19 @@ public function task(Task|string $task, ?Closure $configurator = null): static { } /** - * @param array|string|null $exclude glob(s) to exclude. + * @param array|string $exclude glob(s) to exclude. + */ + public function exclude(array|string $exclude): static { + $this->exclude = array_merge($this->exclude, (array) $exclude); + + return $this; + } + + /** * @param Closure(FilePath $path, Result $result, float $duration): void|null $listener */ public function run( DirectoryPath|FilePath $path, - array|string|null $exclude = null, ?Closure $listener = null, ): float { $start = microtime(true); @@ -75,7 +87,7 @@ public function run( !$this->tasks->has('*') => array_map(static fn ($e) => "*.{$e}", $this->tasks->keys()), default => null, }; - $exclude = array_map(Glob::toRegex(...), (array) $exclude); + $exclude = array_map(Glob::toRegex(...), $this->exclude); $root = new Directory($path->getDirectoryPath(), true); $fs = new FileSystem(); diff --git a/packages/documentator/src/Processor/ProcessorTest.php b/packages/documentator/src/Processor/ProcessorTest.php index 1bfc09f10..7f5412c53 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++; @@ -153,7 +153,6 @@ public function testRunFile(): void { ->task($task) ->run( $path, - null, static function (FilePath $path, Result $result) use (&$count, &$events): void { $events[(string) $path] = $result; $count++; @@ -226,9 +225,9 @@ public function __invoke(Directory $root, File $file): ?bool { (new Processor($this->app()->make(ContainerResolver::class))) ->task($task) + ->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++; @@ -310,9 +309,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++; From 46bc39994c779e5adfc6a4f51844d664ac989a5a Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:53:06 +0400 Subject: [PATCH 3/7] `\LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\FileSystem` simplification. --- .../Dependencies/DirectoryIteratorTest.php | 12 ++--- .../Dependencies/DirectoryReferenceTest.php | 12 ++--- .../Dependencies/FileIteratorTest.php | 12 ++--- .../Dependencies/FileReferenceTest.php | 12 ++--- .../Processor/Dependencies/OptionalTest.php | 8 +-- .../src/Processor/FileSystem/Directory.php | 6 --- .../Processor/FileSystem/DirectoryTest.php | 18 +++---- .../src/Processor/FileSystem/File.php | 12 ++--- .../src/Processor/FileSystem/FileSystem.php | 33 +++++++++--- .../Processor/FileSystem/FileSystemTest.php | 53 ++++++------------- .../src/Processor/FileSystem/FileTest.php | 18 +++---- .../Metadata/PhpClassCommentTest.php | 3 +- .../Metadata/PhpClassMarkdownTest.php | 5 +- .../src/Processor/Metadata/PhpClassTest.php | 4 +- .../Processor/Metadata/PhpDocBlockTest.php | 5 +- .../documentator/src/Processor/Processor.php | 21 ++++---- .../Processor/Tasks/CodeLinks/TaskTest.php | 4 +- .../IncludeArtisan/InstructionTest.php | 12 ++--- .../IncludeDocBlock/InstructionTest.php | 4 +- .../IncludeDocumentList/InstructionTest.php | 4 +- .../IncludeExample/InstructionTest.php | 8 +-- .../IncludeExec/InstructionTest.php | 4 +- .../IncludeFile/InstructionTest.php | 4 +- .../InstructionTest.php | 12 ++--- .../IncludePackageList/InstructionTest.php | 16 +++--- .../IncludeTemplate/InstructionTest.php | 16 +++--- 26 files changed, 151 insertions(+), 167 deletions(-) diff --git a/packages/documentator/src/Processor/Dependencies/DirectoryIteratorTest.php b/packages/documentator/src/Processor/Dependencies/DirectoryIteratorTest.php index 8ad7992ed..767b6644a 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 15d42e0b9..28bca0356 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 ef4c2028e..855dfe363 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 23885615c..cae6d8552 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 c6f312214..93d2f1556 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/FileSystem/Directory.php b/packages/documentator/src/Processor/FileSystem/Directory.php index d5a0ca9a0..f3c6b267b 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 bd9059343..92ae46799 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 b23e54116..cf5d1a09f 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 a9379941d..e58866655 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 } @@ -49,8 +53,7 @@ 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); + $file = new File($pathObject); $this->cache[$path] = WeakReference::create($file); } @@ -89,9 +92,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) + ? new Directory($pathObject) : $root; $this->cache[$path] = WeakReference::create($directory); } @@ -179,7 +181,24 @@ 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; } } diff --git a/packages/documentator/src/Processor/FileSystem/FileSystemTest.php b/packages/documentator/src/Processor/FileSystem/FileSystemTest.php index c6a6eecd2..e25926cd9 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,8 +84,8 @@ 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, '')); @@ -106,7 +96,6 @@ public function testGetDirectory(): void { $readonly = $fs->getDirectory($directory, __DIR__); self::assertNotNull($readonly); - self::assertFalse($readonly->isWritable()); self::assertEquals( (string) (new DirectoryPath(__DIR__))->getNormalizedPath(), (string) $readonly, @@ -116,7 +105,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 +120,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 +133,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 +146,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 +156,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 +163,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 +174,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 +238,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 +284,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 +298,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 +314,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 25da8f300..5f5731668 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/Metadata/PhpClassCommentTest.php b/packages/documentator/src/Processor/Metadata/PhpClassCommentTest.php index 37d5bfbec..60fa0283f 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 ba958fcff..8fc4494ea 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 35e65f236..2d689f814 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 69c58c911..efd5a5331 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 454bb3f43..1d8d477f1 100644 --- a/packages/documentator/src/Processor/Processor.php +++ b/packages/documentator/src/Processor/Processor.php @@ -26,6 +26,7 @@ class Processor { * @var InstanceList */ private InstanceList $tasks; + /** * @var array */ @@ -71,25 +72,25 @@ public function exclude(array|string $exclude): static { } /** - * @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, + 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(...), $this->exclude); - $root = new Directory($path->getDirectoryPath(), true); - $fs = new FileSystem(); + $root = new Directory($input->getDirectoryPath()); + $fs = new FileSystem($root->getPath()); try { $iterator = $fs->getFilesIterator($root, $extensions, $depth, $exclude); @@ -99,7 +100,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/Tasks/CodeLinks/TaskTest.php b/packages/documentator/src/Processor/Tasks/CodeLinks/TaskTest.php index 6ef3b505e..8359fa891 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 a5f87672f..1c9fbcace 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 b10281ada..5375c349c 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 334d4b30f..966e38f38 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 fc0df9d9b..36ddf3eec 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 e9d769f69..1fe8a3a82 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 cee712a3c..c61bf1b66 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 2caabf061..4fda6b9d0 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 b4d4cceb1..cbbcd68af 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 3d72415b5..f27970fe6 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', ]); From 03af0409cf835f94a9e250fa8c9acbfecc00fb3d Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:05:35 +0400 Subject: [PATCH 4/7] Removed `\LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Factory`. --- .../documentator/src/Commands/Preprocess.php | 48 +++++++++++++-- .../src/Commands/PreprocessTest.php | 24 ++++---- packages/documentator/src/PackageProvider.php | 3 - .../src/Processor/Contracts/Factory.php | 9 --- .../documentator/src/Processor/Factory.php | 59 ------------------- phpstan-baseline-well-known.neon | 4 +- 6 files changed, 58 insertions(+), 89 deletions(-) delete mode 100644 packages/documentator/src/Processor/Contracts/Factory.php delete mode 100644 packages/documentator/src/Processor/Factory.php diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php index 318f9ad1c..abe2764cb 100644 --- a/packages/documentator/src/Commands/Preprocess.php +++ b/packages/documentator/src/Commands/Preprocess.php @@ -2,20 +2,30 @@ namespace LastDragon_ru\LaraASP\Documentator\Commands; +use Closure; 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\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)()->exclude($exclude)->run($path, $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 => $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, + ]; + } + #[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 a583b795d..2e447e46b 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 a92789eba..21424a84f 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 9431fd992..000000000 --- a/packages/documentator/src/Processor/Contracts/Factory.php +++ /dev/null @@ -1,9 +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/phpstan-baseline-well-known.neon b/phpstan-baseline-well-known.neon index 486b229cf..ed650e097 100644 --- a/phpstan-baseline-well-known.neon +++ b/phpstan-baseline-well-known.neon @@ -88,6 +88,6 @@ parameters: # 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#" + message: "#^Method LastDragon_ru\\\\LaraASP\\\\Documentator\\\\Commands\\\\Preprocess::tasks\\(\\) should return array, \\(Closure\\(LastDragon_ru\\\\LaraASP\\\\Documentator\\\\Processor\\\\Contracts\\\\Task\\): void\\)\\|null> but returns#" paths: - - packages/documentator/src/Processor/Factory.php + - packages/documentator/src/Commands/Preprocess.php From 425c3ad45959e89230081d1c0225255e80ff6987 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 12 Dec 2024 18:12:00 +0400 Subject: [PATCH 5/7] `\LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\FileSystem` outdated files will be removed from the `$cache`. --- .../src/Processor/FileSystem/FileSystem.php | 55 ++++++++++++------- .../Processor/FileSystem/FileSystemTest.php | 7 ++- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/packages/documentator/src/Processor/FileSystem/FileSystem.php b/packages/documentator/src/Processor/FileSystem/FileSystem.php index e58866655..d4fd8bc58 100644 --- a/packages/documentator/src/Processor/FileSystem/FileSystem.php +++ b/packages/documentator/src/Processor/FileSystem/FileSystem.php @@ -39,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; @@ -52,9 +51,8 @@ public function getFile(Directory $root, SplFileInfo|File|FilePath|string $path) } // Create - if (is_file($path)) { - $file = new File($pathObject); - $this->cache[$path] = WeakReference::create($file); + if (is_file((string) $path)) { + $file = $this->cache(new File($path)); } return $file; @@ -72,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; @@ -91,11 +83,8 @@ public function getDirectory(Directory $root, SplFileInfo|Directory|File|Path|st } // Create - if (is_dir($path)) { - $directory = !$root->getPath()->isEqual($pathObject) - ? new Directory($pathObject) - : $root; - $this->cache[$path] = WeakReference::create($directory); + if (is_dir((string) $path)) { + $directory = $this->cache(new Directory($path)); } return $directory; @@ -201,4 +190,32 @@ public function save(File $file): bool { // 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 e25926cd9..d16444ed7 100644 --- a/packages/documentator/src/Processor/FileSystem/FileSystemTest.php +++ b/packages/documentator/src/Processor/FileSystem/FileSystemTest.php @@ -88,9 +88,10 @@ public function testGetDirectory(): void { $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__); From 2dab32606767476d06968711d4adf193c11a5fa0 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:24:19 +0400 Subject: [PATCH 6/7] `\LastDragon_ru\LaraASP\Documentator\Processor\InstanceFactory` helper to make phpstan happy. --- .../documentator/src/Commands/Preprocess.php | 14 +++++----- .../src/Processor/InstanceFactory.php | 27 +++++++++++++++++++ .../documentator/src/Processor/Processor.php | 16 ++++++++--- .../src/Processor/Tasks/Preprocess/Task.php | 17 +++++++++--- phpstan-baseline-well-known.neon | 8 ------ 5 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 packages/documentator/src/Processor/InstanceFactory.php diff --git a/packages/documentator/src/Commands/Preprocess.php b/packages/documentator/src/Commands/Preprocess.php index abe2764cb..ff154fbad 100644 --- a/packages/documentator/src/Commands/Preprocess.php +++ b/packages/documentator/src/Commands/Preprocess.php @@ -2,7 +2,6 @@ namespace LastDragon_ru\LaraASP\Documentator\Commands; -use Closure; use Illuminate\Console\Command; use LastDragon_ru\LaraASP\Core\Application\ContainerResolver; use LastDragon_ru\LaraASP\Core\Path\DirectoryPath; @@ -12,6 +11,7 @@ use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Heading\Renumber; use LastDragon_ru\LaraASP\Documentator\Package; 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; @@ -127,19 +127,19 @@ public function __invoke(Formatter $formatter): void { private function processor(): Processor { $processor = new Processor($this->container); - foreach ($this->tasks() as $task => $configurator) { - $processor->task($task, $configurator); + foreach ($this->tasks() as $task) { + $processor->task($task); } return $processor; } /** - * @return array, Closure(Task): void|null> + * @return list|Task|class-string> */ protected function tasks(): array { return [ - PreprocessTask::class => static function (PreprocessTask $task): void { + new InstanceFactory(PreprocessTask::class, static function (PreprocessTask $task): void { $task->addInstruction(PreprocessIncludeFile::class); $task->addInstruction(PreprocessIncludeExec::class); $task->addInstruction(PreprocessIncludeExample::class); @@ -149,8 +149,8 @@ protected function tasks(): array { $task->addInstruction(PreprocessIncludePackageList::class); $task->addInstruction(PreprocessIncludeDocumentList::class); $task->addInstruction(PreprocessIncludeGraphqlDirective::class); - }, - CodeLinksTask::class => null, + }), + CodeLinksTask::class, ]; } diff --git a/packages/documentator/src/Processor/InstanceFactory.php b/packages/documentator/src/Processor/InstanceFactory.php new file mode 100644 index 000000000..701592bb1 --- /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/Processor.php b/packages/documentator/src/Processor/Processor.php index 1d8d477f1..cccd28d7e 100644 --- a/packages/documentator/src/Processor/Processor.php +++ b/packages/documentator/src/Processor/Processor.php @@ -53,11 +53,19 @@ 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(Task|string $task, ?Closure $configurator = null): static { - $this->tasks->add($task, $configurator); + 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; } diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Task.php b/packages/documentator/src/Processor/Tasks/Preprocess/Task.php index 06ed36ecc..a6adf1be2 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 ed650e097..ffb4bb3b7 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\\\\Commands\\\\Preprocess::tasks\\(\\) should return array, \\(Closure\\(LastDragon_ru\\\\LaraASP\\\\Documentator\\\\Processor\\\\Contracts\\\\Task\\): void\\)\\|null> but returns#" - paths: - - packages/documentator/src/Commands/Preprocess.php From 44765c2a13b390baeb241ea877b67d0a0082f90b Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:25:43 +0400 Subject: [PATCH 7/7] `\LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Task::__invoke()` cannot return `null` anymore. Reverts: 9028c2366181da1bf6b5c36e896f429e974e3cab --- .../src/Processor/Contracts/Task.php | 14 +-- .../documentator/src/Processor/Executor.php | 9 +- .../src/Processor/ProcessorTest.php | 98 ------------------- 3 files changed, 5 insertions(+), 116 deletions(-) diff --git a/packages/documentator/src/Processor/Contracts/Task.php b/packages/documentator/src/Processor/Contracts/Task.php index f1f407ed7..abbaee607 100644 --- a/packages/documentator/src/Processor/Contracts/Task.php +++ b/packages/documentator/src/Processor/Contracts/Task.php @@ -22,19 +22,13 @@ public static function getExtensions(): array; * or failed (`false`). * * The {@see Generator} means that the task has dependencies (= other files - * which should be processed before the task). Each returned value will be + * which should be processed before the current). Each returned value will be * resolved relative to the directory where the `$file` located, processed, * and then send back into the generator. * - * And, finally, the `null`. Special value that will postpone processing - * until all other files (and their dependencies) are processed. It may be - * useful, for example, if the task should collect information from all - * other files. Please note, the `null` can be returned only once, the - * second time will automatically mark the task as failed. - * - * @return Generator, 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/Executor.php b/packages/documentator/src/Processor/Executor.php index 175ab6f08..adf3020ac 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/ProcessorTest.php b/packages/documentator/src/Processor/ProcessorTest.php index 7f5412c53..4f8fbe142 100644 --- a/packages/documentator/src/Processor/ProcessorTest.php +++ b/packages/documentator/src/Processor/ProcessorTest.php @@ -179,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) - ->exclude(['excluded.txt', '**/**/excluded.txt']) - ->run( - $root, - 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' => [