Skip to content

Commit

Permalink
fix(documentator): Parsing {@see} inline tags while help generation…
Browse files Browse the repository at this point in the history
… for `lara-asp-documentator:preprocess` command.
  • Loading branch information
LastDragon-ru committed Nov 18, 2024
1 parent af69ffa commit ebc708f
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 46 deletions.
5 changes: 4 additions & 1 deletion packages/documentator/docs/Commands/preprocess.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ after the Header will be used as a summary.
* `<target>` - File path.

Includes contents of the `<target>` file as an example wrapped into
` ```code block``` `. If {@see Runner} bound, it will be called to execute
` ```code block``` `. If [`Runner`][code-links/f9077a28b352f84b] bound, it will be called to execute
the example. Its return value will be added right after the code block.

By default, the `Runner` return value will be included as ` ```plain text``` `
Expand Down Expand Up @@ -164,6 +164,9 @@ Glob(s) to exclude.
[//]: # (start: code-links)
[//]: # (warning: Generated automatically. Do not edit.)

[code-links/f9077a28b352f84b]: ../../src/Processor/Tasks/Preprocess/Instructions/IncludeExample/Contracts/Runner.php
"\LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeExample\Contracts\Runner"

[code-links/7e5c66e8748c6ff8]: ../../src/Utils/SortOrder.php
"\LastDragon_ru\LaraASP\Documentator\Utils\SortOrder"

Expand Down
26 changes: 13 additions & 13 deletions packages/documentator/src/Commands/Preprocess.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
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\Document;
use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\HeadingsLevel;
use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Move;
use LastDragon_ru\LaraASP\Documentator\Package;
Expand All @@ -18,7 +17,7 @@
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\Task as PreprocessTask;
use LastDragon_ru\LaraASP\Documentator\Utils\PhpDoc;
use LastDragon_ru\LaraASP\Documentator\Utils\PhpDocumentFactory;
use LastDragon_ru\LaraASP\Documentator\Utils\Text;
use LastDragon_ru\LaraASP\Formatter\Formatter;
use LastDragon_ru\LaraASP\Serializer\Contracts\Serializable;
Expand Down Expand Up @@ -76,6 +75,8 @@ class Preprocess extends Command {
%tasks%
HELP;

private ?PhpDocumentFactory $phpDocumentFactory = null;

public function __construct(
protected readonly Factory $factory,
) {
Expand All @@ -92,7 +93,7 @@ public function __invoke(Formatter $formatter): void {
Result::Failed => ['FAIL', 'red', OutputInterface::VERBOSITY_NORMAL],
Result::Success => ['DONE', 'green', OutputInterface::VERBOSITY_NORMAL],
Result::Skipped => ['SKIP', 'gray', OutputInterface::VERBOSITY_VERBOSE],
Result::Missed => ['MISS', 'gray', OutputInterface::VERBOSITY_VERBOSE],
Result::Missed => ['MISS', 'yellow', OutputInterface::VERBOSITY_VERBOSE],
};

$duration = $formatter->duration($duration);
Expand All @@ -113,9 +114,13 @@ public function __invoke(Formatter $formatter): void {

#[Override]
public function getProcessedHelp(): string {
return strtr(parent::getProcessedHelp(), [
'%tasks%' => trim($this->getProcessedHelpTasks(3)),
]);
try {
return strtr(parent::getProcessedHelp(), [
'%tasks%' => trim($this->getProcessedHelpTasks(3)),
]);
} finally {
$this->phpDocumentFactory = null;
}
}

protected function getProcessedHelpTasks(int $level): string {
Expand Down Expand Up @@ -316,13 +321,8 @@ private function getDocBlock(
?int $level = null,
): string {
// Load
$path = match (true) {
$object instanceof ReflectionProperty => $object->getDeclaringClass()->getFileName(),
default => $object->getFileName(),
};
$path = $path !== false ? new FilePath($path) : null;
$help = (new PhpDoc((string) $object->getDocComment()))->getText();
$help = new Document($help, $path);
$this->phpDocumentFactory ??= $this->laravel->make(PhpDocumentFactory::class);
$help = ($this->phpDocumentFactory)($object);

// Move to cwd
$cwd = new DirectoryPath((string) getcwd());
Expand Down
6 changes: 6 additions & 0 deletions packages/documentator/src/Commands/PreprocessTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public function getProcessedHelpTaskPreprocessInstructions(PreprocessTask $task,
}
};

$command->setLaravel($this->app());

self::assertEquals(
<<<'MARKDOWN'
### `[test:instruction]: <target> <parameters>`
Expand Down Expand Up @@ -94,6 +96,8 @@ public function getProcessedHelpTaskPreprocessInstructionTarget(
}
};

$command->setLaravel($this->app());

self::assertEquals(
<<<'MARKDOWN'
Target target target target target.
Expand Down Expand Up @@ -122,6 +126,8 @@ public function getProcessedHelpTaskPreprocessParameters(
}
};

$command->setLaravel($this->app());

self::assertEquals(
<<<'MARKDOWN'
* `publicPropertyWithoutDefaultValue`: `int` - Description.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@
use LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\File;
use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\CodeLinks\Contracts\LinkFactory;
use Override;
use PhpParser\NameContext;
use PhpParser\Node\Name;

use function preg_replace_callback;
use function trim;

use const PREG_UNMATCHED_AS_NULL;

/**
* @implements Metadata<?Document>
Expand All @@ -39,32 +32,8 @@ public function __invoke(File $file): mixed {
}

// Parse
$content = $this->preprocess($comment->context, $comment->comment->getText());
$document = new Document(trim($content), $file->getPath());
$document = $comment->comment->getDocument($this->factory, $comment->context, $file->getPath());

return $document;
}

private function preprocess(NameContext $context, string $string): string {
return (string) preg_replace_callback(
pattern : '/\{@(?:see|link)\s+(?P<reference>[^}\s]+)\s?}/imu',
callback: function (array $matches) use ($context): string {
$result = $matches[0];
$reference = $this->factory->create(
$matches['reference'],
static function (string $class) use ($context): string {
return (string) $context->getResolvedClassName(new Name($class));
},
);

if ($reference !== null) {
$result = "`{$reference}`";
}

return $result;
},
subject : $string,
flags : PREG_UNMATCHED_AS_NULL,
);
}
}
36 changes: 36 additions & 0 deletions packages/documentator/src/Utils/PhpDoc.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

namespace LastDragon_ru\LaraASP\Documentator\Utils;

use LastDragon_ru\LaraASP\Core\Path\FilePath;
use LastDragon_ru\LaraASP\Documentator\Markdown\Document;
use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\CodeLinks\Contracts\LinkFactory;
use PhpParser\NameContext;
use PhpParser\Node\Name;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
Expand All @@ -12,8 +17,11 @@

use function array_slice;
use function implode;
use function preg_replace_callback;
use function trim;

use const PREG_UNMATCHED_AS_NULL;

/**
* @internal
*/
Expand Down Expand Up @@ -49,6 +57,34 @@ public function isDeprecated(): bool {
return $this->node !== null && $this->node->getDeprecatedTagValues() !== [];
}

public function getDocument(LinkFactory $factory, NameContext $context, ?FilePath $path = null): Document {
return new Document(
trim(
(string) preg_replace_callback(
pattern : '/\{@(?:see|link)\s+(?P<reference>[^}\s]+)\s?}/imu',
callback: static function (array $matches) use ($context, $factory): string {
$result = $matches[0];
$reference = $factory->create(
$matches['reference'],
static function (string $class) use ($context): string {
return (string) $context->getResolvedClassName(new Name($class));
},
);

if ($reference !== null) {
$result = "`{$reference}`";
}

return $result;
},
subject : $this->getText(),
flags : PREG_UNMATCHED_AS_NULL,
),
),
$path,
);
}

/**
* @param array<array-key, string> $strings
*/
Expand Down
75 changes: 75 additions & 0 deletions packages/documentator/src/Utils/PhpDocumentFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\Documentator\Utils;

use LastDragon_ru\LaraASP\Core\Path\FilePath;
use LastDragon_ru\LaraASP\Documentator\Markdown\Document;
use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\CodeLinks\Contracts\LinkFactory;
use PhpParser\NameContext;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\ParserFactory;
use ReflectionClass;
use ReflectionProperty;

use function file_get_contents;

/**
* @internal
*/
class PhpDocumentFactory {
/**
* @var array<string, NameContext>
*/
private array $context = [];

public function __construct(
protected readonly LinkFactory $factory,
) {
// empty
}

/**
* @param ReflectionClass<object>|ReflectionProperty $object
*/
public function __invoke(ReflectionClass|ReflectionProperty $object): Document {
$document = null;
$path = match (true) {
$object instanceof ReflectionProperty => $object->getDeclaringClass()->getFileName(),
default => $object->getFileName(),
};

if ($path !== false) {
$phpdoc = new PhpDoc((string) $object->getDocComment());
$context = $this->getContext($path);
$document = $phpdoc->getDocument($this->factory, $context, new FilePath($path));
} else {
$phpdoc = new PhpDoc((string) $object->getDocComment());
$document = new Document($phpdoc->getText(), null);
}

return $document;
}

private function getContext(string $path): NameContext {
// Resolved?
if (isset($this->context[$path])) {
return $this->context[$path];
}

// Resolve
$resolver = new NameResolver();
$traverser = new NodeTraverser();
$parser = (new ParserFactory())->createForNewestSupportedVersion();
$stmts = (array) $parser->parse((string) file_get_contents($path));

$traverser->addVisitor($resolver);
$traverser->traverse($stmts);

// Save
$this->context[$path] = $resolver->getNameContext();

// Return
return $this->context[$path];
}
}

0 comments on commit ebc708f

Please sign in to comment.