From 4b8b192b48f1df54f3c96f5860b0d15654df53b9 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:33:40 +0400 Subject: [PATCH] Mutations will not touch links label. --- .../src/Markdown/Location/Location.php | 12 ++-- .../src/Markdown/Mutations/Move.php | 58 +++++++++---------- .../src/Markdown/Mutations/MoveTest.php | 4 +- .../Markdown/Mutations/ReferencesInline.php | 28 +++------ .../Mutations/ReferencesInlineTest.php | 4 +- .../Markdown/Mutations/ReferencesPrefix.php | 28 ++++----- .../Mutations/ReferencesPrefixTest.php | 6 +- packages/documentator/src/Markdown/Utils.php | 53 +++++++++-------- 8 files changed, 88 insertions(+), 105 deletions(-) diff --git a/packages/documentator/src/Markdown/Location/Location.php b/packages/documentator/src/Markdown/Location/Location.php index ec56b41e2..1d1efbe86 100644 --- a/packages/documentator/src/Markdown/Location/Location.php +++ b/packages/documentator/src/Markdown/Location/Location.php @@ -11,12 +11,12 @@ */ readonly class Location implements IteratorAggregate { public function __construct( - private int $startLine, - private int $endLine, - private int $offset = 0, - private ?int $length = null, - private int $startLinePadding = 0, - private ?int $internalPadding = null, + public int $startLine, + public int $endLine, + public int $offset = 0, + public ?int $length = null, + public int $startLinePadding = 0, + public ?int $internalPadding = null, ) { // empty } diff --git a/packages/documentator/src/Markdown/Mutations/Move.php b/packages/documentator/src/Markdown/Mutations/Move.php index fbdac694d..ac5bab3be 100644 --- a/packages/documentator/src/Markdown/Mutations/Move.php +++ b/packages/documentator/src/Markdown/Mutations/Move.php @@ -4,25 +4,25 @@ use LastDragon_ru\LaraASP\Core\Utils\Path; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; +use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Data; +use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Offset; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Nodes\Reference\Block as Reference; 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 League\CommonMark\Extension\Table\TableCell; use League\CommonMark\Node\Block\Document as DocumentNode; -use League\CommonMark\Node\Inline\Text; use Override; use function dirname; use function filter_var; +use function ltrim; use function mb_substr; use function preg_match; use function preg_quote; use function rawurldecode; use function rtrim; -use function str_replace; use function str_starts_with; use function trim; @@ -78,45 +78,41 @@ public function __invoke(Document $document, DocumentNode $node): array { } // Changes - $text = null; - $origin = trim((string) $document->getText($location)); + $text = null; if ($resource instanceof Link || $resource instanceof Image) { - $title = (string) $resource->getTitle(); - $titleWrapper = mb_substr(rtrim(mb_substr($origin, 0, -1)), -1, 1); - $label = (string) Utils::getChild($resource, Text::class)?->getLiteral(); - $target = rawurldecode($resource->getUrl()); - $target = Path::getPath($docDirectory, $target); - $target = Path::getRelativePath($newDirectory, $target); - $targetWrap = (bool) preg_match('/^!?\['.preg_quote($label, '/').']\(\s*getText($location)); + $titleValue = (string) $resource->getTitle(); + $titleWrapper = mb_substr(rtrim(mb_substr($origin, 0, -1)), -1, 1); + $title = Utils::getLinkTitle($resource, $titleValue, $titleWrapper); + $targetValue = rawurldecode($resource->getUrl()); + $targetValue = Path::getPath($docDirectory, $targetValue); + $targetValue = Path::getRelativePath($newDirectory, $targetValue); + $targetWrap = mb_substr(ltrim(ltrim($origin, '(')), 0, 1) === '<'; + $target = Utils::getLinkTarget($resource, $targetValue, $targetWrap); + $text = $title ? "({$target} {$title})" : "({$target})"; } } elseif ($resource instanceof Reference) { + $origin = trim((string) $document->getText($location)); $label = $resource->getLabel(); - $title = $resource->getTitle(); + $titleValue = $resource->getTitle(); $titleWrapper = mb_substr($origin, -1, 1); - $target = rawurldecode($resource->getDestination()); - $target = Path::getPath($docDirectory, $target); - $target = Path::getRelativePath($newDirectory, $target); + $title = Utils::getLinkTitle($resource, $titleValue, $titleWrapper); + $targetValue = rawurldecode($resource->getDestination()); + $targetValue = Path::getPath($docDirectory, $targetValue); + $targetValue = Path::getRelativePath($newDirectory, $targetValue); $targetWrap = (bool) preg_match('/^\['.preg_quote($resource->getLabel(), '/').']:\s+ ') text [title](<../from/file/a> (title)) + text [_`link`_](../from/file/b ' ') text [title](<../from/file/a> (title)) [mailto](mailto:mail@example.com) text [absolute](/path/to/file 'title') text [external](https://example.com/). @@ -203,7 +203,7 @@ public static function dataProviderInvoke(): array { # General Text text [tel](tel:+70000000000 "title") text [link](./file/a) - text [link](file/b ' <title> ') text [title](<./file/a> (title)) + text [_`link`_](file/b ' <title> ') text [title](<./file/a> (title)) [mailto](mailto:mail@example.com) text [absolute](/path/to/file 'title') text [external](https://example.com/). diff --git a/packages/documentator/src/Markdown/Mutations/ReferencesInline.php b/packages/documentator/src/Markdown/Mutations/ReferencesInline.php index b9b0db4c5..507d99fe9 100644 --- a/packages/documentator/src/Markdown/Mutations/ReferencesInline.php +++ b/packages/documentator/src/Markdown/Mutations/ReferencesInline.php @@ -3,19 +3,18 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; +use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Data; +use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Offset; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Nodes\Reference\Block as Reference; 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 League\CommonMark\Extension\Table\TableCell; use League\CommonMark\Node\Block\Document as DocumentNode; -use League\CommonMark\Node\Inline\Text; use Override; use function rawurldecode; -use function str_replace; /** * Inlines all references. @@ -45,22 +44,13 @@ public function __invoke(Document $document, DocumentNode $node): array { $text = null; if ($reference instanceof Link || $reference instanceof Image) { - $title = (string) $reference->getTitle(); - $label = (string) Utils::getChild($reference, Text::class)?->getLiteral(); - $target = rawurldecode($reference->getUrl()); + $offset = Data::get($reference, Offset::class); + $location = $offset !== null ? Utils::getOffsetLocation($location, $offset) : null; - if (Utils::getContainer($reference) instanceof TableCell) { - $title = str_replace('|', '\\|', $title); - $label = str_replace('|', '\\|', $label); - $target = str_replace('|', '\\|', $target); - } - - $text = $title - ? Utils::getLink('[%s](%s %s)', $label, $target, $title, null, null) - : Utils::getLink('[%s](%s)', $label, $target, '', null, null); - - if ($reference instanceof Image) { - $text = "!{$text}"; + if ($location !== null) { + $title = Utils::getLinkTitle($reference, (string) $reference->getTitle()); + $target = Utils::getLinkTarget($reference, rawurldecode($reference->getUrl())); + $text = $title ? "({$target} {$title})" : "({$target})"; } } elseif ($reference instanceof Reference) { $text = ''; @@ -68,7 +58,7 @@ public function __invoke(Document $document, DocumentNode $node): array { // skipped } - if ($text !== null) { + if ($location !== null && $text !== null) { $changes[] = [$location, $text ?: null]; } } diff --git a/packages/documentator/src/Markdown/Mutations/ReferencesInlineTest.php b/packages/documentator/src/Markdown/Mutations/ReferencesInlineTest.php index bf9d8d481..16241b106 100644 --- a/packages/documentator/src/Markdown/Mutations/ReferencesInlineTest.php +++ b/packages/documentator/src/Markdown/Mutations/ReferencesInlineTest.php @@ -22,7 +22,7 @@ public function testInvoke(): void { <<<'MARKDOWN' # Header - Text text [link](https://example.com) text text [link][link] text + Text text [link](https://example.com) text text [`link`][link] text text text ![image][image] text text. ![image][image] @@ -55,7 +55,7 @@ public function testInvoke(): void { <<<'MARKDOWN' # Header - Text text [link](https://example.com) text text [link](https://example.com) text + Text text [link](https://example.com) text text [`link`](https://example.com) text text text ![image](https://example.com "image") text text. ![image](https://example.com "image") diff --git a/packages/documentator/src/Markdown/Mutations/ReferencesPrefix.php b/packages/documentator/src/Markdown/Mutations/ReferencesPrefix.php index 89d63bc4e..288bdf143 100644 --- a/packages/documentator/src/Markdown/Mutations/ReferencesPrefix.php +++ b/packages/documentator/src/Markdown/Mutations/ReferencesPrefix.php @@ -3,6 +3,8 @@ namespace LastDragon_ru\LaraASP\Documentator\Markdown\Mutations; use LastDragon_ru\LaraASP\Documentator\Markdown\Contracts\Mutation; +use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Data; +use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Offset; use LastDragon_ru\LaraASP\Documentator\Markdown\Document; use LastDragon_ru\LaraASP\Documentator\Markdown\Location\Location; use LastDragon_ru\LaraASP\Documentator\Markdown\Nodes\Reference\Block as Reference; @@ -10,14 +12,11 @@ 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 League\CommonMark\Extension\Table\TableCell; use League\CommonMark\Node\Block\Document as DocumentNode; -use League\CommonMark\Node\Inline\Text; use Override; use function hash; use function mb_strlen; -use function str_replace; use function uniqid; /** @@ -56,19 +55,14 @@ public function __invoke(Document $document, DocumentNode $node): array { $text = null; if ($reference instanceof Link || $reference instanceof Image) { - $label = (string) Utils::getChild($reference, Text::class)?->getLiteral(); - $target = Utils::getReference($reference)?->getLabel(); - $target = "{$prefix}-{$target}"; - - if (Utils::getContainer($reference) instanceof TableCell) { - $label = str_replace('|', '\\|', $label); - $target = str_replace('|', '\\|', $target); - } - - $text = Utils::getLink('[%s][%s]', $label, $target, '', null, null); - - if ($reference instanceof Image) { - $text = "!{$text}"; + $offset = Data::get($reference, Offset::class); + $location = $offset !== null ? Utils::getOffsetLocation($location, $offset) : null; + + if ($location !== null) { + $target = Utils::getReference($reference)?->getLabel(); + $target = "{$prefix}-{$target}"; + $target = Utils::escapeTextInTableCell($reference, $target); + $text = "[{$target}]"; } } elseif ($reference instanceof Reference) { $coordinate = null; @@ -90,7 +84,7 @@ public function __invoke(Document $document, DocumentNode $node): array { // skipped } - if ($text !== null) { + if ($location !== null && $text !== null) { $changes[] = [$location, $text]; } } diff --git a/packages/documentator/src/Markdown/Mutations/ReferencesPrefixTest.php b/packages/documentator/src/Markdown/Mutations/ReferencesPrefixTest.php index f6d9d0629..e781cbfec 100644 --- a/packages/documentator/src/Markdown/Mutations/ReferencesPrefixTest.php +++ b/packages/documentator/src/Markdown/Mutations/ReferencesPrefixTest.php @@ -20,7 +20,7 @@ final class ReferencesPrefixTest extends TestCase { private const Markdown = <<<'MARKDOWN' # Header - Text text [link](https://example.com) text text [link][link] text + Text text [link](https://example.com) text text [`link`][link] text text text ![image][image] text text. ![image][image] @@ -54,7 +54,7 @@ public function testInvoke(): void { <<<'MARKDOWN' # Header - Text text [link](https://example.com) text text [link][a282e9c32e7eee65-link] text + Text text [link](https://example.com) text text [`link`][a282e9c32e7eee65-link] text text text ![image][a282e9c32e7eee65-image] text text. ![image][a282e9c32e7eee65-image] @@ -91,7 +91,7 @@ public function testInvokeExplicit(): void { <<<'MARKDOWN' # Header - Text text [link](https://example.com) text text [link][prefix-link] text + Text text [link](https://example.com) text text [`link`][prefix-link] text text text ![image][prefix-image] text text. ![image][prefix-image] diff --git a/packages/documentator/src/Markdown/Utils.php b/packages/documentator/src/Markdown/Utils.php index 7d92eed50..3566bbfd3 100644 --- a/packages/documentator/src/Markdown/Utils.php +++ b/packages/documentator/src/Markdown/Utils.php @@ -11,6 +11,7 @@ use LastDragon_ru\LaraASP\Documentator\Markdown\Data\Padding as DataPadding; use LastDragon_ru\LaraASP\Documentator\Markdown\Location\Location; use League\CommonMark\Extension\CommonMark\Node\Inline\AbstractWebResource; +use League\CommonMark\Extension\Table\TableCell; use League\CommonMark\Node\Block\AbstractBlock; use League\CommonMark\Node\Block\Document; use League\CommonMark\Node\Node; @@ -19,10 +20,9 @@ use function mb_strpos; use function preg_match; -use function sprintf; use function str_contains; +use function str_replace; use function strtr; -use function trim; /** * @internal @@ -143,6 +143,17 @@ public static function getLocation(Node $node): ?Location { return $location; } + public static function getOffsetLocation(Location $location, int $offset): Location { + return new Location( + $location->startLine, + $location->endLine, + $location->offset + $offset, + $location->length !== null ? $location->length - $offset : $location->length, + $location->startLinePadding, + $location->internalPadding, + ); + } + public static function isReference(AbstractWebResource $node): bool { return self::getReference($node) !== null; } @@ -154,33 +165,16 @@ public static function getReference(AbstractWebResource $node): ?ReferenceInterf return $reference; } - public static function getLink( - string $format, - string $label, - string $target, - string $title, - ?bool $wrapTarget, - ?string $titleWrapper, - ): string { - $label = self::getLinkLabel($label); - $title = self::getLinkTitle($title, $titleWrapper); - $target = self::getLinkTarget($target, $wrapTarget); - $link = trim(sprintf($format, $label, $target, $title)); - - return $link; - } - - private static function getLinkLabel(string $label): string { - return strtr($label, ['[' => '\\\\[', ']' => '\\\\]']); - } - - private static function getLinkTarget(string $target, ?bool $wrap): string { - return ($wrap ?? preg_match('/\s/u', $target)) + public static function getLinkTarget(Node $container, string $target, ?bool $wrap = null): string { + $target = ($wrap ?? preg_match('/\s/u', $target)) ? '<'.strtr($target, ['<' => '\\<', '>' => '\\>']).'>' : UrlEncoder::unescapeAndEncode($target); + $target = self::escapeTextInTableCell($container, $target); + + return $target; } - private static function getLinkTitle(string $title, ?string $wrapper = null): string { + public static function getLinkTitle(Node $container, string $title, ?string $wrapper = null): string { if (!$title) { return ''; } @@ -201,10 +195,19 @@ private static function getLinkTitle(string $title, ?string $wrapper = null): st "'" => "'".strtr($title, $wrappers['"'])."'", default => '('.strtr($title, $wrappers[')']).')', }; + $title = self::escapeTextInTableCell($container, $title); return $title; } + public static function escapeTextInTableCell(Node $container, string $text): string { + if (self::getContainer($container) instanceof TableCell) { + $text = str_replace('|', '\\|', $text); + } + + return $text; + } + /** * @template T of object *