Skip to content

Commit

Permalink
feat(documentator): IncludeDocBlock (include:docblock) instruction.
Browse files Browse the repository at this point in the history
  • Loading branch information
LastDragon-ru committed Jan 1, 2024
1 parent 95e6b23 commit 8aa9a66
Show file tree
Hide file tree
Showing 16 changed files with 323 additions and 0 deletions.
1 change: 1 addition & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,5 @@ MD053:
"include:file",
"include:package-list",
"include:template",
"include:docblock",
]
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"league/commonmark": "^2.4",
"nuwave/lighthouse": "^6.5.0",
"opis/json-schema": "^2.3.0",
"phpdocumentor/reflection-docblock": "^5.2",
"phpdocumentor/type-resolver": "^1.7",
"phpstan/phpdoc-parser": "^1.23",
"psr/http-message": "^1.0.0|^2.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/documentator/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"composer/semver": "^3.2",
"laravel/framework": "^9.21.0|^10.0.0",
"league/commonmark": "^2.4",
"phpdocumentor/reflection-docblock": "^5.2",
"symfony/filesystem": "^6.3.0",
"symfony/finder": "^6.3.0",
"symfony/process": "^6.3.0",
Expand Down
11 changes: 11 additions & 0 deletions packages/documentator/docs/Commands/preprocess.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ Where:

## Instructions

### `[include:docblock]: <target> <parameters>`

* `<target>` - File path.
* `<parameters>` - additional parameters
* `summary` - Include the class summary? (default `false`)
* `description` - Include the class description? (default `true`)

Includes the docblock of the first PHP class/interface/trait/enum/etc
from `<target>` file. Inline tags include as is. Other tags are
ignored.

### `[include:document-list]: <target> <parameters>`

* `<target>` - Directory path.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions;

use Throwable;

use function sprintf;

