Skip to content

Commit

Permalink
feat(documentator)!: Processor Task can postpone processing until a…
Browse files Browse the repository at this point in the history
…ll other files. (#172)
  • Loading branch information
LastDragon-ru authored Jul 16, 2024
1 parent 2fa609f commit 9028c23
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 12 deletions.
20 changes: 15 additions & 5 deletions packages/documentator/src/Processor/Contracts/Task.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,21 @@ public function getExtensions(): array;
/**
* Performs action on the `$file`.
*
* Each returned value will be treated as a dependency of the task. It will
* be resolved relative to the directory where the `$file` located,
* processed, and then send back into the generator.
* The `bool` value indicates that the task completed successfully (`true`)
* or failed (`false`).
*
* @return Generator<mixed, SplFileInfo|File|string, File, bool>|bool
* The {@see Generator} means that the task has dependencies (= other files
* which should be processed before the task). 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, SplFileInfo|File|string, File, bool>|bool|null
*/
public function __invoke(Directory $root, File $file): Generator|bool;
public function __invoke(Directory $root, File $file): Generator|bool|null;
}
64 changes: 57 additions & 7 deletions packages/documentator/src/Processor/Processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Closure;
use Exception;
use Generator;
use Iterator;
use LastDragon_ru\LaraASP\Core\Utils\Path;
use LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Task;
use LastDragon_ru\LaraASP\Documentator\Processor\Exceptions\CircularDependency;
Expand Down Expand Up @@ -62,9 +63,9 @@ public function run(string $path, array|string|null $exclude = null, ?Closure $l
$root = new Directory($path, true);

try {
foreach ($root->getFilesIterator(patterns: $extensions, exclude: $exclude) as $file) {
$this->runFile($root, $file, $exclude, $listener, $processed, [], []);
}
$iterator = $root->getFilesIterator(patterns: $extensions, exclude: $exclude);

$this->runIterator($iterator, $root, $exclude, $listener, $processed, []);
} catch (ProcessorError $exception) {
throw $exception;
} catch (Exception $exception) {
Expand All @@ -73,20 +74,59 @@ public function run(string $path, array|string|null $exclude = null, ?Closure $l
}

/**
* @param Iterator<array-key, File> $iterator
* @param array<array-key, string> $exclude
* @param Closure(string $path, ?bool $result, float $duration): void|null $listener
* @param array<string, true> $processed
* @param array<string, File> $stack
*/
private function runIterator(
Iterator $iterator,
Directory $root,
array $exclude,
?Closure $listener,
array &$processed,
array $stack,
): float {
$time = 0;

while ($iterator->valid()) {
$file = $iterator->current();

$iterator->next();

$time += (float) $this->runFile(
$iterator,
$root,
$file,
$exclude,
$listener,
$processed,
$stack,
[],
);
}

return $time;
}

/**
* @param Iterator<array-key, File> $iterator
* @param array<array-key, string> $exclude
* @param Closure(string $path, ?bool $result, float $duration): void|null $listener
* @param array<string, true> $processed
* @param array<string, File> $resolved
* @param array<string, File> $stack
* @param array<string, File> $resolved
*/
private function runFile(
Iterator $iterator,
Directory $root,
File $file,
array $exclude,
?Closure $listener,
array &$processed,
array $resolved,
array $stack,
array $resolved,
): ?float {
// Prepare
$start = microtime(true);
Expand Down Expand Up @@ -137,9 +177,18 @@ private function runFile(
try {
foreach ($tasks as $task) {
try {
$result = false;
// Run
$generator = $task($root, $file);

// Postponed?
if ($generator === null) {
$paused += $this->runIterator($iterator, $root, $exclude, $listener, $processed, $stack);
$generator = $task($root, $file) ?? false;
}

// Dependencies?
$result = false;

if ($generator instanceof Generator) {
while ($generator->valid()) {
// Resolve
Expand Down Expand Up @@ -168,13 +217,14 @@ private function runFile(
// Processable?
if (!isset($processed[$dependencyKey]) && $root->isInside($dependency)) {
$paused += (float) $this->runFile(
$iterator,
$root,
$dependency,
$exclude,
$listener,
$processed,
$resolved,
$stack,
$resolved,
);
}

Expand Down
98 changes: 98 additions & 0 deletions packages/documentator/src/Processor/ProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,104 @@ static function (string $path, ?bool $result) use (&$count, &$events): void {
);
}

public function testRunPostpone(): void {
$task = new class() implements Task {
/**
* @var array<array-key, string>
*/
public array $processed = [];
/**
* @var array<string, bool>
*/
public array $postponed = [];

/**
* @inheritDoc
*/
#[Override]
public function getExtensions(): array {
return ['txt', 'htm', 'html'];
}

/**
* @inheritDoc
*/
#[Override]
public function __invoke(Directory $root, File $file): ?bool {
// Postponed?
$path = $file->getRelativePath($root);

if ($file->getExtension() === 'html' && !isset($this->postponed[$path])) {
$this->postponed[$path] = true;

return null;
}

// Process
$this->processed[] = $path;

return true;
}
};

$root = Path::normalize(self::getTestData()->path(''));
$count = 0;
$events = [];

(new Processor())
->task($task)
->run(
$root,
['excluded.txt', '**/**/excluded.txt'],
static function (string $path, ?bool $result) use (&$count, &$events): void {
$events[$path] = $result;
$count++;
},
);

self::assertEquals(
[
'b/a/ba.txt' => true,
'c.txt' => true,
'b/b/bb.txt' => true,
'a/a.txt' => true,
'a/a/aa.txt' => true,
'a/b/ab.txt' => true,
'b/b.txt' => true,
'c.htm' => true,
'c.html' => true,
'b/b.html' => true,
'a/a.html' => true,
],
$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 testRunFileNotFound(): void {
$task = new class() implements Task {
/**
Expand Down

0 comments on commit 9028c23

Please sign in to comment.