From e88ccf35701c27e1da3688b07d183f1b88884956 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:22:41 +0400 Subject: [PATCH 01/14] Base class for Reference mutations. --- .../Markdown/Mutations/Reference/Inline.php | 29 +-------------- .../Mutations/Reference/InlineTest.php | 1 + .../Markdown/Mutations/Reference/Mutation.php | 35 +++++++++++++++++++ .../Markdown/Mutations/Reference/Prefix.php | 26 ++------------ .../Mutations/Reference/PrefixTest.php | 1 + 5 files changed, 40 insertions(+), 52 deletions(-) create mode 100644 packages/documentator/src/Markdown/Mutations/Reference/Mutation.php diff --git a/packages/documentator/src/Markdown/Mutations/Reference/Inline.php b/packages/documentator/src/Markdown/Mutations/Reference/Inline.php index dfb7d071d..3f601d349 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/Inline.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/Inline.php @@ -2,15 +2,11 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Reference; -use Iterator; -use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Content; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location; -use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Reference; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Extensions\Reference\Node as ReferenceNode; use LastDragon_ru\LaraASP\Documentator\Markdown\Utils; -use League\CommonMark\Extension\CommonMark\Node\Inline\AbstractWebResource; use League\CommonMark\Extension\CommonMark\Node\Inline\Image; use League\CommonMark\Extension\CommonMark\Node\Inline\Link; use Override; @@ -20,11 +16,7 @@ /** * Inlines all references. */ -class Inline implements Mutation { - public function __construct() { - // empty - } - +readonly class Inline extends Mutation { /** * @inheritDoc */ @@ -56,23 +48,4 @@ public function __invoke(Document $document): iterable { } } } - - /** - * @return Iterator - */ - private function nodes(Document $document): Iterator { - // Just in case - yield from []; - - // Search - foreach ($document->node->iterator() as $node) { - if ($node instanceof AbstractWebResource && Reference::get($node) !== null) { - yield $node; - } elseif ($node instanceof ReferenceNode) { - yield $node; - } else { - // empty - } - } - } } diff --git a/packages/documentator/src/Markdown/Mutations/Reference/InlineTest.php b/packages/documentator/src/Markdown/Mutations/Reference/InlineTest.php index c15be722d..6f23e3e82 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/InlineTest.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/InlineTest.php @@ -10,6 +10,7 @@ * @internal */ #[CoversClass(Inline::class)] +#[CoversClass(Mutation::class)] final class InlineTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' diff --git a/packages/documentator/src/Markdown/Mutations/Reference/Mutation.php b/packages/documentator/src/Markdown/Mutations/Reference/Mutation.php new file mode 100644 index 000000000..9ff316e80 --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Reference/Mutation.php @@ -0,0 +1,35 @@ + + */ + protected function nodes(Document $document): Iterator { + // Just in case + yield from []; + + // Search + foreach ($document->node->iterator() as $node) { + if ($node instanceof AbstractWebResource && Reference::get($node) !== null) { + yield $node; + } elseif ($node instanceof ReferenceNode) { + yield $node; + } else { + // empty + } + } + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Reference/Prefix.php b/packages/documentator/src/Markdown/Mutations/Reference/Prefix.php index 5ec861bce..fa3c0bb49 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/Prefix.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/Prefix.php @@ -2,16 +2,13 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Reference; -use Iterator; use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; -use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Content as ContentData; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location as LocationData; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Reference as ReferenceData; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Extensions\Reference\Node as ReferenceNode; use LastDragon_ru\LaraASP\Documentator\Markdown\Utils; -use League\CommonMark\Extension\CommonMark\Node\Inline\AbstractWebResource; use League\CommonMark\Extension\CommonMark\Node\Inline\Image; use League\CommonMark\Extension\CommonMark\Node\Inline\Link; use Override; @@ -21,11 +18,11 @@ /** * Adds unique prefix for all references. */ -class Prefix implements Mutation { +readonly class Prefix extends Mutation { public function __construct( protected string $prefix, ) { - // empty + parent::__construct(); } /** @@ -74,23 +71,4 @@ public function __invoke(Document $document): iterable { } } } - - /** - * @return Iterator - */ - private function nodes(Document $document): Iterator { - // Just in case - yield from []; - - // Search - foreach ($document->node->iterator() as $node) { - if ($node instanceof AbstractWebResource && ReferenceData::get($node) !== null) { - yield $node; - } elseif ($node instanceof ReferenceNode) { - yield $node; - } else { - // empty - } - } - } } diff --git a/packages/documentator/src/Markdown/Mutations/Reference/PrefixTest.php b/packages/documentator/src/Markdown/Mutations/Reference/PrefixTest.php index feaa7179f..5980dec12 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/PrefixTest.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/PrefixTest.php @@ -11,6 +11,7 @@ * @internal */ #[CoversClass(Prefix::class)] +#[CoversClass(Mutation::class)] final class PrefixTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' From 9cac0276121ba6c369d7d9f1292c0835bef54f68 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:31:29 +0400 Subject: [PATCH 02/14] Base class for Link mutations. --- .../src/Markdown/Mutations/Link/Mutation.php | 29 +++++++++++++++++++ .../src/Markdown/Mutations/Link/Remove.php | 28 +----------------- .../Markdown/Mutations/Link/RemoveTest.php | 1 + .../Markdown/Mutations/Link/RemoveToSelf.php | 17 +++++++---- .../Mutations/Link/RemoveToSelfTest.php | 1 + 5 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 packages/documentator/src/Markdown/Mutations/Link/Mutation.php diff --git a/packages/documentator/src/Markdown/Mutations/Link/Mutation.php b/packages/documentator/src/Markdown/Mutations/Link/Mutation.php new file mode 100644 index 000000000..763810e28 --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Link/Mutation.php @@ -0,0 +1,29 @@ + + */ + protected function nodes(Document $document): Iterator { + // Just in case + yield from []; + + // Search + foreach ($document->node->iterator() as $node) { + if ($node instanceof Link) { + yield $node; + } + } + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Link/Remove.php b/packages/documentator/src/Markdown/Mutations/Link/Remove.php index e23793f2e..07d32f7be 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/Remove.php +++ b/packages/documentator/src/Markdown/Mutations/Link/Remove.php @@ -2,22 +2,15 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link; -use Iterator; -use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Content; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; -use League\CommonMark\Extension\CommonMark\Node\Inline\Link; use Override; /** * Removes all links. */ -readonly class Remove implements Mutation { - public function __construct() { - // empty - } - +readonly class Remove extends Mutation { /** * @inheritDoc */ @@ -38,23 +31,4 @@ public function __invoke(Document $document): iterable { // Return return true; } - - /** - * @return Iterator - */ - private function nodes(Document $document): Iterator { - // Just in case - yield from []; - - // Search - foreach ($document->node->iterator() as $node) { - if ($node instanceof Link && $this->isLink($document, $node)) { - yield $node; - } - } - } - - protected function isLink(Document $document, Link $node): bool { - return true; - } } diff --git a/packages/documentator/src/Markdown/Mutations/Link/RemoveTest.php b/packages/documentator/src/Markdown/Mutations/Link/RemoveTest.php index eaf179db1..491b3e944 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/RemoveTest.php +++ b/packages/documentator/src/Markdown/Mutations/Link/RemoveTest.php @@ -11,6 +11,7 @@ * @internal */ #[CoversClass(Remove::class)] +#[CoversClass(Mutation::class)] final class RemoveTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' diff --git a/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelf.php b/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelf.php index bb7666695..3b10fb90e 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelf.php +++ b/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelf.php @@ -2,9 +2,9 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link; +use Iterator; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Utils; -use League\CommonMark\Extension\CommonMark\Node\Inline\Link; use Override; use function rawurldecode; @@ -13,11 +13,18 @@ * Removes all links to the self. */ readonly class RemoveToSelf extends Remove { + /** + * @inheritDoc + */ #[Override] - protected function isLink(Document $document, Link $node): bool { - $url = rawurldecode($node->getUrl()); - $self = Utils::isPathRelative($url) && Utils::isPathToSelf($document, $url); + protected function nodes(Document $document): Iterator { + foreach (parent::nodes($document) as $key => $node) { + $url = rawurldecode($node->getUrl()); + $self = Utils::isPathRelative($url) && Utils::isPathToSelf($document, $url); - return $self; + if ($self) { + yield $key => $node; + } + } } } diff --git a/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelfTest.php b/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelfTest.php index 32c204f2b..0fc81ccf2 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelfTest.php +++ b/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelfTest.php @@ -11,6 +11,7 @@ * @internal */ #[CoversClass(RemoveToSelf::class)] +#[CoversClass(Mutation::class)] final class RemoveToSelfTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' From db7de6acc24d4fc1e1d732f433e74856f7bc5e4b Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:43:01 +0400 Subject: [PATCH 03/14] Better mutations names * `\LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\Remove` => `\LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\Unlink` * `\LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\RemoveToSelf` => `\LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\UnlinkToSelf` --- .../src/Markdown/Mutations/Document/MakeSplittable.php | 4 ++-- .../src/Markdown/Mutations/Link/{Remove.php => Unlink.php} | 4 ++-- .../Mutations/Link/{RemoveTest.php => UnlinkTest.php} | 6 +++--- .../Mutations/Link/{RemoveToSelf.php => UnlinkToSelf.php} | 4 ++-- .../Link/{RemoveToSelfTest.php => UnlinkToSelfTest.php} | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) rename packages/documentator/src/Markdown/Mutations/Link/{Remove.php => Unlink.php} (93%) rename packages/documentator/src/Markdown/Mutations/Link/{RemoveTest.php => UnlinkTest.php} (94%) rename packages/documentator/src/Markdown/Mutations/Link/{RemoveToSelf.php => UnlinkToSelf.php} (89%) rename packages/documentator/src/Markdown/Mutations/Link/{RemoveToSelfTest.php => UnlinkToSelfTest.php} (96%) diff --git a/packages/documentator/src/Markdown/Mutations/Document/MakeSplittable.php b/packages/documentator/src/Markdown/Mutations/Document/MakeSplittable.php index 209f3a1e2..a9f5c29f7 100644 --- a/packages/documentator/src/Markdown/Mutations/Document/MakeSplittable.php +++ b/packages/documentator/src/Markdown/Mutations/Document/MakeSplittable.php @@ -4,7 +4,7 @@ use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Composite; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Footnote\Remove as FootnotesRemove; -use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\RemoveToSelf; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\UnlinkToSelf as LinksUnlinkToSelf; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Reference\Inline as ReferencesInline; /** @@ -17,7 +17,7 @@ public function __construct() { parent::__construct( new FootnotesRemove(), new ReferencesInline(), - new RemoveToSelf(), + new LinksUnlinkToSelf(), ); } } diff --git a/packages/documentator/src/Markdown/Mutations/Link/Remove.php b/packages/documentator/src/Markdown/Mutations/Link/Unlink.php similarity index 93% rename from packages/documentator/src/Markdown/Mutations/Link/Remove.php rename to packages/documentator/src/Markdown/Mutations/Link/Unlink.php index 07d32f7be..98b42f7a5 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/Remove.php +++ b/packages/documentator/src/Markdown/Mutations/Link/Unlink.php @@ -8,9 +8,9 @@ use Override; /** - * Removes all links. + * Unlink all links. */ -readonly class Remove extends Mutation { +readonly class Unlink extends Mutation { /** * @inheritDoc */ diff --git a/packages/documentator/src/Markdown/Mutations/Link/RemoveTest.php b/packages/documentator/src/Markdown/Mutations/Link/UnlinkTest.php similarity index 94% rename from packages/documentator/src/Markdown/Mutations/Link/RemoveTest.php rename to packages/documentator/src/Markdown/Mutations/Link/UnlinkTest.php index 491b3e944..537f26716 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/RemoveTest.php +++ b/packages/documentator/src/Markdown/Mutations/Link/UnlinkTest.php @@ -10,9 +10,9 @@ /** * @internal */ -#[CoversClass(Remove::class)] +#[CoversClass(Unlink::class)] #[CoversClass(Mutation::class)] -final class RemoveTest extends TestCase { +final class UnlinkTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' # Header @@ -41,7 +41,7 @@ public function testInvoke(): void { $markdown = $this->app()->make(Markdown::class); $document = $markdown->parse($content, new FilePath('path/to/file.md')); - $actual = (string) $document->mutate(new Remove()); + $actual = (string) $document->mutate(new Unlink()); self::assertSame( <<<'MARKDOWN' diff --git a/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelf.php b/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelf.php similarity index 89% rename from packages/documentator/src/Markdown/Mutations/Link/RemoveToSelf.php rename to packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelf.php index 3b10fb90e..838bf9f77 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelf.php +++ b/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelf.php @@ -10,9 +10,9 @@ use function rawurldecode; /** - * Removes all links to the self. + * Unlink all links to the self. */ -readonly class RemoveToSelf extends Remove { +readonly class UnlinkToSelf extends Unlink { /** * @inheritDoc */ diff --git a/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelfTest.php b/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelfTest.php similarity index 96% rename from packages/documentator/src/Markdown/Mutations/Link/RemoveToSelfTest.php rename to packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelfTest.php index 0fc81ccf2..9d321cb49 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/RemoveToSelfTest.php +++ b/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelfTest.php @@ -10,9 +10,9 @@ /** * @internal */ -#[CoversClass(RemoveToSelf::class)] +#[CoversClass(UnlinkToSelf::class)] #[CoversClass(Mutation::class)] -final class RemoveToSelfTest extends TestCase { +final class UnlinkToSelfTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' # Header @@ -51,7 +51,7 @@ public function testInvoke(): void { $markdown = $this->app()->make(Markdown::class); $document = $markdown->parse($content, new FilePath('path/to/file.md')); - $actual = (string) $document->mutate(new RemoveToSelf()); + $actual = (string) $document->mutate(new UnlinkToSelf()); self::assertSame( <<<'MARKDOWN' From 3e9d1cacd67953f6a5280d0ddad1df385abcac4b Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 16 Jan 2025 09:34:55 +0400 Subject: [PATCH 04/14] Iterable key type fix in `\LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation`. --- packages/documentator/src/Markdown/Contracts/Mutation.php | 2 +- packages/documentator/src/Markdown/Mutations/Changeset.php | 2 +- .../documentator/src/Markdown/Mutations/Footnote/Remove.php | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/documentator/src/Markdown/Contracts/Mutation.php b/packages/documentator/src/Markdown/Contracts/Mutation.php index 29e73ff66..f98a44cbe 100644 --- a/packages/documentator/src/Markdown/Contracts/Mutation.php +++ b/packages/documentator/src/Markdown/Contracts/Mutation.php @@ -7,7 +7,7 @@ interface Mutation { /** - * @return iterable + * @return iterable */ public function __invoke(Document $document): iterable; } diff --git a/packages/documentator/src/Markdown/Mutations/Changeset.php b/packages/documentator/src/Markdown/Mutations/Changeset.php index 34492ab9a..269038c45 100644 --- a/packages/documentator/src/Markdown/Mutations/Changeset.php +++ b/packages/documentator/src/Markdown/Mutations/Changeset.php @@ -13,7 +13,7 @@ readonly class Changeset implements Mutation { public function __construct( /** - * @var iterable + * @var iterable */ protected iterable $changes, ) { diff --git a/packages/documentator/src/Markdown/Mutations/Footnote/Remove.php b/packages/documentator/src/Markdown/Mutations/Footnote/Remove.php index 61c730526..2796e1749 100644 --- a/packages/documentator/src/Markdown/Mutations/Footnote/Remove.php +++ b/packages/documentator/src/Markdown/Mutations/Footnote/Remove.php @@ -2,7 +2,6 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Footnote; -use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location as LocationData; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; @@ -19,7 +18,7 @@ public function __construct() { } /** - * @return iterable + * @inheritDoc */ #[Override] public function __invoke(Document $document): iterable { From ab6b4b7b742a5c66943cbce1a4989ca90c45dba4 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:11:16 +0400 Subject: [PATCH 05/14] `\LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Composite` renamed to `\LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\CompositeMutation`. --- .../Mutations/{Composite.php => CompositeMutation.php} | 2 +- .../{CompositeTest.php => CompositeMutationTest.php} | 6 +++--- .../src/Markdown/Mutations/Document/MakeInlinable.php | 4 ++-- .../src/Markdown/Mutations/Document/MakeSplittable.php | 4 ++-- .../documentator/src/Processor/Tasks/Preprocess/Context.php | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename packages/documentator/src/Markdown/Mutations/{Composite.php => CompositeMutation.php} (93%) rename packages/documentator/src/Markdown/Mutations/{CompositeTest.php => CompositeMutationTest.php} (89%) diff --git a/packages/documentator/src/Markdown/Mutations/Composite.php b/packages/documentator/src/Markdown/Mutations/CompositeMutation.php similarity index 93% rename from packages/documentator/src/Markdown/Mutations/Composite.php rename to packages/documentator/src/Markdown/Mutations/CompositeMutation.php index e5a53ed60..1b0d133ec 100644 --- a/packages/documentator/src/Markdown/Mutations/Composite.php +++ b/packages/documentator/src/Markdown/Mutations/CompositeMutation.php @@ -9,7 +9,7 @@ /** * Merges all mutations into one. */ -readonly class Composite implements Mutation { +readonly class CompositeMutation implements Mutation { /** * @var array */ diff --git a/packages/documentator/src/Markdown/Mutations/CompositeTest.php b/packages/documentator/src/Markdown/Mutations/CompositeMutationTest.php similarity index 89% rename from packages/documentator/src/Markdown/Mutations/CompositeTest.php rename to packages/documentator/src/Markdown/Mutations/CompositeMutationTest.php index c8416c25f..892295366 100644 --- a/packages/documentator/src/Markdown/Mutations/CompositeTest.php +++ b/packages/documentator/src/Markdown/Mutations/CompositeMutationTest.php @@ -14,8 +14,8 @@ /** * @internal */ -#[CoversClass(Composite::class)] -final class CompositeTest extends TestCase { +#[CoversClass(CompositeMutation::class)] +final class CompositeMutationTest extends TestCase { public function testInvoke(): void { $markdown = $this->app()->make(Markdown::class); $document = $markdown->parse(''); @@ -38,7 +38,7 @@ public function testInvoke(): void { ->once() ->andReturn($bChanges); - $mutation = new Composite($aMutation, $bMutation); + $mutation = new CompositeMutation($aMutation, $bMutation); $changes = $mutation($document); $expected = array_merge($aChanges, $bChanges); $actual = []; diff --git a/packages/documentator/src/Markdown/Mutations/Document/MakeInlinable.php b/packages/documentator/src/Markdown/Mutations/Document/MakeInlinable.php index 1ba917292..4b6cd7005 100644 --- a/packages/documentator/src/Markdown/Mutations/Document/MakeInlinable.php +++ b/packages/documentator/src/Markdown/Mutations/Document/MakeInlinable.php @@ -2,7 +2,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document; -use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Composite; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\CompositeMutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Footnote\Prefix as FootnotesPrefix; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Reference\Prefix as ReferencesPrefix; @@ -10,7 +10,7 @@ * Renames all references/footnotes/etc to make possible inline the * document into another document without conflicts/ambiguities. */ -readonly class MakeInlinable extends Composite { +readonly class MakeInlinable extends CompositeMutation { public function __construct(string $prefix) { parent::__construct( new FootnotesPrefix($prefix), diff --git a/packages/documentator/src/Markdown/Mutations/Document/MakeSplittable.php b/packages/documentator/src/Markdown/Mutations/Document/MakeSplittable.php index a9f5c29f7..a11ecf133 100644 --- a/packages/documentator/src/Markdown/Mutations/Document/MakeSplittable.php +++ b/packages/documentator/src/Markdown/Mutations/Document/MakeSplittable.php @@ -2,7 +2,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document; -use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Composite; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\CompositeMutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Footnote\Remove as FootnotesRemove; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\UnlinkToSelf as LinksUnlinkToSelf; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Reference\Inline as ReferencesInline; @@ -12,7 +12,7 @@ * extract any block/paragraph from the document without losing * information. */ -readonly class MakeSplittable extends Composite { +readonly class MakeSplittable extends CompositeMutation { public function __construct() { parent::__construct( new FootnotesRemove(), diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Context.php b/packages/documentator/src/Processor/Tasks/Preprocess/Context.php index 68105d259..fa7102d9b 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Context.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Context.php @@ -5,7 +5,7 @@ use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Extensions\Reference\Node; -use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Composite; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\CompositeMutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\MakeInlinable; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\MakeSplittable; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\Move; @@ -51,7 +51,7 @@ public function toSplittable(Document $document): Document { private function getMutation(Document $document): Mutation { $path = $this->file->getFilePath($document->path?->getName() ?? ''); - return new Composite( + return new CompositeMutation( new Move($path), new Unwrap(), $this->mutation, From 836b8d5e761db5250dae12187d731356c7756e17 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:19:28 +0400 Subject: [PATCH 06/14] New `\LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Extraction` contract to extract parts of document. --- .../src/Markdown/Contracts/Extraction.php | 13 +++++ .../documentator/src/Markdown/Document.php | 9 ++-- .../src/Markdown/DocumentTest.php | 22 +++++++- .../Mutations/CompositeExtraction.php | 35 +++++++++++++ .../Mutations/CompositeExtractionTest.php | 52 +++++++++++++++++++ .../src/Markdown/Mutations/Subset.php | 30 +++++++++++ 6 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 packages/documentator/src/Markdown/Contracts/Extraction.php create mode 100644 packages/documentator/src/Markdown/Mutations/CompositeExtraction.php create mode 100644 packages/documentator/src/Markdown/Mutations/CompositeExtractionTest.php create mode 100644 packages/documentator/src/Markdown/Mutations/Subset.php diff --git a/packages/documentator/src/Markdown/Contracts/Extraction.php b/packages/documentator/src/Markdown/Contracts/Extraction.php new file mode 100644 index 000000000..ce68fbaf3 --- /dev/null +++ b/packages/documentator/src/Markdown/Contracts/Extraction.php @@ -0,0 +1,13 @@ + + */ + public function __invoke(Document $document): iterable; +} diff --git a/packages/documentator/src/Markdown/Document.php b/packages/documentator/src/Markdown/Document.php index a1ea18ff2..fa2cf35d9 100644 --- a/packages/documentator/src/Markdown/Document.php +++ b/packages/documentator/src/Markdown/Document.php @@ -7,6 +7,7 @@ use LastDragon_ru\LaraASP\Documentator\Editor\Coordinate; use LastDragon_ru\LaraASP\Documentator\Editor\Editor; use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; +use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Extraction; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Markdown; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Lines; @@ -101,12 +102,14 @@ public function getText(iterable $location): string { return (string) $this->getEditor()->extract([$location]); } - public function mutate(Mutation ...$mutations): self { + public function mutate(Mutation|Extraction ...$mutations): self { $document = clone $this; foreach ($mutations as $mutation) { - $changes = $mutation($document); - $content = mb_trim((string) $document->getEditor()->mutate($changes))."\n"; + $content = $mutation instanceof Extraction + ? $document->getEditor()->extract($mutation($document)) + : $document->getEditor()->mutate($mutation($document)); + $content = mb_trim((string) $content)."\n"; $document = $this->markdown->parse($content, $document->path); } diff --git a/packages/documentator/src/Markdown/DocumentTest.php b/packages/documentator/src/Markdown/DocumentTest.php index f28678a0f..51fbf971c 100644 --- a/packages/documentator/src/Markdown/DocumentTest.php +++ b/packages/documentator/src/Markdown/DocumentTest.php @@ -3,6 +3,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown; use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Append; +use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Extraction; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Markdown; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Changeset; @@ -55,7 +56,7 @@ public function testIsEmpty(bool $expected, string $content): void { self::assertSame($expected, $actual); } - public function testMutate(): void { + public function testMutateMutation(): void { $markdown = $this->app()->make(Markdown::class); $document = $markdown->parse(''); $mutation = Mockery::mock(Mutation::class); @@ -74,6 +75,25 @@ public function testMutate(): void { self::assertEquals($clone, $document); } + public function testMutateExtraction(): void { + $markdown = $this->app()->make(Markdown::class); + $document = $markdown->parse(''); + $mutation = Mockery::mock(Extraction::class); + $mutation + ->shouldReceive('__invoke') + ->with(Mockery::type(Document::class)) + ->once() + ->andReturn([ + // empty + ]); + + $clone = clone $document; + $mutated = $document->mutate($mutation); + + self::assertNotSame($document, $mutated); + self::assertEquals($clone, $document); + } + #[DataProvider('dataProviderToString')] public function testToString(string $expected, string $content, ?Mutation $mutation): void { $markdown = $this->app()->make(Markdown::class); diff --git a/packages/documentator/src/Markdown/Mutations/CompositeExtraction.php b/packages/documentator/src/Markdown/Mutations/CompositeExtraction.php new file mode 100644 index 000000000..eceddfd9f --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/CompositeExtraction.php @@ -0,0 +1,35 @@ + + */ + private array $extractions; + + public function __construct(Extraction ...$extractions) { + $this->extractions = $extractions; + } + + /** + * @inheritDoc + */ + #[Override] + public function __invoke(Document $document): iterable { + // Just in case + yield from []; + + // Process all + foreach ($this->extractions as $extraction) { + yield from $extraction($document); + } + } +} diff --git a/packages/documentator/src/Markdown/Mutations/CompositeExtractionTest.php b/packages/documentator/src/Markdown/Mutations/CompositeExtractionTest.php new file mode 100644 index 000000000..cd674e5fa --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/CompositeExtractionTest.php @@ -0,0 +1,52 @@ +app()->make(Markdown::class); + $document = $markdown->parse(''); + $aChanges = [ + [new Location(1, 1, 10), 'a'], + ]; + $bChanges = [ + [new Location(2, 3, 0), 'b'], + ]; + $aExtraction = Mockery::mock(Extraction::class); + $aExtraction + ->shouldReceive('__invoke') + ->with($document) + ->once() + ->andReturn($aChanges); + $bExtraction = Mockery::mock(Extraction::class); + $bExtraction + ->shouldReceive('__invoke') + ->with($document) + ->once() + ->andReturn($bChanges); + + $extraction = new CompositeExtraction($aExtraction, $bExtraction); + $locations = $extraction($document); + $expected = array_merge($aChanges, $bChanges); + $actual = []; + + foreach ($locations as $location) { + $actual[] = $location; + } + + self::assertEquals($expected, $actual); + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Subset.php b/packages/documentator/src/Markdown/Mutations/Subset.php new file mode 100644 index 000000000..54101875e --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Subset.php @@ -0,0 +1,30 @@ + + */ + protected iterable $extractions, + ) { + // empty + } + + /** + * @inheritDoc + */ + #[Override] + public function __invoke(Document $document): iterable { + return $this->extractions; + } +} From 1e287dbebf604d9fb577ff0998917c21d336181a Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 16 Jan 2025 11:10:03 +0400 Subject: [PATCH 07/14] Better base classes for mutations. --- .../src/Markdown/Mutations/Document/Move.php | 5 ++-- .../src/Markdown/Mutations/Footnote/Base.php | 28 +++++++++++++++++ .../Markdown/Mutations/Footnote/Prefix.php | 12 ++------ .../Markdown/Mutations/Footnote/Remove.php | 21 +++---------- .../src/Markdown/Mutations/Heading/Base.php | 30 +++++++++++++++++++ .../Markdown/Mutations/Heading/Renumber.php | 21 +++++-------- .../Mutations/Link/{Mutation.php => Base.php} | 7 ++--- .../src/Markdown/Mutations/Link/Unlink.php | 3 +- .../Markdown/Mutations/Link/UnlinkTest.php | 2 +- .../Markdown/Mutations/Link/UnlinkToSelf.php | 6 ++-- .../Mutations/Link/UnlinkToSelfTest.php | 2 +- .../Reference/{Mutation.php => Base.php} | 8 ++--- .../Markdown/Mutations/Reference/Inline.php | 3 +- .../Mutations/Reference/InlineTest.php | 2 +- .../Markdown/Mutations/Reference/Prefix.php | 3 +- .../Mutations/Reference/PrefixTest.php | 2 +- 16 files changed, 94 insertions(+), 61 deletions(-) create mode 100644 packages/documentator/src/Markdown/Mutations/Footnote/Base.php create mode 100644 packages/documentator/src/Markdown/Mutations/Heading/Base.php rename packages/documentator/src/Markdown/Mutations/Link/{Mutation.php => Base.php} (77%) rename packages/documentator/src/Markdown/Mutations/Reference/{Mutation.php => Base.php} (74%) diff --git a/packages/documentator/src/Markdown/Mutations/Document/Move.php b/packages/documentator/src/Markdown/Mutations/Document/Move.php index 6654c29d2..23af2179a 100644 --- a/packages/documentator/src/Markdown/Mutations/Document/Move.php +++ b/packages/documentator/src/Markdown/Mutations/Document/Move.php @@ -2,7 +2,6 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document; -use Iterator; use LastDragon_ru\LaraASP\Core\Path\FilePath; use LastDragon_ru\LaraASP\Documentator\Editor\Coordinate; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; @@ -124,9 +123,9 @@ public function __invoke(Document $document): iterable { } /** - * @return Iterator + * @return iterable */ - private function nodes(Document $document): Iterator { + private function nodes(Document $document): iterable { // Just in case yield from []; diff --git a/packages/documentator/src/Markdown/Mutations/Footnote/Base.php b/packages/documentator/src/Markdown/Mutations/Footnote/Base.php new file mode 100644 index 000000000..ae809802c --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Footnote/Base.php @@ -0,0 +1,28 @@ + + */ + protected function nodes(Document $document): iterable { + // Just in case + yield from []; + + // Search + foreach ($document->node->iterator() as $node) { + if ($node instanceof FootnoteRef || $node instanceof Footnote) { + yield $node; + } + } + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Footnote/Prefix.php b/packages/documentator/src/Markdown/Mutations/Footnote/Prefix.php index 39ef64102..880853e95 100644 --- a/packages/documentator/src/Markdown/Mutations/Footnote/Prefix.php +++ b/packages/documentator/src/Markdown/Mutations/Footnote/Prefix.php @@ -16,11 +16,11 @@ /** * Adds unique prefix for all footnotes. */ -readonly class Prefix implements Mutation { +readonly class Prefix extends Base implements Mutation { public function __construct( protected string $prefix, ) { - // empty + parent::__construct(); } /** @@ -32,13 +32,7 @@ public function __invoke(Document $document): iterable { yield from []; // Process - foreach ($document->node->iterator() as $node) { - // Footnote? - if (!($node instanceof FootnoteRef) && !($node instanceof Footnote)) { - continue; - } - - // Replace + foreach ($this->nodes($document) as $node) { $label = $this->getLabel($document, $node); $location = $this->getLabelLocation($node, $label); diff --git a/packages/documentator/src/Markdown/Mutations/Footnote/Remove.php b/packages/documentator/src/Markdown/Mutations/Footnote/Remove.php index 2796e1749..ef25b69e5 100644 --- a/packages/documentator/src/Markdown/Mutations/Footnote/Remove.php +++ b/packages/documentator/src/Markdown/Mutations/Footnote/Remove.php @@ -3,20 +3,14 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Footnote; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; -use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location as LocationData; +use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; -use League\CommonMark\Extension\Footnote\Node\Footnote; -use League\CommonMark\Extension\Footnote\Node\FootnoteRef; use Override; /** * Removes all footnotes. */ -readonly class Remove implements Mutation { - public function __construct() { - // empty - } - +readonly class Remove extends Base implements Mutation { /** * @inheritDoc */ @@ -26,15 +20,8 @@ public function __invoke(Document $document): iterable { yield from []; // Process - foreach ($document->node->iterator() as $node) { - $location = match (true) { - $node instanceof FootnoteRef, $node instanceof Footnote => LocationData::get($node), - default => null, - }; - - if ($location !== null) { - yield [$location, null]; - } + foreach ($this->nodes($document) as $node) { + yield [Location::get($node), null]; } } } diff --git a/packages/documentator/src/Markdown/Mutations/Heading/Base.php b/packages/documentator/src/Markdown/Mutations/Heading/Base.php new file mode 100644 index 000000000..a24bf804a --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Heading/Base.php @@ -0,0 +1,30 @@ + + */ + protected function nodes(Document $document): iterable { + // Just in case + yield from []; + + // Search + foreach ($document->node->iterator(NodeIterator::FLAG_BLOCKS_ONLY) as $node) { + if ($node instanceof Heading) { + yield $node; + } + } + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php b/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php index 8341452b1..1e433df45 100644 --- a/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php +++ b/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php @@ -20,14 +20,14 @@ /** * Updates all ATX headings levels. */ -class Renumber implements Mutation { +readonly class Renumber extends Base implements Mutation { public function __construct( /** * @var int<1, 6> */ protected int $startLevel, ) { - // empty + parent::__construct(); } /** @@ -39,7 +39,7 @@ public function __invoke(Document $document): iterable { yield from []; // Process - $highest = 6; + $highest = static::MaxLevel; $headings = $this->getHeadings($document, $highest); $diff = $this->startLevel - $highest; @@ -48,7 +48,7 @@ public function __invoke(Document $document): iterable { } foreach ($headings as [$heading, $location, $text]) { - $level = min(6, $heading->getLevel() + $diff); + $level = min(static::MaxLevel, $heading->getLevel() + $diff); $prefix = mb_substr($text, 0, (int) mb_strpos($text, '#')); $eols = mb_strlen($text) - mb_strlen(mb_trim($text, "\n")); $text = mb_substr($text, mb_strlen($prefix)); @@ -64,14 +64,9 @@ public function __invoke(Document $document): iterable { private function getHeadings(Document $document, int &$highest): array { $headings = []; - foreach ($document->node->iterator() as $node) { - // Heading? - if (!($node instanceof Heading)) { - continue; - } - + foreach ($this->nodes($document) as $heading) { // ATX? - $location = LocationData::get($node); + $location = LocationData::get($heading); $line = $document->getText($location); if (!str_starts_with(mb_trim($line), '#')) { @@ -79,8 +74,8 @@ private function getHeadings(Document $document, int &$highest): array { } // Ok - $headings[] = [$node, $location, $line]; - $highest = min($highest, $node->getLevel()); + $headings[] = [$heading, $location, $line]; + $highest = min($highest, $heading->getLevel()); } return $headings; diff --git a/packages/documentator/src/Markdown/Mutations/Link/Mutation.php b/packages/documentator/src/Markdown/Mutations/Link/Base.php similarity index 77% rename from packages/documentator/src/Markdown/Mutations/Link/Mutation.php rename to packages/documentator/src/Markdown/Mutations/Link/Base.php index 763810e28..544b92c47 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/Mutation.php +++ b/packages/documentator/src/Markdown/Mutations/Link/Base.php @@ -2,20 +2,19 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link; -use Iterator; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation as MutationContract; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use League\CommonMark\Extension\CommonMark\Node\Inline\Link; -abstract readonly class Mutation implements MutationContract { +abstract readonly class Base implements MutationContract { public function __construct() { // empty } /** - * @return Iterator + * @return iterable */ - protected function nodes(Document $document): Iterator { + protected function nodes(Document $document): iterable { // Just in case yield from []; diff --git a/packages/documentator/src/Markdown/Mutations/Link/Unlink.php b/packages/documentator/src/Markdown/Mutations/Link/Unlink.php index 98b42f7a5..76e923727 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/Unlink.php +++ b/packages/documentator/src/Markdown/Mutations/Link/Unlink.php @@ -2,6 +2,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link; +use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Content; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; @@ -10,7 +11,7 @@ /** * Unlink all links. */ -readonly class Unlink extends Mutation { +readonly class Unlink extends Base implements Mutation { /** * @inheritDoc */ diff --git a/packages/documentator/src/Markdown/Mutations/Link/UnlinkTest.php b/packages/documentator/src/Markdown/Mutations/Link/UnlinkTest.php index 537f26716..035f37d8a 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/UnlinkTest.php +++ b/packages/documentator/src/Markdown/Mutations/Link/UnlinkTest.php @@ -11,7 +11,7 @@ * @internal */ #[CoversClass(Unlink::class)] -#[CoversClass(Mutation::class)] +#[CoversClass(Base::class)] final class UnlinkTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' diff --git a/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelf.php b/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelf.php index 838bf9f77..b45e69034 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelf.php +++ b/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelf.php @@ -2,7 +2,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link; -use Iterator; +use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Utils; use Override; @@ -12,12 +12,12 @@ /** * Unlink all links to the self. */ -readonly class UnlinkToSelf extends Unlink { +readonly class UnlinkToSelf extends Unlink implements Mutation { /** * @inheritDoc */ #[Override] - protected function nodes(Document $document): Iterator { + protected function nodes(Document $document): iterable { foreach (parent::nodes($document) as $key => $node) { $url = rawurldecode($node->getUrl()); $self = Utils::isPathRelative($url) && Utils::isPathToSelf($document, $url); diff --git a/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelfTest.php b/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelfTest.php index 9d321cb49..0613eaa2f 100644 --- a/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelfTest.php +++ b/packages/documentator/src/Markdown/Mutations/Link/UnlinkToSelfTest.php @@ -11,7 +11,7 @@ * @internal */ #[CoversClass(UnlinkToSelf::class)] -#[CoversClass(Mutation::class)] +#[CoversClass(Base::class)] final class UnlinkToSelfTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' diff --git a/packages/documentator/src/Markdown/Mutations/Reference/Mutation.php b/packages/documentator/src/Markdown/Mutations/Reference/Base.php similarity index 74% rename from packages/documentator/src/Markdown/Mutations/Reference/Mutation.php rename to packages/documentator/src/Markdown/Mutations/Reference/Base.php index 9ff316e80..08b2ff9d2 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/Mutation.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/Base.php @@ -2,22 +2,20 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Reference; -use Iterator; -use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation as MutationContract; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Reference; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Extensions\Reference\Node as ReferenceNode; use League\CommonMark\Extension\CommonMark\Node\Inline\AbstractWebResource; -abstract readonly class Mutation implements MutationContract { +abstract readonly class Base { public function __construct() { // empty } /** - * @return Iterator + * @return iterable */ - protected function nodes(Document $document): Iterator { + protected function nodes(Document $document): iterable { // Just in case yield from []; diff --git a/packages/documentator/src/Markdown/Mutations/Reference/Inline.php b/packages/documentator/src/Markdown/Mutations/Reference/Inline.php index 3f601d349..f7ebc0752 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/Inline.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/Inline.php @@ -2,6 +2,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Reference; +use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Content; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; @@ -16,7 +17,7 @@ /** * Inlines all references. */ -readonly class Inline extends Mutation { +readonly class Inline extends Base implements Mutation { /** * @inheritDoc */ diff --git a/packages/documentator/src/Markdown/Mutations/Reference/InlineTest.php b/packages/documentator/src/Markdown/Mutations/Reference/InlineTest.php index 6f23e3e82..2560c0aff 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/InlineTest.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/InlineTest.php @@ -10,7 +10,7 @@ * @internal */ #[CoversClass(Inline::class)] -#[CoversClass(Mutation::class)] +#[CoversClass(Base::class)] final class InlineTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' diff --git a/packages/documentator/src/Markdown/Mutations/Reference/Prefix.php b/packages/documentator/src/Markdown/Mutations/Reference/Prefix.php index fa3c0bb49..9fa837c72 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/Prefix.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/Prefix.php @@ -3,6 +3,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Reference; use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; +use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Content as ContentData; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location as LocationData; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Reference as ReferenceData; @@ -18,7 +19,7 @@ /** * Adds unique prefix for all references. */ -readonly class Prefix extends Mutation { +readonly class Prefix extends Base implements Mutation { public function __construct( protected string $prefix, ) { diff --git a/packages/documentator/src/Markdown/Mutations/Reference/PrefixTest.php b/packages/documentator/src/Markdown/Mutations/Reference/PrefixTest.php index 5980dec12..2df92f05e 100644 --- a/packages/documentator/src/Markdown/Mutations/Reference/PrefixTest.php +++ b/packages/documentator/src/Markdown/Mutations/Reference/PrefixTest.php @@ -11,7 +11,7 @@ * @internal */ #[CoversClass(Prefix::class)] -#[CoversClass(Mutation::class)] +#[CoversClass(Base::class)] final class PrefixTest extends TestCase { public function testInvoke(): void { $content = <<<'MARKDOWN' From d3f787f2a5a60fc851ded2ca16681ab9109296ef Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:26:44 +0400 Subject: [PATCH 08/14] Setext heading support for `\LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Heading\Renumber`. --- .../Markdown/Mutations/Heading/Renumber.php | 77 +++++++++++-------- .../Mutations/Heading/RenumberTest.php | 51 +++++++----- 2 files changed, 80 insertions(+), 48 deletions(-) diff --git a/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php b/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php index 1e433df45..40893561d 100644 --- a/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php +++ b/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php @@ -2,23 +2,25 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Heading; -use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location as LocationData; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; -use League\CommonMark\Extension\CommonMark\Node\Block\Heading; +use LastDragon_ru\LaraASP\Documentator\Utils\Text; use Override; +use function array_map; +use function array_slice; +use function implode; +use function mb_ltrim; +use function mb_rtrim; use function mb_strlen; -use function mb_strpos; -use function mb_substr; use function mb_trim; use function min; use function str_repeat; use function str_starts_with; /** - * Updates all ATX headings levels. + * Updates all headings levels. */ readonly class Renumber extends Base implements Mutation { public function __construct( @@ -39,45 +41,60 @@ public function __invoke(Document $document): iterable { yield from []; // Process - $highest = static::MaxLevel; - $headings = $this->getHeadings($document, $highest); - $diff = $this->startLevel - $highest; + $initial = static::MaxLevel; + $nodes = $this->nodes($document, $initial); + $diff = $this->startLevel - $initial; if ($diff === 0) { return; } - foreach ($headings as [$heading, $location, $text]) { - $level = min(static::MaxLevel, $heading->getLevel() + $diff); - $prefix = mb_substr($text, 0, (int) mb_strpos($text, '#')); - $eols = mb_strlen($text) - mb_strlen(mb_trim($text, "\n")); - $text = mb_substr($text, mb_strlen($prefix)); - $text = $prefix.str_repeat('#', $level).' '.mb_trim(mb_trim($text, '#')).str_repeat("\n", $eols); + foreach ($nodes as $node) { + $location = LocationData::get($node); + $heading = $document->getText($location); + $setext = $this->isSetext($heading); + $level = min(static::MaxLevel, $node->getLevel() + $diff); + $eols = str_repeat("\n", mb_strlen($heading) - mb_strlen(mb_rtrim($heading, "\n"))); + $text = mb_trim($heading); + $lines = $setext + ? array_slice(Text::getLines($text), 0, -1) + : [mb_trim($text, '#')]; + $lines = array_map(mb_trim(...), $lines); + $prefix = ''; + $suffix = ''; - yield [$location, $text]; + if ($setext && $level <= 2) { + $text = implode("\n", $lines); + $suffix = "\n".str_repeat($level === 1 ? '=' : '-', 5); + } else { + $prefix = str_repeat('#', $level).' '; + $text = implode(' ', $lines); + } + + yield [$location, $prefix.$text.$suffix.$eols]; } } /** - * @return list + * @inheritDoc */ - private function getHeadings(Document $document, int &$highest): array { - $headings = []; + #[Override] + protected function nodes(Document $document, int &$initial = 0): iterable { + $nodes = []; - foreach ($this->nodes($document) as $heading) { - // ATX? - $location = LocationData::get($heading); - $line = $document->getText($location); + foreach (parent::nodes($document) as $node) { + $initial = min($initial, $node->getLevel()); + $nodes[] = $node; + } - if (!str_starts_with(mb_trim($line), '#')) { - continue; - } + return $nodes; + } - // Ok - $headings[] = [$heading, $location, $line]; - $highest = min($highest, $heading->getLevel()); - } + private function isAtx(string $heading): bool { + return str_starts_with(mb_ltrim($heading), '#'); + } - return $headings; + private function isSetext(string $heading): bool { + return !$this->isAtx($heading); } } diff --git a/packages/documentator/src/Markdown/Mutations/Heading/RenumberTest.php b/packages/documentator/src/Markdown/Mutations/Heading/RenumberTest.php index c17d9a35e..6c62c82d4 100644 --- a/packages/documentator/src/Markdown/Mutations/Heading/RenumberTest.php +++ b/packages/documentator/src/Markdown/Mutations/Heading/RenumberTest.php @@ -73,15 +73,14 @@ public static function dataProviderInvoke(): array { Text text. ## Special - #### foo - ### foo - ## foo + #### foo + ### foo + ## foo Foo *bar* - ========= + ----- - Foo *bar* - --------- + ### Foo *bar* ### Header 2 @@ -132,12 +131,17 @@ public static function dataProviderInvoke(): array { <<<'MARKDOWN' ## Header 2 + * item + * item + # Header 1 Text text. ## Header 2 + * item + Text text. ### Header 3 @@ -148,27 +152,35 @@ public static function dataProviderInvoke(): array { Text text. # Special - ### foo - ## foo - # foo + ### foo + ## foo + # foo Foo *bar* - ========= + ===== - Foo *bar* - --------- + ## Foo *bar* + + ## Header 2 + + * item MARKDOWN, 1, <<<'MARKDOWN' ### Header 2 + * item + * item + ## Header 1 Text text. ### Header 2 + * item + Text text. #### Header 3 @@ -179,15 +191,18 @@ public static function dataProviderInvoke(): array { Text text. ## Special - #### foo - ### foo - ## foo + #### foo + ### foo + ## foo Foo *bar* - ========= + ----- - Foo *bar* - --------- + ### Foo *bar* + + ### Header 2 + + * item MARKDOWN, ], ]; From 91ba8292dca335ffe1f35516656061cbe1e3cad7 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:54:50 +0400 Subject: [PATCH 09/14] Mutation contracts will use `iterable` instead of `\LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location`. --- packages/documentator/src/Editor/Locations/Location.php | 4 ++-- packages/documentator/src/Markdown/Contracts/Extraction.php | 4 ++-- packages/documentator/src/Markdown/Contracts/Mutation.php | 4 ++-- packages/documentator/src/Markdown/Mutations/Changeset.php | 4 ++-- packages/documentator/src/Markdown/Mutations/Subset.php | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/documentator/src/Editor/Locations/Location.php b/packages/documentator/src/Editor/Locations/Location.php index aad2907f5..2e58222c1 100644 --- a/packages/documentator/src/Editor/Locations/Location.php +++ b/packages/documentator/src/Editor/Locations/Location.php @@ -8,7 +8,7 @@ use Traversable; /** - * @implements IteratorAggregate + * @implements IteratorAggregate */ readonly class Location implements IteratorAggregate { public function __construct( @@ -23,7 +23,7 @@ public function __construct( } /** - * @return Traversable + * @return Traversable */ #[Override] public function getIterator(): Traversable { diff --git a/packages/documentator/src/Markdown/Contracts/Extraction.php b/packages/documentator/src/Markdown/Contracts/Extraction.php index ce68fbaf3..27b75c5c2 100644 --- a/packages/documentator/src/Markdown/Contracts/Extraction.php +++ b/packages/documentator/src/Markdown/Contracts/Extraction.php @@ -2,12 +2,12 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Contracts; -use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; +use LastDragon_ru\LaraASP\Documentator\Editor\Coordinate; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; interface Extraction { /** - * @return iterable + * @return iterable> */ public function __invoke(Document $document): iterable; } diff --git a/packages/documentator/src/Markdown/Contracts/Mutation.php b/packages/documentator/src/Markdown/Contracts/Mutation.php index f98a44cbe..4270d93f0 100644 --- a/packages/documentator/src/Markdown/Contracts/Mutation.php +++ b/packages/documentator/src/Markdown/Contracts/Mutation.php @@ -2,12 +2,12 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Contracts; -use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; +use LastDragon_ru\LaraASP\Documentator\Editor\Coordinate; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; interface Mutation { /** - * @return iterable + * @return iterable, ?string}> */ public function __invoke(Document $document): iterable; } diff --git a/packages/documentator/src/Markdown/Mutations/Changeset.php b/packages/documentator/src/Markdown/Mutations/Changeset.php index 269038c45..d24af801e 100644 --- a/packages/documentator/src/Markdown/Mutations/Changeset.php +++ b/packages/documentator/src/Markdown/Mutations/Changeset.php @@ -2,7 +2,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations; -use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; +use LastDragon_ru\LaraASP\Documentator\Editor\Coordinate; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use Override; @@ -13,7 +13,7 @@ readonly class Changeset implements Mutation { public function __construct( /** - * @var iterable + * @var iterable, ?string}> */ protected iterable $changes, ) { diff --git a/packages/documentator/src/Markdown/Mutations/Subset.php b/packages/documentator/src/Markdown/Mutations/Subset.php index 54101875e..c011ef6db 100644 --- a/packages/documentator/src/Markdown/Mutations/Subset.php +++ b/packages/documentator/src/Markdown/Mutations/Subset.php @@ -2,7 +2,7 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations; -use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; +use LastDragon_ru\LaraASP\Documentator\Editor\Coordinate; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Extraction; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use Override; @@ -13,7 +13,7 @@ readonly class Subset implements Extraction { public function __construct( /** - * @var iterable + * @var iterable> */ protected iterable $extractions, ) { From 26bc11805ec57f4200f8e487a74971c5d466e209 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:19:08 +0400 Subject: [PATCH 10/14] Markdown node data can be nullable. --- .../documentator/src/Markdown/Data/Data.php | 19 ++++++++++++------- .../src/Markdown/Data/Nullable.php | 13 +++++++++++++ phpstan-baseline-well-known.neon | 7 +++++++ 3 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 packages/documentator/src/Markdown/Data/Nullable.php diff --git a/packages/documentator/src/Markdown/Data/Data.php b/packages/documentator/src/Markdown/Data/Data.php index f670a5ab5..cb85d921e 100644 --- a/packages/documentator/src/Markdown/Data/Data.php +++ b/packages/documentator/src/Markdown/Data/Data.php @@ -27,20 +27,25 @@ final public function __construct( * @return T */ public static function get(Node $node): mixed { - $data = $node->data->get(Package::Name.'.'.static::class, null); - $value = is_object($data) && is_a($data, static::class, true) - ? $data->value - : static::default($node); + // Cached? + $data = $node->data->get(Package::Name.'.'.static::class, null); - if ($data === null && $value !== null) { - static::set($node, $value); + if (is_object($data) && is_a($data, static::class, true)) { + return $data->value; + } + + // Default? + $value = static::default($node); + + if ($value === null && is_a(static::class, Nullable::class, true)) { + return static::set($node, $value); } if ($value === null) { throw new DataMissed($node, static::class); } - return $value; + return static::set($node, $value); } /** diff --git a/packages/documentator/src/Markdown/Data/Nullable.php b/packages/documentator/src/Markdown/Data/Nullable.php new file mode 100644 index 000000000..e871cb10a --- /dev/null +++ b/packages/documentator/src/Markdown/Data/Nullable.php @@ -0,0 +1,13 @@ + + */ +abstract readonly class Nullable extends Data { + // empty +} diff --git a/phpstan-baseline-well-known.neon b/phpstan-baseline-well-known.neon index bb594857d..96e0884d5 100644 --- a/phpstan-baseline-well-known.neon +++ b/phpstan-baseline-well-known.neon @@ -107,6 +107,13 @@ parameters: paths: - packages/documentator/src/Commands/Preprocess.php + # is_a(static::class, Class::class, true) false positive + # https://github.com/phpstan/phpstan/issues/1239 + - + message: '#^Parameter \#2 \$value of static method LastDragon_ru\\LaraASP\\Documentator\\Markdown\\Data\\Data::set\(\) expects T, null given\.$#' + paths: + - packages/documentator/src/Markdown/Data/Data.php + # (dev) Required for tests - message: "#^Class `[^`]+` must be marked by `@internal`\\.$#" From a083704df9ef005d39379a271a9bb9bbaa841280 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:26:38 +0400 Subject: [PATCH 11/14] `\LastDragon_ru\LaraASP\Documentator\Markdown\Document::__toString()` will return empty string if no lines. --- packages/documentator/src/Markdown/Document.php | 9 +++++++-- packages/documentator/src/Markdown/DocumentTest.php | 10 ++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/documentator/src/Markdown/Document.php b/packages/documentator/src/Markdown/Document.php index fa2cf35d9..ed636cded 100644 --- a/packages/documentator/src/Markdown/Document.php +++ b/packages/documentator/src/Markdown/Document.php @@ -109,7 +109,7 @@ public function mutate(Mutation|Extraction ...$mutations): self { $content = $mutation instanceof Extraction ? $document->getEditor()->extract($mutation($document)) : $document->getEditor()->mutate($mutation($document)); - $content = mb_trim((string) $content)."\n"; + $content = mb_trim((string) $content); $document = $this->markdown->parse($content, $document->path); } @@ -198,6 +198,11 @@ private function getSummaryNode(): ?Paragraph { #[Override] public function __toString(): string { - return implode("\n", $this->getLines())."\n"; + $lines = $this->getLines(); + $string = $lines !== [] + ? implode("\n", $this->getLines())."\n" + : ''; + + return $string; } } diff --git a/packages/documentator/src/Markdown/DocumentTest.php b/packages/documentator/src/Markdown/DocumentTest.php index 51fbf971c..7bbdee98c 100644 --- a/packages/documentator/src/Markdown/DocumentTest.php +++ b/packages/documentator/src/Markdown/DocumentTest.php @@ -444,6 +444,16 @@ public static function dataProviderToString(): array { MARKDOWN, new Changeset([[new Append(), 'fsdfsdfsdf']]), ], + 'Blank' => [ + '', + <<<'MARKDOWN' + + + + + MARKDOWN, + null, + ], ]; } // From aab18e652027ea5d98a7a05ceb3364dee0994b53 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:30:52 +0400 Subject: [PATCH 12/14] New extractions to get Document title, summary and body. --- .../src/Markdown/Mutations/Document/Body.php | 27 ++++ .../Markdown/Mutations/Document/BodyTest.php | 143 ++++++++++++++++++ .../Markdown/Mutations/Document/Summary.php | 25 +++ .../Mutations/Document/SummaryData.php | 60 ++++++++ .../Mutations/Document/SummaryTest.php | 112 ++++++++++++++ .../src/Markdown/Mutations/Document/Title.php | 25 +++ .../Markdown/Mutations/Document/TitleData.php | 51 +++++++ .../Markdown/Mutations/Document/TitleTest.php | 104 +++++++++++++ 8 files changed, 547 insertions(+) create mode 100644 packages/documentator/src/Markdown/Mutations/Document/Body.php create mode 100644 packages/documentator/src/Markdown/Mutations/Document/BodyTest.php create mode 100644 packages/documentator/src/Markdown/Mutations/Document/Summary.php create mode 100644 packages/documentator/src/Markdown/Mutations/Document/SummaryData.php create mode 100644 packages/documentator/src/Markdown/Mutations/Document/SummaryTest.php create mode 100644 packages/documentator/src/Markdown/Mutations/Document/Title.php create mode 100644 packages/documentator/src/Markdown/Mutations/Document/TitleData.php create mode 100644 packages/documentator/src/Markdown/Mutations/Document/TitleTest.php diff --git a/packages/documentator/src/Markdown/Mutations/Document/Body.php b/packages/documentator/src/Markdown/Mutations/Document/Body.php new file mode 100644 index 000000000..19d479747 --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Document/Body.php @@ -0,0 +1,27 @@ +node) ?? TitleData::get($document->node))?->getEndLine(); + $location = $endLine !== null + ? [[new Location(0, $endLine), null]] + : []; + + return $location; + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Document/BodyTest.php b/packages/documentator/src/Markdown/Mutations/Document/BodyTest.php new file mode 100644 index 000000000..9e9b3ee43 --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Document/BodyTest.php @@ -0,0 +1,143 @@ + + // ========================================================================= + #[DataProvider('dataProviderInvoke')] + public function testInvoke(string $expected, string $content): void { + $markdown = $this->app()->make(Markdown::class); + $document = $markdown->parse($content); + $actual = (string) $document->mutate(new Body()); + + self::assertSame($expected, $actual); + } + // + + // + // ========================================================================= + /** + * @return array + */ + public static function dataProviderInvoke(): array { + return [ + 'The # is not first' => [ + <<<'TEXT' + ## Header A + # Header B + + sdfsdfsdf + + TEXT, + <<<'MARKDOWN' + ## Header A + # Header B + + sdfsdfsdf + MARKDOWN, + ], + 'Summary is the first node' => [ + <<<'TEXT' + # Header + + sdfsdfsdf + + TEXT, + <<<'MARKDOWN' + fsdfsdfsdf + + # Header + + sdfsdfsdf + MARKDOWN, + ], + 'Quote before #' => [ + <<<'TEXT' + > Not a paragraph + + fsdfsdfsdf + + text text text + + TEXT, + <<<'MARKDOWN' + # Header + + > Not a paragraph + + fsdfsdfsdf + + text text text + MARKDOWN, + ], + 'Empty #' => [ + <<<'TEXT' + text text text + + text text text + + TEXT, + <<<'MARKDOWN' + # + + fsdfsdfsdf + + text text text + + text text text + MARKDOWN, + ], + 'Multiline summary' => [ + <<<'TEXT' + text text text + + text text text + + TEXT, + <<<'MARKDOWN' + + # Header + + fsdfsdfsdf + fsdfsdfsdf + + text text text + + text text text + MARKDOWN, + ], + 'Comments should be ignored' => [ + <<<'TEXT' + + + text text text + + TEXT, + <<<'MARKDOWN' + + + # Header + + + + summary + + + + text text text + MARKDOWN, + ], + ]; + } + // +} diff --git a/packages/documentator/src/Markdown/Mutations/Document/Summary.php b/packages/documentator/src/Markdown/Mutations/Document/Summary.php new file mode 100644 index 000000000..144bf6eee --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Document/Summary.php @@ -0,0 +1,25 @@ +node); + $location = $summary !== null ? [Location::get($summary)] : []; + + return $location; + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Document/SummaryData.php b/packages/documentator/src/Markdown/Mutations/Document/SummaryData.php new file mode 100644 index 000000000..e504bd7c7 --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Document/SummaryData.php @@ -0,0 +1,60 @@ + + */ +readonly class SummaryData extends Nullable { + #[Override] + protected static function default(Node $node): mixed { + // Document? + if (!($node instanceof Document)) { + return null; + } + + // Title? + $title = TitleData::get($node); + $found = $title === null; + $summary = null; + + foreach ($node->iterator(NodeIterator::FLAG_BLOCKS_ONLY) as $child) { + // Found? + if (!$found) { + $found = $title === $child; + + continue; + } + + // Document? + if ($child instanceof Document) { + continue; + } + + // Comment? + if ($child instanceof HtmlBlock && $child->getType() === HtmlBlock::TYPE_2_COMMENT) { + continue; + } + + // Title? + if ($child instanceof Paragraph) { + $summary = $child; + } + + // Only first needed + break; + } + + // Return + return $summary; + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Document/SummaryTest.php b/packages/documentator/src/Markdown/Mutations/Document/SummaryTest.php new file mode 100644 index 000000000..7043f81f6 --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Document/SummaryTest.php @@ -0,0 +1,112 @@ + + // ========================================================================= + #[DataProvider('dataProviderInvoke')] + public function testInvoke(string $expected, string $content): void { + $markdown = $this->app()->make(Markdown::class); + $document = $markdown->parse($content); + $actual = (string) $document->mutate(new Summary()); + + self::assertSame($expected, $actual); + } + // + + // + // ========================================================================= + /** + * @return array + */ + public static function dataProviderInvoke(): array { + return [ + 'The # is not first' => [ + '', + <<<'MARKDOWN' + ## Header A + # Header B + + sdfsdfsdf + MARKDOWN, + ], + 'Summary is the first node' => [ + <<<'MARKDOWN' + fsdfsdfsdf + + MARKDOWN, + <<<'MARKDOWN' + fsdfsdfsdf + + # Header + + sdfsdfsdf + MARKDOWN, + ], + 'Quote before #' => [ + '', + <<<'MARKDOWN' + # Header + + > Not a paragraph + + fsdfsdfsdf + MARKDOWN, + ], + 'Empty #' => [ + <<<'MARKDOWN' + fsdfsdfsdf + + MARKDOWN, + <<<'MARKDOWN' + # + + fsdfsdfsdf + MARKDOWN, + ], + 'Multiline' => [ + <<<'TEXT' + fsdfsdfsdf + fsdfsdfsdf + + TEXT, + <<<'MARKDOWN' + + # Header + + fsdfsdfsdf + fsdfsdfsdf + MARKDOWN, + ], + 'Comments should be ignored' => [ + <<<'TEXT' + fsdfsdfsdf + fsdfsdfsdf + + TEXT, + <<<'MARKDOWN' + + + # Header + + + + fsdfsdfsdf + fsdfsdfsdf + MARKDOWN, + ], + ]; + } + // +} diff --git a/packages/documentator/src/Markdown/Mutations/Document/Title.php b/packages/documentator/src/Markdown/Mutations/Document/Title.php new file mode 100644 index 000000000..59fcd938d --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Document/Title.php @@ -0,0 +1,25 @@ +node); + $location = $title !== null ? [Location::get($title)] : []; + + return $location; + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Document/TitleData.php b/packages/documentator/src/Markdown/Mutations/Document/TitleData.php new file mode 100644 index 000000000..9a618791c --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Document/TitleData.php @@ -0,0 +1,51 @@ + + */ +readonly class TitleData extends Nullable { + #[Override] + protected static function default(Node $node): mixed { + // Document? + if (!($node instanceof Document)) { + return null; + } + + // Search + $title = null; + + foreach ($node->iterator(NodeIterator::FLAG_BLOCKS_ONLY) as $child) { + // Document? + if ($child instanceof Document) { + continue; + } + + // Comment? + if ($child instanceof HtmlBlock && $child->getType() === HtmlBlock::TYPE_2_COMMENT) { + continue; + } + + // Title? + if ($child instanceof Heading && $child->getLevel() === 1) { + $title = $child; + } + + // Only first needed + break; + } + + // Return + return $title; + } +} diff --git a/packages/documentator/src/Markdown/Mutations/Document/TitleTest.php b/packages/documentator/src/Markdown/Mutations/Document/TitleTest.php new file mode 100644 index 000000000..cae3b0e15 --- /dev/null +++ b/packages/documentator/src/Markdown/Mutations/Document/TitleTest.php @@ -0,0 +1,104 @@ + + // ========================================================================= + #[DataProvider('dataProviderInvoke')] + public function testInvoke(string $expected, string $content): void { + $markdown = $this->app()->make(Markdown::class); + $document = $markdown->parse($content); + $actual = (string) $document->mutate(new Title()); + + self::assertSame($expected, $actual); + } + // + + // + // ========================================================================= + /** + * @return array + */ + public static function dataProviderInvoke(): array { + return [ + 'No #' => [ + '', + <<<'MARKDOWN' + ## Header A + # Header B + MARKDOWN, + ], + 'The # is not first' => [ + '', + <<<'MARKDOWN' + fsdfsdfsdf + + # Header + MARKDOWN, + ], + 'The # is empty' => [ + <<<'MARKDOWN' + # + + MARKDOWN, + <<<'MARKDOWN' + # + + fsdfsdfsdf + MARKDOWN, + ], + 'Empty line before #' => [ + <<<'MARKDOWN' + # Header + + MARKDOWN, + <<<'MARKDOWN' + + # Header + + fsdfsdfsdf + MARKDOWN, + ], + 'Comment before #' => [ + <<<'MARKDOWN' + # Header + + MARKDOWN, + <<<'MARKDOWN' + + + # Header + + fsdfsdfsdf + MARKDOWN, + ], + 'Setext' => [ + <<<'MARKDOWN' + Header + ===== + + MARKDOWN, + <<<'MARKDOWN' + + + Header + ===== + + fsdfsdfsdf + MARKDOWN, + ], + ]; + } + // +} From df8739633dd8d13dd438f62fd0151017ad1158e8 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 23 Jan 2025 09:33:03 +0400 Subject: [PATCH 13/14] Removed `\LastDragon_ru\LaraASP\Documentator\Markdown\Document::getTitle()`, `\LastDragon_ru\LaraASP\Documentator\Markdown\Document::getSummary()`, `\LastDragon_ru\LaraASP\Documentator\Markdown\Document::getBody()`. The new extractions will be used instead. --- .../documentator/src/Markdown/Document.php | 123 +-------- .../src/Markdown/DocumentTest.php | 248 ------------------ .../Markdown/Mutations/Heading/Renumber.php | 28 +- packages/documentator/src/Markdown/Utils.php | 26 ++ .../documentator/src/Markdown/UtilsTest.php | 50 ++++ .../IncludeDocBlock/Instruction.php | 6 +- .../IncludeDocumentList/Instruction.php | 14 +- .../IncludeDocumentList/Template/Document.php | 2 +- .../IncludePackageList/Instruction.php | 13 +- 9 files changed, 110 insertions(+), 400 deletions(-) diff --git a/packages/documentator/src/Markdown/Document.php b/packages/documentator/src/Markdown/Document.php index ed636cded..68f1bc7ca 100644 --- a/packages/documentator/src/Markdown/Document.php +++ b/packages/documentator/src/Markdown/Document.php @@ -2,42 +2,28 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown; -use Closure; use LastDragon_ru\LaraASP\Core\Path\FilePath; use LastDragon_ru\LaraASP\Documentator\Editor\Coordinate; use LastDragon_ru\LaraASP\Documentator\Editor\Editor; -use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Extraction; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Markdown; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Lines; -use League\CommonMark\Extension\CommonMark\Node\Block\Heading; -use League\CommonMark\Extension\CommonMark\Node\Block\HtmlBlock; -use League\CommonMark\Node\Block\AbstractBlock; use League\CommonMark\Node\Block\Document as DocumentNode; -use League\CommonMark\Node\Block\Paragraph; -use League\CommonMark\Node\Node; use Override; use Stringable; use function array_key_first; -use function array_key_last; use function array_values; use function count; use function implode; -use function is_int; -use function mb_ltrim; use function mb_trim; -use function str_ends_with; -use function str_starts_with; // todo(documentator): There is no way to convert AST back to Markdown yet // https://github.com/thephpleague/commonmark/issues/419 class Document implements Stringable { - private ?Editor $editor = null; - private ?string $title = null; - private ?string $summary = null; + private ?Editor $editor = null; public function __construct( protected readonly Markdown $markdown, @@ -51,50 +37,6 @@ public function isEmpty(): bool { return !$this->node->hasChildren() && count($this->node->getReferenceMap()) === 0; } - /** - * Returns the first `# Header` if present. - */ - public function getTitle(): ?string { - if ($this->title === null) { - $title = $this->getFirstNode(Heading::class, static fn ($n) => $n->getLevel() === 1); - $title = $this->getBlockText($title) ?? ''; - $title = mb_trim(mb_ltrim("{$title}", '#')); - $this->title = $title; - } - - return $this->title !== '' ? $this->title : null; - } - - /** - * Returns the first paragraph if present. - */ - public function getSummary(): ?string { - if ($this->summary === null) { - $summary = $this->getSummaryNode(); - $summary = $this->getBlockText($summary); - $summary = mb_trim("{$summary}"); - $this->summary = $summary; - } - - return $this->summary !== '' ? $this->summary : null; - } - - /** - * Returns the rest of the document text after the summary. - */ - public function getBody(): ?string { - $summary = $this->getSummaryNode(); - $start = $summary?->getEndLine(); - $end = array_key_last($this->getLines()); - $body = $start !== null && is_int($end) - ? $this->getText(new Location($start + 1, $end)) - : null; - $body = mb_trim((string) $body); - $body = $body !== '' ? $body : null; - - return $body; - } - /** * @param iterable $location */ @@ -133,69 +75,6 @@ protected function getEditor(): Editor { return $this->editor; } - /** - * @template T of Node - * - * @param class-string $class - * @param Closure(T): bool|null $filter - * @param Closure(Node): bool|null $skip - * - * @return ?T - */ - private function getFirstNode(string $class, ?Closure $filter = null, ?Closure $skip = null): ?Node { - $node = null; - - foreach ($this->node->children() as $child) { - // Comment? - if ( - $child instanceof HtmlBlock - && str_starts_with($child->getLiteral(), '') - ) { - continue; - } - - // Skipped? - if ($skip !== null && $skip($child)) { - continue; - } - - // Wanted? - if ($child instanceof $class) { - if ($filter === null || $filter($child)) { - $node = $child; - } - - break; - } - - // End - break; - } - - return $node; - } - - private function getBlockText(?AbstractBlock $node): ?string { - $startLine = $node?->getStartLine(); - $endLine = $node?->getEndLine(); - $location = $startLine !== null && $endLine !== null - ? new Location($startLine, $endLine) - : null; - $text = $location !== null - ? $this->getText($location) - : null; - - return $text; - } - - private function getSummaryNode(): ?Paragraph { - $skip = static fn ($node) => $node instanceof Heading && $node->getLevel() === 1; - $node = $this->getFirstNode(Paragraph::class, skip: $skip); - - return $node; - } - #[Override] public function __toString(): string { $lines = $this->getLines(); diff --git a/packages/documentator/src/Markdown/DocumentTest.php b/packages/documentator/src/Markdown/DocumentTest.php index 7bbdee98c..fc74e0916 100644 --- a/packages/documentator/src/Markdown/DocumentTest.php +++ b/packages/documentator/src/Markdown/DocumentTest.php @@ -20,33 +20,6 @@ final class DocumentTest extends TestCase { // // ========================================================================= - #[DataProvider('dataProviderGetTitle')] - public function testGetTitle(?string $expected, string $content): void { - $markdown = $this->app()->make(Markdown::class); - $document = $markdown->parse($content); - $actual = $document->getTitle(); - - self::assertSame($expected, $actual); - } - - #[DataProvider('dataProviderGetSummary')] - public function testGetSummary(?string $expected, string $content): void { - $markdown = $this->app()->make(Markdown::class); - $document = $markdown->parse($content); - $actual = $document->getSummary(); - - self::assertSame($expected, $actual); - } - - #[DataProvider('dataProviderGetBody')] - public function testGetBody(?string $expected, string $content): void { - $markdown = $this->app()->make(Markdown::class); - $document = $markdown->parse($content); - $actual = $document->getBody(); - - self::assertSame($expected, $actual); - } - #[DataProvider('dataProviderIsEmpty')] public function testIsEmpty(bool $expected, string $content): void { $markdown = $this->app()->make(Markdown::class); @@ -106,227 +79,6 @@ public function testToString(string $expected, string $content, ?Mutation $mutat // // ========================================================================= - /** - * @return array - */ - public static function dataProviderGetTitle(): array { - return [ - 'No #' => [ - null, - <<<'MARKDOWN' - ## Header A - # Header B - MARKDOWN, - ], - 'The # is not first' => [ - null, - <<<'MARKDOWN' - fsdfsdfsdf - - # Header - MARKDOWN, - ], - 'The # is empty' => [ - null, - <<<'MARKDOWN' - # - - fsdfsdfsdf - MARKDOWN, - ], - 'Empty line before #' => [ - 'Header', - <<<'MARKDOWN' - - # Header - - fsdfsdfsdf - MARKDOWN, - ], - 'Comment before #' => [ - 'Header', - <<<'MARKDOWN' - - - # Header - - fsdfsdfsdf - MARKDOWN, - ], - ]; - } - - /** - * @return array - */ - public static function dataProviderGetSummary(): array { - return [ - 'The # is not first' => [ - null, - <<<'MARKDOWN' - ## Header A - # Header B - - sdfsdfsdf - MARKDOWN, - ], - 'Summary is the first node' => [ - 'fsdfsdfsdf', - <<<'MARKDOWN' - fsdfsdfsdf - - # Header - - sdfsdfsdf - MARKDOWN, - ], - 'Quote before #' => [ - null, - <<<'MARKDOWN' - # Header - - > Not a paragraph - - fsdfsdfsdf - MARKDOWN, - ], - 'Empty #' => [ - 'fsdfsdfsdf', - <<<'MARKDOWN' - # - - fsdfsdfsdf - MARKDOWN, - ], - 'Multiline' => [ - <<<'TEXT' - fsdfsdfsdf - fsdfsdfsdf - TEXT, - <<<'MARKDOWN' - - # Header - - fsdfsdfsdf - fsdfsdfsdf - MARKDOWN, - ], - 'Comments should be ignored' => [ - <<<'TEXT' - fsdfsdfsdf - fsdfsdfsdf - TEXT, - <<<'MARKDOWN' - - - # Header - - - - fsdfsdfsdf - fsdfsdfsdf - MARKDOWN, - ], - ]; - } - - /** - * @return array - */ - public static function dataProviderGetBody(): array { - return [ - 'The # is not first' => [ - null, - <<<'MARKDOWN' - ## Header A - # Header B - - sdfsdfsdf - MARKDOWN, - ], - 'Summary is the first node' => [ - <<<'TEXT' - # Header - - sdfsdfsdf - TEXT, - <<<'MARKDOWN' - fsdfsdfsdf - - # Header - - sdfsdfsdf - MARKDOWN, - ], - 'Quote before #' => [ - null, - <<<'MARKDOWN' - # Header - - > Not a paragraph - - fsdfsdfsdf - - text text text - MARKDOWN, - ], - 'Empty #' => [ - <<<'TEXT' - text text text - - text text text - TEXT, - <<<'MARKDOWN' - # - - fsdfsdfsdf - - text text text - - text text text - MARKDOWN, - ], - 'Multiline summary' => [ - <<<'TEXT' - text text text - - text text text - TEXT, - <<<'MARKDOWN' - - # Header - - fsdfsdfsdf - fsdfsdfsdf - - text text text - - text text text - MARKDOWN, - ], - 'Comments should be ignored' => [ - <<<'TEXT' - - - text text text - TEXT, - <<<'MARKDOWN' - - - # Header - - - - summary - - - - text text text - MARKDOWN, - ], - ]; - } - /** * @return array */ diff --git a/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php b/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php index 40893561d..9d5a53441 100644 --- a/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php +++ b/packages/documentator/src/Markdown/Mutations/Heading/Renumber.php @@ -5,19 +5,14 @@ use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Location as LocationData; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; -use LastDragon_ru\LaraASP\Documentator\Utils\Text; +use LastDragon_ru\LaraASP\Documentator\Markdown\Utils; use Override; -use function array_map; -use function array_slice; -use function implode; -use function mb_ltrim; use function mb_rtrim; use function mb_strlen; -use function mb_trim; use function min; use function str_repeat; -use function str_starts_with; +use function str_replace; /** * Updates all headings levels. @@ -52,23 +47,18 @@ public function __invoke(Document $document): iterable { foreach ($nodes as $node) { $location = LocationData::get($node); $heading = $document->getText($location); - $setext = $this->isSetext($heading); + $setext = Utils::isHeadingSetext($heading); $level = min(static::MaxLevel, $node->getLevel() + $diff); $eols = str_repeat("\n", mb_strlen($heading) - mb_strlen(mb_rtrim($heading, "\n"))); - $text = mb_trim($heading); - $lines = $setext - ? array_slice(Text::getLines($text), 0, -1) - : [mb_trim($text, '#')]; - $lines = array_map(mb_trim(...), $lines); + $text = Utils::getHeadingText($heading); $prefix = ''; $suffix = ''; if ($setext && $level <= 2) { - $text = implode("\n", $lines); $suffix = "\n".str_repeat($level === 1 ? '=' : '-', 5); } else { $prefix = str_repeat('#', $level).' '; - $text = implode(' ', $lines); + $text = str_replace("\n", ' ', $text); } yield [$location, $prefix.$text.$suffix.$eols]; @@ -89,12 +79,4 @@ protected function nodes(Document $document, int &$initial = 0): iterable { return $nodes; } - - private function isAtx(string $heading): bool { - return str_starts_with(mb_ltrim($heading), '#'); - } - - private function isSetext(string $heading): bool { - return !$this->isAtx($heading); - } } diff --git a/packages/documentator/src/Markdown/Utils.php b/packages/documentator/src/Markdown/Utils.php index 563e30d55..8cf699d7d 100644 --- a/packages/documentator/src/Markdown/Utils.php +++ b/packages/documentator/src/Markdown/Utils.php @@ -3,12 +3,18 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown; use LastDragon_ru\LaraASP\Core\Path\FilePath; +use LastDragon_ru\LaraASP\Documentator\Utils\Text; use League\CommonMark\Extension\Table\TableCell; use League\CommonMark\Node\Block\AbstractBlock; use League\CommonMark\Node\Node; use League\CommonMark\Util\UrlEncoder; +use function array_map; +use function array_slice; use function filter_var; +use function implode; +use function mb_ltrim; +use function mb_trim; use function parse_url; use function preg_match; use function str_contains; @@ -127,4 +133,24 @@ public static function isPathToSelf(Document $document, FilePath|string $path): return $is; } + + public static function isHeadingAtx(string $heading): bool { + return str_starts_with(mb_ltrim($heading), '#'); + } + + public static function isHeadingSetext(string $heading): bool { + return !static::isHeadingAtx($heading); + } + + public static function getHeadingText(string $heading): string { + $heading = mb_trim($heading); + $setext = static::isHeadingSetext($heading); + $lines = $setext + ? array_slice(Text::getLines($heading), 0, -1) + : [mb_trim($heading, '#')]; + $lines = array_map(mb_trim(...), $lines); + $text = implode($setext ? "\n" : '', $lines); + + return $text; + } } diff --git a/packages/documentator/src/Markdown/UtilsTest.php b/packages/documentator/src/Markdown/UtilsTest.php index ba7bf3936..447b3e8a4 100644 --- a/packages/documentator/src/Markdown/UtilsTest.php +++ b/packages/documentator/src/Markdown/UtilsTest.php @@ -52,4 +52,54 @@ public function testIsPathToSelf(): void { self::assertTrue(Utils::isPathToSelf($a, new FilePath('a.md'))); self::assertTrue(Utils::isPathToSelf($a, new FilePath('../to/a.md'))); } + + public function testIsHeadingAtx(): void { + self::assertTrue(Utils::isHeadingAtx('# Header')); + self::assertFalse( + Utils::isHeadingAtx( + <<<'MARKDOWN' + Header + ------ + MARKDOWN, + ), + ); + } + + public function testIsHeadingSetext(): void { + self::assertFalse(Utils::isHeadingSetext('# Header')); + self::assertTrue( + Utils::isHeadingSetext( + <<<'MARKDOWN' + Header + ------ + MARKDOWN, + ), + ); + } + + public function testGetHeadingText(): void { + self::assertSame( + 'Header', + Utils::getHeadingText( + <<<'MARKDOWN' + # Header + + MARKDOWN, + ), + ); + self::assertSame( + <<<'TEXT' + Header + line b + TEXT, + Utils::getHeadingText( + <<<'MARKDOWN' + Header + line b + ====== + + MARKDOWN, + ), + ); + } } diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocBlock/Instruction.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocBlock/Instruction.php index dfc532e8d..15eecd6b8 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocBlock/Instruction.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocBlock/Instruction.php @@ -5,6 +5,8 @@ use Generator; use LastDragon_ru\LaraASP\Core\Utils\Cast; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\Body; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\Summary; use LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Dependency; use LastDragon_ru\LaraASP\Documentator\Processor\Dependencies\FileReference; use LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\File; @@ -59,8 +61,8 @@ public function __invoke(Context $context, InstructionParameters $parameters): G // Parse $result = match (true) { $parameters->summary && $parameters->description => $document, - $parameters->summary => $context->toSplittable($document)->getSummary() ?? '', - $parameters->description => $context->toSplittable($document)->getBody() ?? '', + $parameters->summary => (string) $context->toSplittable($document)->mutate(new Summary()), + $parameters->description => (string) $context->toSplittable($document)->mutate(new Body()), default => '', }; diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/Instruction.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/Instruction.php index 358c005e2..b5d04e565 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/Instruction.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/Instruction.php @@ -5,6 +5,10 @@ use Generator; use Iterator; use LastDragon_ru\LaraASP\Core\Utils\Cast; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\Summary; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\Title; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\Unlink; +use LastDragon_ru\LaraASP\Documentator\Markdown\Utils; use LastDragon_ru\LaraASP\Documentator\PackageViewer; use LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Dependency; use LastDragon_ru\LaraASP\Documentator\Processor\Dependencies\FileIterator; @@ -23,7 +27,9 @@ use function array_filter; use function max; +use function mb_trim; use function min; +use function str_replace; use function usort; /** @@ -85,10 +91,14 @@ public function __invoke(Context $context, InstructionParameters $parameters): G // Add $document = $context->toSplittable($document); + $summary = mb_trim((string) $document->mutate(new Summary())); + $title = mb_trim((string) $document->mutate(new Title(), new Unlink())); + $title = mb_trim(str_replace("\n", ' ', Utils::getHeadingText($title))); + $title = $title === '' ? Text::getPathTitle($file->getName()) : $title; $documents[] = new TemplateDocument( $context->file->getRelativePath($file), - $document->getTitle() ?? Text::getPathTitle($file->getName()), - $document->getSummary(), + $title, + $summary, ); } diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/Template/Document.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/Template/Document.php index bbe68b780..69768e531 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/Template/Document.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludeDocumentList/Template/Document.php @@ -8,7 +8,7 @@ public function __construct( public FilePath $path, public string $title, - public ?string $summary, + public string $summary, ) { // empty } diff --git a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludePackageList/Instruction.php b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludePackageList/Instruction.php index 75ac1f470..9ed110970 100644 --- a/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludePackageList/Instruction.php +++ b/packages/documentator/src/Processor/Tasks/Preprocess/Instructions/IncludePackageList/Instruction.php @@ -5,6 +5,10 @@ use Generator; use Iterator; use LastDragon_ru\LaraASP\Core\Utils\Cast; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\Summary; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Document\Title; +use LastDragon_ru\LaraASP\Documentator\Markdown\Mutations\Link\Unlink; +use LastDragon_ru\LaraASP\Documentator\Markdown\Utils; use LastDragon_ru\LaraASP\Documentator\Package; use LastDragon_ru\LaraASP\Documentator\PackageViewer; use LastDragon_ru\LaraASP\Documentator\Processor\Contracts\Dependency; @@ -25,6 +29,8 @@ use LastDragon_ru\LaraASP\Documentator\Utils\Text; use Override; +use function mb_trim; +use function str_replace; use function trigger_deprecation; use function usort; @@ -98,10 +104,13 @@ public function __invoke(Context $context, InstructionParameters $parameters): G $content = $context->toSplittable($content); $upgrade = $package->getFilePath('UPGRADE.md'); $upgrade = Cast::toNullable(File::class, yield new Optional(new FileReference($upgrade))); + $title = mb_trim((string) $content->mutate(new Title(), new Unlink())); + $title = mb_trim(str_replace("\n", ' ', Utils::getHeadingText($title))); + $title = $title === '' ? Text::getPathTitle($package->getName()) : $title; $packages[] = [ 'path' => $context->file->getRelativePath($readme), - 'title' => $content->getTitle() ?? Text::getPathTitle("{$package->getName()}.md"), - 'summary' => $content->getSummary(), + 'title' => $title, + 'summary' => mb_trim((string) $content->mutate(new Summary())), 'upgrade' => $upgrade !== null ? $context->file->getRelativePath($upgrade) : null, From 2b922d32496404b40a55ba8c137e1fa17d8556cb Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 23 Jan 2025 10:46:58 +0400 Subject: [PATCH 14/14] Generated parser priority fix. --- .../src/Markdown/Extensions/Generated/Extension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/documentator/src/Markdown/Extensions/Generated/Extension.php b/packages/documentator/src/Markdown/Extensions/Generated/Extension.php index 019a6b9d1..591638f2f 100644 --- a/packages/documentator/src/Markdown/Extensions/Generated/Extension.php +++ b/packages/documentator/src/Markdown/Extensions/Generated/Extension.php @@ -21,7 +21,7 @@ class Extension implements ExtensionInterface { #[Override] public function register(EnvironmentBuilderInterface $environment): void { $environment - ->addBlockStartParser(new ParserStart(), 100) + ->addBlockStartParser(new ParserStart()) ->addRenderer(Node::class, new Renderer()); } }