Skip to content

Commit

Permalink
Preprocessor.
Browse files Browse the repository at this point in the history
  • Loading branch information
LastDragon-ru committed Aug 25, 2023
1 parent 2842250 commit 4e67b4a
Show file tree
Hide file tree
Showing 15 changed files with 563 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/documentator/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"ext-mbstring": "*",
"composer/semver": "^3.2",
"laravel/framework": "^9.21.0|^10.0.0",
"symfony/filesystem": "^6.3.0",
"symfony/process": "^6.3.0",
"lastdragon-ru/lara-asp-core": "self.version",
"lastdragon-ru/lara-asp-serializer": "self.version"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions;

use LastDragon_ru\LaraASP\Documentator\PackageException;

class PreprocessFailed extends PackageException {
// empty
}
9 changes: 9 additions & 0 deletions packages/documentator/src/Preprocessor/Instruction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor;

interface Instruction {
public static function getName(): string;

public function process(string $path, string $target): string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use Exception;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;

use function sprintf;

class IncludeCommand implements Instruction {
public function __construct(
protected readonly Process $process,
) {
// empty
}

public static function getName(): string {
return 'include:command';
}

public function process(string $path, string $target): string {
try {
return $this->process->run([$target], $path);
} catch (Exception $exception) {
throw new PreprocessFailed(
sprintf(
'Failed to execute command `%s`.',
$target,
),
$exception,
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;
use Mockery;
use PHPUnit\Framework\Attributes\CoversClass;

/**
* @internal
*/
#[CoversClass(IncludeFile::class)]
class IncludeCommandTest extends TestCase {
public function testProcess(): void {
$path = 'current/working/directory';
$expected = 'result';
$command = 'command to execute';
$process = Mockery::mock(Process::class);
$process
->shouldReceive('run')
->with([$command], $path)
->once()
->andReturn($expected);

$instance = $this->app->make(IncludeCommand::class, [
'process' => $process,
]);

self::assertEquals($expected, $instance->process($path, $command));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use Exception;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;
use Symfony\Component\Filesystem\Filesystem;

use function implode;
use function is_file;
use function pathinfo;
use function preg_match_all;
use function sprintf;
use function trim;

use const PATHINFO_EXTENSION;

class IncludeExample extends IncludeFile {
public const Limit = 20;

public function __construct(
protected readonly Process $process,
) {
parent::__construct();
}

public static function getName(): string {
return 'include:example';
}

public function process(string $path, string $target): string {
$language = $this->getLanguage($path, $target);
$content = trim(parent::process($path, $target));
$content = <<<CODE
```{$language}
$content
```
CODE;
$command = $this->getCommand($path, $target);

if ($command) {
try {
$output = $this->process->run($command, $path);
} catch (Exception $exception) {
throw new PreprocessFailed(
sprintf(
'Failed to execute command `%s`.',
implode(' ', $command),
),
$exception,
);
}

if (preg_match_all('/\R/u', $output) > static::Limit) {
$output = <<<CODE
<details><summary>Output</summary>
```plain
$output
```
</details>
CODE;
} else {
$output = <<<CODE
Output:
```plain
$output
```
CODE;
}

$content .= "\n\n{$output}";
}

return $content;
}

protected function getLanguage(string $path, string $target): string {
return pathinfo($target, PATHINFO_EXTENSION);
}

/**
* @return list<string>
*/
protected function getCommand(string $path, string $target): ?array {
$info = pathinfo($target);
$file = isset($info['dirname'])
? "{$info['dirname']}/{$info['filename']}.run"
: "{$info['filename']}.run";
$path = (new Filesystem())->isAbsolutePath($file) ? $file : "{$path}/{$file}";
$command = is_file($path) ? [$file] : null;

return $command;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
use LastDragon_ru\LaraASP\Documentator\Utils\Process;
use Mockery;
use PHPUnit\Framework\Attributes\CoversClass;

use function basename;
use function dirname;
use function implode;
use function range;
use function trim;

/**
* @internal
*/
#[CoversClass(IncludeFile::class)]
class IncludeExampleTest extends TestCase {
public function testProcessNoRun(): void {
$path = dirname(self::getTestData()->path('~example.md'));
$file = basename(self::getTestData()->path('~example.md'));
$expected = trim(self::getTestData()->content('~example.md'));
$process = Mockery::mock(Process::class);
$process
->shouldReceive('run')
->never();

$instance = $this->app->make(IncludeExample::class, [
'process' => $process,
]);

self::assertEquals(
<<<EXPECTED
```md
{$expected}
```
EXPECTED,
$instance->process($path, $file),
);
}

public function testProcess(): void {
$path = dirname(self::getTestData()->path('~runnable.md'));
$file = self::getTestData()->path('~runnable.md');
$expected = trim(self::getTestData()->content('~runnable.md'));
$output = 'command output';
$process = Mockery::mock(Process::class);
$process
->shouldReceive('run')
->with([self::getTestData()->path('~runnable.run')], $path)
->once()
->andReturn($output);

$instance = $this->app->make(IncludeExample::class, [
'process' => $process,
]);

self::assertEquals(
<<<EXPECTED
```md
{$expected}
```
Output:
```plain
{$output}
```
EXPECTED,
$instance->process($path, $file),
);
}

public function testProcessLongOutput(): void {
$path = dirname(self::getTestData()->path('~runnable.md'));
$file = self::getTestData()->path('~runnable.md');
$expected = trim(self::getTestData()->content('~runnable.md'));
$output = implode("\n", range(0, IncludeExample::Limit + 1));
$process = Mockery::mock(Process::class);
$process
->shouldReceive('run')
->with([self::getTestData()->path('~runnable.run')], $path)
->once()
->andReturn($output);

$instance = $this->app->make(IncludeExample::class, [
'process' => $process,
]);

self::assertEquals(
<<<EXPECTED
```md
{$expected}
```
<details><summary>Output</summary>
```plain
{$output}
```
</details>
EXPECTED,
$instance->process($path, $file),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# File

content of the file
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# File

content of the file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/command
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instruction;
use Symfony\Component\Filesystem\Filesystem;

use function file_get_contents;
use function sprintf;

class IncludeFile implements Instruction {
public function __construct() {
// empty
}

public static function getName(): string {
return 'include:file';
}

public function process(string $path, string $target): string {
$file = (new Filesystem())->isAbsolutePath($target) ? $target : "{$path}/{$target}";
$content = file_get_contents($file);

if ($content === false) {
throw new PreprocessFailed(
sprintf(
'Failed to include `%s`.',
$target,
),
);
}

return $content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# File

content of the file
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;

use function basename;
use function dirname;

/**
* @internal
*/
#[CoversClass(IncludeFile::class)]
class IncludeFileTest extends TestCase {
public function testProcessRelative(): void {
$path = dirname(self::getTestData()->path('.md'));
$file = basename(self::getTestData()->path('.md'));
$expected = self::getTestData()->content('.md');
$instance = $this->app->make(IncludeFile::class);

self::assertEquals($expected, $instance->process($path, $file));
}

public function testProcessAbsolute(): void {
$path = 'invalid/directory';
$file = self::getTestData()->path('.md');
$expected = self::getTestData()->content('.md');
$instance = $this->app->make(IncludeFile::class);

self::assertEquals($expected, $instance->process($path, $file));
}
}
Loading

0 comments on commit 4e67b4a

Please sign in to comment.