From d30f70083f0748d2dfe602eddd44ebc1578d8d2d Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Mon, 16 Oct 2023 12:46:59 +0200 Subject: [PATCH] New rule: Ensure link are at the bottom of the file (#1542) --- docs/rules.md | 7 +++ src/Rule/EnsureLinkBottom.php | 66 ++++++++++++++++++++ tests/Rule/EnsureLinkBottomTest.php | 94 +++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 src/Rule/EnsureLinkBottom.php create mode 100644 tests/Rule/EnsureLinkBottomTest.php diff --git a/docs/rules.md b/docs/rules.md index dbc3e788..52c091a7 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -22,6 +22,7 @@ * [ensure_bash_prompt_before_composer_command](#ensure_bash_prompt_before_composer_command) * [ensure_exactly_one_space_before_directive_type](#ensure_exactly_one_space_before_directive_type) * [ensure_exactly_one_space_between_link_definition_and_link](#ensure_exactly_one_space_between_link_definition_and_link) +* [ensure_link_bottom](#ensure_link_bottom) * [ensure_link_definition_contains_valid_url](#ensure_link_definition_contains_valid_url) * [ensure_order_of_code_blocks_in_configuration_block](#ensure_order_of_code_blocks_in_configuration_block) * [ensure_php_reference_syntax](#ensure_php_reference_syntax) @@ -356,6 +357,12 @@ composer require symfony/var-dumper .. _DOCtor-RST: https://github.com/OskarStark/DOCtor-RST ``` +## `ensure_link_bottom` + + > _Ensure link lines are at the bottom of the file._ + +#### Groups [`@Symfony`] + ## `ensure_link_definition_contains_valid_url` > _Ensure link definition contains valid link._ diff --git a/src/Rule/EnsureLinkBottom.php b/src/Rule/EnsureLinkBottom.php new file mode 100644 index 00000000..f254114b --- /dev/null +++ b/src/Rule/EnsureLinkBottom.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Rule; + +use App\Attribute\Rule\Description; +use App\Rst\RstParser; +use App\Value\Lines; +use App\Value\NullViolation; +use App\Value\RuleGroup; +use App\Value\Violation; +use App\Value\ViolationInterface; + +#[Description('Ensure link lines are at the bottom of the file.')] +class EnsureLinkBottom extends AbstractRule implements LineContentRule +{ + public static function getGroups(): array + { + return [RuleGroup::Symfony()]; + } + + public function check(Lines $lines, int $number, string $filename): ViolationInterface + { + $lines->seek($number); + $line = $lines->current(); + + if (!RstParser::isLinkDefinition($line)) { + return NullViolation::create(); + } + + while ($lines->valid()) { + $lines->next(); + + if (!$lines->valid()) { + break; + } + + $current = $lines->current(); + + if ($current->isBlank()) { + continue; + } + + if (!RstParser::isLinkDefinition($current)) { + return Violation::from( + 'Please move link definition to the bottom of the page', + $filename, + $number + 1, + $line, + ); + } + } + + return NullViolation::create(); + } +} diff --git a/tests/Rule/EnsureLinkBottomTest.php b/tests/Rule/EnsureLinkBottomTest.php new file mode 100644 index 00000000..97cd18cf --- /dev/null +++ b/tests/Rule/EnsureLinkBottomTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Tests\Rule; + +use App\Rule\EnsureLinkBottom; +use App\Tests\RstSample; +use App\Tests\UnitTestCase; +use App\Value\NullViolation; +use App\Value\Violation; +use App\Value\ViolationInterface; + +final class EnsureLinkBottomTest extends UnitTestCase +{ + /** + * @test + * + * @dataProvider checkProvider + */ + public function check(ViolationInterface $expected, RstSample $sample): void + { + self::assertEquals( + $expected, + (new EnsureLinkBottom())->check($sample->lines, $sample->lineNumber, 'filename'), + ); + } + + /** + * @return \Generator + */ + public static function checkProvider(): iterable + { + yield [ + NullViolation::create(), + new RstSample('temp'), + ]; + + yield [ + NullViolation::create(), + new RstSample([ + '', + '.. _`first-link`: https://foo.bar', + ], 1), + ]; + + yield [ + NullViolation::create(), + new RstSample([ + '', + '.. _`first-link`: https://foo.bar', + '.. _`second-link`: https://foo.baz', + ], 1), + ]; + + yield [ + Violation::from( + 'Please move link definition to the bottom of the page', + 'filename', + 2, + '.. _`first-link`: https://foo.bar', + ), + new RstSample([ + '', + '.. _`first-link`: https://foo.bar', + 'text after link', + ], 1), + ]; + + yield [ + Violation::from( + 'Please move link definition to the bottom of the page', + 'filename', + 2, + '.. _`first-link`: https://foo.bar', + ), + new RstSample([ + '', + '.. _`first-link`: https://foo.bar', + '', + 'text after link', + ], 1), + ]; + } +}