class TargetIsNotValidPhpFile extends InstructionFailed {
public function __construct(string $path, string $target, Throwable $previous = null) {
parent::__construct(
$path,
$target,
sprintf(
'The `%s` is not a valid PHP file (in `%s`).',
$target,
$path,
),
$previous,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use Exception;
use LastDragon_ru\LaraASP\Documentator\PackageViewer;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Contracts\ParameterizableInstruction;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetIsNotFile;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetIsNotValidPhpFile;
use LastDragon_ru\LaraASP\Documentator\Utils\Path;
use LastDragon_ru\LaraASP\Serializer\Contracts\Serializable;
use Override;
use phpDocumentor\Reflection\DocBlockFactory;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\NodeFinder;
use PhpParser\ParserFactory;

use function dirname;
use function file_get_contents;
use function trim;

/**
* @implements ParameterizableInstruction<IncludeDocBlockParameters>
*/
class IncludeDocBlock implements ParameterizableInstruction {
public function __construct(
protected readonly PackageViewer $viewer,
) {
// empty
}

#[Override]
public static function getName(): string {
return 'include:docblock';
}

#[Override]
public static function getDescription(): string {
return <<<'DESC'
Includes the docblock of the first PHP class/interface/trait/enum/etc
from `<target>` file. Inline tags include as is. Other tags are
ignored.
DESC;
}

#[Override]
public static function getTargetDescription(): ?string {
return 'File path.';
}

#[Override]
public static function getParameters(): string {
return IncludeDocBlockParameters::class;
}

/**
* @inheritDoc
*/
#[Override]
public static function getParametersDescription(): array {
return [
'summary' => 'Include the class summary? (default `false`)',
'description' => 'Include the class description? (default `true`)',
];
}

#[Override]
public function process(string $path, string $target, Serializable $parameters): string {
// File?
$file = Path::getPath(dirname($path), $target);
$content = file_get_contents($file);

if ($content === false) {
throw new TargetIsNotFile($path, $target);
}

// Class?
try {
$class = null;
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
$stmts = (array) $parser->parse($content);
$finder = new NodeFinder();
$class = $finder->findFirst($stmts, static function (Node $node): bool {
return $node instanceof ClassLike;
});
} catch (Exception $exception) {
throw new TargetIsNotValidPhpFile($path, $target, $exception);
}

if (!($class instanceof ClassLike)) {
return '';
}

// DocBlock?
$comment = $class->getDocComment()?->getText();

if (!$comment) {
return '';
}

// Parse
$eol = "\n";
$result = '';
$factory = DocBlockFactory::createInstance();
$docblock = $factory->create($comment);

if ($parameters->summary) {
$summary = trim($docblock->getSummary());

if ($summary) {
$result .= $summary.$eol.$eol;
}
}

if ($parameters->description) {
$description = trim((string) $docblock->getDescription());

if ($description) {
$result .= $description.$eol.$eol;
}
}

if ($result) {
$result = trim($result).$eol;
}

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

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use LastDragon_ru\LaraASP\Serializer\Contracts\Serializable;

class IncludeDocBlockParameters implements Serializable {
public function __construct(
public readonly bool $summary = false,
public readonly bool $description = true,
) {
// empty
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions;

use Exception;
use Illuminate\Container\Container;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\TargetIsNotValidPhpFile;
use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;

/**
* @internal
*/
#[CoversClass(IncludeDocBlock::class)]
class IncludeDocBlockTest extends TestCase {
// <editor-fold desc="Tests">
// =========================================================================
/**
* @dataProvider dataProviderProcess
*/
public function testProcess(Exception|string $expected, string $file, IncludeDocBlockParameters $params): void {
$file = self::getTestData()->file($file);
$instance = Container::getInstance()->make(IncludeDocBlock::class);

if ($expected instanceof Exception) {
self::expectExceptionObject($expected);
} else {
$expected = self::getTestData()->content($expected);
}

self::assertEquals($expected, $instance->process($file->getPathname(), $file->getFilename(), $params));
}

public function testProcessAbsolute(): void {
$path = 'invalid/directory';
$file = self::getTestData()->path('Valid.txt');
$params = new IncludeDocBlockParameters();
$instance = Container::getInstance()->make(IncludeDocBlock::class);
$expected = self::getTestData()->content('ValidExpected.txt');

self::assertEquals($expected, $instance->process($path, $file, $params));
}
//</editor-fold>

// <editor-fold desc="DataProviders">
// =========================================================================
/**
* @return array<string, array{Exception|string, string, IncludeDocBlockParameters}>
*/
public static function dataProviderProcess(): array {
return [
'default' => [
'ValidExpected.txt',
'Valid.txt',
new IncludeDocBlockParameters(),
],
'with summary' => [
'ValidWithSummaryExpected.txt',
'Valid.txt',
new IncludeDocBlockParameters(summary: true),
],
'only summary' => [
'ValidOnlySummaryExpected.txt',
'Valid.txt',
new IncludeDocBlockParameters(summary: true, description: false),
],
'no docblock' => [
'NoDocblockExpected.txt',
'NoDocblock.txt',
new IncludeDocBlockParameters(),
],
'invalid' => [
new TargetIsNotValidPhpFile(__DIR__.'/IncludeDocBlockTest/Invalid.txt', 'Invalid.txt'),
'Invalid.txt',
new IncludeDocBlockParameters(),
],
];
}
// </editor-fold>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php declare(strict_types = 1);

/**
* Description description description description description description
* description description description description description description
* description description description description description description
*/
A {
// empty
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php declare(strict_types = 1);

trait A {
// empty
}

/**
* Summary B.
*
* Description description description description description description
* description description description description description description
* description description description description description description
*/
class B {
// empty
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types = 1);

/**
* Summary A.
*
* Description description description description description description
* description description description description description description
* description description description description description description
*
* @see https://example.com/
*/
interface A {
// empty
}

/**
* Summary B.
*
* Description description description description description description
* description description description description description description
* description description description description description description
*/
class B {
// empty
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Description description description description description description
description description description description description description
description description description description description description
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Summary A.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Summary A.

Description description description description description description
description description description description description description
description description description description description description
2 changes: 2 additions & 0 deletions packages/documentator/src/Preprocessor/Preprocessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Contracts\ParameterizableInstruction;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Contracts\ProcessableInstruction;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Exceptions\PreprocessFailed;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeDocBlock;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeDocumentList;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeExample;
use LastDragon_ru\LaraASP\Documentator\Preprocessor\Instructions\IncludeExec;
Expand Down Expand Up @@ -88,6 +89,7 @@ public function __construct(
$this->addInstruction(IncludeExec::class);
$this->addInstruction(IncludeExample::class);
$this->addInstruction(IncludeTemplate::class);
$this->addInstruction(IncludeDocBlock::class);
$this->addInstruction(IncludePackageList::class);
$this->addInstruction(IncludeDocumentList::class);
}
Expand Down

0 comments on commit 8aa9a66

Please sign in to comment.